Announcement

Collapse
No announcement yet.

Editing GFxUDKFrontEnd to add system settings

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Editing GFxUDKFrontEnd to add system settings

    I'm trying to add a menu in GFxUDKFrontEnd to provide system settings. I originally started with my own custom menu implementation which I was able to get working with relative ease, but I decided to go back to the UDK-provided menus because I didn't want to have to rewrite all of the multiplayer/instant action menus.

    My gut instinct is to just derive GFxUDKFrontEnd_SettingsBase and hack away at it, but everything is tied to the UTGameSettings class, which seems to be loaded in GFxUDKFrontEnd_LaunchGame. I'm having a hard time understanding this specific flow (read: I understand the MVC paradigm; just not this specific UTGameSettings system). I want to create a new dummy class to take the place of UTGameSettings, but this feels like it's really dumb because I don't want to be modifying game settings anyways. These are system settings which require their own special handling.

    I thought about going into the Flash side and modifying the "settings" swf in udk_assets to just statically add in the menu items I want, but I can't make heads or tails of it, and I suck at Flash. Also, if I do this, localization and modification later will be a total *****.

    I feel like I'm going about this the wrong way. There's no feasible solution that I can think of, let alone a good one. Anyone have any thoughts, or even better any example UnrealScript/Flash for this?

    #2
    I would suggest making your own, but using the GFxUDKFrontEnd as a reference

    Comment


      #3
      That's just not feasible for a project that needs to have multiplayer support, multiple game modes, and basically use everything that GFxUDKFrontEnd already provides. It's reinventing the wheel for no reason. The only thing I'm missing is this system settings menu which, even if I have to use one of the methods above to make, will be far less costly to make than restarting the whole thing.

      Comment


        #4
        Anyone else?

        Comment


          #5
          Have you tried adding datasource entries for your new pages?

          I have talked to a number of people who have gone down the road you describe (myself included) to just add one or two new windows and maybe some further configuration. It has not worked out for anyone, for a number of reasons, primarily because of how it was architected, as its not a simply copypasta or couple of ini entries to extend. The system requires some considerable work to understand. Start with the Scaleform tutorials, then move to the code and Flash files to see what triggers what and when.

          You may be the first to pull it off, though. msg me on AIM if you would like to chat.

          Comment


            #6
            Originally posted by Bob_Gneu View Post
            Have you tried adding datasource entries for your new pages?
            Yeah, that was pretty much my first thing to do. My impression is though that some setup is done by the LaunchGame code. Here's the flow of how you get to the game settings view:
            • MainMenu
              • InstantAction extends LaunchGame
                • Settings extends SettingsBase


            But the flow I want for my new menu is:
            • MainMenu
              • SystemSettings extends SettingsBase


            I bolded LaunchGame because I think it's the spot where some work is done which needed before SettingsBase can work (i.e. creating a DataStore or something, which I don't fully understand).

            Originally posted by Bob_Gneu View Post
            I have talked to a number of people who have gone down the road you describe (myself included) to just add one or two new windows and maybe some further configuration. It has not worked out for anyone, for a number of reasons, primarily because of how it was architected, as its not a simply copypasta or couple of ini entries to extend. The system requires some considerable work to understand. Start with the Scaleform tutorials, then move to the code and Flash files to see what triggers what and when.
            Yeah, I've been messing around with ini entries, some relatively simple code changes, and changing values while debugging, but haven't come up with anything which seems to have helped much.

            Originally posted by Bob_Gneu View Post
            You may be the first to pull it off, though. msg me on AIM if you would like to chat.
            Thanks, I added you on MSN instead (I don't really use AIM). I'll post back any useful info given to me back here so anyone searching for the same thing can find it.

            Comment


              #7
              Setting up a new ListOption in GFxUDKFrontEnd

              Hey guys! Did you make any progress yet? I'm trying to do the same thing, but I'm not there yet. But to simply get the entry for the menu I can give you some clues, which might then lead you the way. Which is left are the settings themselves via the Datastore System.

              Edit: I AM there now. This is what you get, if you read on:

              But first a word of caution: usually I'm the non-destructive type and would recommend deriving your classes from the existing GFxUDKFrontEnd_ classes and setting up your own configuration files. But since there are so much dependencies and private final functions involved, it would overcomplicate things just for the sake of explaining the basic principle here.
              To get to your custom "SettingsView" from within the main menu this is what you have to do:

              In UTGame create a class called "GFxUDKFrontEnd_SystemSettings". This is what I have:
              Code:
              class GFxUDKFrontEnd_SystemSettings extends GFxUDKFrontEnd_ServerSettings;
              
                  //Your Code here
              
              DefaultProperties
              {
              }
              For this example I simply route to GFxUDKFrontEnd_ServerSettings to see something in my menu.

              Next open up GFxUDKFrontEnd.uc and add a reference to the class in the variable declaration section (always without the "..." of course!):
              Code:
              class GFxUDKFrontEnd extends GFxMoviePlayer
                  config(UI);
              
              var GFxUDKFrontEnd_SystemSettings SystemSettingsView;
              ...
              We will be adding some more to this class. In the function PushViewByName add a case in the switch statement for the new menu entry:
              Code:
                      ...
                  case ( 'SystemSettings' ):
                      ConfigureTargetView( SystemSettingsView );
                      break;
                      ...
              In the WidgetInitialized event we kind of do the same:
              Code:
                      ...
                  case ('SystemSettings'):
                          if (SystemSettingsView == none)
                          {
                              SystemSettingsView = GFxUDKFrontEnd_SystemSettings(Widget);
                              ConfigureView(SystemSettingsView, WidgetName, WidgetPath);
                              bResult = true;
                          }
                          break;
                      ...
              One last thing for this class: bind the widget in the defaultproperties.
              Code:
              defaultproperties
              {    
                  // Views & Dialogs
                  ...
                  WidgetBindings.Add((WidgetName="SystemSettings",WidgetClass=class'GFxUDKFrontEnd_SystemSettings')  )
              ...
              Next up is the GFxUDKFrontEnd_MainMenu class. Add a function that will be called, when the item is clicked:
              Code:
              /** 
               *  Pushes the Settings view on to the stack. This method is fired
               *  by the list's OnListItemPress() listener.
               */
              function Select_SystemSettings()
              {    
                  MenuManager.PushViewByName('SystemSettings');
              }
              Again, add a case in "private final function OnListItemPress(GFxClikWidget.EventData ev)":
              Code:
                      ...
                  case('SystemSettings'):    
                      Select_SystemSettings();   
                      break;
                      ...
              We are almost done. We need to add the new view to the DefaultUI.ini
              Code:
              ;setup the link to the SWF movie file
              [UTGame.GFxUDKFrontEnd]
              ...
              +ViewData=(ViewName="SystemSettings",SWFName="udk_settings.swf",DependantViews=())
              
              ;add the entry to the main menu
              [UTGame.GFxUDKFrontEnd_MainMenu]
              ...
              +ListOptions=(OptionName="SystemSettings",OptionLabel="SYSTEM SETTINGS",OptionDesc="Modify the system settings.")   ;You might want to localize this
              
              ;give it a nice Title
              [UTGame.GFxUDKFrontEnd_SystemSettings]
              +ViewTitle="SYSTEM SETTINGS"
              Compile the scripts and run the game or open the editor and the UDKFrontEndMap and play it. The main menu should now have an entry "SYSTEM SETTINGS" and a nice description. When you click it you'll get, not yet to the settings we want, but the server settings. What we can learn from this though is, that the work has to be done in our very own GFxUDKFrontEnd_SystemSettings class! That's my guess and as of now I will be working that out. The DataStoreSystem is indeed overly complicated and mind-boggling for a beginner like me.

              As a last reminder: If you don't want to touch the UDK files you'll be doing a lot of copying and pasting, all of the GFxUDKFrontEnd classes an renaming them and every reference in them to your own classes. Just derivng some didn't work for me, because sooner or later you'll probably get a type mismatch error in the configureView function. You can then setup your own ini and localization files. If you built your own GFxYourGameFrontEnd class you will need to set it as the movie class in the Open Gfx Movie Node in Kismet! And of course add your project to the defaultengine.ini under [UnrealEd.EditorEngine] for it to compile

              I hope this was of any help for someone and get a few more people to delve into this matter and continue from here. There doesn't seem to be floating much knowledge around regarding the GFxUDKFrontend.

              Comment


                #8
                Setting up a custom system settings screen in GFxUDKFrontEnd

                If you followed my last post so far, we should move on. What we've done so far is really just a matter of minutes once you know, what you're doing. I will now show you the way I implemented my own custom system settings menu in the GFxUDKFrontEnd. For now, it only displays our desired options, but they have no effect in this stage, if you manipulate them.
                On a side note: Even though I was a professional technical artist for several years, I'm by no means a full fledged programmer. That means, if you know UnrealScript or any other language a bit, or at least the overall concept of scripting, you should be able to follow and better yet: understand what's going on. I, personally, am very glad I use nFringe as a development environment, it helps a lot with the understanding.
                As I suggested in the last post, we should put our efforts in our very own GFxUDKFrontEnd_SystemSettings class. But before I give you a fairly large block of code to swallow, I think it's better to start at the bottom and move our way up.
                Open up the DefaultGame.ini file. First we are going to decide which options we want to appear on our system settings screen. I chose resolution, fullscreen and an input field for let's say a filepath for example. Go to the part were all the options are and somewhere add the following menu options:
                Code:
                ;///////////////
                ; Custom SystemSettings Menu
                ;///////////////
                [Resolution UTUIDataProvider_MenuOption]
                +OptionSet=System
                DataStoreMarkup=<UTStringList:Resolution>
                bRemoveOn360=true
                bRemoveOnPS3=true
                
                [Fullscreen UTUIDataProvider_MenuOption]
                +OptionSet=System
                DataStoreMarkup=<UTStringList:Fullscreen>
                bRemoveOn360=true
                bRemoveOnPS3=true
                
                [CustomInput UTUIDataProvider_MenuOption]
                +OptionSet=System
                DataStoreMarkup=<Registry:CustomInput>
                OptionType=UTOT_EditBox
                EditBoxMaxLength=512
                bRemoveOn360=true
                bRemoveOnPS3=true
                In configuration files the semicolon is used for comments. There we have our 3 options. They all belong to the new OptionSet "System". We don't want them to appear on consoles. So where are the new options getting their data from? That's what the DataStoreMarkup is for. The last one, the input, will add a KeyValuePair to the registry datastore, where the entered text will be the value and "CustomInput" will be the key. The first two options will get their data from the UTStringList. So let's go there and let it know! Still in the DefaultGame.ini search for [UTGame.UTUIDataStore_StringList] and add the following:
                Code:
                [UTGame.UTUIDataStore_StringList]
                ;... some other entries
                +StringData=(Tag="Resolution",DefaultValueIndex=3)
                +StringData=(Tag="Fullscreen",DefaultValueIndex=1)
                The + means they will be added to the already existing array. You should count the entries and start with 0 for the first, because in the next step you'll need to know which indices our new options will have! (The DefaultValueIndex is just a personal choice out of the entries we will define.) We are already done with the DefaultGame.ini. Open the utgame.int which you'll find in the localization folder. Find the [UTUIDataStore_StringList] block. As you can see, there already are entries for "Fullscreen" and "Resolution". But I can tell you right know, something is wrong and that are the indices from before! See to it, that the index of each of our options matches the rank of the StringData we added in the DefaultGame.ini and is unique. Start counting with 0. So for me it looks like this:
                Code:
                [UTUIDataStore_StringList]
                StringData[0]=(ColumnHeaderText="Match Type",Strings=("LAN","Internet"))
                StringData[1]=(ColumnHeaderText="Match Type",Strings=("System Link","Player","Ranked"))
                StringData[2]=(ColumnHeaderText="Match Type",Strings=("LAN","Internet"))
                StringData[3]=(ColumnHeaderText="Match Type",Strings=("System Link","Player","Ranked"))
                StringData[4]=(ColumnHeaderText="Bot Team",Strings=("Random","Iron Guard","Ronin","Krall","Liandri","Necris"))
                StringData[5]=(ColumnHeaderText="Demo Recording",Strings=("No","Yes"))
                StringData[6]=(ColumnHeaderText="Button Preset",Strings=("Preset 1", "Preset 2", "Preset 3"))
                StringData[7]=(ColumnHeaderText="Resolution",Strings=("800x600","960x720","1024x768","1280x720","1600x1200","1920x1080"))
                StringData[8]=(ColumnHeaderText="Fullscreen",Strings=("Fullscreen","Windowed"))
                StringData[9]=(ColumnHeaderText="Splitscreen",Strings=("No", "Yes"))
                StringData[10]=(ColumnHeaderText="Uniform",Strings=("Facemask", "Helmet", "Goggles", "Torso", "Shoulder Pads", "Arms", "Thighs", "Boots"))
                StringData[12]=(ColumnHeaderText="Server Mode",Strings=("Listen","Dedicated"))
                You'll also notice, that I added a resolution setting ("1920x1080"). The "ColumnHeaderText" seems to be a leftover from the old UI system. You'll find a lot garbage of this kind. The Strings=() are organized as arrays, so each item within that has an index. Now you can see, that I chose DefaultValueIndex=3 for resolution, which means "1280x720" if you start your count with 0 as always. Now look for a nice place in the utgame.int where we can give our options friendly names. I feel better if I fit it into the other options. So there you go:
                Code:
                ;///////////////
                ; Custom SystemSettings Menu
                ;///////////////
                [Fullscreen UTUIDataProvider_MenuOption]
                FriendlyName=Fullscreen
                Description=Whether the program runs in 'fullscreen' or 'windowed' mode.
                
                [Resolution UTUIDataProvider_MenuOption]
                FriendlyName=Screen Resolution
                Description=Set the screen resolution according to your device.
                
                [CustomInput UTUIDataProvider_MenuOption]
                FriendlyName=Custom Input
                Description=Demonstration of an Editbox.
                That's it for the easy part. Now the big chunk of code to gulp. Get back to our GFxUDKFrontEnd_SystemSettings class, as we will rewrite that. Open up wide, here it comes:
                Code:
                class GFxUDKFrontEnd_SystemSettings extends GFxUDKFrontEnd_SettingsBase;
                
                /** Defines the set of data/options which we will retrieve for this view. */
                function SetSelectedOptionSet()
                {
                    SelectedOptionSet = "System";
                }
                
                /** Saves the state of the settings to the GameSettings object. */
                function SaveState()
                {
                    local int i;
                    local int StepperSelectedIndex;
                    local String ValueToSave;
                    local String ControlType;
                    local String SettingName;
                    local GFxObject Data;
                    local DataStoreClient DSClient;
                    local string LocationPart, RelevantPart;
                    local UIDataStore_Registry Registry;
                    local UTUIDataStore_StringList StringListDataStore;
                
                    for (i = 0; i < SettingsList.Length; i++)
                    {   
                        // Retrieve the data at the index from the list's dataProvider.
                        Data = ListDataProvider.GetElementObject(i);
                        
                        // Get the datastore tag and its path in seperate variables
                        SplitMarkupString(i, RelevantPart, LocationPart);
                
                        // Check what type of control we're dealing with.
                        ControlType = Data.GetString("control");
                        switch(ControlType)
                        {
                            case("stepper"):                                
                                // Retrieve the name for this setting to retrieve its index.
                                SettingName = Data.GetString("name");
                
                                // Retrieve the selectedIndex for this optionStepper.
                                StepperSelectedIndex = Data.GetFloat("optIndex");
                
                                // Get the global data store client
                                DSClient = class'UIInteraction'.static.GetDataStoreClient();
                                StringListDataStore = UTUIDataStore_StringList(DSClient.FindDataStore('UTStringList'));
                
                                if (SettingName == "Resolution")
                                {
                                    // Index encoding current selected resolution in <UTStringList:Resolution>
                                    StringListDataStore.SetCurrentValueIndex('Resolution', StepperSelectedIndex);
                                }
                                else if (SettingName == "Fullscreen")
                                {
                                    // Fullscreen=0 Windowed=1
                                    StringListDataStore.SetCurrentValueIndex('Fullscreen', StepperSelectedIndex);
                                }
                                break;
                            
                            case("input"):
                                SettingName = StrinG(SettingsList[i].Name);
                                ValueToSave = Data.GetString("text");
                
                                if (LocationPart == "Registry")
                                {
                                    Registry = UIDataStore_Registry(class'UIRoot'.static.StaticResolveDataStore('Registry'));
                
                                    Registry.SetData(RelevantPart,ValueToSave);
                                }
                            default:
                                break;
                        }
                    }
                }
                
                /** Updates the list's dataProvider. */
                function UpdateListDataProvider()
                {
                    local byte i;
                    local string MenuOptionName;
                    local string ControlType;
                    local string DefaultValue;
                    local int DefaultIndex;
                    local GFxObject RendererDataProvider;
                    local GFxObject DataProvider;
                    local GFxObject TempObj;
                    local string LocationPart, RelevantPart;
                    local int StringIter, ChoiceIter;
                    local bool bFoundDefault;
                
                    local DataStoreClient DSClient;
                    local UTUIDataStore_StringList StringListDataStore;
                
                    local UIDataStore_Registry Registry;
                
                    Registry = UIDataStore_Registry(class'UIRoot'.static.StaticResolveDataStore('Registry'));
                
                    DSClient = class'UIInteraction'.static.GetDataStoreClient();
                    StringListDataStore = UTUIDataStore_StringList(DSClient.FindDataStore('UTStringList'));
                    
                    DataProvider = Outer.CreateArray();
                    for ( i = 0; i < SettingsList.Length; i++)
                    {        
                        bFoundDefault = false;
                
                        // Create a AS object to hold the data for SettingsList[i].
                        TempObj = CreateObject("Object");              
                
                        // We need to keep track of the name so that we can update Min/Max players
                        // if they are changed and become conflicting. OnSettingListChange will be
                        // fired by the list, which will check which control fired the event and
                        // update both steppers if one of them is the source.
                        TempObj.SetString("name", String(SettingsList[i].Name));
                
                        // Parse SettingsList[i] into TempObj.
                        TempObj.SetString("label", Caps(SettingsList[i].FriendlyName));
                
                        ControlType = FindControlByUTClassName(SettingsList[i].OptionType);
                        TempObj.SetString("control", ControlType);  
                
                        // Get the datastore tag and its path in seperate variables
                        SplitMarkupString(i, RelevantPart, LocationPart);
                
                        if (ControlType == "stepper")
                        {
                            RendererDataProvider = Outer.CreateArray();  
                            MenuOptionName = String(SettingsList[i].Name);
                            switch ( MenuOptionName )
                            {
                                case "Resolution":
                                    for (StringIter = 0; StringIter < StringListDataStore.StringData.Length; StringIter++)
                                    {
                                        // Populate the server types with the friendly names of different resolutions
                                        if (string(StringListDataStore.StringData[StringIter].Tag) == RelevantPart)
                                        {
                                            for (ChoiceIter = 0; ChoiceIter < StringListDataStore.StringData[StringIter].Strings.Length; ChoiceIter++)
                                            {
                                                RendererDataProvider.SetElementString(ChoiceIter, StringListDataStore.StringData[StringIter].Strings[ChoiceIter]);
                                            }
                
                                            DefaultIndex = StringListDataStore.GetCurrentValueIndex('Resolution');
                                            bFoundDefault = true;
                                            break;
                                        }
                                    }
                                    break;
                                case "Fullscreen":
                                    for (StringIter = 0; StringIter < StringListDataStore.StringData.Length; StringIter++)
                                    {
                                        // Populate the server types with the friendly names of "fullscreen=0/windowed=1"
                                        if (string(StringListDataStore.StringData[StringIter].Tag) == RelevantPart)
                                        {
                                            for (ChoiceIter = 0; ChoiceIter < StringListDataStore.StringData[StringIter].Strings.Length; ChoiceIter++)
                                            {
                                                RendererDataProvider.SetElementString(ChoiceIter, StringListDataStore.StringData[StringIter].Strings[ChoiceIter]);
                                            }
                
                                            DefaultIndex = StringListDataStore.GetCurrentValueIndex('Fullscreen');
                                            bFoundDefault = true;
                                            break;
                                        }
                                    }
                                    break;
                                default:
                                    // Left out for simplicity, but you could use this function from 'GFxUDKFrontEnd_ServerSettings' or 'GFxUDKFrontEnd_Settings':
                                    // PopulateOptionDataProviderForIndex(i, RendererDataProvider, DefaultValue, DefaultIndex);
                                    break;
                            }
                
                            // Set the dataProvider and the selectedIndex for the embeddedOptionStepper control.
                            TempObj.SetBool("bUpdateFromUnreal", true);
                            TempObj.SetObject("dataProvider", RendererDataProvider);  
                            TempObj.SetFloat("optIndex", DefaultIndex);
                        }
                
                        //Is it in the registry?
                        if (!bFoundDefault)
                        {
                            if (LocationPart == "Registry")
                            {
                                 Registry.GetData(RelevantPart, DefaultValue);
                                 bFoundDefault = true;
                            }
                        }
                
                        TempObj.SetString("text", DefaultValue);
                        TempObj.SetBool("bNumericCombo", SettingsList[i].bNumericCombo);
                        TempObj.SetBool("bEditableCombo", SettingsList[i].bEditableCombo);
                        TempObj.SetFloat("editBoxMaxLength", SettingsList[i].EditBoxMaxLength);   
                        DataProvider.SetElementObject(i, TempObj);
                    }
                
                    ListMC.SetObject("dataProvider", DataProvider);   
                    ListDataProvider = ListMC.GetObject("dataProvider");
                
                }
                
                /** Split the DataStoreMarkup string into 2 parts*/
                function SplitMarkupString(const int Index, out string OutRelevantPart, out string OutLocationPart)
                {
                        //Get the part to the right of the :
                        OutRelevantPart = Split(SettingsList[Index].DataStoreMarkup, ":",true);
                        //Get the part to the left of the :
                        OutLocationPart = Left(SettingsList[Index].DataStoreMarkup, Len(SettingsList[Index].DataStoreMarkup) - (Len(OutRelevantPart)+1));
                        //Remove the < from the left end;
                        OutLocationPart = Right(OutLocationPart, Len(OutLocationPart)-1);
                        //Remove the > from the right end
                        OutRelevantPart = Left(OutRelevantPart, Len(OutRelevantPart)-1);
                }
                
                /** Converts the class name for a UTUIObject to a name that can be handled by AS class for the list's itemRenderers. */
                function string FindControlByUTClassName(byte UTUIControlClass)
                {
                    switch(UTUIControlClass)
                    {
                        case (UTOT_Slider):
                            return "stepper";
                            break;
                        
                        case (UTOT_EditBox):
                            return "input";
                            break;
                
                        default:
                            return "stepper";
                            break;
                    }
                }
                
                
                DefaultProperties
                {
                }
                I will not go into the details on this, but let it be known that I mainly ripped this off of the GFxUDKFrontEnd_ServerSettings class with a few tweaks. I also cut out a lot to make it easier to understand, so all the UTGameSettings Datastore part is gone. If you're interested in that, take a look at the GFxUDKFrontEnd_Settings and GFxUDKFrontEnd_ServerSettings classes to get a hang of it, because it uses a different method for localization.
                Right in the beginning we set the OptionSet "System" that we introduced before in the DefaultGame.ini. Then there's a function that saves the settings to the datastore (as long as the game is running), and one to fill the UI with what we've been doing so far.
                If I haven't forgotten to mention something and you did everything right, you should have something like this:

                And again: At this stage these options don't do anything! They are just nice to look at and play around with. The next thing I will tackle is the functionality. I still have no clue where to go from here but I'm sure I'll get there. One more sleepless night I guess. Let me know what you think and what you come up with!

                PS: This is the first "tutorial" I've ever written.

                Comment


                  #9
                  Adding functionality to menu options

                  Let's start right away were we left. To make our options actually do stuff, there are only 2 files we need to touch.
                  In the GFxUDKFrontEnd_SystemSettings class add the following function:
                  Code:
                  /** 
                   *  Listener for changes in the options
                   */
                  function OnOptionChanged(GFxClikWidget.EventData ev)
                  {
                      SaveState();
                      ApplySystemSettings();
                  }
                  This function overwrites the one in the parent class that doesn't do anything anyway. The important thing is, that it is executed everytime you change a menu item to another value. It calls our SaveState() function that we've already written and then calls a function I named ApplySystemSettings(). Let's add this function too.
                  Code:
                  /** Set the screen settings. */
                  function ApplySystemSettings()
                  {
                      local int i, ResolutionIndex, FullscreenIndex;
                      local string LocationPart, RelevantPart, ResolutionVal, FullscreenVal;
                      local DataStoreClient DSClient;
                      local UTUIDataStore_StringList StringListDataStore;
                  
                      for ( i = 0; i < SettingsList.Length; i++)
                      {
                          // Get the datastore tag and its path in seperate variables
                          SplitMarkupString(i, RelevantPart, LocationPart);
                  
                          if (RelevantPart == "Resolution"|| RelevantPart == "Fullscreen")
                          {
                              // Get the global data store client
                              DSClient = class'UIInteraction'.static.GetDataStoreClient();
                              StringListDataStore = UTUIDataStore_StringList(DSClient.FindDataStore('UTStringList'));
                  
                              // Get current value of 'Resolution' and index of value 'Fullscreen'
                              StringListDataStore.GetCurrentValue('Resolution', ResolutionVal);
                              FullscreenIndex = StringListDataStore.GetCurrentValueIndex('Fullscreen');
                  
                              // If true(fullscreen[1]) "windowed", if false(fullscreen[0]) "fullscreen"
                              FullscreenVal = bool(FullscreenIndex) ? "w" : "f";
                  
                              // This console command will save the settings automatically to the UDKEngine.ini
                              `log("GFxUDKFrontEnd_SystemSettings: Setres"@ResolutionVal$FullscreenVal);
                              ConsoleCommand("Setres"@ResolutionVal$FullscreenVal);
                  
                                          // Set the current values as the DefaultValueIndex in UDKGame.ini
                              ResolutionIndex = StringListDataStore.GetCurrentValueIndex('Resolution');
                              StringListDataStore.SetDefaultValueIndex('Resolution', ResolutionIndex);
                              StringListDataStore.SetDefaultValueIndex('Fullscreen', FullscreenIndex);
                          }
                      }
                  }
                  This is where the magic happens! Look if an option is 'resolution' or 'fullscreen' and then retrieve the current values. With that we build a console command that does the rest for us. The "setres [height]x[width]f|w" command even saves the values in the UDKEngine.ini for us! But we still need to save our preferences in the UDKGame.ini, so they'll be correctly displayed in the settings menu next time we start the game. Therefore I added a function to the UTStringList which is called in the last lines. Open the UTUIDataStore_StringList class. As you can see it's pretty empty. So go ahead and add the function:
                  Code:
                  /**
                   * Sets the default value index of a given field.
                   *
                   * @param FieldName        Field to change.
                   * @param int            NewValueIndex
                   */
                  function SetDefaultValueIndex(name FieldName, int NewValueIndex)
                  {
                      local int FieldIndex;
                  
                      FieldIndex = GetFieldIndex(FieldName);
                      if(FieldIndex!=INDEX_NONE && StringData[FieldIndex].Strings.length > NewValueIndex)
                      {
                          StringData[FieldIndex].DefaultValueIndex = NewValueIndex;
                          `log("UTUIDataStore_StringList.SetDefaultValueIndex("$FieldName$"):"@NewValueIndex);
                          SaveConfig();
                      }
                  }
                  The StringData array and the other functions are inherited from its parent class, as is the path to the config file. So the SaveConfig() function saves to the appropiate file. All I do here is to set a new value for the DefaultValueIndex that we earlier defined in the DefaultGame.ini ( [UTGame.UTUIDataStore_StringList] +StringData=(Tag="Resolution",DefaultValueIndex=3) ).

                  That should be it!
                  Here's a video example: http://www.youtube.com/watch?v=i3AqcJYAlic

                  Actually you should notice that I didn't care about my input field anymore. I didn't know what I should use it for, so that is up to you now! You could also introduce an "apply changes" button in the menu, if that instant thingy isn't to your liking.
                  Thanks, if you followed my instructions. If you have questions fell free to ask. Or if you have an even better solution, let me know! I'll be here... watching.... waiting... lurking in the shadows.

                  Comment


                    #10
                    Fantastic, i wish i had you on my team, time to do a lot of copy/paste for me then

                    Comment


                      #11
                      An additional hint: If you're going to create your own datastores (e.g. stringlists), don't forget to add them to the DefaultEngine.ini! like this:
                      Code:
                      [Engine.DataStoreClient]
                      +GlobalDataStoreClasses=YourGame.YGUIDataStore_StringList
                      I just forgot myself and was wondering, what I was missing. Gladly I remembered before tearing my whole menu apart to find "the bug".

                      Comment


                        #12
                        ok i haven't tried datastore's (over my head) but the rest works a treat, though an apply button would be better i think as the screen res changes every time you press the < or >

                        begging pm sent

                        Comment

                        Working...
                        X