- Added float, double settingentry types. Adjusted display formatting.

- Added menu refresh on Apply button.
- Fixed package name resolution for invalid chars.
- Added helper console command to get xml-safe name for use in localization files.
- Made error messages for bad settings xml more descriptive.
- Modified GUISlider.
- Converted HarmonyEventPatchesService to a System.
- Fixed package name resolution for incompatible names in Xml and files, in many places.
- Fixed base textbox implementation for settings.
This commit is contained in:
MapleWheels
2026-03-05 15:45:00 -05:00
parent f38a7bd574
commit 1fe68aa861
16 changed files with 203 additions and 27 deletions
@@ -98,7 +98,7 @@ public static class GUIUtil
public static (GUIScrollBar, GUITextBlock) Slider(GUILayoutGroup parent, Vector2 range, int steps, Func<float, public static (GUIScrollBar, GUITextBlock) Slider(GUILayoutGroup parent, Vector2 range, int steps, Func<float,
string> labelFunc, float currentValue, Action<float> setter, LocalizedString? tooltip, Vector2 adjustRatio) string> labelFunc, float currentValue, Action<float> setter, LocalizedString? tooltip, Vector2 adjustRatio)
{ {
var layout = new GUILayoutGroup(NewItemRectT(parent, adjustRatio), isHorizontal: true); var layout = new GUILayoutGroup(new RectTransform(adjustRatio, parent.RectTransform), isHorizontal: true);
var slider = new GUIScrollBar(new RectTransform((0.72f, 1.0f), layout.RectTransform), style: "GUISlider") var slider = new GUIScrollBar(new RectTransform((0.72f, 1.0f), layout.RectTransform), style: "GUISlider")
{ {
Range = range, Range = range,
@@ -13,19 +13,20 @@ namespace Barotrauma.LuaCs;
internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase
{ {
private readonly ImmutableArray<ISettingBase> _settingsInstancesGameplay; private ImmutableArray<ISettingBase> _settingsInstancesGameplay;
// menu vars // menu vars
private GUILayoutGroup _modCategoryDisplayGroup, _settingsDisplayGroup; private GUILayoutGroup _modCategoryDisplayGroup, _settingsDisplayGroup;
private string _selectedSearchQuery = string.Empty; private string _selectedSearchQuery = string.Empty;
private ContentPackage _selectedContentPackage; private ContentPackage _selectedContentPackage;
private string _selectedCategory = string.Empty; private string _selectedCategory = string.Empty;
private event Action OnApplyInstalledModsChanges;
public ModsGameplaySettingsMenu(GUIFrame contentFrame, public ModsGameplaySettingsMenu(GUIFrame contentFrame,
IPackageManagementService packageManagementService, IPackageManagementService packageManagementService,
IConfigService configService, IConfigService configService,
SettingsMenu settingsMenuInstance) : base(contentFrame, packageManagementService, configService, settingsMenuInstance) SettingsMenu settingsMenuInstance) : base(contentFrame, packageManagementService, configService, settingsMenuInstance)
{ {
_settingsInstancesGameplay = configService.GetDisplayableConfigs() _settingsInstancesGameplay = configService.GetDisplayableConfigs()
.Where(s => s is not ISettingControl) .Where(s => s is not ISettingControl)
.ToImmutableArray(); .ToImmutableArray();
@@ -65,6 +66,21 @@ internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase
// default category // default category
_selectedCategory = "All"; _selectedCategory = "All";
OnApplyInstalledModsChanges = () =>
{
_settingsInstancesGameplay = configService.GetDisplayableConfigs()
.Where(s => s is not ISettingControl)
.ToImmutableArray();
if (_selectedContentPackage is not null && !GetTargetPackagesList().Contains(_selectedContentPackage))
{
_selectedContentPackage = null;
_selectedCategory = string.Empty;
}
GenerateCategoryListDisplay(_modCategoryDisplayGroup, GetTargetPackagesList(), GetDisplayCategoriesList());
GenerateSettingsListDisplay(_settingsDisplayGroup, GetDisplaySettingsList());
};
GenerateCategoryListDisplay(_modCategoryDisplayGroup, GetTargetPackagesList(), GetDisplayCategoriesList()); GenerateCategoryListDisplay(_modCategoryDisplayGroup, GetTargetPackagesList(), GetDisplayCategoriesList());
GenerateSettingsListDisplay(_settingsDisplayGroup, GetDisplaySettingsList()); GenerateSettingsListDisplay(_settingsDisplayGroup, GetDisplaySettingsList());
@@ -100,7 +116,7 @@ internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase
.Select(s => s.OwnerPackage) .Select(s => s.OwnerPackage)
.Concat(new[] { ContentPackageManager.VanillaCorePackage }) .Concat(new[] { ContentPackageManager.VanillaCorePackage })
.Distinct() .Distinct()
.OrderBy(p => p == ContentPackageManager.VanillaCorePackage ? 1 : 0) .OrderByDescending(p => p == ContentPackageManager.VanillaCorePackage ? 0 : 1)
.ThenBy(p => p.Name) .ThenBy(p => p.Name)
.ToImmutableArray(); .ToImmutableArray();
} }
@@ -153,12 +169,33 @@ internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase
return package is null || package == ContentPackageManager.VanillaCorePackage ? "All" : package.Name; return package is null || package == ContentPackageManager.VanillaCorePackage ? "All" : package.Name;
} }
ContentPackage GetCurrentSelectedPackage(ImmutableArray<ContentPackage> packages)
{
if (_selectedContentPackage is null)
{
return ContentPackageManager.VanillaCorePackage;
}
if (packages.Contains(_selectedContentPackage))
{
return _selectedContentPackage;
}
if (packages.Length > 0)
{
_selectedContentPackage = packages[0];
return packages[0];
}
return null;
}
void GenerateCategoryListDisplay(GUILayoutGroup layoutGroup, ImmutableArray<ContentPackage> packagesList, void GenerateCategoryListDisplay(GUILayoutGroup layoutGroup, ImmutableArray<ContentPackage> packagesList,
ImmutableArray<string> categories) ImmutableArray<string> categories)
{ {
layoutGroup.ClearChildren(); layoutGroup.ClearChildren();
var packageSelectionList = GUIUtil.Dropdown<ContentPackage>(layoutGroup, cp => GetPackageName(cp), null, var packageSelectionList = GUIUtil.Dropdown<ContentPackage>(layoutGroup, cp => GetPackageName(cp), null,
packagesList, packagesList.Length > 0 ? packagesList[0] : null, cp => packagesList, GetCurrentSelectedPackage(packagesList), cp =>
{ {
_selectedContentPackage = cp; _selectedContentPackage = cp;
_selectedCategory = string.Empty; _selectedCategory = string.Empty;
@@ -246,6 +283,7 @@ internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase
_settingsDisplayGroup?.Parent.RemoveChild(_settingsDisplayGroup); _settingsDisplayGroup?.Parent.RemoveChild(_settingsDisplayGroup);
_modCategoryDisplayGroup = null; _modCategoryDisplayGroup = null;
_settingsDisplayGroup = null; _settingsDisplayGroup = null;
} }
public override void ApplyInstalledModChanges() public override void ApplyInstalledModChanges()
@@ -258,7 +296,9 @@ internal sealed class ModsGameplaySettingsMenu : ModsSettingsMenuBase
} }
kvp.Key.TrySetValue(kvp.Value); kvp.Key.TrySetValue(kvp.Value);
ConfigService.SaveConfigValue(kvp.Key);
} }
NewValuesCache.Clear(); NewValuesCache.Clear();
OnApplyInstalledModsChanges?.Invoke();
} }
} }
@@ -11,6 +11,9 @@ public class SettingsMenuSystem : ISettingsMenuSystem
private ModsControlsSettingsMenu _controlsMenuInstance; private ModsControlsSettingsMenu _controlsMenuInstance;
private ModsGameplaySettingsMenu _gameplayMenuInstance; private ModsGameplaySettingsMenu _gameplayMenuInstance;
private GUIFrame _gameplayContentFrame;
private GUIFrame _controlsContentFrame;
private SettingsMenu _settingsMenuInstance;
private readonly Harmony _harmony; private readonly Harmony _harmony;
private readonly IPackageManagementService _packageManagementService; private readonly IPackageManagementService _packageManagementService;
@@ -28,6 +31,7 @@ public class SettingsMenuSystem : ISettingsMenuSystem
[HarmonyPatch(typeof(SettingsMenu), "CreateModsTab"), HarmonyPostfix] [HarmonyPatch(typeof(SettingsMenu), "CreateModsTab"), HarmonyPostfix]
private static void SettingsMenu_CreateModsTab_Post(SettingsMenu __instance) private static void SettingsMenu_CreateModsTab_Post(SettingsMenu __instance)
{ {
SystemInstance._settingsMenuInstance = __instance;
SystemInstance.CreateSettingsMenu(__instance); SystemInstance.CreateSettingsMenu(__instance);
} }
@@ -39,13 +43,13 @@ public class SettingsMenuSystem : ISettingsMenuSystem
var tabGameplayIndex = (SettingsMenu.Tab)tabCount; var tabGameplayIndex = (SettingsMenu.Tab)tabCount;
var tabControlsIndex = (SettingsMenu.Tab)tabCount+1; var tabControlsIndex = (SettingsMenu.Tab)tabCount+1;
var gameplayContentFrame = CreateNewContentTab(tabGameplayIndex, __instance, _gameplayContentFrame = CreateNewContentTab(tabGameplayIndex, __instance,
"SettingsMenuTab.Mods", "LuaCsForBarotrauma.SettingsMenu.ModGameplayButton"); "SettingsMenuTab.Mods", "LuaCsForBarotrauma.SettingsMenu.ModGameplayButton");
var controlsContentFrame = CreateNewContentTab(tabControlsIndex, __instance, _controlsContentFrame = CreateNewContentTab(tabControlsIndex, __instance,
"SettingsMenuTab.Controls", "LuaCsForBarotrauma.SettingsMenu.ModControlsButton"); "SettingsMenuTab.Controls", "LuaCsForBarotrauma.SettingsMenu.ModControlsButton");
_gameplayMenuInstance = new ModsGameplaySettingsMenu(gameplayContentFrame, _packageManagementService, _configService, __instance); _gameplayMenuInstance = new ModsGameplaySettingsMenu(_gameplayContentFrame, _packageManagementService, _configService, __instance);
_controlsMenuInstance = new ModsControlsSettingsMenu(controlsContentFrame, _packageManagementService, _configService, __instance); _controlsMenuInstance = new ModsControlsSettingsMenu(_controlsContentFrame, _packageManagementService, _configService, __instance);
} }
private GUIFrame CreateNewContentTab(SettingsMenu.Tab tab, SettingsMenu settingsMenuInstance, string settingsMenuTabName, string settingMenuHoverTextIdent) private GUIFrame CreateNewContentTab(SettingsMenu.Tab tab, SettingsMenu settingsMenuInstance, string settingsMenuTabName, string settingMenuHoverTextIdent)
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ModConfig> <ModConfig>
<Lua File="%ModDir%/Lua/init.lua" Target="Any" IsAutorun="true" /> <Lua File="%ModDir%/Lua/init.lua" Target="Any" IsAutorun="true" />
<Config File="%ModDir%/Settings.xml"/>
</ModConfig> </ModConfig>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
<Settings>
<Setting Name="TestTickbox" Type="bool"/>
<Setting Name="TestFloat" Type="float"/>
<Setting Name="TestHidden" Type="bool" ShowInMenus="false"/>
<Setting Name="TestRangeFloat" Type="rangeFloat" Min="0" Max="25" Steps="11"/>
<Setting Name="TestRangeInt" Type="rangeInt" Min="0" Max="10" Steps="11"/>
<Setting Name="TestString" Type="string" />
</Settings>
<Profiles>
<Profile Name="default">
<SettingValue Name="TestTickbox" Value="true"/>
<SettingValue Name="TestFloat" Value="5"/>
<SettingValue Name="TestHidden" Value="true"/>
<SettingValue Name="TestRangeFloat" Value="15"/>
<SettingValue Name="TestRangeInt" Value="7"/>
<SettingValue Name="TestString" Value="Hello!"/>
</Profile>
<Profile Name="other">
<SettingValue Name="TestTickbox" Value="false"/>
<SettingValue Name="TestFloat" Value="9"/>
<SettingValue Name="TestHidden" Value="false"/>
<SettingValue Name="TestRangeFloat" Value="4"/>
<SettingValue Name="TestRangeInt" Value="4"/>
<SettingValue Name="TestString" Value="Other loaded!"/>
</Profile>
</Profiles>
</Configuration>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<infotexts language="English" nowhitespace="false" translatedname="English">
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestTickbox.DisplayName>Test TickBox</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestTickbox.DisplayName>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestTickbox.DisplayCategory>Tests</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestTickbox.DisplayCategory>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestFloat.DisplayName>Test Float</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestFloat.DisplayName>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestFloat.DisplayCategory>Tests</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestFloat.DisplayCategory>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeFloat.DisplayName>Test Range Float</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeFloat.DisplayName>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeFloat.DisplayCategory>Tests</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeFloat.DisplayCategory>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeInt.DisplayName>Test Range Int</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeInt.DisplayName>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeInt.DisplayCategory>Tests</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestRangeInt.DisplayCategory>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestString.DisplayName>Test String</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestString.DisplayName>
<_x005B_DebugOnlyTest_x005D_TestLuaMod.TestString.DisplayCategory>Tests</_x005B_DebugOnlyTest_x005D_TestLuaMod.TestString.DisplayCategory>
</infotexts>
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<contentpackage name="[DebugOnlyTest]TestLuaMod" > <contentpackage name="[DebugOnlyTest]TestLuaMod" >
<Text file="%ModDir%/Texts/English.xml"/>
</contentpackage> </contentpackage>
@@ -66,7 +66,8 @@ public abstract class SettingBase : ISettingBase
{ {
new GUITextBox(new RectTransform(relativeSize, layoutGroup.RectTransform), font: GUIStyle.SmallFont) new GUITextBox(new RectTransform(relativeSize, layoutGroup.RectTransform), font: GUIStyle.SmallFont)
{ {
OnEnterPressed = (box, txt) => Text = GetStringValue(),
OnTextChangedDelegate = (box, txt) =>
{ {
onSerializedValue?.Invoke(txt); onSerializedValue?.Invoke(txt);
return true; return true;
@@ -1,7 +1,9 @@
using System; using System;
using System.Globalization;
using System.Xml.Linq; using System.Xml.Linq;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using Microsoft.Toolkit.Diagnostics; using Microsoft.Toolkit.Diagnostics;
using Microsoft.Xna.Framework;
using OneOf; using OneOf;
namespace Barotrauma.LuaCs.Data; namespace Barotrauma.LuaCs.Data;
@@ -44,6 +46,19 @@ public class SettingRangeFloat : SettingRangeBase<float>
} }
return base.TrySetValue(value); return base.TrySetValue(value);
} }
#if CLIENT
public override void AddDisplayComponent(GUILayoutGroup layoutGroup, Vector2 relativeSize, Action<string> onSerializedValue)
{
GUIUtil.Slider(layoutGroup, new Vector2(MinValue, MaxValue), IncrementalSteps, labelFunc: val =>
{
return val.ToString("G4", CultureInfo.InvariantCulture);
}, Value, setter: val =>
{
onSerializedValue?.Invoke(val.ToString());
}, TextManager.Get(this.GetDisplayInfo().Tooltip), relativeSize);
}
#endif
} }
public class SettingRangeInt : SettingRangeBase<int> public class SettingRangeInt : SettingRangeBase<int>
@@ -73,4 +88,17 @@ public class SettingRangeInt : SettingRangeBase<int>
} }
return base.TrySetValue(value); return base.TrySetValue(value);
} }
#if CLIENT
public override void AddDisplayComponent(GUILayoutGroup layoutGroup, Vector2 relativeSize, Action<string> onSerializedValue)
{
GUIUtil.Slider(layoutGroup, new Vector2(MinValue, MaxValue), IncrementalSteps, labelFunc: val =>
{
return ((int)val).ToString();
}, Value, setter: val =>
{
onSerializedValue?.Invoke(((int)val).ToString());
}, TextManager.Get(this.GetDisplayInfo().Tooltip), relativeSize);
}
#endif
} }
@@ -34,6 +34,9 @@ public class SettingsEntryRegistrar : ISettingsRegistrationProvider
RegisterSettingEntry<long>(configService, "long", valueChangePredicate); RegisterSettingEntry<long>(configService, "long", valueChangePredicate);
RegisterSettingEntry<ulong>(configService, "ulong", valueChangePredicate); RegisterSettingEntry<ulong>(configService, "ulong", valueChangePredicate);
RegisterSettingEntry<string>(configService, "string", valueChangePredicate); RegisterSettingEntry<string>(configService, "string", valueChangePredicate);
RegisterSettingEntry<float>(configService, "float", valueChangePredicate);
RegisterSettingEntry<float>(configService, "single", valueChangePredicate);
RegisterSettingEntry<double>(configService, "double", valueChangePredicate);
// ISettingRangeBase<T> // ISettingRangeBase<T>
configService.RegisterSettingTypeInitializer("rangeInt", cfgInfo => configService.RegisterSettingTypeInitializer("rangeInt", cfgInfo =>
@@ -9,6 +9,7 @@ using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
using AssemblyLoader = Barotrauma.LuaCs.AssemblyLoader; using AssemblyLoader = Barotrauma.LuaCs.AssemblyLoader;
[assembly: InternalsVisibleTo("ImpromptuInterfaceDynamicAssembly")] [assembly: InternalsVisibleTo("ImpromptuInterfaceDynamicAssembly")]
@@ -19,6 +20,7 @@ namespace Barotrauma
internal delegate void LuaCsErrorHandler(Exception ex, LuaCsMessageOrigin origin); internal delegate void LuaCsErrorHandler(Exception ex, LuaCsMessageOrigin origin);
internal delegate void LuaCsExceptionHandler(Exception ex, LuaCsMessageOrigin origin); internal delegate void LuaCsExceptionHandler(Exception ex, LuaCsMessageOrigin origin);
partial class LuaCsSetup : IDisposable, IEventScreenSelected, IEventEnabledPackageListChanged, partial class LuaCsSetup : IDisposable, IEventScreenSelected, IEventEnabledPackageListChanged,
IEventReloadAllPackages IEventReloadAllPackages
{ {
@@ -35,7 +37,6 @@ namespace Barotrauma
// == startup // == startup
_servicesProvider = SetupServicesProvider(); _servicesProvider = SetupServicesProvider();
_runStateMachine = SetupStateMachine(); _runStateMachine = SetupStateMachine();
_servicesProvider.GetService<HarmonyEventPatchesService>();
SubscribeToLuaCsEvents(); SubscribeToLuaCsEvents();
} }
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using Barotrauma.LuaCs.Events; using Barotrauma.LuaCs.Events;
@@ -447,21 +448,29 @@ public sealed partial class ConfigService : IConfigService
using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult(); using var lck = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
IService.CheckDisposed(this); IService.CheckDisposed(this);
if (_storageService.LoadLocalXml(setting.OwnerPackage, SaveDataFileName) is not { } saveFileResult if (_storageService.LoadLocalXml(setting.OwnerPackage, SaveDataFileName) is not { } saveFileResult)
|| saveFileResult is { IsFailed: true })
{ {
return FluentResults.Result.Fail( return FluentResults.Result.Fail(
$"{nameof(LoadSavedValueForConfig)}: Could not open save file for setting [{setting.OwnerPackage.Name}.{setting.InternalName}]"); $"{nameof(LoadSavedValueForConfig)}: Could not open save file for setting [{setting.OwnerPackage.Name}.{setting.InternalName}]");
} }
if (saveFileResult is { IsFailed: true })
{
#if DEBUG
_logger.LogResults(saveFileResult.ToResult());
#endif
return FluentResults.Result.Fail(
$"{nameof(LoadSavedValueForConfig)}: Could not open save file for setting [{setting.OwnerPackage.Name}.{setting.InternalName}]");
}
if (saveFileResult.Value.Root is not {} rootElement if (saveFileResult.Value.Root is not {} rootElement
|| !string.Equals(rootElement.Name.LocalName, "Configuration", StringComparison.InvariantCultureIgnoreCase)) || !string.Equals(rootElement.Name.LocalName, "Configuration", StringComparison.InvariantCultureIgnoreCase))
{ {
return FluentResults.Result.Fail($"{nameof(LoadSavedValueForConfig)}: Root invalid for setting [{setting.OwnerPackage.Name}.{setting.InternalName}]"); return FluentResults.Result.Fail($"{nameof(LoadSavedValueForConfig)}: Root invalid for setting [{setting.OwnerPackage.Name}.{setting.InternalName}]");
} }
if (rootElement.GetChildElement(setting.OwnerPackage.Name, StringComparison.InvariantCulture) if (rootElement.GetChildElement(XmlConvert.EncodeLocalName(setting.OwnerPackage.Name.Trim()), StringComparison.InvariantCultureIgnoreCase)
?.GetChildElement(setting.InternalName, StringComparison.InvariantCulture) is not {} cfgValueElement) ?.GetChildElement(setting.InternalName, StringComparison.InvariantCultureIgnoreCase) is not {} cfgValueElement)
{ {
return FluentResults.Result.Fail($"{nameof(LoadSavedValueForConfig)}: Could not find saved value for setting:[{setting.OwnerPackage.Name}.{setting.InternalName}]"); return FluentResults.Result.Fail($"{nameof(LoadSavedValueForConfig)}: Could not find saved value for setting:[{setting.OwnerPackage.Name}.{setting.InternalName}]");
} }
@@ -547,7 +556,7 @@ public sealed partial class ConfigService : IConfigService
return FluentResults.Result.Fail($"{nameof(SaveConfigValue)}: Bad save file format for setting: [{setting.OwnerPackage.Name}.{setting.InternalName}]"); return FluentResults.Result.Fail($"{nameof(SaveConfigValue)}: Bad save file format for setting: [{setting.OwnerPackage.Name}.{setting.InternalName}]");
} }
XElement currentTarget = GetOrAddElement(cpCfgValues.Root, setting.OwnerPackage.Name, name => new XElement(name)); XElement currentTarget = GetOrAddElement(cpCfgValues.Root, XmlConvert.EncodeLocalName(setting.OwnerPackage.Name.Trim()), name => new XElement(name));
currentTarget = GetOrAddElement(currentTarget, setting.InternalName, name => new XElement(name)); currentTarget = GetOrAddElement(currentTarget, setting.InternalName, name => new XElement(name));
var ret = setting.GetSerializableValue().Match(str => var ret = setting.GetSerializableValue().Match(str =>
@@ -13,9 +13,15 @@ using static Barotrauma.ContentPackageManager;
namespace Barotrauma.LuaCs; namespace Barotrauma.LuaCs;
[HarmonyPatch] [HarmonyPatch]
internal class HarmonyEventPatchesService : IService internal class HarmonyEventPatchesService : ISystem
{ {
public bool IsDisposed { get; private set; } public bool IsDisposed { get; private set; }
public FluentResults.Result Reset()
{
Unpatch();
Patch();
return FluentResults.Result.Ok();
}
private static IEventService _eventService; private static IEventService _eventService;
private static ILoggerService _loggerService; private static ILoggerService _loggerService;
@@ -26,12 +32,23 @@ internal class HarmonyEventPatchesService : IService
_eventService = eventService; _eventService = eventService;
_loggerService = loggerService; _loggerService = loggerService;
Harmony = new Harmony("LuaCsForBarotrauma.Events"); Harmony = new Harmony("LuaCsForBarotrauma.Events");
Harmony.PatchAll(typeof(HarmonyEventPatchesService)); Patch();
}
private void Patch()
{
this.Harmony?.PatchAll(typeof(HarmonyEventPatchesService));
#if SERVER #if SERVER
Harmony.PatchAll(typeof(HarmonyEventPatchesService.Patch_StartGame_End)); this.Harmony?.PatchAll(typeof(HarmonyEventPatchesService.Patch_StartGame_End));
#endif #endif
} }
private void Unpatch()
{
this.Harmony?.UnpatchSelf();
}
[HarmonyPatch(typeof(CoroutineManager), nameof(CoroutineManager.Update)), HarmonyPostfix] [HarmonyPatch(typeof(CoroutineManager), nameof(CoroutineManager.Update)), HarmonyPostfix]
public static void CoroutineManager_Update_Post() public static void CoroutineManager_Update_Post()
{ {
@@ -308,7 +325,7 @@ internal class HarmonyEventPatchesService : IService
public void Dispose() public void Dispose()
{ {
IsDisposed = true; IsDisposed = true;
Harmony.UnpatchSelf(); this.Harmony?.UnpatchSelf();
} }
#if SERVER #if SERVER
@@ -5,6 +5,7 @@ using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using Barotrauma.Extensions; using Barotrauma.Extensions;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using FluentResults; using FluentResults;
@@ -20,6 +21,7 @@ public sealed class PackageManagementService : IPackageManagementService
private IConfigService _configService; private IConfigService _configService;
private ILuaScriptManagementService _luaScriptManagementService; private ILuaScriptManagementService _luaScriptManagementService;
private IPluginManagementService _pluginManagementService; private IPluginManagementService _pluginManagementService;
private IConsoleCommandsService _commandsService;
#if CLIENT #if CLIENT
private IUIStylesService _uiStylesService; private IUIStylesService _uiStylesService;
#endif #endif
@@ -44,6 +46,7 @@ public sealed class PackageManagementService : IPackageManagementService
ILuaScriptManagementService luaScriptManagementService, ILuaScriptManagementService luaScriptManagementService,
IPluginManagementService pluginManagementService, IPluginManagementService pluginManagementService,
IConfigService configService, IConfigService configService,
IConsoleCommandsService commandsService,
#if CLIENT #if CLIENT
IUIStylesService uiStylesService, IUIStylesService uiStylesService,
#endif #endif
@@ -58,6 +61,31 @@ public sealed class PackageManagementService : IPackageManagementService
#if CLIENT #if CLIENT
_uiStylesService = uiStylesService; _uiStylesService = uiStylesService;
#endif #endif
_commandsService = commandsService;
commandsService.RegisterCommand("pms_getxmlname",
"Gets the XML encoded name for the given package, as used in localization.",
onExecute: args =>
{
if (args.Length < 1)
{
_logger.LogError("Please specify the name of the package.");
return;
}
if (ContentPackageManager.AllPackages.FirstOrDefault(p => p.Name == args[0]) is { } pkg)
{
_logger.Log($"Package Xml Name: '{XmlConvert.EncodeLocalName(pkg.Name)}'");
return;
}
_logger.Log($"Could not find package with the name '{args[0]}'");
},
getValidArgs: () =>
{
return new[]
{
this._loadedPackages.Keys.Select(p => p.Name).ToArray()
};
});
} }
public void Dispose() public void Dispose()
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using FluentResults; using FluentResults;
@@ -75,7 +76,7 @@ public sealed class SettingsFileParserService :
continue; continue;
} }
var packageIdent = res.path.ContentPackage!.Name; var packageIdent = XmlConvert.EncodeLocalName(res.path.ContentPackage!.Name);
foreach (var element in settingElements) foreach (var element in settingElements)
{ {
@@ -108,7 +109,7 @@ public sealed class SettingsFileParserService :
}; };
if (!IsInfoValid(newSetting)) if (!IsInfoValid(newSetting))
{ {
return ReturnFail($"A setting was invalid. ContentPackage: {res.path.ContentPackage}"); return ReturnFail($"A setting was invalid. ContentPackage: {res.path.ContentPackage.Name}. Name: {newSetting?.InternalName}");
} }
parsedInfo.Add(newSetting); parsedInfo.Add(newSetting);
} }
@@ -128,7 +129,6 @@ public sealed class SettingsFileParserService :
return info.OwnerPackage != null return info.OwnerPackage != null
&& !info.InternalName.IsNullOrWhiteSpace() && !info.InternalName.IsNullOrWhiteSpace()
&& !info.DataType.IsNullOrWhiteSpace() && !info.DataType.IsNullOrWhiteSpace()
&& !info.DataType.IsNullOrWhiteSpace()
&& info.Element != null && info.Element != null
#if CLIENT #if CLIENT
&& !info.DisplayName.IsNullOrWhiteSpace() && !info.DisplayName.IsNullOrWhiteSpace()
@@ -7,6 +7,7 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Barotrauma.LuaCs.Data; using Barotrauma.LuaCs.Data;
using Barotrauma.Networking; using Barotrauma.Networking;
@@ -128,7 +129,7 @@ public class StorageService : IStorageService
try try
{ {
var path = System.IO.Path.GetFullPath(Path.Combine( var path = System.IO.Path.GetFullPath(Path.Combine(
ConfigData.LocalPackageDataPath.Replace(ConfigData.LocalDataPathRegex, package.Name).CleanUpPathCrossPlatform(), ConfigData.LocalPackageDataPath.Replace(ConfigData.LocalDataPathRegex, XmlConvert.EncodeLocalName(package.Name)).CleanUpPathCrossPlatform(),
localFilePath.CleanUpPathCrossPlatform())); localFilePath.CleanUpPathCrossPlatform()));
if (!path.StartsWith(Path.GetFullPath(ConfigData.LocalDataSavePath))) if (!path.StartsWith(Path.GetFullPath(ConfigData.LocalDataSavePath)))
ThrowHelper.ThrowUnauthorizedAccessException($"{nameof(GetAbsolutePathForLocal)}: The local path of '{path}' is not a local path!"); ThrowHelper.ThrowUnauthorizedAccessException($"{nameof(GetAbsolutePathForLocal)}: The local path of '{path}' is not a local path!");