Mod Switch – Menu Classes and Datastore Needs

UT3 LogoIn the previous article I talked about how to get the stand-alone mod to compile. When we left off you should have had the ability to compile your code and it should output the .u file in the proper directory. Beyond that, nothing has changed. Running UT3 with the mod switch should only show you UT’s defaults menus. We are going to be continuing forward now, pressing into the UScript classes that we will need to be able to replace the menus and the related topics. In the next entry we will be focusing on the front end map and the kismet related to it. =) That is primarily pictures though I will be doing my part to expand where I find it necessary.

Similar to the saying in wood and metal shop, measure twice – cut once, we are going to research our needs before we jump into the code. It is imperative that you don’t skip through this portion of the tutorial, because I will be going over some of the underlying features in the classes and why I am making the choices I am in this tutorial that may impact your implementation options.

Taking a peek into the distributed items (UTFrontEnd.ut3, UTUI_Scenes_ChrisBLayout.upk for starters), shows us that Unreal is expecting a certain format to our development of the main menu. The menu is actually triggered within the title screen, which is triggered by kismet on the event that the level has loaded. This tells us that our own frontend map that will have to trigger the appropriate UIScene and that we will need our own UIScene for the frontend menu, at least.

Stopping here will work. I have taken the route of putting off redesigning and changing the theme of the underlying configuration menus for lack of time and need. You can surely replace them all as your mod requires. I will be focusing on how to get these two things settled and cover the issues that arise because of them. From what I discuss here you can surely take over and achieve everything you need to for your own menu. There is, however, one further issue. If you have already followed the code dumps within the community you have undoubtedly crossed into a very spotty landscape. The primary issue is that the code is copied from other classes, without thought first of derivation. The secondary issue is related to the title screen.

UT3 provides a lot of functionality to us through, so called, Native classes. These classes are coupled with the underlying engine, bypassing the UScript interpreter. To the lay developer this is quite meaningless, but to all of us within the unreal development community that care about performance and abilities, it is a flag to tell us there is something else going on under the hood. The specifics do not matter, the reason I point this out is that if you were to look at the code for UTUIFrontEnd_MainMenu you will see that the class is extending UTUIFrontEnd_BasicMenu which extends UTUIFrontEnd, a native class. When I was first working on this I was incredibly irritated by functionality and functions not being executed. I had followed the tutorials that were being distributed and had failed to realize this hierarchy until a few days had gone by. The problem is that one of the distributions creates a new UIScene class which does not get to take advantage of the derived capabilites. We should surely note this down for our later work, as it has a side effect of decreasing the work we need to do. Welcome to OOP =)

With regards to the title screen, this will not be apparent to anyone until they ignore it. Epic has taken a number of liberties with the new menu system. Let it be known here and now that if you are really bent on it you can ignore the rest of this paragraph, but this is actually a juicy tid-bit that you might get a giggle out of. You can actually bypass the login menu as well as the CDKey check by leaving them out and directly linking to your Main Menu. I don’t suggest you do, in fact I strongly urge you not to as I am pretty sure there will be some mentioning of this in an EULA somewhere or another. This was really a bit amazing to me initially, but tough titties I guess. We’ll just go ahead and add that to our checklist.

We need to add this to our checklist so that we can leverage the underlying functionality, forwarding to our main menu and bypassing the ut3 menu. Kismet will only forward us into the menu hierarchy itself, a single destination within the tree. The Login and CDKey scenes are driven by landing on the main menu from another scene, which explains why they act the way they do.

A final poorly discussed checklist item is the datastore. When working with the UIList element it is expecting a datastore and we will be happy to oblige. The datastore we will be using is going to be simple though. Here is our checklist.

  • New Frontend Map
  • New UIScene for the MainMenu
  • New UIScene for the TitleScreen
  • New DataStore for the MainMenu UIList

We will be going into the map and kismet later; likewise for the creation of the UIScenes. At this point we need to create the three classes that we need for our menu and title screen. We will begin with the title screen because it is dirt simple. My files are named EUIFrontEnd_MainMenu.uc, EUIDataStore_MenuItems.uc and EUIFrontEnd_TitleScreen.uc, following the standards set by the Epic code base. Lets go ahead and open up TitleScreen and make our lives a little easier.

[Source]/ EUIFrontEnd_TitleScreen.uc

class EUIFrontEnd_TitleScreen extends UTUIFrontEnd_TitleScreen;

defaultproperties
{
    MainMenuScene="End3rUIAssets.Scenes.MainMenu"
}

What this is doing is letting the underlying TitleScreen class handle it’s forwarding by use f the MainMenuScene variable, conveniently left out for us to leverage, and change what it loads once a key has been hit, as you would expect. I strongly encourage you to code with this style of replacement where applicable instead of doing what is called hard coding and dropping your classes directly into your code. As a quick alert, I would like to stress that I did not pull that variable out of my own ass. It is already present in the underlying class and being used for what we are asking of it.

Now we have to create the class for our main menu. The version of the main menu that we are going to use is going to be based on a simple datastore string array. This is not a localized array, we will address localization in a couple days.

[Source]/EUIFrontEnd_MainMenu.uc

class EUIFrontEnd_MainMenu extends UTUIFrontEnd_MainMenu;

const EMAINMENU_OPTION_INSTANTACTION = 0;
const EMAINMENU_OPTION_MULTIPLAYER = 1;
const EMAINMENU_OPTION_COMMUNITTY = 2;
const EMAINMENU_OPTION_SETTINGS = 3;
const EMAINMENU_OPTION_EXIT = 4;

This is a series of const variables to help the readability of our code. The options that I will be implementing are Instant Action, Multiplayer, Community, Settings and Exit. We will only need to implement a single function here, simply overwriting the UT Main Menu function called OnSelectItem.

[Source]/EUIFrontEnd_MainMenu.uc

function OnSelectItem(int PlayerIndex=0)
{
    switch(MenuList.GetCurrentItem())
    {
        case EMAINMENU_OPTION_INSTANTACTION:
            OpenSceneByName(InstantActionScene);
            break;

        case EMAINMENU_OPTION_MULTIPLAYER:
            if ( CheckLinkConnectionAndError() && CheckOnlinePrivilegeAndError() )
                OpenSceneByName(MultiplayerScene);

            break;

        case EMAINMENU_OPTION_COMMUNITTY:
            OpenSceneByName(CommunityScene);
            break;

        case EMAINMENU_OPTION_SETTINGS:
            OpenSceneByName(SettingsScene);
            break;

        case EMAINMENU_OPTION_EXIT:
            OnMenu_ExitGame();
            break;
    }
}

As you can see here there are a few pretty interesting statements being shown. This function is executed when you click on a menu option in the drop down list. The MenuList.GetCurrentItem method is derived from the underlying class and will give you the index of the item that the used has clicked on, based on the list that is provided in the datastore.  I pass this value into a switch block and test against the defined constants we had above (instead of just throwing the index up there, that would have been absurd. Alternatively you could use an enum, but I am simply following the standards Epic has set). InstantActionScene, MultiplayerScene, CommunityScene, and SettingsScene are also derived from the UT Main Menu class, and are variables holding the class names of the scenes you want to change. You can save yourself a lot of trouble and just simply add a statement in your defaultsettings block to redefine these variables.

Do note that Exit executes a derived function and multiplayer has two tests before it actually executes the scene. You can add a message box to the else there if you want to be kind and let the user know that they have failed at life, but the tests themselves trigger the message boxes so you shouldnt need to.

And now for the moment you have all been dreading. The Datastore. Because of the monumental size of the file you will be able to find a link to it below. I don’t know how realistic it is to just toss you the link to the file, but if it didn’t bloat the page so much I would surely have put it here. In fact, you know what, nix all of that, I’m going to paste it in line.

[Source]/EUIDataStore_MenuItems.uc

class EUIDataStore_MenuItems extends UTUIDataStore_StringList;

defaultproperties
{
    StringData(0)=(Tag="MainMenu",ColumnHeaderText="Main Menu",Strings=("Instant Action", "Multiplayer", "Community", "Settings", "Exit"))
    Tag="EMenuItems"
}

Wait what? Oh uh, sorry yea, did I mention that this was not as complicated as any of us had made it out to be? StringList is actually a datastore class for organizing arrays of strings for use within the UI system of Unreal. You can leverage it by simply creating a new element in the StringData array and giving it a new tag and some entries. The entries will be displayed in this order and will be explicitly shown in this order.

The final thing to do is registering the datastore globally. Open up your [Config]/DefaultEngine.ini file and go down to the bottom. You can put this anywhere, but bottom is easy. We are going to add a new block and a statement to this document. Once we have completed this change you will need to delete the UTEngine.ini file so it can be recreated, and you will need to do so every time that you make a change to your default ini’s as we discussed previously. I strongly urge you to keep your changes inside your default ini’s to avoid missing something when you finally distribute your mod.

[Config]/DefaultEngine.ini

[Engine.DataStoreClient]
+GlobalDataStoreClasses=End3r.EUIDataStore_MenuItems

With that we are done. This phase is complete, we can now move into the UIScenes and setting up the Map. If you are ready, please build your code and let me know if there are any errors/issues that arise. I have tested this with 5 of my tester buddies but issues may slip through.

11 thoughts on “Mod Switch – Menu Classes and Datastore Needs”

  1. Just wanted to let you know about a typo. This sentence:

    “My files are named EFrontEnd_MainMenu.uc, EUIDataStore_MenuItems.uc and EFrontEnd_TitleScreen.uc, following the standards set by the Epic code base.”

    should be:

    “My files are named EUIFrontEnd_MainMenu.uc, EUIDataStore_MenuItems.uc and EUIFrontEnd_TitleScreen.uc, following the standards set by the Epic code base.”

    You were missing the “UI” in two of the file names.

    Thanks for the tutorials!

  2. class EUIFrontEnd_TitleScreen extends UTUIFrontEnd_TitleScreen;

    defaultproperties
    {
    MainMenuScene=”End3rUIAssets.Scenes.MainMenu”
    }

    The MainMenuScene default property described here has got me a bit lost. Is its creation described somewhere or is it something we should have already created?

  3. I’ve been struggling to follow this tutorial for about a week now. Every time I try running the mod switch, Unreal 3 seems to be overlooking my new Config settings. It strikes me that this is the case since I’m not even getting the video skip I included in DefaultEngine.ini

    I’m running the shortcut commandline as such:
    “[UT Install Directory]Unreal Tournament 3BinariesUT3.exe” -mod=AvariceGame -log -useunpublished

    Where AvariceGame is the name of the folder my mod is packaged in, located in “My DocumentsMy GamesUnreal Tournament 3”

    I’ve got 1.3 installed, but I really don’t know what the deal is. I used EnvyEntry.ut3 as the startup map and changed the name to AvariceFrontEnd.ut3, and I’m pretty sure that should give me a blank map to begin with, but to no avail. Any suggestions?

  4. Does this apply only to the UT3 specific game or for the UDK too? because i’m having problems with the Datastore compilation it ends up with 0 errors but 1 warning that says this stuff:

    C:DevelopmentUDKUDK-2009-11-2DevelopmentSrcMyMenuClassesUIDataStore_MyStringStore.uc(5) : Warning, Import failed for ‘StringData’: property is config (Check to see if the property is listed in the DefaultProperties. It should only be listed in the specific .ini/.int file)
    Scripts successfully compiled – saving package ‘C:DevelopmentUDKUDK-2009-11-2BinariesWin32….UTGameScriptMyMenu.u’

    Warning/Error Summary
    ———————
    C:DevelopmentUDKUDK-2009-11-2DevelopmentSrcMyMenuClassesUIDataStore_MyStringStore.uc(5) : Warning, Import failed for ‘StringData’: property is config (Check to see if the property is listed in the DefaultProperties. It should only be listed in the specific .ini/.int file)

    Success – 0 error(s), 1 warning(s)
    Execution of commandlet took: 6.71 seconds

    [COMMANDLET ‘UDK.exe make’ SUCCEEDED] dicembre 2, 9:32

    and it ends up in this way into the DataString Browser in Kismet:
    http://img248.imageshack.us/img248/2919/udkproblem.png

    i followed the whole tutorial but i end up only with this issue…the rest compiles just fine
    any ideas?

  5. Yeah this is pretty much driving me out of my mind FireFox. Have you been able to get this to work with the UDK problem since you posted your last comment?

  6. Ill go ahead and check this out. The UDK was released long after this tutorial was written, but i would like to say yes. Ill let you know, hopefully by the end of the week =)

Leave a Reply