Unable to save Name based Session Settings

Iv been trying for a few days now, i got a edit test widget with an on text commited handler, that works fine to enter text and fire handler but i cant find out how to store the value on a Session Setting First i tried in BP, it looks correct but it wont store any value. then i moved my code to cpp using a UBlueprintFunctionLibrary so i could attach the debugger session setting use the IFGOptionInterface interface that has a method for text based options SetNameOptionValue and with the debugger attached i see the option interface is pointing to the SessionSettingManager but the value is never updated
No description
No description
Solution:
You do need a value selector, because it defines the default value, and allows configuring it for each setting
Jump to solution
61 Replies
Jarno
JarnoOP•2w ago
in the screenshot i also tested it with an interger option and i did get the SetIntOptionValue to work after an ApplyChanges(), but still no luck for the Name based value
Robb
Robb•2w ago
@Mircea I know you looked briefly into string-based session settings so you may have some insights
Mircea
Mircea•2w ago
Anything in the log? All the SetXOptionValue functions just go through the template function, so if one works they all should I didn't really look into that, it was only the idea of storing arbitrary structs/classes serialized as strings or as byte arrays (but that would be harder for stuff like SCIM to extract maybe)
Jarno
JarnoOP•2w ago
well the log does print out an warning about not able to find the option
[2025.02.11-21.59.49:572][393]LogGame: Warning: Attempt to access non-existent option 'Archipelago.Demo6' on Option Interface 'SessionSettingsManager /Game/FactoryGame/Map/MenuScenes/Map_Menu_1_0.Map_Menu_1_0:SessionSettingsManager_2147481960'
[2025.02.11-21.59.49:572][393]LogGame: Warning: Attempt to access non-existent option 'Archipelago.Demo6' on Option Interface 'SessionSettingsManager /Game/FactoryGame/Map/MenuScenes/Map_Menu_1_0.Map_Menu_1_0:SessionSettingsManager_2147481960'
obiusly that seems like super easy to fix, but i garantee you it exists 😄 it shows in menu and all
Mircea
Mircea•2w ago
Can you add a breakpoint in IFGOptionInterfaceImpl::GetOptionDisplayValue and see if it calls UFGUserSettingApplyType::GetDisplayValue? If not, FindUserSetting returns null, if yes, the value of the setting is actually an empty variant All of the settings are apply instantly, right?
Jarno
JarnoOP•2w ago
currently they are not set to instantly, but on normal apply type
No description
Mircea
Mircea•2w ago
Huh, I thought the base class was abstract
Jarno
JarnoOP•2w ago
meanwhiile i was testing a more direct aprouch
FName testValue2("Test2");
optionsInterface->SetOptionValueTyped("Archipelago.Demo6", testValue2);
auto optionNameAfterTypedSet = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionNameAfterTypedSetAfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");

FName testValue3("Test3");
optionsInterface->SetOptionValue("Archipelago.Demo6", testValue3);
auto optionNameAfterTypelessSet = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionNameAfterTypelessSetAfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
FName testValue2("Test2");
optionsInterface->SetOptionValueTyped("Archipelago.Demo6", testValue2);
auto optionNameAfterTypedSet = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionNameAfterTypedSetAfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");

FName testValue3("Test3");
optionsInterface->SetOptionValue("Archipelago.Demo6", testValue3);
auto optionNameAfterTypelessSet = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionNameAfterTypelessSetAfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
and it did work on optionNameAfterTypelessSetAfterApply so without any typed method by directly calling SetOptionValue with the FVariant parameter
Jarno
JarnoOP•2w ago
No description
Mircea
Mircea•2w ago
In that case, calling the untyped one twice should also work
Jarno
JarnoOP•2w ago
🤔 i am not following you, why twice?
Mircea
Mircea•2w ago
Because that's what you just tested now Using the typed vs untyped makes no difference But apparently setting the value twice does
Jarno
JarnoOP•2w ago
oke intresting let me try that meanwhile i did try this, but i cant get a breakpoint to bind there as i only have the stub implementation
Mircea
Mircea•2w ago
You can add method breakpoints (not sure where in VS, I only did it in Rider)
Jarno
JarnoOP•2w ago
ah function breakpoints, never used those lets see Oke with the breakpoints optionsInterface->SetNameOptionValue("Archipelago.Demo6", testValue) then hits IFGOptionInterfaceImpl::GetOptionDisplayValue and than UFGUserSettingApplyType::GetDisplayValue after now lets try setting the value twice
FName testValue("Test");
optionsInterface->SetNameOptionValue("Archipelago.Demo6", testValue);
optionsInterface->SetNameOptionValue("Archipelago.Demo6", testValue);
auto optionName = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionNameAferApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");

FName testValue2("Test2");
optionsInterface->SetOptionValueTyped("Archipelago.Demo6", testValue2);
optionsInterface->SetOptionValueTyped("Archipelago.Demo6", testValue2);
auto optionName2 = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionName2AAfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");

FName testValue3("Test3");
optionsInterface->SetOptionValue("Archipelago.Demo6", testValue3);
auto optionName3 = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionName3AfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
FName testValue("Test");
optionsInterface->SetNameOptionValue("Archipelago.Demo6", testValue);
optionsInterface->SetNameOptionValue("Archipelago.Demo6", testValue);
auto optionName = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionNameAferApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");

FName testValue2("Test2");
optionsInterface->SetOptionValueTyped("Archipelago.Demo6", testValue2);
optionsInterface->SetOptionValueTyped("Archipelago.Demo6", testValue2);
auto optionName2 = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionName2AAfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");

FName testValue3("Test3");
optionsInterface->SetOptionValue("Archipelago.Demo6", testValue3);
auto optionName3 = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
optionsInterface->ApplyChanges();
auto optionName3AfterApply = optionsInterface->GetNameOptionValue("Archipelago.Demo6");
well it seems there is a difference as still only the optionName3AfterApply got a value, let me retry with just that one set
Jarno
JarnoOP•2w ago
No description
Mircea
Mircea•2w ago
The untyped one literally just calls the typed one https://github.com/satisfactorymodding/SatisfactoryModLoader/blob/master/Source/FactoryGame/Public/FGOptionInterface.h#L96 Is your value selector implemented in cpp or BP?
Jarno
JarnoOP•2w ago
after just 1 call to untyped SetOptionValue it works, i can see its correctly updating state
No description
Mircea
Mircea•2w ago
This is the issue
No description
Mircea
Mircea•2w ago
You need to implement the value selector in cpp, so that you can override GetDefaultValue to return a real FVariant, not the default empty one
Jarno
JarnoOP•2w ago
i did indeed not initailize it any way as i have no idea how to set that up, i dont see any place to put in like a default in the blueprint widget or session setting
Mircea
Mircea•2w ago
FVariants aren't available to blueprints Which is why you need to implement the value selector in cpp, or at least implement it with a BPImplementable function for the widget creation, if you really want to do the widget side in BP
Jarno
JarnoOP•2w ago
oh i prefer cpp anyway but can you point me in the right direction, where in cpp do i need to implement the value selector? i guess i got to inherit some cpp class, implement a few methods and then put it somewhere?
Mircea
Mircea•2w ago
UFGUserSetting_ValueSelector Looking at the other fields of UFGUserSetting, I guess what you did was set ValueSelector to custom and only made a custom value selection widget?
Jarno
JarnoOP•2w ago
yes
No description
Jarno
JarnoOP•2w ago
i though that how that was meant to work 😅
Solution
Mircea
Mircea•2w ago
You do need a value selector, because it defines the default value, and allows configuring it for each setting
Mircea
Mircea•2w ago
And that value selector returns the class for the selector widget (I thought it was returning an actual widget, but it's just the class, CSS also implements those in BP)
Jarno
JarnoOP•2w ago
i though the custom one was just generic to be used for anything thats not the normal checkbox, int or slider :adithinka: as there are like 20 other custom widgets to use with it ill see if i can create one for strings than
Jarno
JarnoOP•2w ago
hmmz actuallly, it seems the widget itzelf is also the value controller, so my widget already implemented that class, i guess otherwise i would not have been able to select it in that dropdown anyway
No description
Mircea
Mircea•2w ago
You want a value selector
Jarno
JarnoOP•2w ago
ohh riiight
Mircea
Mircea•2w ago
The value selector has the configuration for the setting (default value, min, max, allowed enum values) and which value controller (widget) to use
Jarno
JarnoOP•2w ago
riiight so basicly i got screwed by this todo
UCLASS( Blueprintable, DefaultToInstanced, editinlinenew, meta = ( DisplayName = "Custom" ) )
class FACTORYGAME_API UFGUserSetting_Custom : public UFGUserSetting_ValueSelector
{
GENERATED_BODY()
public:
virtual EOptionType GetOptionType() const override { return EOptionType::OT_Custom; }

// @todok2 Add support for GetDefaultValue
};
UCLASS( Blueprintable, DefaultToInstanced, editinlinenew, meta = ( DisplayName = "Custom" ) )
class FACTORYGAME_API UFGUserSetting_Custom : public UFGUserSetting_ValueSelector
{
GENERATED_BODY()
public:
virtual EOptionType GetOptionType() const override { return EOptionType::OT_Custom; }

// @todok2 Add support for GetDefaultValue
};
Mircea
Mircea•2w ago
Yes, which can't really be solved, because FVariants aren't exposed to blueprints And also you should still have a value selector even if that did work, to allow the settings to specify a default value
Jarno
JarnoOP•2w ago
yeah well makes sense, but the OptionInterface only supports bool,int,float,FName so it could have alteast supported those 😅 well i delayed my lunch break by enough for now, ill try these things out this evening, thanks for the extended help so far :adithinka: yet it does not really explain why the Custom value selector works for all those 20 other widgets that use it, like color picker
Jarno
JarnoOP•2w ago
well can confirm it works now out of the box with the SetNameOptionValue()
No description
Robb
Robb•2w ago
Is the approach you found extensible enough to turn into string based session settings in SML? As in, set up so that mods don't require custom c++ to use it
Jarno
JarnoOP•6d ago
Yeah that was my plan, to PR it to SML are see if it gets accepted Created: https://github.com/satisfactorymodding/SatisfactoryModLoader/pull/344
Robb
Robb•5d ago
is this intentionally unhooked?
No description
Jarno
JarnoOP•5d ago
yeah, sort of that was a plan but connecting it gives a stack overflow so i disconnected it i guess i could have removed it
Robb
Robb•5d ago
right now having the unhooked node prevents the parent implementation in FGOptionsValueController from running (if there is one) wasn't sure if that was intended or not. sounds like not; I'll remove it what is the purpose of defaultText being FText and not FString? I would think it is not desirable for default config values to be localized
Jarno
JarnoOP•5d ago
i though it be a nice feature to be able to localize it
Robb
Robb•5d ago
hmm... if people stick with the default value, that default value is then literally copied as an fstring for storage in their save file, right? so there would never be a situation where their stored value would change based on their language selection - only at creation time, right? as long as that is the case, I think it's fine to keep it as ftext @Jarno (the Archipelago guy) pushed some tweaks and more features described in commit message, it's working on my end, could you test it on yours as well? I might have broken AP's with a field rename, but better to have that now than after it launches
Jarno
JarnoOP•5d ago
oh my you have been busy, if you change fontszie you likely also need to realign it to center
Robb
Robb•5d ago
it seemed to only need 1px of padding changed to look fine again the vanilla slider value widget uses font size 12 which is why I switched to it
Jarno
JarnoOP•5d ago
ah nice you decibered my trick with the widget
Robb
Robb•5d ago
@Mircea (Area Actions) would appreciate your thoughts before we merge this, but I think it's ready. screenshots on the PR comments are outdated
Jarno
JarnoOP•5d ago
yeah i was going to update those screenshts
Mircea
Mircea•5d ago
I can check it out tomorrow Yes, but the value that the session settings menu will show as default will change. To be fair, it's quite unlikely that someone will change their language mid-game, and even then, since the backing type is a string coming from user input, it's expected that this is unlocalizable text, so mods shouldn't expect to be able to compare it to an actual FText One issue with the default being FText is that on dedicated servers it will likely always be english (unless there's a way to set the server's language that I don't know about), but I tested and resetting the settings does apply the locally localized value. Naming the type Text rather than String could be a bit confusing, since both are known UE types, but then again, besides a text dropdown (which would be more useful/implemented as an enum), you can't get localizable text from user input, so we likely won't need to add an actual FText option type in the future The OnOptionValueReset event is not necessary, resetting reinitializes the widget, and that event is from the console-specific stuff, no vanilla option controller implements it as far as I can tell (and neither do they implement the OnOptionReverted event) And it would be better if the new valuecontroller/selector BPs are not in /SML/SessionSettings, because that's where SML's settings are stored. They should go in /SML/Interface/UI/Menu/Options, similar folder structure to FG's
Robb
Robb•5d ago
So switch it to FString and rename accordingly, remove event, and move the supporting stuff to the relevant folder. Sounds good. I can't do this with my PC broken, so Jarno can or we can wait
Jarno
JarnoOP•5d ago
i guess i can do that, but i dont see a clear answer on the FText part in here, to me i read this as its fine the way it is right now?
Mircea
Mircea•5d ago
If you see actual use in having the default be text, it's fine, but it will only be relevant for clients. As for the name, the assets are already named SomethingString, so it's only the display name that says Text, which can be changed later without causing issues, in the unlikely event that we will have a FText session setting type
Jarno
JarnoOP•5d ago
i changed the default to FString i am not an ui dsigner, but i feel we would call it a text input not a string input as a string is really just a fancy developer world to store texts but then again this is kinda focused toward developers so i dunno Oke iv implemeted the review results
Robb
Robb•5d ago
End users will never know if it's stored as FText or FString, and for us developers those words have special meanings
Mircea
Mircea•3d ago
I'm fine with either option, so from me the PR is good to go
Robb
Robb•3d ago
I'll look at the changes on my laptop this evening but won't be able to compile it to check anything
Jarno
JarnoOP•2d ago
Fine from my side aswel
Robb
Robb•2d ago
My checking didn't happen, busy evening. Will get out laptop now
Jarno
JarnoOP•2d ago
understandable, its unfortunate your pc died this PR isnt really in a hurry either, but would love to have it in next SML release
Robb
Robb•2d ago
I had another work meeting come up and couldn't check it lol

Did you find this page helpful?