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)))