diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod.XCOM_sln b/MCMBuilderClientTestMod/MCMBuilderClientTestMod.XCOM_sln new file mode 100644 index 0000000..7c96003 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod.XCOM_sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# XCOM ModBuddy Solution File, Format Version 11.00 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{5DAE07AF-E217-45C1-8DE7-FF99D6011E8A}") = "MCMBuilderClientTestMod", "MCMBuilderClientTestMod\MCMBuilderClientTestMod.x2proj", "{9431E66B-C62F-45C5-AFDB-9F51743A224E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|XCOM 2 = Debug|XCOM 2 + Default|XCOM 2 = Default|XCOM 2 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9431E66B-C62F-45C5-AFDB-9F51743A224E}.Debug|XCOM 2.ActiveCfg = Debug|XCOM 2 + {9431E66B-C62F-45C5-AFDB-9F51743A224E}.Debug|XCOM 2.Build.0 = Debug|XCOM 2 + {9431E66B-C62F-45C5-AFDB-9F51743A224E}.Default|XCOM 2.ActiveCfg = Default|XCOM 2 + {9431E66B-C62F-45C5-AFDB-9F51743A224E}.Default|XCOM 2.Build.0 = Default|XCOM 2 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComEditor.ini b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComEditor.ini new file mode 100644 index 0000000..4f83d00 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComEditor.ini @@ -0,0 +1,2 @@ +[ModPackages] ++ModPackages=MCMBuilderClientTestMod \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComEngine.ini b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComEngine.ini new file mode 100644 index 0000000..69a2d39 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComEngine.ini @@ -0,0 +1,6 @@ +[Engine.ScriptPackages] ++NonNativePackages=ModConfigMenuBuilderAPI_1_0_0 ++NonNativePackages=MCMBuilderClientTestMod + +[UnrealEd.EditorEngine] ++ModEditPackages=ModConfigMenuBuilderAPI_1_0_0 \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComGame.ini b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComGame.ini new file mode 100644 index 0000000..7004743 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComGame.ini @@ -0,0 +1,2 @@ +[MCMBuilderClientTestMod.X2DownloadableContentInfo_MCMBuilderClientTestMod] +DLCIdentifier="MCMBuilderClientTestMod" \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComJsonConfigManager.ini b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComJsonConfigManager.ini new file mode 100644 index 0000000..48074c5 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComJsonConfigManager.ini @@ -0,0 +1,5 @@ +[MCMBuilderClientTestModConfigManager JsonConfig_ManagerDefault] ++ConfigProperties = {"HUNGRY":{"Value":"true"}} ++ConfigProperties = {"HUNGER_SCALE":{"Value":"1"}} ++ConfigProperties = {"HUNGER_SCALE_NERD":{"Value":"0.1"}} ++ConfigProperties = {"FOOD":{"Value":"Apple"}} diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComMCMBuilder.ini b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComMCMBuilder.ini new file mode 100644 index 0000000..0ce5bc3 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Config/XComMCMBuilder.ini @@ -0,0 +1,19 @@ +[ModConfigMenuBuilder.MCM_Builder_Screen] ++MCMBuilder="MCMBuilderClientTestMod" + +[MCMBuilderClientTestMod JsonConfig_MCM_Builder] ++MCMPages = { \\ + "TESTMOD_SETTINGS_PAGE":{ \\ + "SaveConfigManager": "MCMBuilderClientTestModConfigManager",\\ + "EnableResetButton": "true", \\ + "TESTMOD_SETTINGS_GROUP_1":{ \\ + "HUNGRY": { "Type": "Checkbox" }, \\ + "HUNGER_SCALE_NERD": { "Type": "Slider", "SliderMin": "0.0", "SliderMax": "1.0", "SliderStep":"0.1" }, \\ + "HUNGER_SCALE": { "Type": "Spinner", "Options": "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" }, \\ + "FOOD": { "Type": "Dropdown", "Options": "Apple, Chocolate, Burger" }, \\ + }, \\ + "TESTMOD_SETTINGS_GROUP_2":{ \\ + "A_LABEL": { "Type": "Label" }, \\ + }, \\ + }, \\ +} \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Localization/ModConfigMenu.int b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Localization/ModConfigMenu.int new file mode 100644 index 0000000..0b813dd Binary files /dev/null and b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Localization/ModConfigMenu.int differ diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/MCMBuilderClientTestMod.x2proj b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/MCMBuilderClientTestMod.x2proj new file mode 100644 index 0000000..16a2357 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/MCMBuilderClientTestMod.x2proj @@ -0,0 +1,59 @@ + + + + 91050dba-9f3c-4243-90d9-f6bdef9ad716 + MCMBuilderClientTestMod + Description of My XCOM 2 Mod. + 0 + MCMBuilderClientTestMod + MCMBuilderClientTestMod + + + bin\Debug\ + + + + + + + + + + + + + Content + + + Content + + + Content + + + + + + + + Content + + + + Content + + + Content + + + Content + + + Content + + + Content + + + + \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/ModPreview.jpg b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/ModPreview.jpg new file mode 100644 index 0000000..5bdd8d8 Binary files /dev/null and b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/ModPreview.jpg differ diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/ReadMe.txt b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/ReadMe.txt new file mode 100644 index 0000000..fc6b988 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/ReadMe.txt @@ -0,0 +1 @@ +You created an XCOM 2 Mod Project! \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/Helper.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/Helper.uc new file mode 100644 index 0000000..edb1027 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/Helper.uc @@ -0,0 +1,15 @@ +//----------------------------------------------------------- +// Class: Helper +// Author: Musashi +// +//----------------------------------------------------------- + + +class Helper extends Object; + +const CONFIG_MANAGER = "MCMBuilderClientTestModConfigManager"; + +public static final function JsonConfig_ManagerInterface GetConfig() +{ + return class'ConfigFactory'.static.GetConfigManager(CONFIG_MANAGER); +} \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/X2DownloadableContentInfo_MCMBuilderClientTestMod.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/X2DownloadableContentInfo_MCMBuilderClientTestMod.uc new file mode 100644 index 0000000..7882bd0 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/X2DownloadableContentInfo_MCMBuilderClientTestMod.uc @@ -0,0 +1,25 @@ +//--------------------------------------------------------------------------------------- +// FILE: XComDownloadableContentInfo_MCMBuilderClientTestMod.uc +// +// Use the X2DownloadableContentInfo class to specify unique mod behavior when the +// player creates a new campaign or loads a saved game. +// +//--------------------------------------------------------------------------------------- +// Copyright (c) 2016 Firaxis Games, Inc. All rights reserved. +//--------------------------------------------------------------------------------------- + +class X2DownloadableContentInfo_MCMBuilderClientTestMod extends X2DownloadableContentInfo; + +static function bool AbilityTagExpandHandler(string InString, out string OutString) +{ + local string PossibleValue; + + PossibleValue = class'Helper'.static.GetConfig().GetConfigTagValue(InString); + if (PossibleValue != "") + { + OutString = PossibleValue; + return true; + } + + return false; +} diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/X2EventListener_TestMod.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/X2EventListener_TestMod.uc new file mode 100644 index 0000000..3fe68c0 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/MCMBuilderClientTestMod/Classes/X2EventListener_TestMod.uc @@ -0,0 +1,175 @@ +class X2EventListener_TestMod extends X2EventListener; + +static function array CreateTemplates() +{ + local array Templates; + + Templates.AddItem(CreateListenerTemplate_MCMBuilderListener()); + + return Templates; +} + +static function CHEventListenerTemplate CreateListenerTemplate_MCMBuilderListener() +{ + local CHEventListenerTemplate Template; + + `CREATE_X2TEMPLATE(class'CHEventListenerTemplate', Template, 'MCMBuilderClientTestMod_MCMBuilderListener'); + + Template.RegisterInStrategy = true; + Template.RegisterInTactical = true; + + Template.AddCHEvent('MCM_ButtonClick', OnMCM_ButtonClick, ELD_Immediate); + Template.AddCHEvent('MCM_ChangeHandler', OnMCM_ChangeHandler, ELD_Immediate); + Template.AddCHEvent('MCM_SaveHandler', OnMCM_SaveHandler, ELD_Immediate); + Template.AddCHEvent('MCM_SaveButtonClicked', OnMCM_SaveButtonClicked, ELD_Immediate); + Template.AddCHEvent('MCM_ConfigSaved', OnMCM_ConfigSaved, ELD_Immediate); + Template.AddCHEvent('MCM_ResetButtonClicked', OnMCM_ResetButtonClicked, ELD_Immediate); + Template.AddCHEvent('MCM_ConfigResetted', OnMCM_ConfigResetted, ELD_Immediate); + + return Template; +} + + +static function EventListenerReturn OnMCM_ButtonClick(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + if (EventSource != none) + { + `LOG(default.class @ GetFuncName() @ EventSource,, 'MCMBuilderClientTestMod'); + } + + return ELR_NoInterrupt; +} + +static function EventListenerReturn OnMCM_ChangeHandler(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + local MCM_Builder_Interface Builder; + local JsonObject Tuple; + + Tuple = JsonObject(EventSource); + Builder = MCM_Builder_Interface(Tuple.GetObject("MCMBuilder")); + + if (Builder != none && Builder.GetBuilderName() == "MCMBuilderClientTestMod") + { + `LOG(default.class @ GetFuncName() @ + Tuple.GetObject("MCMBuilder") @ + Tuple.GetStringValue("SettingLabel") @ + Tuple.GetStringValue("SettingValue") @ + Tuple.GetBoolValue("bOverrideDefaultHandler") + ,, 'MCMBuilderClientTestMod'); + + MakePopup(EventName, Tuple.GetStringValue("SettingLabel") $ "(" $ Tuple.GetStringValue("SettingName") $ ")" $ ":" @ Tuple.GetStringValue("SettingValue")); + } + + return ELR_NoInterrupt; +} + + +static function EventListenerReturn OnMCM_SaveHandler(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + local MCM_Builder_Interface Builder; + local JsonObject Tuple; + + Tuple = JsonObject(EventSource); + Builder = MCM_Builder_Interface(Tuple.GetObject("MCMBuilder")); + + if (Builder != none && Builder.GetBuilderName() == "MCMBuilderClientTestMod") + { + `LOG(default.class @ GetFuncName() @ + Tuple.GetObject("MCMBuilder") @ + Tuple.GetStringValue("SettingLabel") @ + Tuple.GetStringValue("SettingValue") @ + Tuple.GetBoolValue("bOverrideDefaultHandler") + ,, 'MCMBuilderClientTestMod'); + + MakePopup(EventName, Tuple.GetStringValue("SettingLabel") $ "(" $ Tuple.GetStringValue("SettingName") $ ")" $ ":" @ Tuple.GetStringValue("SettingValue")); + } + + return ELR_NoInterrupt; +} + +static function EventListenerReturn OnMCM_SaveButtonClicked(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + local MCM_Builder_Interface Builder; + local JsonObject Tuple; + + Tuple = JsonObject(EventSource); + Builder = MCM_Builder_Interface(Tuple.GetObject("MCMBuilder")); + + `LOG(default.class @ GetFuncName() @ + Builder @ + Tuple.GetBoolValue("bOverrideDefaultHandler") + ,, 'MCMBuilderClientTestMod'); + + if (Builder != none && Builder.GetBuilderName() == "MCMBuilderClientTestMod") + { + MakePopup(EventName, "bOverrideDefaultHandler:" @ Tuple.GetBoolValue("bOverrideDefaultHandler")); + } + + return ELR_NoInterrupt; +} + +static function EventListenerReturn OnMCM_ConfigSaved(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + local MCM_Builder_Interface Builder; + + Builder = MCM_Builder_Interface(EventSource); + + if (Builder != none && Builder.GetBuilderName() == "MCMBuilderClientTestMod") + { + `LOG(default.class @ GetFuncName() @ Builder.GetBuilderName() @ Builder,, 'MCMBuilderClientTestMod'); + MakePopup(EventName); + } + + return ELR_NoInterrupt; +} + +static function EventListenerReturn OnMCM_ResetButtonClicked(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + local MCM_Builder_Interface Builder; + + Builder = MCM_Builder_Interface(EventSource); + + if (Builder != none && Builder.GetBuilderName() == "MCMBuilderClientTestMod") + { + `LOG(default.class @ GetFuncName() @ EventSource,, 'MCMBuilderClientTestMod'); + MakePopup(EventName); + } + + return ELR_NoInterrupt; +} + +static function EventListenerReturn OnMCM_ConfigResetted(Object EventData, Object EventSource, XComGameState GameState, Name EventName, Object CallbackData) +{ + local MCM_Builder_Interface Builder; + + Builder = MCM_Builder_Interface(EventSource); + + if (Builder != none && Builder.GetBuilderName() == "MCMBuilderClientTestMod") + { + `LOG(default.class @ GetFuncName() @ EventSource,, 'MCMBuilderClientTestMod'); + MakePopup(EventName); + } + + return ELR_NoInterrupt; +} + +simulated static function MakePopup(Name EventName, optional string Text = "") +{ + local TDialogueBoxData kDialogData; + local JsonConfig_ManagerInterface ConfigManager; + + ConfigManager = class'Helper'.static.GetConfig(); + + kDialogData.eType = eDialog_Normal; + kDialogData.strTitle = string(EventName); + kDialogData.strText = Text != "" ? Text : + "HUNGRY:" @ ConfigManager.GetConfigBoolValue("HUNGRY") $ "\n" $ + "HUNGER_SCALE:" @ ConfigManager.GetConfigIntValue("HUNGER_SCALE") $ "\n" $ + "HUNGER_SCALE_NERD:" @ ConfigManager.GetConfigFloatValue("HUNGER_SCALE_NERD") $ "\n" $ + "FOOD:" @ ConfigManager.GetConfigStringValue("FOOD"); + //kDialogData.fnCallback = OKClickedGeneric; + + kDialogData.strAccept = class'UIUtilities_Text'.default.m_strGenericContinue; + + `PRESBASE.UIRaiseDialog(kDialogData); +} \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/ConfigFactory.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/ConfigFactory.uc new file mode 100644 index 0000000..a1c4cc0 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/ConfigFactory.uc @@ -0,0 +1,26 @@ +//----------------------------------------------------------- +// Class: ConfigFactory +// Author: Musashi +// DO NOT MAKE ANY CHANGES TO THIS CLASS +//----------------------------------------------------------- +class ConfigFactory extends Object; + +static function JsonConfig_ManagerInterface GetConfigManager(string ManagerName) +{ + local MCM_Builder_SingletonFactoryInterface SingletonFactoryInterface; + local object SingletonFactoryCDO; + + SingletonFactoryCDO = class'XComEngine'.static.GetClassDefaultObjectByName('MCM_Builder_SingletonFactory'); + SingletonFactoryInterface = MCM_Builder_SingletonFactoryInterface(SingletonFactoryCDO); + return SingletonFactoryInterface.static.GetManagerInstance(ManagerName); +} + +static function MCM_Builder_Interface GetMCMBuilder(string BuilderName) +{ + local MCM_Builder_SingletonFactoryInterface SingletonFactoryInterface; + local object SingletonFactoryCDO; + + SingletonFactoryCDO = class'XComEngine'.static.GetClassDefaultObjectByName('MCM_Builder_SingletonFactory'); + SingletonFactoryInterface = MCM_Builder_SingletonFactoryInterface(SingletonFactoryCDO); + return SingletonFactoryInterface.static.GetMCMBuilderInstance(BuilderName); +} \ No newline at end of file diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/JsonConfig_ManagerInterface.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/JsonConfig_ManagerInterface.uc new file mode 100644 index 0000000..42fdbca --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/JsonConfig_ManagerInterface.uc @@ -0,0 +1,43 @@ +//----------------------------------------------------------- +// Interface: JsonConfig_ManagerInterface +// Author: Musashi +// DO NOT MAKE ANY CHANGES TO THIS CLASS +//----------------------------------------------------------- +interface JsonConfig_ManagerInterface; + +static public function JsonConfig_ManagerInterface GetConfigManager(string InstanceName, optional bool bHasDefaultConfig = true); + +static public function JsonConfig_ManagerInterface GetDefaultConfigManager(); + +public function SerializeAndSaveConfig(); + +public function bool HasConfigProperty(coerce string PropertyName, optional string Namespace); + +public function SetConfigString(string PropertyName, coerce string Value); + +public function int GetConfigIntValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function float GetConfigFloatValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function name GetConfigNameValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function int GetConfigByteValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function bool GetConfigBoolValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigIntArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigFloatArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigNameArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function vector GetConfigVectorValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigStringArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function WeaponDamageValue GetConfigDamageValue(coerce string PropertyName, optional string Namespace); + +public function string GetConfigStringValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function string GetConfigTagValue(coerce string PropertyName, optional string Namespace); + diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_Interface.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_Interface.uc new file mode 100644 index 0000000..d2df583 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_Interface.uc @@ -0,0 +1,20 @@ +//----------------------------------------------------------- +// Interface: MCM_Builder_Interface +// Author: Musashi +// +//----------------------------------------------------------- + + +interface MCM_Builder_Interface; + +static public function MCM_Builder_Interface GetMCMBuilder(string InstanceName); + +public function array GetConfig(); + +public function string GetBuilderName(); + +public function string LocalizeItem(string Key); + +public function SerializeAndSaveBuilderConfig(); + +public function SerializeConfig(); diff --git a/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_SingletonFactoryInterface.uc b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_SingletonFactoryInterface.uc new file mode 100644 index 0000000..d5dbad5 --- /dev/null +++ b/MCMBuilderClientTestMod/MCMBuilderClientTestMod/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_SingletonFactoryInterface.uc @@ -0,0 +1,11 @@ +//----------------------------------------------------------- +// Class: MCM_Builder_SingletonFactoryInterface +// Author: Musashi +// DO NOT MAKE ANY CHANGES TO THIS CLASS +//----------------------------------------------------------- + +interface MCM_Builder_SingletonFactoryInterface; + +static function JsonConfig_ManagerInterface GetManagerInstance(string InstanceName, optional bool bHasDefaultConfig = true); + +static function MCM_Builder_Interface GetMCMBuilderInstance(string InstanceName); \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Config/XComEngine.ini b/ModConfigMenu/ModConfigMenu/Config/XComEngine.ini index 1ca7353..aa16def 100755 --- a/ModConfigMenu/ModConfigMenu/Config/XComEngine.ini +++ b/ModConfigMenu/ModConfigMenu/Config/XComEngine.ini @@ -1,8 +1,14 @@ [UnrealEd.EditorEngine] +EditPackages=ModConfigMenuAPI ++ModEditPackages=ModConfigMenuBuilderAPI_1_0_0 ++ModEditPackages=ModConfigMenuBuilder + [Engine.ScriptPackages] +NonNativePackages=ModConfigMenu ++NonNativePackages=ModConfigMenuBuilderAPI_1_0_0 ++NonNativePackages=ModConfigMenuBuilder + ;+NonNativePackages=ModConfigMenuAPI [Engine.Engine] diff --git a/ModConfigMenu/ModConfigMenu/Config/XComMCMBuilder.ini b/ModConfigMenu/ModConfigMenu/Config/XComMCMBuilder.ini new file mode 100644 index 0000000..66296b2 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Config/XComMCMBuilder.ini @@ -0,0 +1,2 @@ +[MusashisModToolbox.MCM_Builder_Screen] +VERSION_CFG = 1 diff --git a/ModConfigMenu/ModConfigMenu/ModConfigMenu.x2proj b/ModConfigMenu/ModConfigMenu/ModConfigMenu.x2proj index 04e7fa0..550f9e6 100755 --- a/ModConfigMenu/ModConfigMenu/ModConfigMenu.x2proj +++ b/ModConfigMenu/ModConfigMenu/ModConfigMenu.x2proj @@ -17,6 +17,9 @@ For full details on using this mod, troubleshooting, or even building your own m + + Content + Content @@ -70,6 +73,66 @@ For full details on using this mod, troubleshooting, or even building your own m Content + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + Content @@ -169,7 +232,11 @@ For full details on using this mod, troubleshooting, or even building your own m + + + + \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_OptionsScreen.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_OptionsScreen.uc index f4c965d..4819a28 100755 --- a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_OptionsScreen.uc +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_OptionsScreen.uc @@ -99,6 +99,9 @@ simulated function OnInit() { `log("MCM Core: hiding soldier guy on main menu for visibility."); HideSoldierIfMainMenu(); + + `LOG(default.class @ GetFuncName() @ "RegisterStrategyListeners",, 'ModConfigMenuBuilder'); + class'X2EventListenerTemplateManager'.static.RegisterStrategyListeners(); } } @@ -108,6 +111,9 @@ simulated function OnRemoved() { `log("MCM Core: unhiding soldier guy on main menu for visibility."); ShowSoldierIfMainMenu(); + + `LOG(default.class @ GetFuncName() @ "UnRegisterAllListeners",, 'ModConfigMenuBuilder'); + class'X2EventListenerTemplateManager'.static.UnRegisterAllListeners(); } } diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_SettingsPanelFacade.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_SettingsPanelFacade.uc index 869395f..8821115 100755 --- a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_SettingsPanelFacade.uc +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenu/Classes/MCM_SettingsPanelFacade.uc @@ -31,6 +31,7 @@ simulated function MCM_SettingsPanelFacade InitSettingsPanelFacade(int _PageID, Container = _Container; UiInstance = none; + return self; } // Internal diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig.uc new file mode 100644 index 0000000..09bb68e --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig.uc @@ -0,0 +1,167 @@ +//----------------------------------------------------------- +// Class: JsonConfiguc +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig extends JsonObject; + +struct ObjectKey +{ + var string Key; + var string ParentKey; +}; + +static public final function string GetPropertyName(coerce string PropertyName, optional string Namespace) +{ + if (Namespace != "") + { + PropertyName $= ":" $ Namespace; + } + + return PropertyName; +} + +static public function string SanitizeJson(string Json) +{ + local string Buffer; + local int CountBracketsOpen, CountBracketsClose, CountDoubleQuotes; + + Buffer = Repl(Repl(Repl(Json, "\n", ""), " ", ""), " ", ""); + + CountBracketsOpen = CountCharacters(Buffer, "{"); + CountBracketsClose = CountCharacters(Buffer, "}"); + CountDoubleQuotes = CountCharacters(Buffer, "\""); + + if (CountBracketsOpen != CountBracketsClose || + InStr(Buffer, "\"{") != INDEX_NONE || + CountDoubleQuotes % 2 != 0) + { + //`LOG(default.class @ GetFuncName() @ "Warning: invalid json" @ Buffer,, 'ModConfigMenuBuilder'); + return ""; + } + + Buffer = LTrimToFirstBracket(Buffer); + Buffer = RTrimToFirstBracket(Buffer); + + return Buffer; +} + +static public final function int CountCharacters(coerce string S, string Character) +{ + local int Count, Index, Max; + local string copy; + + copy = S; + + Max = Len(copy); + + for (Index = 0; Index < Max; Index++) + { + if (Left(copy, 1) == Character) + { + Count++; + } + copy = Right(copy, Len(copy) - 1); + } + + return Count; +} + +static public final function string LTrimToFirstBracket(coerce string S) +{ + while (Left(S, 1) != "{" && Len(S) > 0) + { + S = Right(S, Len(S) - 1); + } + return S; +} +static public final function string RTrimToFirstBracket(coerce string S) +{ + while (Right(S, 1) != "}" && Len(S) > 0) + { + S = Left(S, Len(S) - 1); + } + return S; +} + +static public final function array GetAllObjectKeys(coerce string Str) +{ + local array Chunks; + local string Chunk, ParentKey, GrandParentKey; + local array Keys; + local ObjectKey ObjKey, EmptyKey; + + ParentKey = ""; + GrandParentKey = ""; + + Str = Repl(Str, "\":{", "$$$\":{"); + Str = Repl(Str, "\"}}", "}\"}"); + Str = Repl(Str, "},", "}\""); + + Chunks = SplitString(Str, "\"", true); + + foreach Chunks(Chunk) + { + if (InStr(Chunk, "$$$") != INDEX_NONE) + { + ObjKey = EmptyKey; + ObjKey.ParentKey = ParentKey; + ObjKey.Key = Repl(Chunk, "$$$", ""); + Keys.AddItem(ObjKey); + } + + if (InStr(Chunk, "{") != INDEX_NONE) + { + if (ParentKey != "") + { + GrandParentKey = ParentKey; + } + ParentKey = ObjKey.Key; + } + + // Last level + if (InStr(Chunk, "}") != INDEX_NONE && ObjKey.Key == ParentKey) + { + ParentKey = GrandParentKey; + GrandParentKey = ""; + ObjKey = EmptyKey; + } + else if (InStr(Chunk, "}") != INDEX_NONE && ParentKey != "") + { + ParentKey = Keys[Keys.Find('Key', ParentKey)].ParentKey; + ObjKey = EmptyKey; + } + } + + return Keys; +} + +static public final function string GetObjectKey(coerce string S) +{ + local int Index, Max, DoubleQuoteUnicode; + local string Key; + local bool bStart; + + Max = Len(S); + DoubleQuoteUnicode = 34; + + for (Index = 0; Index < Max; Index++) + { + if (Asc(Left(S, 1)) == DoubleQuoteUnicode) + { + if (bStart) + break; + if (!bStart) + bStart = true; + } + + if (bStart && Asc(Left(S, 1)) != DoubleQuoteUnicode) + { + Key $= Left(S, 1); + } + + S = Right(S, Len(S) - 1); + } + + return Key; +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Array.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Array.uc new file mode 100644 index 0000000..a4df003 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Array.uc @@ -0,0 +1,59 @@ +//----------------------------------------------------------- +// Class: JsonConfig_Array +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig_Array extends Object implements (JsonConfig_Interface); + +var protectedwrite array ArrayValue; + +public function SetArrayValue(array StringArray) +{ + ArrayValue = StringArray; +} + +public function array GetArrayValue() +{ + return ArrayValue; +} + +public function string ToString() +{ + return Join(ArrayValue, ", "); +} + +public function Serialize(out JsonObject JsonObject, string PropertyName) +{ + if (ArrayValue.Length > 0) + { + JSonObject.SetStringValue(PropertyName, Join(ArrayValue, ", ")); + } +} + +public function bool Deserialize(out JSonObject Data, string PropertyName) +{ + local string UnserializedArrayValue; + local array EmptyArray; + + UnserializedArrayValue = Data.GetStringValue(PropertyName); + if (UnserializedArrayValue != "") + { + ArrayValue = SplitString(Repl(Repl(UnserializedArrayValue, " ", ""), " ", ""), ",", true); + return true; + } + + EmptyArray.Length = 0; + ArrayValue = EmptyArray; + + return false; +} + +function static string Join(array StringArray, optional string Delimiter = ",", optional bool bIgnoreBlanks = true) +{ + local string Result; + + JoinArray(StringArray, Result, Delimiter, bIgnoreBlanks); + + return Result; +} + diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Interface.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Interface.uc new file mode 100644 index 0000000..873a99e --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Interface.uc @@ -0,0 +1,12 @@ +//----------------------------------------------------------- +// Class: JsonConfig_Interface +// Author: Musashi +// +//----------------------------------------------------------- + + +interface JsonConfig_Interface; + +public function Serialize(out JsonObject JsonObject, string PropertyName); +public function bool Deserialize(JSonObject Data, string PropertyName); + diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Builder.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Builder.uc new file mode 100644 index 0000000..e613665 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Builder.uc @@ -0,0 +1,110 @@ +class JsonConfig_MCM_Builder extends JsonConfig implements(MCM_Builder_Interface) config(MCMBuilder) perobjectconfig perobjectlocalized; + +struct MCMConfigMapEntry +{ + var string PageID; + var JsonConfig_MCM_Page MCMConfigPage; +}; + +var config array MCMPages; +var protectedwrite array DeserialzedPagesMap; +var string BuilderName; +var array ObjectKeys; + +public function array GetConfig() +{ + return MCMPages; +} + +static public function MCM_Builder_Interface GetMCMBuilder(string InstanceName) +{ + local JsonConfig_MCM_Builder MCMBuilder; + + MCMBuilder = new (none, InstanceName) default.class; + MCMBuilder.DeserializeConfig(); + MCMBuilder.BuilderName = InstanceName; + + return MCM_Builder_Interface(MCMBuilder); +} + +public function string GetBuilderName() +{ + return BuilderName; +} + +public function string LocalizeItem(string Key) +{ + local string Locale; + + Locale = Localize(name @ default.class, Key, "ModConfigMenu"); + + if (InStr(Locale, "?INT?") > 0) + { + //`LOG(default.class @ GetFuncName() @ "Warning localization not found:" @ Key @ "in" @ name @ default.class,, 'ModConfigMenuBuilder'); + } + + return Locale; +} + +public function SerializeAndSaveBuilderConfig() +{ + SerializeConfig(); + SaveConfig(); +} + +private function DeserializeConfig() +{ + local MCMConfigMapEntry MapEntry; + local JSonObject JSonObject; + local JsonConfig_MCM_Page MCMPage; + local ObjectKey ObjKey; + local string SanitizedJsonString, SerializedMCMPage; + local array LocalMCMPages; + + ////`LOG(default.class @ GetFuncName() @ "found entries:" @ MCMPages.Length,, 'ModConfigMenuBuilder'); + + LocalMCMPages = GetConfig(); + + foreach LocalMCMPages(SerializedMCMPage) + { + SanitizedJsonString = SanitizeJson(SerializedMCMPage); + + if (SanitizedJsonString != "") + { + ObjectKeys = GetAllObjectKeys(SanitizedJsonString); + JSonObject = class'JSonObject'.static.DecodeJson(SanitizedJsonString); + + foreach ObjectKeys(ObjKey) + { + if (JSonObject != none && ObjKey.ParentKey == "") + { + if (DeserialzedPagesMap.Find('PageID', ObjKey.Key) == INDEX_NONE) + { + MCMPage = new class'JsonConfig_MCM_Page'; + if (MCMPage.Deserialize(JSonObject, ObjKey.Key, self)) + { + MapEntry.PageID = ObjKey.Key; + MapEntry.MCMConfigPage = MCMPage; + DeserialzedPagesMap.AddItem(MapEntry); + } + } + } + } + } + } +} + +public function SerializeConfig() +{ + local MCMConfigMapEntry MapEntry; + local JSonObject JSonObject; + + MCMPages.Length = 0; + + foreach DeserialzedPagesMap(MapEntry) + { + JSonObject = new () class'JsonObject'; + MapEntry.MCMConfigPage.Serialize(JSonObject, MapEntry.PageID); + MCMPages.AddItem(class'JSonObject'.static.EncodeJson(JSonObject)); + } +} diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Element.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Element.uc new file mode 100644 index 0000000..db01e29 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Element.uc @@ -0,0 +1,93 @@ +//----------------------------------------------------------- +// Class: JsonConfig_MCM_Element +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig_MCM_Element extends Object; + +var string ConfigKey; +var JsonConfig_MCM_Builder Builder; +var string SettingName; +var string Type; +var string Label; +var string Tooltip; +var string SliderMin; +var string SliderMax; +var string SliderStep; +var string ButtonLabel; +var JsonConfig_Array Options; + +public function string GetLabel() +{ + if (Label != "") + { + return Label; + } + + return Builder.LocalizeItem(SettingName $ "_LABEL"); +} + +public function string GetTooltip() +{ + if (Tooltip != "") + { + return Tooltip; + } + + return Builder.LocalizeItem(SettingName $ "_TOOLTIP"); +} + +public function Serialize(out JsonObject JsonObject, string PropertyName) +{ + local JsonObject JsonSubObject; + + ConfigKey = PropertyName; + + JsonSubObject = new () class'JsonObject'; + JsonSubObject.SetStringValue("SettingName", ConfigKey); + JsonSubObject.SetStringValue("Type", Type); + JsonSubObject.SetStringValue("Label", Label); + JsonSubObject.SetStringValue("Tooltip", Tooltip); + JsonSubObject.SetStringValue("SliderMin", SliderMin); + JsonSubObject.SetStringValue("SliderMax", SliderMax); + JsonSubObject.SetStringValue("SliderStep", SliderStep); + JsonSubObject.SetStringValue("ButtonLabel", ButtonLabel); + Options.Serialize(JsonSubObject, "Options"); + + JSonObject.SetObject(PropertyName, JsonSubObject); +} + +public function bool Deserialize(JSonObject Data, string PropertyName, JsonConfig_MCM_Builder BuilderParam) +{ + local JsonObject ElementJson; + + ConfigKey = PropertyName; + + Options = new class'JsonConfig_Array'; + + ElementJson = Data.GetObject(PropertyName); + if (ElementJson != none) + { + Builder = BuilderParam; + SettingName = ConfigKey; + Type = ElementJson.GetStringValue("Type"); + Label = ElementJson.GetStringValue("Label"); + Tooltip = ElementJson.GetStringValue("Tooltip"); + SliderMin = ElementJson.GetStringValue("SliderMin"); + SliderMax = ElementJson.GetStringValue("SliderMax"); + SliderStep = ElementJson.GetStringValue("SliderStep"); + ButtonLabel = ElementJson.GetStringValue("ButtonLabel"); + Options.Deserialize(ElementJson, "Options"); + + return (Type != ""); + } + return false; +} + + +defaultproperties +{ + Begin Object Class=JsonConfig_Array Name=DefaultJsonConfig_Array + End Object + Options = DefaultJsonConfig_Array; +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Group.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Group.uc new file mode 100644 index 0000000..d60ebcb --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Group.uc @@ -0,0 +1,102 @@ +//----------------------------------------------------------- +// Class: JsonConfig_MCM_Group +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig_MCM_Group extends Object; + +var JsonConfig_MCM_Builder Builder; +var protectedwrite string GroupName; +var protectedwrite string GroupLabel; +var string ConfigKey; + +var array Elements; +var string SaveConfigManager; + +public function SetGroupName(string GroupNameParam) +{ + GroupName = GroupNameParam; +} + +public function string GetGroupName() +{ + if (GroupName != "") + { + return GroupName; + } + + return ConfigKey; +} + +public function SetGroupLabel(string GroupLabelParam) +{ + GroupLabel = GroupLabelParam; +} + +public function string GetGroupLabel() +{ + if (GroupLabel != "") + { + return GroupLabel; + } + + return Builder.LocalizeItem(ConfigKey $ "_LABEL"); +} + +public function Serialize(out JsonObject JsonObject, string PropertyName) +{ + local JsonObject JsonSubObject; + + ConfigKey = PropertyName; + + JsonSubObject = new () class'JsonObject'; + JsonSubObject.SetStringValue("GroupName", GroupName); + JsonSubObject.SetStringValue("GroupLabel", GroupLabel); + JsonSubObject.SetStringValue("SaveConfigManager", SaveConfigManager); + + JSonObject.SetObject(PropertyName, JsonSubObject); +} + +public function bool Deserialize(JSonObject Data, string PropertyName, JsonConfig_MCM_Builder BuilderParam) +{ + local JsonObject GroupJson; + + ConfigKey = PropertyName; + + GroupJson = Data.GetObject(PropertyName); + if (GroupJson != none) + { + GroupName = GroupJson.GetStringValue("GroupName"); + GroupLabel = GroupJson.GetStringValue("GroupLabel"); + SaveConfigManager = GroupJson.GetStringValue("SaveConfigManager"); + + if (SaveConfigManager != "") + { + + } + + Builder = BuilderParam; + DeserializeElements(GroupJson); + + return true; + } + return false; +} + +private function DeserializeElements(JsonObject GroupJson) +{ + local JsonConfig_MCM_Element Element; + local ObjectKey ObjKey; + + foreach Builder.ObjectKeys(ObjKey) + { + if (ObjKey.ParentKey == ConfigKey) + { + Element = new class'JsonConfig_MCM_Element'; + if(Element.Deserialize(GroupJson, ObjKey.Key, Builder)) + { + Elements.AddItem(Element); + } + } + } +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Page.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Page.uc new file mode 100644 index 0000000..c5a0310 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_MCM_Page.uc @@ -0,0 +1,106 @@ +//----------------------------------------------------------- +// Class: JsonConfig_MCM_Page +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig_MCM_Page extends Object; + +var JsonConfig_MCM_Builder Builder; +var int MCMPageId; +var string ConfigKey; +var string PageTitle; +var string TabLabel; +var string EnableResetButton; +var string SaveConfigManager; +var array Groups; + +public function bool ShouldEnableResetButton() +{ + return bool(EnableResetButton); +} + +public function SetPageTitle(string PageTitleParam) +{ + PageTitle = PageTitleParam; +} + +public function string GetPageTitle() +{ + if (PageTitle != "") + { + return PageTitle; + } + + return Builder.LocalizeItem(ConfigKey $ "_TITLE"); +} + +public function SetTabLabel(string TabLabelParam) +{ + TabLabel = TabLabelParam; +} + +public function string GetTabLabel() +{ + if (TabLabel != "") + { + return TabLabel; + } + + return Builder.LocalizeItem(ConfigKey $ "_LABEL"); +} + +public function Serialize(out JsonObject JsonObject, string PropertyName) +{ + local JsonObject JsonSubObject; + + ConfigKey = PropertyName; + + JsonSubObject = new () class'JsonObject'; + JsonSubObject.SetStringValue("PageTitle", PageTitle); + JsonSubObject.SetStringValue("TabLabel", TabLabel); + JsonSubObject.SetStringValue("EnableResetButton", EnableResetButton); + JsonSubObject.SetStringValue("SaveConfigManager", SaveConfigManager); + + JSonObject.SetObject(PropertyName, JsonSubObject); +} + +public function bool Deserialize(JSonObject Data, string PropertyName, JsonConfig_MCM_Builder BuilderParam) +{ + local JsonObject PageJson; + + ConfigKey = PropertyName; + + PageJson = Data.GetObject(PropertyName); + if (PageJson != none) + { + PageTitle = PageJson.GetStringValue("PageTitle"); + TabLabel = PageJson.GetStringValue("TabLabel"); + EnableResetButton = PageJson.GetStringValue("EnableResetButton"); + SaveConfigManager = PageJson.GetStringValue("SaveConfigManager"); + Builder = BuilderParam; + + DeserializeGroups(PageJson); + + return true; + } + + return false; +} + +private function DeserializeGroups(JsonObject PageJson) +{ + local JsonConfig_MCM_Group Group; + local ObjectKey ObjKey; + + foreach Builder.ObjectKeys(ObjKey) + { + if (ObjKey.ParentKey == ConfigKey) + { + Group = new class'JsonConfig_MCM_Group'; + if(Group.Deserialize(PageJson, ObjKey.Key, Builder)) + { + Groups.AddItem(Group); + } + } + } +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Manager.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Manager.uc new file mode 100644 index 0000000..842e45d --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Manager.uc @@ -0,0 +1,314 @@ +class JsonConfig_Manager extends JsonConfig implements (JsonConfig_ManagerInterface) config(JsonConfigManager_NullConfig) perobjectconfig; + +struct ConfigPropertyMapEntry +{ + var string PropertyName; + var JsonConfig_TaggedConfigProperty ConfigProperty; +}; + +var config array ConfigProperties; +var protectedwrite array DeserialzedConfigPropertyMap; +var JsonConfig_Manager DefaultConfigManager; + +delegate bool TagFunctionDelegate(name TagFunctionName, JsonConfig_TaggedConfigProperty ConfigProperty, out string TagValue); + + +public function array GetConfig() +{ + return ConfigProperties; +} + +static public function JsonConfig_ManagerInterface GetConfigManager(string InstanceName, optional bool bHasDefaultConfig = true) +{ + local JsonConfig_Manager ConfigManager; + + ConfigManager = new (none, InstanceName) default.class; + + //`LOG(default.class @ GetFuncName() @ `ShowVar(ConfigManager) @ `ShowVar(InstanceName) @ `ShowVar(default.class) @ `ShowVar(JsonConfig_ManagerInterface(ConfigManager)),, 'ModConfigMenuBuilder'); + + ConfigManager.DeserializeConfig(); + + if (bHasDefaultConfig) + { + ConfigManager.SetDefaultConfigManager(InstanceName); + } + + return JsonConfig_ManagerInterface(ConfigManager); +} + +public function JsonConfig_ManagerInterface GetDefaultConfigManager() +{ + return JsonConfig_ManagerInterface(DefaultConfigManager); +} + +public function SetDefaultConfigManager(string InstanceName) +{ + local JsonConfig_ManagerInterface LocalJsonConfig_ManagerInterface; + LocalJsonConfig_ManagerInterface = class'JsonConfig_ManagerDefault'.static.GetConfigManager(InstanceName, false); + DefaultConfigManager = JsonConfig_Manager(LocalJsonConfig_ManagerInterface); + //`LOG(default.class @ GetFuncName() @ `ShowVar(InstanceName) @ `ShowVar(DefaultConfigManager),, 'ModConfigMenuBuilder'); +} + +public function SerializeAndSaveConfig() +{ + SerializeConfig(); + SaveConfig(); +} + +private function DeserializeConfig() +{ + local ConfigPropertyMapEntry MapEntry; + local JSonObject JSonObject, JSonObjectProperty; + local JsonConfig_TaggedConfigProperty ConfigProperty; + local string SerializedConfigProperty, PropertyName; + local array Sections; + + GetPerObjectConfigSections(self.Class, Sections); + + //`LOG(default.class @ GetFuncName() @ self.Name @ "found entries:" @ ConfigProperties.Length @ Sections[0],, 'ModConfigMenuBuilder'); + + foreach ConfigProperties(SerializedConfigProperty) + { + PropertyName = GetObjectKey(SanitizeJson(SerializedConfigProperty)); + JSonObject = class'JSonObject'.static.DecodeJson(SanitizeJson(SerializedConfigProperty)); + + if (JSonObject != none && PropertyName != "") + { + JSonObjectProperty = JSonObject.GetObject(PropertyName); + + if (JSonObjectProperty != none && + DeserialzedConfigPropertyMap.Find('PropertyName', PropertyName) == INDEX_NONE) + { + ConfigProperty = new class'JsonConfig_TaggedConfigProperty'; + ConfigProperty.ManagerInstance = self; + ConfigProperty.Deserialize(JSonObjectProperty); + MapEntry.PropertyName = PropertyName; + MapEntry.ConfigProperty = ConfigProperty; + DeserialzedConfigPropertyMap.AddItem(MapEntry); + } + } + } +} + +private function SerializeConfig() +{ + local ConfigPropertyMapEntry MapEntry; + local JSonObject JSonObject; + + ConfigProperties.Length = 0; + + foreach DeserialzedConfigPropertyMap(MapEntry) + { + JSonObject = new () class'JsonObject'; + JSonObject.SetObject(MapEntry.PropertyName, MapEntry.ConfigProperty.Serialize()); + ConfigProperties.AddItem(class'JSonObject'.static.EncodeJson(JSonObject)); + } +} + +public function bool HasConfigProperty(coerce string PropertyName, optional string Namespace) +{ + PropertyName = GetPropertyName(PropertyName, Namespace); + + return DeserialzedConfigPropertyMap.Find('PropertyName', PropertyName) != INDEX_NONE; +} + +public function SetConfigString(string PropertyName, coerce string Value) +{ + local JsonConfig_TaggedConfigProperty ConfigProperty; + local ConfigPropertyMapEntry MapEntry; + + if (HasConfigProperty(PropertyName)) + { + ConfigProperty = GetConfigProperty(PropertyName); + ConfigProperty.SetValue(Value); + } + else + { + ConfigProperty = new class'JsonConfig_TaggedConfigProperty'; + ConfigProperty.ManagerInstance = self; + ConfigProperty.SetValue(Value); + + MapEntry.PropertyName = PropertyName; + MapEntry.ConfigProperty = ConfigProperty; + + DeserialzedConfigPropertyMap.AddItem(MapEntry); + } +} + +public function int GetConfigIntValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + return int(GetConfigStringValue(PropertyName, TagFunction, Namespace)); +} + +public function float GetConfigFloatValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + return float(GetConfigStringValue(PropertyName, TagFunction, Namespace)); +} + +public function name GetConfigNameValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + return name(GetConfigStringValue(PropertyName, TagFunction, Namespace)); +} + +public function int GetConfigByteValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + return byte(GetConfigStringValue(PropertyName, TagFunction, Namespace)); +} + +public function bool GetConfigBoolValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + return bool(GetConfigStringValue(PropertyName, TagFunction, Namespace)); +} + +public function array GetConfigIntArray(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + local array StringArray; + local string Value; + local array IntArray; + + StringArray = GetConfigStringArray(PropertyName, TagFunction, Namespace); + + foreach StringArray(Value) + { + IntArray.AddItem(int(Value)); + } + + return IntArray; +} + +public function array GetConfigFloatArray(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + local array StringArray; + local string Value; + local array FloatArray; + + StringArray = GetConfigStringArray(PropertyName, TagFunction, Namespace); + + foreach StringArray(Value) + { + FloatArray.AddItem(float(Value)); + } + + return FloatArray; +} + +public function array GetConfigNameArray(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + local array StringArray; + local string Value; + local array NameArray; + + StringArray = GetConfigStringArray(PropertyName, TagFunction, Namespace); + + foreach StringArray(Value) + { + NameArray.AddItem(name(Value)); + } + + return NameArray; +} + +public function vector GetConfigVectorValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + local JsonConfig_TaggedConfigProperty ConfigProperty; + + ConfigProperty = GetConfigProperty(PropertyName); + + if (ConfigProperty != none) + { + ////`LOG(default.class @ GetFuncName() @ `ShowVar(PropertyName) @ "Value:" @ ConfigProperty.VectorValue.ToString() @ `ShowVar(Namespace),, 'ModConfigMenuBuilder'); + return ConfigProperty.GetVectorValue(); + } + + return vect(0, 0, 0); +} + +public function array GetConfigStringArray(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + local JsonConfig_TaggedConfigProperty ConfigProperty; + local array EmptyArray; + + ConfigProperty = GetConfigProperty(PropertyName, Namespace); + + if (ConfigProperty != none) + { + ////`LOG(default.class @ GetFuncName() @ `ShowVar(PropertyName) @ "Value:" @ ConfigProperty.ArrayValue.ToString() @ `ShowVar(Namespace),, 'ModConfigMenuBuilder'); + return ConfigProperty.GetArrayValue(); + } + + EmptyArray.Length = 0; // Prevent unassigned warning + + return EmptyArray; +} + +public function WeaponDamageValue GetConfigDamageValue(coerce string PropertyName, optional string Namespace) +{ + local JsonConfig_TaggedConfigProperty ConfigProperty; + local WeaponDamageValue Value; + + ConfigProperty = GetConfigProperty(PropertyName, Namespace); + + if (ConfigProperty != none) + { + Value = ConfigProperty.GetDamageValue(); + ////`LOG(default.class @ GetFuncName() @ `ShowVar(PropertyName) @ "Value:" @ ConfigProperty.DamageValue.ToString() @ `ShowVar(Namespace),, 'ModConfigMenuBuilder'); + } + + return Value; +} + +public function string GetConfigStringValue(coerce string PropertyName, optional string TagFunction, optional string Namespace) +{ + local JsonConfig_TaggedConfigProperty ConfigProperty; + local string Value; + + ConfigProperty = GetConfigProperty(PropertyName, Namespace); + + if (ConfigProperty != none) + { + Value = ConfigProperty.GetValue(TagFunction); + ////`LOG(default.class @ GetFuncName() @ `ShowVar(PropertyName) @ `ShowVar(Value) @ `ShowVar(TagFunction) @ `ShowVar(Namespace),, 'ModConfigMenuBuilder'); + } + + return Value; +} + +public function string GetConfigTagValue(coerce string PropertyName, optional string Namespace) +{ + local JsonConfig_TaggedConfigProperty ConfigProperty; + + ConfigProperty = GetConfigProperty(PropertyName, Namespace); + + if (ConfigProperty != none) + { + return ConfigProperty.GetTagValue(); + } + + return ""; +} + + +public function JsonConfig_TaggedConfigProperty GetConfigProperty( + coerce string PropertyName, + optional string Namespace +) +{ + local int Index; + + PropertyName = GetPropertyName(PropertyName, Namespace); + + Index = DeserialzedConfigPropertyMap.Find('PropertyName', PropertyName); + if (Index != INDEX_NONE) + { + return DeserialzedConfigPropertyMap[Index].ConfigProperty; + } + + if (DefaultConfigManager != none) + { + return DefaultConfigManager.GetConfigProperty(PropertyName, Namespace); + } + + //`LOG(default.class @ GetFuncName() @ "could not find config property for" @ PropertyName @ DeserialzedConfigPropertyMap.Length,, 'ModConfigMenuBuilder'); + + return none; +} diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_ManagerDefault.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_ManagerDefault.uc new file mode 100644 index 0000000..6ed972c --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_ManagerDefault.uc @@ -0,0 +1,8 @@ +//----------------------------------------------------------- +// Class: JsonConfig_ManagerDefault +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig_ManagerDefault extends JsonConfig_Manager config(JsonConfigManager); + + diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_TaggedConfigProperty.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_TaggedConfigProperty.uc new file mode 100644 index 0000000..fc4df0b --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_TaggedConfigProperty.uc @@ -0,0 +1,269 @@ +//----------------------------------------------------------- +// Class: JsonConfig_TaggedConfigProperty +// Author: Musashi +// Defines a config entry for a config value with meta information for automatic localization tags +//----------------------------------------------------------- + +class JsonConfig_TaggedConfigProperty extends Object dependson(JsonConfig_Manager); + +var JsonConfig_Manager ManagerInstance; +var protected string Value; +var protectedwrite JsonConfig_Vector VectorValue; +var protectedwrite JsonConfig_Array ArrayValue; +var protectedwrite JsonConfig_WeaponDamageValue DamageValue; + +var protected string Namespace; +var protected string TagFunction; +var protected string TagParam; +var protected string TagPrefix; +var protected string TagSuffix; + +var protectedwrite bool bIsVector; +var protectedwrite bool bIsArray; +var protectedwrite bool bIsDamageValue; + +public function string GetTagParam() +{ + local string PropertyRefValue; + + // Check if the tag param is referencing another property value + if (ManagerInstance.HasConfigProperty(TagParam)) + { + PropertyRefValue = ManagerInstance.GetConfigStringValue(TagParam); + + if (PropertyRefValue != "") + { + return PropertyRefValue; + } + } + + return TagParam; +} + +public function string GetValue(optional string TagFunctionIn) +{ + if (TagFunctionIn != "") + { + return GetTagValueModifiedByTagFunction(TagFunctionIn); + } + + return Value; +} + +public function SetValue(string ValueParam) +{ + bIsVector = false; + bIsArray = false; + bIsDamageValue = false; + Value = ValueParam; +} + +public function vector GetVectorValue() +{ + return VectorValue.GetVectorValue(); +} + +public function SetVectorValue(vector VectorParam) +{ + bIsVector = true; + bIsArray = false; + bIsDamageValue = false; + VectorValue.SetVectorValue(VectorParam); +} + +public function array GetArrayValue() +{ + return ArrayValue.GetArrayValue(); +} + +public function SetArrayValue(array ArrayValueParam) +{ + bIsVector = false; + bIsArray = true; + bIsDamageValue = false; + ArrayValue.SetArrayValue(ArrayValueParam); +} + +public function WeaponDamageValue GetDamageValue() +{ + return DamageValue.GetDamageValue(); +} + +public function SetDamageValue(WeaponDamageValue DamageValueParam) +{ + bIsVector = false; + bIsArray = false; + bIsDamageValue = true; + DamageValue.SetDamageValue(DamageValueParam); +} + +public function string GetTagFunctionValue() +{ + return TagFunction; +} + +public function SetTagFunctionValue(string TagFunctionParam) +{ + TagFunction = TagFunctionParam; +} + +public function SetTagParamValue(string TagParamParam) +{ + TagParam = TagParamParam; +} + +public function string GetTagParamValue() +{ + return TagParam; +} + +public function string GetTagValue() +{ + local string TagValue; + + if (bIsVector) + { + TagValue = VectorValue.ToString(); + } + else if (bIsArray) + { + TagValue = ArrayValue.ToString(); + } + else if (bIsDamageValue) + { + DamageValue.ToString(); + } + else + { + TagValue = Value; + } + + if (!bIsVector && + TagFunction != "") + { + TagValue = GetTagValueModifiedByTagFunction(TagFunction); + } + + return TagPrefix $ TagValue $ TagSuffix; +} + +function string GetTagValueModifiedByTagFunction(string TagFunctionIn) +{ + local int OutValue; + local array LocalArrayValue; + + switch (name(TagFunctionIn)) + { + case 'TagValueToPercent': + OutValue = int(float(Value) * 100); + break; + case 'TagValueToPercentMinusHundred': + OutValue = int(float(Value) * 100 - 100); + break; + case 'TagValueMetersToTiles': + OutValue = int(float(Value) * class'XComWorldData'.const.WORLD_METERS_TO_UNITS_MULTIPLIER / class'XComWorldData'.const.WORLD_StepSize); + break; + case 'TagValueTilesToMeters': + OutValue = int(float(Value) * class'XComWorldData'.const.WORLD_StepSize / class'XComWorldData'.const.WORLD_METERS_TO_UNITS_MULTIPLIER); + break; + case 'TagValueTilesToUnits': + OutValue = int(float(Value) * class'XComWorldData'.const.WORLD_StepSize); + break; + case 'TagValueParamAddition': + OutValue = int(float(Value) + float(GetTagParam())); + break; + case 'TagValueParamMultiplication': + OutValue = int(float(Value) * float(GetTagParam())); + break; + case 'TagArrayValue': + LocalArrayValue = GetArrayValue(); + return LocalArrayValue[int(GetTagParam())]; + break; + default: + break; + } + + return string(OutValue); +} + + +function JSonObject Serialize() +{ + local JsonObject JsonObject; + + JSonObject = new () class'JsonObject'; + + if (bIsArray) + { + ArrayValue.Serialize(JSonObject, "ArrayValue"); + } + else if (bIsVector) + { + VectorValue.Serialize(JSonObject, "VectorValue"); + } + else if (bIsDamageValue) + { + DamageValue.Serialize(JSonObject, "DamageValue"); + } + else + { + JSonObject.SetStringValue("Value", Value); + } + + if (Namespace != "") + { + JSonObject.SetStringValue("Namespace", Namespace); + } + if (TagFunction != "") + { + JSonObject.SetStringValue("TagFunction", TagFunction); + } + if (TagParam != "") + { + JSonObject.SetStringValue("TagParam", TagParam); + } + if (TagPrefix != "") + { + JSonObject.SetStringValue("TagPrefix", TagPrefix); + } + if (TagSuffix != "") + { + JSonObject.SetStringValue("TagSuffix", TagSuffix); + } + + return JSonObject; +} + +function Deserialize(JSonObject Data) +{ + VectorValue = new class'JsonConfig_Vector'; + ArrayValue = new class'JsonConfig_Array'; + DamageValue = new class'JsonConfig_WeaponDamageValue'; + + bIsVector = VectorValue.Deserialize(Data, "VectorValue"); + bIsArray = ArrayValue.Deserialize(Data, "ArrayValue"); + bIsDamageValue = DamageValue.Deserialize(Data, "DamageValue"); + + Value = Data.GetStringValue("Value"); + + Namespace = Data.GetStringValue("Namespace"); + TagFunction = Data.GetStringValue("TagFunction"); + TagParam = Data.GetStringValue("TagParam"); + TagPrefix = Data.GetStringValue("TagPrefix"); + TagSuffix = Data.GetStringValue("TagSuffix"); +} + +defaultproperties +{ + Begin Object Class=JsonConfig_Vector Name=TaggedDefaultJsonConfig_Vector + End Object + VectorValue = TaggedDefaultJsonConfig_Vector; + + Begin Object Class=JsonConfig_Array Name=TaggedDefaultJsonConfig_Array + End Object + ArrayValue = TaggedDefaultJsonConfig_Array; + + Begin Object Class=JsonConfig_WeaponDamageValue Name=TaggedDefaultJsonConfig_WeaponDamageValue + End Object + DamageValue = TaggedDefaultJsonConfig_WeaponDamageValue; +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Vector.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Vector.uc new file mode 100644 index 0000000..7194fd8 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_Vector.uc @@ -0,0 +1,55 @@ +//----------------------------------------------------------- +// Class: JsonConfig_Vector +// Author: Muasshi +// +//----------------------------------------------------------- +class JsonConfig_Vector extends Object implements(JsonConfig_Interface); + +var protectedwrite vector VectorValue; + +public function SetVectorValue(vector VectorParam) +{ + VectorValue = VectorParam; +} + +public function vector GetVectorValue() +{ + return VectorValue; +} + +public function string ToString() +{ + return VectorValue.X $ "," $ VectorValue.Y $ "," $ VectorValue.Z; +} + +public function Serialize(out JsonObject JsonObject, string PropertyName) +{ + local JsonObject JsonSubObject; + + JsonSubObject = new () class'JsonObject'; + JsonSubObject.SetIntValue("X", VectorValue.X); + JsonSubObject.SetIntValue("Y", VectorValue.X); + JsonSubObject.SetIntValue("Z", VectorValue.X); + + JSonObject.SetObject(PropertyName, JsonSubObject); +} + +public function bool Deserialize(JSonObject Data, string PropertyName) +{ + local JSonObject VectorJson; + + VectorJson = Data.GetObject(PropertyName); + if (VectorJson != none) + { + VectorValue.X = VectorJson.GetIntValue("X"); + VectorValue.Y = VectorJson.GetIntValue("Y"); + VectorValue.Z = VectorJson.GetIntValue("Z"); + return true; + } + + VectorValue.X = 0; + VectorValue.Y = 0; + VectorValue.Z = 0; + + return false; +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_WeaponDamageValue.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_WeaponDamageValue.uc new file mode 100644 index 0000000..bb9fb6d --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/JsonConfig_WeaponDamageValue.uc @@ -0,0 +1,74 @@ +//----------------------------------------------------------- +// Class: JsonConfig_WeaponDamageValue +// Author: Musashi +// +//----------------------------------------------------------- +class JsonConfig_WeaponDamageValue extends Object implements (JsonConfig_Interface); + +var protectedwrite WeaponDamageValue DamageValue; + +public function SetDamageValue(WeaponDamageValue DamageValueParam) +{ + DamageValue = DamageValueParam; +} + +public function WeaponDamageValue GetDamageValue() +{ + return DamageValue; +} + +public function string ToString() +{ + // @TODO make proper damage preview function + return (DamageValue.Damage - DamageValue.Spread) $ "-" $ (DamageValue.Damage + DamageValue.Spread); +} + +public function Serialize(out JsonObject JsonObject, string PropertyName) +{ + local JsonObject JsonSubObject; + + JsonSubObject = new () class'JsonObject'; + JsonSubObject.SetIntValue("Damage", DamageValue.Damage); + JsonSubObject.SetIntValue("Spread", DamageValue.Spread); + JsonSubObject.SetIntValue("PlusOne", DamageValue.PlusOne); + JsonSubObject.SetIntValue("Crit", DamageValue.Crit); + JsonSubObject.SetIntValue("Pierce", DamageValue.Pierce); + JsonSubObject.SetIntValue("Rupture", DamageValue.Rupture); + JsonSubObject.SetIntValue("Shred", DamageValue.Shred); + JsonSubObject.SetStringValue("Tag", string(DamageValue.Tag)); + JsonSubObject.SetStringValue("DamageType", string(DamageValue.DamageType)); + + JSonObject.SetObject(PropertyName, JsonSubObject); +} + +public function bool Deserialize(JSonObject Data, string PropertyName) +{ + local JsonObject DamageValueJson; + + DamageValueJson = Data.GetObject(PropertyName); + if (DamageValueJson != none) + { + DamageValue.Damage = DamageValueJson.GetIntValue("Damage"); + DamageValue.Spread = DamageValueJson.GetIntValue("Spread"); + DamageValue.PlusOne = DamageValueJson.GetIntValue("PlusOne"); + DamageValue.Crit = DamageValueJson.GetIntValue("Crit"); + DamageValue.Pierce = DamageValueJson.GetIntValue("Pierce"); + DamageValue.Rupture = DamageValueJson.GetIntValue("Rupture"); + DamageValue.Shred = DamageValueJson.GetIntValue("Shred"); + DamageValue.Tag = name(DamageValueJson.GetStringValue("Tag")); + DamageValue.DamageType = name(DamageValueJson.GetStringValue("DamageType")); + return true; + } + + DamageValue.Damage = 0; + DamageValue.Spread = 0; + DamageValue.PlusOne = 0; + DamageValue.Crit = 0; + DamageValue.Pierce = 0; + DamageValue.Rupture = 0; + DamageValue.Shred = 0; + DamageValue.Tag = ''; + DamageValue.DamageType = ''; + + return false; +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_Defaults.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_Defaults.uc new file mode 100644 index 0000000..91308c7 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_Defaults.uc @@ -0,0 +1,8 @@ +//----------------------------------------------------------- +// Class: MCMBuilder_Defaults +// Author: Musashi +// Dummy for MCM Framework. DO NOT DELETE +//----------------------------------------------------------- +class MCM_Builder_Defaults extends Object config(MCMBuilder); + +var config int VERSION_CFG; \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_Screen.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_Screen.uc new file mode 100644 index 0000000..0fba42c --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_Screen.uc @@ -0,0 +1,453 @@ +//----------------------------------------------------------- +// Class: MCM_Builder_Screen +// Author: Musashi +// Here we marry the MCMBuilder with the MCM Api +// ATTENTION: The event api is experimental at the moment and doesnt work if the MCM Options are openend in the Shell screen +// This could be fixed in the Highlander (https://github.com/X2CommunityCore/X2WOTCCommunityHighlander/issues/297) but even then would need the highlander to work properly +// Maybe it would be better to replace it by an delegate based system. +// Note the event system isnt necessary for the basic functionality +//----------------------------------------------------------- +class MCM_Builder_Screen extends Object config(MCMBuilder); + +struct BuilderInstance +{ + var int PageId; + var JsonConfig_MCM_Builder Builder; +}; + +var config int VERSION_CFG; +var config array MCMBuilder; + +var array BuilderInstances; + +event OnInit(UIScreen Screen) +{ + if (MCM_API(Screen) != none) + { + MCM_API(Screen).RegisterClientMod(1, 0, ClientModCallback); + } +} + +simulated function ClientModCallback(MCM_API_Instance ConfigAPI, int GameMode) +{ + local string BuilderName; + + foreach default.MCMBuilder(BuilderName) + { + BuildMCM( + BuilderName, + ConfigAPI, + GameMode + ); + } +} + +simulated function BuildMCM( + string BuilderName, + MCM_API_Instance ConfigAPI, + int GameMode +) +{ + local MCM_Builder_Interface BuilderInterface; + local BuilderInstance Instance; + local MCMConfigMapEntry MapEntry; + local JsonConfig_MCM_Page MCMPageConfig; + local JsonConfig_MCM_Group MCMGroupConfig; + local JsonConfig_MCM_Element MCMElementConfig; + local JsonConfig_ManagerInterface SaveConfigManager; + local MCM_API_SettingsPage Page; + local MCM_API_SettingsGroup Group; + local name SetttingName; + + BuilderInterface = class'ConfigFactory'.static.GetMCMBuilder(BuilderName); + // BuilderInterface = class'MCM_Builder_SingletonFactory'.static.GetMCMBuilderInstance(BuilderName); + Instance.Builder = JsonConfig_MCM_Builder(BuilderInterface); + + foreach Instance.Builder.DeserialzedPagesMap(MapEntry) + { + MCMPageConfig = MapEntry.MCMConfigPage; + Page = ConfigAPI.NewSettingsPage(MCMPageConfig.GetPageTitle()); + Page.SetPageTitle(MCMPageConfig.GetTabLabel()); + + if (MCMPageConfig.ShouldEnableResetButton()) + { + Page.EnableResetButton(ResetButtonClicked); + } + + MCMPageConfig.MCMPageId = Page.GetPageId(); + Instance.PageId = Page.GetPageId(); + BuilderInstances.AddItem(Instance); + + foreach MCMPageConfig.Groups(MCMGroupConfig) + { + SaveConfigManager = GetConfigManager(MCMPageConfig, MCMGroupConfig); + + Group = Page.AddGroup(name(MCMGroupConfig.GetGroupName()), MCMGroupConfig.GetGroupLabel()); + + foreach MCMGroupConfig.Elements(MCMElementConfig) + { + SetttingName = name(Caps(MCMElementConfig.SettingName)); + + switch (MCMElementConfig.Type) + { + case "Label": + Group.AddLabel( + SetttingName, + MCMElementConfig.GetLabel(), + MCMElementConfig.GetTooltip() + ); + break; + case "Button": + Group.AddButton( + SetttingName, + MCMElementConfig.GetLabel(), + MCMElementConfig.GetTooltip(), + MCMElementConfig.ButtonLabel, + ButtonClickHandler + ); + break; + case "Checkbox": + Group.AddCheckbox( + SetttingName, + MCMElementConfig.GetLabel(), + MCMElementConfig.GetTooltip(), + SaveConfigManager.GetConfigBoolValue(MCMElementConfig.SettingName), + BoolSaveHandler, + BoolChangeHandler + ); + break; + case "Slider": + Group.AddSlider( + SetttingName, + MCMElementConfig.GetLabel(), + MCMElementConfig.GetTooltip(), + float(MCMElementConfig.SliderMin), + float(MCMElementConfig.SliderMax), + float(MCMElementConfig.SliderStep), + SaveConfigManager.GetConfigFloatValue(MCMElementConfig.SettingName), + FloatSaveHandler, + FloatChangeHandler + ); + break; + case "Spinner": + Group.AddSpinner( + SetttingName, + MCMElementConfig.GetLabel(), + MCMElementConfig.GetTooltip(), + MCMElementConfig.Options.GetArrayValue(), + SaveConfigManager.GetConfigStringValue(MCMElementConfig.SettingName), + StringSaveHandler, + StringChangeHandler + ); + break; + case "Dropdown": + Group.AddDropdown( + SetttingName, + MCMElementConfig.GetLabel(), + MCMElementConfig.GetTooltip(), + MCMElementConfig.Options.GetArrayValue(), + SaveConfigManager.GetConfigStringValue(MCMElementConfig.SettingName), + StringSaveHandler, + StringChangeHandler + ); + break; + default: + //`LOG(default.class @ GetFuncName() @ "unknown MCM element type" @ MCMElementConfig.Type); + break; + } + } + } + + Page.ShowSettings(); + Page.SetSaveHandler(SaveButtonClicked); + } +} + +simulated function ButtonClickHandler(MCM_API_Setting Setting) +{ + `XEVENTMGR.TriggerEvent('MCM_ButtonClick', Setting, GetBuilder(Setting.GetParentGroup().GetParentPage().GetPageId()), none); +} + +simulated function BoolChangeHandler(MCM_API_Setting Setting, bool SettingValue) +{ + ElementChangeHandler(Setting, SettingValue); +} + +simulated function BoolSaveHandler(MCM_API_Setting Setting, bool SettingValue) +{ + ElementSaveHandler(Setting, SettingValue); +} + +simulated function FloatChangeHandler(MCM_API_Setting Setting, float SettingValue) +{ + ElementChangeHandler(Setting, SettingValue); +} + +simulated function FloatSaveHandler(MCM_API_Setting Setting, float SettingValue) +{ + ElementSaveHandler(Setting, SettingValue); +} + +simulated function StringChangeHandler(MCM_API_Setting Setting, string SettingValue) +{ + ElementChangeHandler(Setting, SettingValue); +} + +simulated function StringSaveHandler(MCM_API_Setting Setting, string SettingValue) +{ + ElementSaveHandler(Setting, SettingValue); +} + +simulated function ElementChangeHandler(MCM_API_Setting Setting, coerce string SettingValue) +{ + local JsonObject Tuple; + + Tuple = new class'JsonObject'; + Tuple.SetStringValue("Id", "MCM_ChangeHandler"); + Tuple.SetObject("MCMBuilder", GetBuilder(Setting.GetParentGroup().GetParentPage().GetPageId())); + Tuple.SetStringValue("SettingValue", SettingValue); + Tuple.SetStringValue("SettingName", string(Setting.GetName())); + Tuple.SetStringValue("SettingLabel", Setting.GetLabel()); + + `LOG(default.class @ GetFuncName() @ Setting @ Setting.GetName() @ Setting.GetLabel() @ Setting.GetSettingType(),, 'ModConfigMenuBuilder'); + + `XEVENTMGR.TriggerEvent('MCM_ChangeHandler', Setting, Tuple, none); +} + +simulated function ElementSaveHandler(MCM_API_Setting Setting, coerce string SettingValue) +{ + local JsonConfig_MCM_Page Page; + local JsonConfig_MCM_Group Group; + local JsonConfig_ManagerInterface SaveConfigManager; + local JsonObject Tuple; + local bool bOverrideDefaultHandler; + + bOverrideDefaultHandler = false; + + Tuple = new class'JsonObject'; + Tuple.SetStringValue("Id", "MCM_SaveHandler"); + Tuple.SetObject("MCMBuilder", GetBuilder(Setting.GetParentGroup().GetParentPage().GetPageId())); + Tuple.SetStringValue("SettingValue", SettingValue); + Tuple.SetBoolValue("bOverrideDefaultHandler", bOverrideDefaultHandler); + Tuple.SetStringValue("SettingName", string(Setting.GetName())); + Tuple.SetStringValue("SettingLabel",Setting.GetLabel()); + + `XEVENTMGR.TriggerEvent('MCM_SaveHandler', Setting, Tuple, none); + + if (!Tuple.GetBoolValue("bOverrideDefaultHandler")) + { + + Page = GetPage(Setting.GetParentGroup().GetParentPage().GetPageId()); + Group = GetGroup( + Setting.GetParentGroup().GetParentPage().GetPageId(), + Setting.GetParentGroup().GetName() + ); + SaveConfigManager = GetConfigManager(Page, Group); + SaveConfigManager.SetConfigString(Caps(string(Setting.GetName())), SettingValue); + } +} + +simulated function SaveButtonClicked(MCM_API_SettingsPage Page) +{ + local JsonConfig_MCM_Page ConfigPage; + local JsonConfig_MCM_Group ConfigGroup; + local JsonConfig_Manager SaveConfigManager; + local JsonConfig_ManagerInterface Temp; + local JsonObject Tuple; + local bool bOverrideDefaultHandler; + local int Index; + + bOverrideDefaultHandler = false; + + Tuple = new class'JsonObject'; + Tuple.SetStringValue("Id", "MCM_SaveButtonClicked"); + Tuple.SetBoolValue("bOverrideDefaultHandler", bOverrideDefaultHandler); + Tuple.SetObject("MCMBuilder", GetBuilder(Page.GetPageId())); + + `XEVENTMGR.TriggerEvent('MCM_SaveButtonClicked', Page, Tuple, none); + + if (!Tuple.GetBoolValue("bOverrideDefaultHandler")) + { + for (Index = 0; Index < Page.GetGroupCount(); Index++) + { + ConfigGroup = GetGroup( + Page.GetPageId(), + Page.GetGroupByIndex(Index).GetName() + ); + if (ConfigGroup.SaveConfigManager != "") + { + Temp = class'MCM_Builder_SingletonFactory'.static.GetManagerInstance(ConfigGroup.SaveConfigManager); + SaveConfigManager = JsonConfig_Manager(Temp); + SaveConfigManager.SerializeAndSaveConfig(); + } + } + + ConfigPage = GetPage(Page.GetPageId()); + + Temp = class'MCM_Builder_SingletonFactory'.static.GetManagerInstance(ConfigPage.SaveConfigManager); + Temp.SerializeAndSaveConfig(); + + `XEVENTMGR.TriggerEvent('MCM_ConfigSaved', Page, GetBuilder(Page.GetPageId()), none); + } +} + +simulated function ResetButtonClicked(MCM_API_SettingsPage Page) +{ + local JsonConfig_MCM_Page ConfigPage; + local JsonConfig_MCM_Group ConfigGroup; + local JsonConfig_ManagerInterface SaveConfigManager, DefaultConfigManager; + local int Index; + local int SettingIndex; + local MCM_API_SettingsGroup Group; + local MCM_API_Setting Setting; + local MCM_API_Checkbox Checkbox; + local MCM_API_Slider Slider; + local MCM_API_Spinner Spinner; + local MCM_API_Dropdown Dropdown; + local JsonObject Tuple; + local bool bOverrideDefaultHandler; + + bOverrideDefaultHandler = false; + + Tuple = new class'JsonObject'; + Tuple.SetStringValue("Id", "ResetButtonClicked"); + Tuple.SetObject("MCMBuilder", GetBuilder(Page.GetPageId())); + Tuple.SetBoolValue("bOverrideDefaultHandler", bOverrideDefaultHandler); + + `XEVENTMGR.TriggerEvent('MCM_ResetButtonClicked', Page, Tuple, none); + if (!Tuple.GetBoolValue("bOverrideDefaultHandler")) + { + ConfigPage = GetPage(Page.GetPageId()); + + for (Index = 0; Index < Page.GetGroupCount(); Index++) + { + Group = Page.GetGroupByIndex(Index); + + ConfigGroup = GetGroup( + Page.GetPageId(), + Page.GetGroupByIndex(Index).GetName() + ); + SaveConfigManager = GetConfigManager(ConfigPage, ConfigGroup); + DefaultConfigManager = SaveConfigManager.GetDefaultConfigManager(); + + for (SettingIndex = 0; SettingIndex < Group.GetNumberOfSettings(); SettingIndex++) + { + Setting = Group.GetSettingByIndex(SettingIndex); + + switch (Setting.GetSettingType()) + { + case eSettingType_Checkbox: + Checkbox = MCM_API_Checkbox(Setting); + Checkbox.SetValue(DefaultConfigManager.GetConfigBoolValue(Checkbox.GetName()), true); + break; + case eSettingType_Slider: + Slider = MCM_API_Slider(Setting); + Slider.SetValue(DefaultConfigManager.GetConfigFloatValue(Slider.GetName()), true); + break; + case eSettingType_Dropdown: + Dropdown = MCM_API_Dropdown(Setting); + if (Dropdown == none) + { + Spinner = MCM_API_Spinner(Setting); + Spinner.SetValue(DefaultConfigManager.GetConfigStringValue(Spinner.GetName()), true); + } + else + { + Dropdown.SetValue(DefaultConfigManager.GetConfigStringValue(Dropdown.GetName()), true); + } + break; + case eSettingType_Spinner: + Spinner = MCM_API_Spinner(Setting); + Spinner.SetValue(DefaultConfigManager.GetConfigStringValue(Spinner.GetName()), true); + break; + } + } + } + + `XEVENTMGR.TriggerEvent('MCM_ConfigResetted', Page, GetBuilder(Page.GetPageId()), none); + } +} + +function JsonConfig_ManagerInterface GetConfigManager(JsonConfig_MCM_Page Page, JsonConfig_MCM_Group Group) +{ + if (Group.SaveConfigManager != "") + { + return class'MCM_Builder_SingletonFactory'.static.GetManagerInstance(Group.SaveConfigManager); + } + else + { + return class'MCM_Builder_SingletonFactory'.static.GetManagerInstance(Page.SaveConfigManager); + } +} + +simulated public function JsonConfig_MCM_Page GetPage(int PageID) +{ + local JsonConfig_MCM_Builder Builder; + local MCMConfigMapEntry MCMConfig; + local JsonConfig_MCM_Page Page; + + + Builder = GetBuilder(PageID); + + if (Builder != none) + { + foreach Builder.DeserialzedPagesMap(MCMConfig) + { + Page = MCMConfig.MCMConfigPage; + + if (Page.MCMPageId == PageID) + { + return Page; + } + } + } + + //`LOG(default.class @ GetFuncName() @ Builder @ "could not find MCMConfigPage for" @ PageID,, 'ModConfigMenuBuilder'); + + return none; +} + +simulated public function JsonConfig_MCM_Group GetGroup(int PageID, name GroupName) +{ + local JsonConfig_MCM_Page Page; + local JsonConfig_MCM_Group Group; + + Page = GetPage(PageID); + + foreach Page.Groups(Group) + { + if (name(Group.GetGroupName()) == GroupName) + { + return Group; + } + } + + //`LOG(default.class @ GetFuncName() @ "could not find JsonConfig_MCM_Group for" @ PageID @ GroupName,, 'ModConfigMenuBuilder'); + + return none; +} + +simulated public function JsonConfig_MCM_Element GetElement(int PageID, name GroupName, name SettingName) +{ + local JsonConfig_MCM_Group Group; + local JsonConfig_MCM_Element Element; + + Group = GetGroup(PageID, GroupName); + + foreach Group.Elements(Element) + { + if (name(Element.SettingName) == SettingName) + { + return Element; + } + } + + //`LOG(default.class @ GetFuncName() @ "could not find JsonConfig_MCM_Element for" @ PageID @ GroupName @ SettingName,, 'ModConfigMenuBuilder'); + + return none; +} + +simulated function JsonConfig_MCM_Builder GetBuilder(int PageID) +{ + return BuilderInstances[BuilderInstances.Find('PageId', PageID)].Builder; +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_ScreenListener.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_ScreenListener.uc new file mode 100644 index 0000000..8efcaba --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_ScreenListener.uc @@ -0,0 +1,31 @@ +//----------------------------------------------------------- +// Class: MCM_Builder_ScreenListener +// Author: Musashi +// +//----------------------------------------------------------- +class MCM_Builder_ScreenListener extends UIScreenListener; + +event OnInit(UIScreen Screen) +{ + local MCM_Builder_Screen MCMScreen; + + if (ScreenClass==none) + { + if (MCM_API(Screen) != none) + { + ScreenClass = Screen.Class; + } + else + { + return; + } + } + + MCMScreen = new class'MCM_Builder_Screen'; + MCMScreen.OnInit(Screen); +} + +defaultproperties +{ + ScreenClass = none; +} diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_SingletonFactory.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_SingletonFactory.uc new file mode 100644 index 0000000..a3ac655 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilder/Classes/MCM_Builder_SingletonFactory.uc @@ -0,0 +1,67 @@ +//----------------------------------------------------------- +// Class: MCM_Builder_SingletonFactory +// Author: Musashi +// +//----------------------------------------------------------- +class MCM_Builder_SingletonFactory extends Object implements(MCM_Builder_SingletonFactoryInterface) config(Null); + +struct ManagerInstanceCache +{ + var string InstanceName; + var JsonConfig_Manager Manager; +}; + +struct MCMBuilderInstanceCache +{ + var string InstanceName; + var JsonConfig_MCM_Builder Builder; +}; + +// only config for fake singleton +var config array ManagerInstances; +var config array MCMBuilderInstances; + +static function JsonConfig_ManagerInterface GetManagerInstance(string InstanceName, optional bool bHasDefaultConfig = true) +{ + local JsonConfig_ManagerInterface JsonConfigManagerInterface; + local ManagerInstanceCache NewManagerInstance; + local int Index; + + Index = default.ManagerInstances.Find('InstanceName', InstanceName); + if (Index == INDEX_NONE) + { + JsonConfigManagerInterface = class'JsonConfig_Manager'.static.GetConfigManager(InstanceName, bHasDefaultConfig); + + `LOG(default.class @ GetFuncName() @ "create singleton instance" @ JsonConfigManagerInterface,, 'ModConfigMenuBuilder'); + + NewManagerInstance.InstanceName = InstanceName; + NewManagerInstance.Manager = JsonConfig_Manager(JsonConfigManagerInterface); + default.ManagerInstances.AddItem(NewManagerInstance); + return JsonConfig_ManagerInterface(NewManagerInstance.Manager); + } + + return JsonConfig_ManagerInterface(default.ManagerInstances[Index].Manager); +} + +static function MCM_Builder_Interface GetMCMBuilderInstance(string InstanceName) +{ + local MCM_Builder_Interface BuilderInterface; + local MCMBuilderInstanceCache NewBuilderInstance; + local int Index; + + Index = default.MCMBuilderInstances.Find('InstanceName', InstanceName); + if (Index == INDEX_NONE) + { + BuilderInterface = class'JsonConfig_MCM_Builder'.static.GetMCMBuilder(InstanceName); + + `LOG(default.class @ GetFuncName() @ "create singleton instance" @ BuilderInterface,, 'ModConfigMenuBuilder'); + + NewBuilderInstance.InstanceName = InstanceName; + NewBuilderInstance.Builder = JsonConfig_MCM_Builder(BuilderInterface); + default.MCMBuilderInstances.AddItem(NewBuilderInstance); + + return MCM_Builder_Interface(NewBuilderInstance.Builder); + } + + return MCM_Builder_Interface(default.MCMBuilderInstances[Index].Builder); +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/ConfigFactory.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/ConfigFactory.uc new file mode 100644 index 0000000..b43e4a6 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/ConfigFactory.uc @@ -0,0 +1,26 @@ +//----------------------------------------------------------- +// Class: ConfigFactory +// Author: Musashi +// DO NOT MAKE ANY CHANGES TO THIS CLASS +//----------------------------------------------------------- +class ConfigFactory extends Object; + +static function JsonConfig_ManagerInterface GetConfigManager(string ManagerName) +{ + local MCM_Builder_SingletonFactoryInterface SingletonFactoryInterface; + local object SingletonFactoryCDO; + + SingletonFactoryCDO = class'XComEngine'.static.GetClassDefaultObjectByName('MCM_Builder_SingletonFactory'); + SingletonFactoryInterface = MCM_Builder_SingletonFactoryInterface(SingletonFactoryCDO); + return SingletonFactoryInterface.static.GetManagerInstance(ManagerName); +} + +static function MCM_Builder_Interface GetMCMBuilder(string BuilderName) +{ + local MCM_Builder_SingletonFactoryInterface SingletonFactoryInterface; + local object SingletonFactoryCDO; + + SingletonFactoryCDO = class'XComEngine'.static.GetClassDefaultObjectByName('MCM_Builder_SingletonFactory'); + SingletonFactoryInterface = MCM_Builder_SingletonFactoryInterface(SingletonFactoryCDO); + return SingletonFactoryInterface.static.GetMCMBuilderInstance(BuilderName); +} \ No newline at end of file diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/JsonConfig_ManagerInterface.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/JsonConfig_ManagerInterface.uc new file mode 100644 index 0000000..42fdbca --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/JsonConfig_ManagerInterface.uc @@ -0,0 +1,43 @@ +//----------------------------------------------------------- +// Interface: JsonConfig_ManagerInterface +// Author: Musashi +// DO NOT MAKE ANY CHANGES TO THIS CLASS +//----------------------------------------------------------- +interface JsonConfig_ManagerInterface; + +static public function JsonConfig_ManagerInterface GetConfigManager(string InstanceName, optional bool bHasDefaultConfig = true); + +static public function JsonConfig_ManagerInterface GetDefaultConfigManager(); + +public function SerializeAndSaveConfig(); + +public function bool HasConfigProperty(coerce string PropertyName, optional string Namespace); + +public function SetConfigString(string PropertyName, coerce string Value); + +public function int GetConfigIntValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function float GetConfigFloatValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function name GetConfigNameValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function int GetConfigByteValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function bool GetConfigBoolValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigIntArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigFloatArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigNameArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function vector GetConfigVectorValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function array GetConfigStringArray(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function WeaponDamageValue GetConfigDamageValue(coerce string PropertyName, optional string Namespace); + +public function string GetConfigStringValue(coerce string PropertyName, optional string TagFunction, optional string Namespace); + +public function string GetConfigTagValue(coerce string PropertyName, optional string Namespace); + diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_Interface.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_Interface.uc new file mode 100644 index 0000000..d2df583 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_Interface.uc @@ -0,0 +1,20 @@ +//----------------------------------------------------------- +// Interface: MCM_Builder_Interface +// Author: Musashi +// +//----------------------------------------------------------- + + +interface MCM_Builder_Interface; + +static public function MCM_Builder_Interface GetMCMBuilder(string InstanceName); + +public function array GetConfig(); + +public function string GetBuilderName(); + +public function string LocalizeItem(string Key); + +public function SerializeAndSaveBuilderConfig(); + +public function SerializeConfig(); diff --git a/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_SingletonFactoryInterface.uc b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_SingletonFactoryInterface.uc new file mode 100644 index 0000000..d5dbad5 --- /dev/null +++ b/ModConfigMenu/ModConfigMenu/Src/ModConfigMenuBuilderAPI_1_0_0/Classes/MCM_Builder_SingletonFactoryInterface.uc @@ -0,0 +1,11 @@ +//----------------------------------------------------------- +// Class: MCM_Builder_SingletonFactoryInterface +// Author: Musashi +// DO NOT MAKE ANY CHANGES TO THIS CLASS +//----------------------------------------------------------- + +interface MCM_Builder_SingletonFactoryInterface; + +static function JsonConfig_ManagerInterface GetManagerInstance(string InstanceName, optional bool bHasDefaultConfig = true); + +static function MCM_Builder_Interface GetMCMBuilderInstance(string InstanceName); \ No newline at end of file diff --git a/documentation/img/mcmbuilder_api_package.jpg b/documentation/img/mcmbuilder_api_package.jpg new file mode 100644 index 0000000..ae73e43 Binary files /dev/null and b/documentation/img/mcmbuilder_api_package.jpg differ diff --git a/documentation/img/mcmbuilder_screenshot.jpg b/documentation/img/mcmbuilder_screenshot.jpg new file mode 100644 index 0000000..a9207f3 Binary files /dev/null and b/documentation/img/mcmbuilder_screenshot.jpg differ diff --git a/documentation/img/mcmbuilder_xcomengine_ini.jpg b/documentation/img/mcmbuilder_xcomengine_ini.jpg new file mode 100644 index 0000000..30301e7 Binary files /dev/null and b/documentation/img/mcmbuilder_xcomengine_ini.jpg differ diff --git a/documentation/jsonconfigmanager.md b/documentation/jsonconfigmanager.md new file mode 100644 index 0000000..8d5ef8f --- /dev/null +++ b/documentation/jsonconfigmanager.md @@ -0,0 +1,150 @@ +## JsonConfig Manager +The JsonConfig Manager introduces a new method of defining config values as json string. + +#### Integration +You will need to add the package +**ModConfigMenuBuilderAPI_1_0_0** from **ModConfigMenu** to your mod project + +![Screenshot](img/mcmbuilder_api_package.jpg) + +![Screenshot](img/mcmbuilder_xcomengine_ini.jpg) + +You mod will be dependend on the ModConfigMenu mod and the funtionality will only work if MCM is active. + +#### Usage +``` +[FancyModManagerName JsonConfig_ManagerDefault] ++ConfigProperties = {"BAR":{"Value":"Foo"}} +``` +these config values can be accessed like +``` +local JsonConfig_ManagerInterface ConfigManager; + +ConfigManager = class'ConfigFactory'.static.GetConfigManager("FancyModManagerName"); +ConfigManager.GetConfigStringValue("BAR") +``` + +The advantage over regular config properties is that they can be accessed by string identifiers which makes automatic localization tag generation and mapping in the MCMBuilder possible. + +#### Current type support +currently supported accessors/types are + +``` +string GetConfigStringValue +int GetConfigIntValue +float GetConfigFloatValue +name GetConfigNameValue +byte GetConfigByteValue +bool GetConfigBoolValue +array GetConfigIntArray +array GetConfigFloatArray +array GetConfigNameArray +array GetConfigStringArray +vector GetConfigVectorValue +WeaponDamageValue GetConfigDamageValue +string GetConfigTagValue +``` + +more support for common X2 structs is planned. + +#### Tag generation + +There are a whole bunch of meta attributes you can use for localization tag generation. Here are some example: + +``` ++ConfigProperties = {"ACTIVIST_DETECTION_MOD":{"Value":"-5", "TagFunction":"TagValueMetersToTiles"}} ++ConfigProperties = {"ACTIVIST_DETECTION_MOD_CIVS":{"Value":"0.5", "TagFunction":"TagValueToPercent", "TagSuffix": "%"}} ++ConfigProperties = {"AGRESSION_CRIT_CHANCE":{"Value":"5", "TagPrefix":"+"}} ++ConfigProperties = {"AGRESSION_SCALE_MAX":{"Value":"6", "TagPrefix":"+", "TagFunction":"TagValueParamMultiplication", "TagParam":"AGRESSION_CRIT_CHANCE"}} ++ConfigProperties = {"AIRSTRIKECHARGES":{"Value":"1"}}; ++ConfigProperties = {"AIRSTRIKEDAMAGE":{"DamageValue":{"Damage": 10, "Spread": 2, "Shred": 3, "DamageType":"Explosion"}}} ++ConfigProperties = {"ANARCHIST_CHARGES":{"Value":"1"}} ++ConfigProperties = {"ANARCHIST_CRIT":{"Value":"2", "TagPrefix":"+", "TagSuffix":"%"}} ++ConfigProperties = {"ANARCHIST_CRIT_MAX":{"Value":"50", "TagSuffix":"%"}} ++ConfigProperties = {"ARCTHROWER_ABILITIES":{"ArrayValue":"ArcThrowerStun, EMPulser, ChainLightning"}} +``` + +The mapping code in client mods DLCInfo class just looks like this: + +```unrealscript +static function bool AbilityTagExpandHandler(string InString, out string OutString) +{ + local string PossibleValue; + local JsonConfig_ManagerInterface ConfigManager; + + ConfigManager = class'ConfigFactory'.static.GetConfigManager("FancyModManagerName"); + PossibleValue = ConfigManager.GetConfigTagValue(InString) + + if (PossibleValue != "") + { + OutString = PossibleValue; + return true; + } + + return false; +} +``` +For the tag generation add the AbilityTagExpandHandler code snippet above to you DLCInfo file. + +#### Complete Example: + +Config: +``` ++ConfigProperties = {"MILITIA_AIM":{"Value":"3", "TagPrefix":"+"}} ++ConfigProperties = {"MILITIA_RANGE_MULTIPLIER":{"Value":"0.5", "TagPrefix": "-" , "TagFunction":"TagValueToPercent"}} ++ConfigProperties = {"MILITIA_SIGHT_RADIUS":{"Value":"3", "TagPrefix":"+", "TagSuffix":" tiles", "TagFunction":"TagValueMetersToTiles"}}} +``` + +Usage: +```unrealscript +// Best to put this in a static helper class somewhere +static function JsonConfig_ManagerInterface GetJsonConfig() +{ + return class'ConfigFactory'.static.GetConfigManager("FancyModManagerName"); +} + +static function X2AbilityTemplate Militia() +{ + local X2AbilityTemplate Template; + local X2Effect_RangeMultiplier RangeEffect; + local X2Effect_PersistentStatChange Effect; + + RangeEffect = new class'X2Effect_RangeMultiplier'; + RangeEffect.RangeMultiplier = GetJsonConfig().GetConfigFloatValue("MILITIA_RANGE_MULTIPLIER"); + RangeEffect.BuildPersistentEffect(1, true, false, false); + + Template = Passive('APT_Militia', "img:///UILibrary_PerkIcons.UIPerk_Urban_Aim", true, RangeEffect); + + Effect = new class'X2Effect_PersistentStatChange'; + Effect.AddPersistentStatChange(eStat_Offense, GetJsonConfig().static.GetConfigIntValue("MILITIA_AIM")); + Effect.AddPersistentStatChange(eStat_SightRadius, GetJsonConfig.static.GetConfigIntValue("MILITIA_SIGHT_RADIUS")); + + AddSecondaryEffect(Template, Effect); + + return Template; +} +``` + +Localization: +`LocLongDescription="A militia marksman from one of the Resistance camps we saved. Has aim and sight radius, and weapon range penalties."` + +Expanded String: +`A militia marksman from one of the Resistance camps we saved. Has +1 aim and +2 tiles sight radius, and -50% weapon range penalties.` + +#### TagFunctions: +There are some predefined functions you can use in tag generation and to convert values on the fly: + +- TagValueToPercent +- TagValueToPercentMinusHundred +- TagValueMetersToTiles +- TagValueTilesToMeters +- TagValueTilesToUnits +- TagValueParamAddition +- TagValueParamMultiplication +- TagArrayValue + +usage for tag generation: +`+ConfigProperties = {"MILITIA_RANGE_MULTIPLIER":{"Value":"0.5", "TagFunction":"TagValueToPercent"}}` + +usage for converting values in code: +`ConeMultiTarget.ConeEndDiameter = GetJsonConfig().static.GetConfigIntValue("SPRAY_TILE_WIDTH", "TagValueTilesToUnits");` diff --git a/documentation/mcm_builder.md b/documentation/mcm_builder.md new file mode 100644 index 0000000..7e66f6c --- /dev/null +++ b/documentation/mcm_builder.md @@ -0,0 +1,192 @@ +# MCMBuilderClientTestMod +## MCM Builder + +MCM Builder provides a new way of creating MCM Pages. +Instead of writing the mcm code the pages are completely generated from a json config. +Lets get right down to it and have a look at this example config: + +``` +[ModConfigMenuBuilder.MCM_Builder_Screen] ++MCMBuilder="MCMBuilderClientTestMod" + +[MCMBuilderClientTestMod JsonConfig_MCM_Builder] ++MCMPages = { \\ + "TESTMOD_SETTINGS_PAGE":{ \\ + "SaveConfigManager": "MCMBuilderClientTestModConfigManager",\\ + "EnableResetButton": "true", \\ + "TESTMOD_SETTINGS_GROUP_1":{ \\ + "HUNGRY": { "Type": "Checkbox" }, \\ + "HUNGER_SCALE_NERD": { "Type": "Slider", "SliderMin": "0.0", "SliderMax": "1.0", "SliderStep":"0.1" }, \\ + "HUNGER_SCALE": { "Type": "Spinner", "Options": "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" }, \\ + "FOOD": { "Type": "Dropdown", "Options": "Apple, Chocolate, Burger" }, \\ + }, \\ + "TESTMOD_SETTINGS_GROUP_2":{ \\ + "A_LABEL": { "Type": "Label" }, \\ + }, \\ + }, \\ +} +``` + +This small config is enough to generate a complete MCM page. +Lets have a look at the elements in detail. + +### Pages and Groups + +``` +TESTMOD_SETTINGS_PAGE +TESTMOD_SETTINGS_GROUP_1 +TESTMOD_SETTINGS_GROUP_2 +``` +are mcm page or group identifiers that are used to for localization mapping: +`ModConfigMenu.int` +``` +[MCMBuilderClientTestMod JsonConfig_MCM_Builder] + +TESTMOD_SETTINGS_PAGE_TITLE="Test Mod" +TESTMOD_SETTINGS_PAGE_LABEL="MCMBuilder Test Mod" + +TESTMOD_SETTINGS_GROUP_1_LABEL="First settings group" +TESTMOD_SETTINGS_GROUP_2_LABEL="Second setting group" +``` + +There are two special config properties: + +`"SaveConfigManager": "MCMBuilderClientTestModConfigManager"` + +Use a unique name that will used to create a json config manager instance that will be used to get default config properties and thats responsible to save your properties to the user config directory. + +`"EnableResetButton": "true"` + +this just tells the builder if you want to display a reset button on your page. + +### Elements +``` +"HUNGRY": { "Type": "Checkbox" }, \\ +"HUNGER_SCALE_NERD": { "Type": "Slider", "SliderMin": "0.0", "SliderMax": "1.0", "SliderStep":"0.1" }, \\ +"HUNGER_SCALE": { "Type": "Spinner", "Options": "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" }, \\ +"FOOD": { "Type": "Dropdown", "Options": "Apple, Chocolate, Burger" }, \\ +``` + +These are the actual mcm elements that are displayed. +The identifiers (like "HUNGRY") are actual referencing config properties from the JsonConfigManager System. + +localization works the same as with pages and groups: +Just define localization properties following the convention: +``` +_LABEL +_TOOLTIP +``` +e.g. +``` +HUNGRY_LABEL="Hungry?" +HUNGRY_TOOLTIP="Are you hungry?" +``` + +## Client Side Integration +You will need to add the package +**ModConfigMenuBuilderAPI_1_0_0** from **ModConfigMenu** to your mod project + +![Screenshot](img/mcmbuilder_api_package.jpg) + +![Screenshot](img/mcmbuilder_xcomengine_ini.jpg) + +``` +[Engine.ScriptPackages] ++NonNativePackages=ModConfigMenuBuilderAPI_1_0_0 ++NonNativePackages=MCMBuilderClientTestMod + +[UnrealEd.EditorEngine] ++ModEditPackages=ModConfigMenuBuilderAPI_1_0_0 +``` +### MCMBuilder config and localization + +Then you need two config files and a localization file: +(this example assumes you mod safe name is **YourMod** + +- `Config/XComJsonConfigManager.ini` +- `Config/XComMCMBuilder.ini` +- `Localization/ModConfigMenu.int` + +Lets see there contents in detail: + +##### `XComMCMBuilder.ini` + +As explained in detail above this confi will be used to generate a MCM page + +``` +[ModConfigMenuBuilder.MCM_Builder_Screen] ++MCMBuilder="YourModMCMPage1" ;can be any name but have to match below and in the localization file + +[YourModMCMPage1 JsonConfig_MCM_Builder] ++MCMPages = { \\ + "TESTMOD_SETTINGS_PAGE":{ \\ + "SaveConfigManager": "YourModConfigManager",\\ + "EnableResetButton": "true", \\ + "TESTMOD_SETTINGS_GROUP_1":{ \\ + "HUNGRY": { "Type": "Checkbox" }, \\ + "HUNGER_SCALE_NERD": { "Type": "Slider", "SliderMin": "0.0", "SliderMax": "1.0", "SliderStep":"0.1" }, \\ + "HUNGER_SCALE": { "Type": "Spinner", "Options": "1, 2, 3, 4, 5, 6, 7, 8, 9, 10" }, \\ + "FOOD": { "Type": "Dropdown", "Options": "Apple, Chocolate, Burger" }, \\ + }, \\ + "TESTMOD_SETTINGS_GROUP_2":{ \\ + "A_LABEL": { "Type": "Label" }, \\ + }, \\ + }, \\ +} +``` +##### `XComJsonConfigManager.ini` + +These are the *default* values you want your mcm elements to initialize with. They will be also used for resetting the values to the default if the Reset Button is clicked. + +``` +[YourModConfigManager JsonConfig_ManagerDefault] ++ConfigProperties = {"HUNGRY":{"Value":"true"}} ++ConfigProperties = {"HUNGER_SCALE":{"Value":"1"}} ++ConfigProperties = {"HUNGER_SCALE_NERD":{"Value":"0.1"}} ++ConfigProperties = {"FOOD":{"Value":"Apple"}} +``` +##### `ModConfigMenu.int` + +The localization of your page + +``` +[YourModMCMPage1 JsonConfig_MCM_Builder] + +TESTMOD_SETTINGS_PAGE_TITLE="Test Mod" +TESTMOD_SETTINGS_PAGE_LABEL="MCMBuilder Test Mod" + +TESTMOD_SETTINGS_GROUP_1_LABEL="First settings group" +TESTMOD_SETTINGS_GROUP_2_LABEL="Second setting group" + +HUNGRY_LABEL="Hungry?" +HUNGRY_TOOLTIP="Are you hungry?" + +HUNGER_SCALE_LABEL="Hunger Scale" +HUNGER_SCALE_TOOLTIP="On a scale from 1 to 10" + +HUNGER_SCALE_NERD_LABEL="Hunger Scale (Nerd)" +HUNGER_SCALE_NERD_TOOLTIP="On a scale from 0.0 to 1.0" + +FOOD_LABEL="Food" +FOOD_TOOLTIP="Which food you want to eat?" + +A_LABEL_LABEL="Label" +A_LABEL_TOOLTIP="Just a tooltip" +``` + +You can access the values in your mod like + +```unrealscript +local JsonConfig_ManagerInterface ConfigManager; + +ConfigManager = class'ConfigFactory'.static.GetConfigManager("MCMBuilderClientTestModConfigManager"); +ConfigManager.GetConfigBoolValue("HUNGRY") +``` + +It will return the values that the user made in the mcm page or the default settings in case the user hasnt made any changes yet. +For more information about the config system see the [JsonConfigManager Documentation](jsonconfigmanager.md) + +### Thats all! +The MCMBuilder in ModConfigMenu will take care of the rest. + +![Screenshot](img/mcmbuilder_screenshot.jpg)