From ac329a70a4f9f1fca16f40adb9fd2f4d32183ce4 Mon Sep 17 00:00:00 2001 From: MapleWheels Date: Sun, 22 Mar 2026 18:01:19 -0400 Subject: [PATCH] - Reduced console spam when failing to load config file in release builds. - Added console logging for failing to unload assembly load ctx. - Removed unused StorageService instance. - Removed unused luacs settings. - Added plugin event service and event service dispatcher api. --- .../ClientSource/LuaCs/LuaCsSettingsMenu.cs | 82 ------------------ .../Config/SettingsShared.xml | 4 - .../SharedSource/LuaCs/LuaCsSetup.cs | 69 ++------------- .../LuaCs/_Services/ConfigService.cs | 9 +- .../LuaCs/_Services/EventService.cs | 24 ++++++ .../LuaCs/_Services/LuaCsInfoProvider.cs | 26 +----- .../_Services/LuaScriptManagementService.cs | 2 + .../_Services/PluginManagementService.cs | 84 ++++++++++++++----- .../_Services/_Interfaces/IEventService.cs | 12 +++ .../_Interfaces/ILuaCsInfoProvider.cs | 20 ----- .../_Services/_Lua/LuaClasses/LuaCsUtility.cs | 10 +-- 11 files changed, 123 insertions(+), 219 deletions(-) delete mode 100644 Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSettingsMenu.cs diff --git a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSettingsMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSettingsMenu.cs deleted file mode 100644 index 8b1004165..000000000 --- a/Barotrauma/BarotraumaClient/ClientSource/LuaCs/LuaCsSettingsMenu.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Microsoft.Xna.Framework; - -namespace Barotrauma -{ - static class LuaCsSettingsMenu - { - private static GUIFrame frame; - - public static void Open(RectTransform rectTransform) - { - Close(); - - frame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.6f), rectTransform, Anchor.Center)); - - GUIListBox list = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.95f), frame.RectTransform, Anchor.Center), false); - - new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), list.Content.RectTransform), "LuaCs Settings", textAlignment: Alignment.Center); - - - new GUITickBox(new RectTransform(new Vector2(0.8f, 0.1f), list.Content.RectTransform), "Enable CSharp Scripting") - { - Selected = LuaCsSetup.Instance.IsCsEnabled, - ToolTip = "This enables CSharp Scripting for mods to use, WARNING: CSharp is NOT sandboxed, be careful with what mods you download.", - OnSelected = (GUITickBox tick) => - { - LuaCsSetup.Instance.IsCsEnabled = tick.Selected; - return true; - } - }; - - new GUITickBox(new RectTransform(new Vector2(0.8f, 0.1f), list.Content.RectTransform), "Disable Error GUI Overlay") - { - Selected = LuaCsSetup.Instance.DisableErrorGUIOverlay, - ToolTip = "", - OnSelected = (GUITickBox tick) => - { - LuaCsSetup.Instance.DisableErrorGUIOverlay = tick.Selected; - return true; - } - }; - - new GUITickBox(new RectTransform(new Vector2(0.8f, 0.1f), list.Content.RectTransform), "Hide usernames In Error Logs") - { - Selected = LuaCsSetup.Instance.HideUserNamesInLogs, - ToolTip = "Hides the operating system username when displaying error logs (eg your username on windows).", - OnSelected = (GUITickBox tick) => - { - LuaCsSetup.Instance.HideUserNamesInLogs = tick.Selected; - return true; - } - }; - - new GUIButton(new RectTransform(new Vector2(1f, 0.1f), list.Content.RectTransform), $"Remove Client-Side LuaCs", style: "GUIButtonSmall") - { - ToolTip = "Remove Client-Side LuaCs.", - OnClicked = (tb, userdata) => - { - LuaCsInstaller.Uninstall(); - return true; - } - }; - - new GUIButton(new RectTransform(new Vector2(0.8f, 0.01f), frame.RectTransform, Anchor.BottomCenter) - { - RelativeOffset = new Vector2(0f, 0.05f) - }, "Close") - { - OnClicked = (GUIButton button, object obj) => - { - Close(); - return true; - } - }; - } - - public static void Close() - { - frame?.Parent.RemoveChild(frame); - frame = null; - } - } -} diff --git a/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/Config/SettingsShared.xml b/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/Config/SettingsShared.xml index 4fcdaf06f..6546e5370 100644 --- a/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/Config/SettingsShared.xml +++ b/Barotrauma/BarotraumaShared/LocalMods/LuaCsForBarotrauma/Config/SettingsShared.xml @@ -1,11 +1,7 @@  - - - - diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs index ec9caba49..a813a33c3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/LuaCsSetup.cs @@ -82,7 +82,6 @@ namespace Barotrauma private LuaGame _game; public LuaGame Game => _game ??= _servicesProvider.GetService(); - internal IStorageService StorageService => _servicesProvider.GetService(); /// /// Whether C# plugin code is enabled. @@ -95,16 +94,6 @@ namespace Barotrauma private ISettingBase _isCsEnabled; - /// - /// Whether the popup error GUI should be hidden/suppressed. - /// - public bool DisableErrorGUIOverlay - { - get => _disableErrorGUIOverlay?.Value ?? false; - internal set => _disableErrorGUIOverlay?.TrySetValue(value); - } - private ISettingBase _disableErrorGUIOverlay; - /// /// Whether usernames are anonymized or show in logs. /// @@ -115,66 +104,25 @@ namespace Barotrauma } private ISettingBase _hideUserNamesInLogs; - /// - /// The SteamId of the Workshop LuaCs CPackage in use, if available. - /// - public ulong LuaForBarotraumaSteamId + public static ContentPackage GetLuaCsPackage() { - get => _luaForBarotraumaSteamId?.Value ?? 0; - internal set => _luaForBarotraumaSteamId?.TrySetValue(value); - } - private ISettingBase _luaForBarotraumaSteamId; - - /// - /// Whether the maximum message size over the network should be restricted. - /// - public bool RestrictMessageSize - { - get => _restrictMessageSize?.Value ?? false; - internal set => _restrictMessageSize?.TrySetValue(value); - } - private ISettingBase _restrictMessageSize; - - /// - /// The local save path for all local data storage for mods. - /// - public string LocalDataSavePath - { - get => _localDataSavePath?.Value ?? Path.Combine(Directory.GetCurrentDirectory(), "/Data/Mods"); - internal set => _localDataSavePath?.TrySetValue(value); - } - private ISettingBase _localDataSavePath; - - void LoadLuaCsConfig() - { - var luaCsPackage = ContentPackageManager.EnabledPackages.Regular.FirstOrDefault(cp => cp.NameMatches(PackageId), null) + return ContentPackageManager.EnabledPackages.Regular.FirstOrDefault(cp => cp.NameMatches(PackageId), null) ?? ContentPackageManager.LocalPackages.FirstOrDefault(cp => cp.NameMatches(PackageId)) ?? ContentPackageManager.WorkshopPackages.FirstOrDefault(cp => cp.NameMatches(PackageId)); + } + + void LoadLuaCsConfig() + { + var luaCsPackage = GetLuaCsPackage(); _isCsEnabled = ConfigService.TryGetConfig>(luaCsPackage, "IsCsEnabled", out var val1) ? val1 : null; - _disableErrorGUIOverlay = - ConfigService.TryGetConfig>(luaCsPackage, "DisableErrorGUIOverlay", out var val3) - ? val3 - : null; _hideUserNamesInLogs = ConfigService.TryGetConfig>(luaCsPackage, "HideUserNamesInLogs", out var val4) ? val4 : null; - _luaForBarotraumaSteamId = - ConfigService.TryGetConfig>(luaCsPackage, "LuaForBarotraumaSteamId", out var val5) - ? val5 - : null; - _restrictMessageSize = - ConfigService.TryGetConfig>(luaCsPackage, "RestrictMessageSize", out var val7) - ? val7 - : null; - _localDataSavePath = - ConfigService.TryGetConfig>(luaCsPackage, "LocalDataSavePath", out var val8) - ? val8 - : null; } private IServicesProvider SetupServicesProvider() @@ -485,10 +433,7 @@ namespace Barotrauma void DisposeLuaCsConfig() { _isCsEnabled = null; - _disableErrorGUIOverlay = null; _hideUserNamesInLogs = null; - _luaForBarotraumaSteamId = null; - _restrictMessageSize = null; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ConfigService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ConfigService.cs index d84e32473..8357d31b9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ConfigService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/ConfigService.cs @@ -450,17 +450,21 @@ public sealed partial class ConfigService : IConfigService if (_storageService.LoadLocalXml(setting.OwnerPackage, SaveDataFileName) is not { } saveFileResult) { +#if DEBUG return FluentResults.Result.Fail( $"{nameof(LoadSavedValueForConfig)}: Could not open save file for setting [{setting.OwnerPackage.Name}.{setting.InternalName}]"); +#endif + return FluentResults.Result.Ok(); } 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}]"); +#endif + return FluentResults.Result.Ok(); } if (saveFileResult.Value.Root is not {} rootElement @@ -472,7 +476,10 @@ public sealed partial class ConfigService : IConfigService if (rootElement.GetChildElement(XmlConvert.EncodeLocalName(setting.OwnerPackage.Name.Trim()), StringComparison.InvariantCultureIgnoreCase) ?.GetChildElement(setting.InternalName, StringComparison.InvariantCultureIgnoreCase) is not {} cfgValueElement) { +#if DEBUG return FluentResults.Result.Fail($"{nameof(LoadSavedValueForConfig)}: Could not find saved value for setting:[{setting.OwnerPackage.Name}.{setting.InternalName}]"); +#endif + return FluentResults.Result.Ok(); } return FluentResults.Result.OkIf(setting.TrySetValue(cfgValueElement), new Error($"Failed to set value for [{setting.OwnerPackage.Name}.{setting.InternalName}]")); diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventService.cs index 9971b369a..862f507c6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/EventService.cs @@ -6,6 +6,8 @@ using OneOf; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -55,6 +57,7 @@ public partial class EventService : IEventService private readonly ConcurrentDictionary, IEvent>> _subscribers = new(); private readonly ConcurrentDictionary RunnerFactory)> _luaAliasEventFactory = new(); private readonly ConcurrentDictionary> _luaLegacyEventsSubscribers = new(); + private readonly ConcurrentDictionary _subscribedEventDispatchers = new(); #region LifeCycle @@ -316,9 +319,30 @@ public partial class EventService : IEventService } } + foreach (var dispatchers in _subscribedEventDispatchers.ToImmutableArray()) + { + dispatchers.Value.PublishEvent(action); + } + return results; } + public void AddDispatcherEventService(IEventService eventService) + { + using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + + _subscribedEventDispatchers.TryAdd(eventService, eventService); + } + + public void RemoveDispatcherEventService(IEventService eventService) + { + using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult(); + IService.CheckDisposed(this); + + _subscribedEventDispatchers.TryRemove(eventService, out _); + } + #region LuaPatcherAdapter public string Patch(string identifier, string className, string methodName, string[] parameterTypes, LuaCsPatchFunc patch, LuaCsHook.HookMethodType hookType = LuaCsHook.HookMethodType.Before) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaCsInfoProvider.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaCsInfoProvider.cs index edf63fc32..5225e710b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaCsInfoProvider.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaCsInfoProvider.cs @@ -13,35 +13,15 @@ public sealed class LuaCsInfoProvider : ILuaCsInfoProvider public bool IsDisposed => false; public bool IsCsEnabled => LuaCsSetup.Instance.IsCsEnabled; - public bool DisableErrorGUIOverlay => LuaCsSetup.Instance.DisableErrorGUIOverlay; public bool HideUserNamesInLogs => LuaCsSetup.Instance.HideUserNamesInLogs; - public ulong LuaForBarotraumaSteamId => LuaCsSetup.Instance.LuaForBarotraumaSteamId; - public bool RestrictMessageSize => LuaCsSetup.Instance.RestrictMessageSize; - public string LocalDataSavePath => LuaCsSetup.Instance.LocalDataSavePath; public RunState CurrentRunState => LuaCsSetup.Instance.CurrentRunState; public ContentPackage LuaCsForBarotraumaPackage { get { - var luaCs = FirstOrDefaultLua(ContentPackageManager.EnabledPackages.All); - if (luaCs == null) - { - luaCs = FirstOrDefaultLua(ContentPackageManager.LocalPackages.Regular); - } - - if (luaCs == null) - { - luaCs = FirstOrDefaultLua(ContentPackageManager.WorkshopPackages.Regular); - } - - return luaCs; - - ContentPackage FirstOrDefaultLua(IEnumerable packages) - { - return packages.FirstOrDefault(p => - p.Name.Equals("LuaCsForBarotrauma", StringComparison.InvariantCultureIgnoreCase) - || p.Name.Equals("Lua for Barotrauma", StringComparison.InvariantCultureIgnoreCase)); - } + return ContentPackageManager.EnabledPackages.Regular.FirstOrDefault(cp => cp.NameMatches(LuaCsSetup.PackageId), null) + ?? ContentPackageManager.LocalPackages.FirstOrDefault(cp => cp.NameMatches(LuaCsSetup.PackageId)) + ?? ContentPackageManager.WorkshopPackages.FirstOrDefault(cp => cp.NameMatches(LuaCsSetup.PackageId)); } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs index 04c58caad..502021b23 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/LuaScriptManagementService.cs @@ -214,11 +214,13 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService, if (!LuaCsFile.CanReadFromPath(file)) { + // TODO: Replace with LuaScriptLoader IsFileAccessible. throw new ScriptRuntimeException($"dofile: File access to {file} not allowed."); } if (!LuaCsFile.Exists(file)) { + // TODO: Replace with LuaScriptLoader IsFileAccessible. throw new ScriptRuntimeException($"dofile: File {file} not found."); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs index 639f27045..db7d40f17 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/PluginManagementService.cs @@ -195,6 +195,8 @@ public class PluginManagementService : IAssemblyManagementService private Lazy _eventService; private Lazy _configService; private Lazy _luaScriptManagementService; + private IEventService _pluginEventService; + private Lazy _pluginLuaPatcherService; private readonly ConcurrentDictionary _assemblyLoaders = new(); private readonly ConcurrentDictionary _pluginPackageLookup = new(); private readonly ConcurrentDictionary> _pluginInstances = new(); @@ -208,7 +210,8 @@ public class PluginManagementService : IAssemblyManagementService ILoggerService logger, Lazy eventService, Lazy luaScriptManagementService, - Lazy configService) + Lazy configService, + Lazy pluginLuaPatcherService) { _assemblyLoaderFactory = assemblyLoaderFactory; _storageService = storageService; @@ -216,19 +219,22 @@ public class PluginManagementService : IAssemblyManagementService _eventService = eventService; _luaScriptManagementService = luaScriptManagementService; _configService = configService; + _pluginLuaPatcherService = pluginLuaPatcherService; } private ServiceContainer CreatePluginServiceContainer() { var container = new ServiceContainer(new ContainerOptions() { - EnablePropertyInjection = true, - + EnablePropertyInjection = true }); + _pluginEventService ??= new EventService(_logger, _pluginLuaPatcherService.Value); + _eventService.Value.AddDispatcherEventService(_pluginEventService); + container.Register(fac => _logger); container.Register(fac => _storageService); - container.Register(fac => _eventService.Value); + container.Register(fac => _pluginEventService); container.Register(fac => this); container.Register(fac => _luaScriptManagementService.Value); container.Register(fac => _configService.Value); @@ -707,6 +713,37 @@ public class PluginManagementService : IAssemblyManagementService _assemblyLoaders.Clear(); GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true); + +#if DEBUG + // Print still loaded assembly load ctx after giving some time + CoroutineManager.Invoke(() => + { + if (!_unloadingAssemblyLoaders.Any()) + { + return; + } + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("The following ContentPackages have not unloaded their assemblies:"); + + foreach (var kvp in _unloadingAssemblyLoaders.ToImmutableArray()) + { + sb.AppendLine($"- '{kvp.Value.Name}'"); + } + + + // Use DebugConsole in case logger is null by the time this executes. + if (_logger is null) + { + DebugConsole.LogError(sb.ToString()); + } + else + { + _logger.LogWarning(sb.ToString()); + } + }, 3.0f); +#endif return results; } @@ -714,24 +751,29 @@ public class PluginManagementService : IAssemblyManagementService private FluentResults.Result UnsafeDisposeManagedTypeInstances() { var results = new FluentResults.Result(); + + if (!_pluginInstances.IsEmpty) + { + foreach (var instance in _pluginInstances.SelectMany(kvp => kvp.Value)) + { + try + { + instance.Dispose(); + } + catch (Exception e) + { + results.WithError(new ExceptionalError(e)); + continue; + } + } + } + + if (_pluginEventService is not null) + { + _eventService.Value.RemoveDispatcherEventService(_pluginEventService); + _pluginEventService = null; + } _pluginInjectorContainer = null; - if (_pluginInstances.IsEmpty) - { - return FluentResults.Result.Ok(); - } - - foreach (var instance in _pluginInstances.SelectMany(kvp => kvp.Value)) - { - try - { - instance.Dispose(); - } - catch (Exception e) - { - results.WithError(new ExceptionalError(e)); - continue; - } - } _pluginInstances.Clear(); _pluginPackageLookup.Clear(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/IEventService.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/IEventService.cs index 39c7ad347..867742321 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/IEventService.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/IEventService.cs @@ -37,4 +37,16 @@ public interface IEventService : IReusableService, ILuaEventService /// /// FluentResults.Result PublishEvent(Action action) where T : class, IEvent; + + /// + /// Adds an event service that will receive all published events. + /// + /// + void AddDispatcherEventService(IEventService eventService); + + /// + /// Removes an event service from the dispatcher list. + /// + /// + void RemoveDispatcherEventService(IEventService eventService); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/ILuaCsInfoProvider.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/ILuaCsInfoProvider.cs index 2cf93ed94..bf5e38c08 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/ILuaCsInfoProvider.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Interfaces/ILuaCsInfoProvider.cs @@ -10,30 +10,10 @@ public interface ILuaCsInfoProvider : IService /// public bool IsCsEnabled { get; } - /// - /// Whether the popup error GUI should be hidden/suppressed. - /// - public bool DisableErrorGUIOverlay { get; } - /// /// Whether usernames are anonymized or show in logs. /// public bool HideUserNamesInLogs { get; } - - /// - /// The SteamId of the Workshop LuaCs CPackage in use, if available. - /// - public ulong LuaForBarotraumaSteamId { get; } - - /// - /// Restrict the maximum size of messages sent over the network. - /// - public bool RestrictMessageSize { get; } - - /// - /// The local save path for all local data storage for mods. - /// - public string LocalDataSavePath { get; } /// /// The current state of the Execution State Machine. diff --git a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Lua/LuaClasses/LuaCsUtility.cs b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Lua/LuaClasses/LuaCsUtility.cs index b4aca75b9..dc7b0b835 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Lua/LuaClasses/LuaCsUtility.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/LuaCs/_Services/_Lua/LuaClasses/LuaCsUtility.cs @@ -52,19 +52,17 @@ namespace Barotrauma public static bool CanWriteToPath(string path) { + const long LuaCsPackageId = 2559634234; + string getFullPath(string p) => System.IO.Path.GetFullPath(p).CleanUpPath(); path = getFullPath(path); bool pathStartsWith(string prefix) => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); - foreach (var package in ContentPackageManager.AllPackages) + if (pathStartsWith(getFullPath(LuaCsSetup.GetLuaCsPackage().Path))) { - if (package.UgcId.ValueEquals(new SteamWorkshopId(LuaCsSetup.Instance.LuaForBarotraumaSteamId)) - && pathStartsWith(getFullPath(package.Path))) - { - return false; - } + return false; } if (pathStartsWith(getFullPath(string.IsNullOrEmpty(GameSettings.CurrentConfig.SavePath) ? SaveUtil.DefaultSaveFolder : GameSettings.CurrentConfig.SavePath)))