- Moved all console commands to their respective services and added via injector service.

- Fixed LuaCs IsCsEnabled prompt not working.
- Add settings profiles support.
This commit is contained in:
MapleWheels
2026-02-24 15:26:49 -05:00
parent 394856fa04
commit d9d980122d
9 changed files with 298 additions and 121 deletions

View File

@@ -4240,28 +4240,8 @@ namespace Barotrauma
var result = GameMain.LuaCs.LuaScriptManagementService.DoString(string.Join(" ", args));
GameMain.LuaCs.Logger.LogResults(result.ToResult());
}));
commands.Add(new Command("cl_reloadlua|cl_reloadcs|cl_reloadluacs", "Re-initializes the LuaCs environment.", (string[] args) =>
{
GameMain.LuaCs.EventService.PublishEvent<IEventReloadAllPackages>(sub => sub.OnReloadAllPackages());
}));
commands.Add(new Command("cl_toggleluadebug", "Toggles the MoonSharp Debug Server.", (string[] args) =>
{
int port = 41912;
if (args.Length > 0)
{
int.TryParse(args[0], out port);
}
throw new NotImplementedException();
//GameMain.LuaCs.ToggleDebugger(port);
}));
}
private static void ReloadWearables(Character character, int variant = 0)
{
foreach (var limb in character.AnimController.Limbs)

View File

@@ -53,15 +53,39 @@ namespace Barotrauma
msg.Buttons[0].OnClicked = (GUIButton button, object obj) =>
{
this.IsCsEnabled = true;
isCsValueChanged = true;
return true;
try
{
this.IsCsEnabled = true;
isCsValueChanged = true;
CoroutineManager.Invoke(() =>
{
if (CurrentRunState >= RunState.Running)
{
var currentRunState = CurrentRunState;
SetRunState(RunState.LoadedNoExec);
SetRunState(currentRunState);
}
}, 0f);
return true;
}
finally
{
msg.Close();
}
};
msg.Buttons[1].OnClicked = (GUIButton button, object obj) =>
{
this.IsCsEnabled = false;
return true;
try
{
// avoid a TOCTOU scenario.
this.IsCsEnabled = false;
return true;
}
finally
{
msg.Close();
}
};
return isCsValueChanged;

View File

@@ -2311,93 +2311,7 @@ namespace Barotrauma
NewMessage($"Start item set changed to \"{AutoItemPlacer.DefaultStartItemSet}\"");
}, isCheat: false));
commands.Add(new Command("cfg_getvalue", "cfg_getvalue [Content Package] [InternalName] [ValueString]: gets a config value.", (string[] args) =>
{
if (args.Length < 1)
{
ThrowError("Please specify the name of the package to set the config.");
return;
}
if (args.Length < 2)
{
ThrowError("Please specify the name of the config.");
return;
}
var package = ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name == args[0]);
if (package == null)
{
ThrowError($"Could not find the package {args[0]}!");
return;
}
string internalName = args[1];
if (!GameMain.LuaCs.ConfigService.TryGetConfig(package, internalName, out LuaCs.Data.ISettingBase setting))
{
ThrowError($"Could not get config with name {internalName}");
return;
}
NewMessage($"config {internalName} value is {setting.GetStringValue()}", Color.Green);
}, getValidArgs: () => new[]
{
ContentPackageManager.RegularPackages.Select(p => p.Name).ToArray()
}));
commands.Add(new Command("cfg_setvalue", "cfg_setvalue [Content Package] [InternalName] [ValueString]: sets a config.", (string[] args) =>
{
if (args.Length < 1)
{
ThrowError("Please specify the name of the package to set the config.");
return;
}
if (args.Length < 2)
{
ThrowError("Please specify the name of the config.");
return;
}
if (args.Length < 3)
{
ThrowError("Please specify the value to set the config to.");
return;
}
var package = ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name == args[0]);
if (package == null)
{
ThrowError($"Could not find the package {args[0]}!");
return;
}
string internalName = args[1];
string valueString = args[2];
if (!GameMain.LuaCs.ConfigService.TryGetConfig(package, internalName, out LuaCs.Data.ISettingBase setting))
{
ThrowError($"Could not get config with name {internalName}");
return;
}
if (setting.TrySetValue(valueString))
{
NewMessage($"Set config {internalName} value to {valueString}", Color.Green);
if (GameMain.LuaCs.ConfigService.SaveConfigValue(setting) is { IsFailed: true } res)
{
NewMessage($"Failed to save new config data to disk. Reasons: {res.ToString()}");
}
}
else
{
ThrowError($"Failed to set config value");
}
}, getValidArgs: () => new[]
{
ContentPackageManager.RegularPackages.Select(p => p.Name).ToArray()
}));
//"dummy commands" that only exist so that the server can give clients permissions to use them
//TODO: alphabetical order?

View File

@@ -181,7 +181,8 @@ namespace Barotrauma
servicesProvider.RegisterServiceType<INetworkingService, NetworkingService>(ServiceLifetime.Singleton);
servicesProvider.RegisterServiceType<INetworkIdProvider, NetworkingIdProvider>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<HarmonyEventPatchesService, HarmonyEventPatchesService>(ServiceLifetime.Singleton);
servicesProvider.RegisterServiceType<IConsoleCommandsService, ConsoleCommandsService>(ServiceLifetime.Transient);
// Extension/Sub Services
servicesProvider.RegisterServiceType<IAssemblyLoaderService.IFactory, AssemblyLoader.Factory>(ServiceLifetime.Transient);
servicesProvider.RegisterServiceType<ISettingsRegistrationProvider, SettingsEntryRegistrar>(ServiceLifetime.Transient);

View File

@@ -14,6 +14,7 @@ using Barotrauma.LuaCs.Events;
using Barotrauma.LuaCs;
using FluentResults;
using Microsoft.Toolkit.Diagnostics;
using Microsoft.Xna.Framework;
namespace Barotrauma.LuaCs;
@@ -71,12 +72,14 @@ public sealed partial class ConfigService : IConfigService
_settingsInstances.Clear();
_instanceFactory.Clear();
_settingsInstancesByPackage.Clear();
_commandsService.Dispose();
_storageService = null;
_logger = null;
_eventService = null;
_configInfoParserService = null;
_configProfileInfoParserService = null;
_commandsService = null;
}
public FluentResults.Result Reset()
@@ -136,7 +139,7 @@ public sealed partial class ConfigService : IConfigService
private IStorageService _storageService;
private ILoggerService _logger;
private IEventService _eventService;
private ILuaCsInfoProvider _luaCsInfoProvider;
private IConsoleCommandsService _commandsService;
private IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigInfo> _configInfoParserService;
private IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo> _configProfileInfoParserService;
@@ -145,16 +148,143 @@ public sealed partial class ConfigService : IConfigService
IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigInfo> configInfoParserService,
IParserServiceOneToManyAsync<IConfigResourceInfo, IConfigProfileInfo> configProfileInfoParserService,
IEventService eventService,
ILuaCsInfoProvider luaCsInfoProvider)
IConsoleCommandsService commandsService)
{
_logger = logger;
_storageService = storageService;
_configInfoParserService = configInfoParserService;
_configProfileInfoParserService = configProfileInfoParserService;
_eventService = eventService;
_luaCsInfoProvider = luaCsInfoProvider;
_commandsService = commandsService;
_storageService.UseCaching = true;
InjectCommands(commandsService);
}
private void InjectCommands(IConsoleCommandsService commandsService)
{
commandsService.RegisterCommand("cfg_getvalue", "cfg_getvalue [Content Package] [InternalName] [ValueString]: gets a config value.", (string[] args) =>
{
if (args.Length < 1)
{
_logger.LogError("Please specify the name of the package to set the config.");
return;
}
if (args.Length < 2)
{
_logger.LogError("Please specify the name of the config.");
return;
}
var package = ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name == args[0]);
if (package == null)
{
_logger.LogError($"Could not find the package {args[0]}!");
return;
}
string internalName = args[1];
if (!TryGetConfig(package, internalName, out ISettingBase setting))
{
_logger.LogError($"Could not get config with name {internalName}");
return;
}
_logger.LogMessage($"config {internalName} value is {setting.GetStringValue()}", Color.Green);
}, getValidArgs: () => new[]
{
ContentPackageManager.RegularPackages.Select(p => p.Name).ToArray()
});
commandsService.RegisterCommand("cfg_setvalue", "cfg_setvalue [Content Package] [InternalName] [ValueString]: sets a config.", (string[] args) =>
{
if (args.Length < 1)
{
_logger.LogError("Please specify the name of the package to set the config.");
return;
}
if (args.Length < 2)
{
_logger.LogError("Please specify the name of the config.");
return;
}
if (args.Length < 3)
{
_logger.LogError("Please specify the value to set the config to.");
return;
}
var package = ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name == args[0]);
if (package == null)
{
_logger.LogError($"Could not find the package {args[0]}!");
return;
}
string internalName = args[1];
string valueString = args[2];
if (!TryGetConfig(package, internalName, out ISettingBase setting))
{
_logger.LogError($"Could not get config with name {internalName}");
return;
}
if (setting.TrySetValue(valueString))
{
_logger.LogMessage($"Set config {internalName} value to {valueString}", Color.Green);
if (SaveConfigValue(setting) is { IsFailed: true } res)
{
_logger.LogMessage($"Failed to save new config data to disk. Reasons: {res.ToString()}");
}
}
else
{
_logger.LogError($"Failed to set config value");
}
}, getValidArgs: () => new[]
{
ContentPackageManager.RegularPackages.Select(p => p.Name).ToArray()
});
commandsService.RegisterCommand("cfg_setprofile", "cfg_setprofile [ContentPackage] [InternalProfileName]",
(string[] args) =>
{
if (args.Length < 1 || args[0].IsNullOrWhiteSpace())
{
_logger.LogError("Please specify the name of the package of the profile.");
return;
}
if (args.Length < 2 || args[1].IsNullOrWhiteSpace())
{
_logger.LogError("Please specify the name of the profile.");
return;
}
var package = ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name == args[0], null);
if (package == null)
{
_logger.LogError($"Could not find the package {args[0]}!");
return;
}
var res = ApplyConfigProfile(package, args[1]);
if (res.IsFailed)
{
_logger.LogError($"Errors while applying profile {args[1]}!");
_logger.LogResults(res);
return;
}
_logger.Log($"Profile {args[1]} applied successfully!", Color.Green);
}, getValidArgs: () => new[]
{
ContentPackageManager.RegularPackages.Select(p => p.Name).ToArray()
}, false);
}
@@ -357,7 +487,38 @@ public sealed partial class ConfigService : IConfigService
return ret;
}
public FluentResults.Result ApplyConfigProfile(ContentPackage package, string internalName)
{
Guard.IsNotNull(package, nameof(package));
Guard.IsNotNullOrWhiteSpace(internalName, nameof(internalName));
using var _ = _operationLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
IService.CheckDisposed(this);
if (!_settingsProfiles.TryGetValue((package, internalName), out var setting))
{
return FluentResults.Result.Fail($"{nameof(ApplyConfigProfile)}: Could not find profile [{package.Name}.{internalName}]");
}
var result = new FluentResults.Result();
foreach (var profileValue in setting.ProfileValues)
{
if (!_settingsInstances.TryGetValue((package, profileValue.SettingName), out var instance))
{
result.WithError(new Error($"{nameof(ApplyConfigProfile)}: Could not find setting [{profileValue.SettingName}]."));
continue;
}
if (!instance.TrySetValue(profileValue.Element))
{
result.WithError(new Error($"{nameof(ApplyConfigProfile)}: Failed to set value for [{profileValue.SettingName}]."));
}
}
return result;
}
public FluentResults.Result SaveConfigValue(ISettingBase setting)
{
XDocument cpCfgValues;

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Barotrauma.LuaCs;
public class ConsoleCommandsService : IConsoleCommandsService
{
private readonly ConcurrentDictionary<string, DebugConsole.Command> _registeredCommands = new();
public void Dispose()
{
if (!ModUtils.Threading.CheckIfClearAndSetBool(ref _isDisposed))
{
return;
}
foreach (var cmd in _registeredCommands.Values.ToImmutableArray())
{
DebugConsole.Commands.Remove(cmd);
}
_registeredCommands.Clear();
}
private int _isDisposed = 0;
public bool IsDisposed
{
get => ModUtils.Threading.GetBool(ref _isDisposed);
private set => ModUtils.Threading.SetBool(ref _isDisposed, value);
}
public FluentResults.Result RegisterCommand(string name, string help, Action<string[]> onExecute, Func<string[][]> getValidArgs = null, bool isCheat = false)
{
IService.CheckDisposed(this);
var cmd = new DebugConsole.Command(name, help, onExecute, getValidArgs, isCheat);
if (!_registeredCommands.TryAdd(name, cmd))
{
return FluentResults.Result.Fail($"{nameof(RegisterCommand)}: A command with the name '{name}' is already added.");
}
DebugConsole.Commands.Add(cmd);
return FluentResults.Result.Ok();
}
public void RemoveCommand(string name)
{
IService.CheckDisposed(this);
if (_registeredCommands.TryRemove(name, out DebugConsole.Command cmd))
{
DebugConsole.Commands.Remove(cmd);
}
}
public void RemoveRegisteredCommands()
{
IService.CheckDisposed(this);
foreach (var cmd in _registeredCommands.Values.ToImmutableArray())
{
DebugConsole.Commands.Remove(cmd);
}
_registeredCommands.Clear();
}
}

View File

@@ -50,6 +50,7 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
private readonly IDefaultLuaRegistrar _defaultLuaRegistrar;
private readonly IPluginManagementService _pluginManagementService;
private readonly INetworkingService _networkingService;
private readonly IConsoleCommandsService _commandsService;
//private readonly ILuaCsUtility _luaCsUtility;
public LuaScriptManagementService(
@@ -64,7 +65,8 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
LuaGame luaGame,
IEventService eventService,
//ILuaCsUtility luaCsUtility,
ILuaCsTimer luaCsTimer
ILuaCsTimer luaCsTimer,
IConsoleCommandsService commandsService
)
{
_luaScriptLoader = loader;
@@ -78,13 +80,33 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
_luaGame = luaGame;
_eventService = eventService;
//_luaCsNetworking = luaCsNetworking;
//_luaCsUtility = luaCsUtility;
_commandsService = commandsService;
_luaCsTimer = luaCsTimer;
RegisterLuaEvents();
}
private void RegisterConsoleCommands(IConsoleCommandsService commands)
{
commands.RegisterCommand("cl_reloadlua|cl_reloadcs|cl_reloadluacs", "Re-initializes the LuaCs environment.", (string[] args) =>
{
GameMain.LuaCs.EventService.PublishEvent<IEventReloadAllPackages>(sub => sub.OnReloadAllPackages());
});
commands.RegisterCommand("cl_toggleluadebug", "Toggles the MoonSharp Debug Server.", (string[] args) =>
{
int port = 41912;
if (args.Length > 0)
{
int.TryParse(args[0], out port);
}
throw new NotImplementedException();
//GameMain.LuaCs.ToggleDebugger(port);
});
}
public bool IsDisposed { get; private set; }
public async Task<FluentResults.Result> LoadScriptResourcesAsync(ImmutableArray<ILuaScriptResourceInfo> resourcesInfo)
@@ -400,6 +422,7 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
public FluentResults.Result Reset()
{
IService.CheckDisposed(this);
_luaScriptLoader.ClearCaches();
_userDataService.Reset();
_luaCsTimer.Reset();
@@ -409,9 +432,10 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService
public void Dispose()
{
IsDisposed = true;
_userDataService.Dispose();
_luaScriptLoader.Dispose();
IsDisposed = true;
_commandsService.Dispose();
}
public object? GetGlobalTableValue(string tableName)

View File

@@ -19,6 +19,7 @@ public partial interface IConfigService : IReusableService, ILuaConfigService
Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigResourceInfo> configProfileResources);
FluentResults.Result LoadSavedValueForConfig(ISettingBase setting);
FluentResults.Result LoadSavedConfigsValues();
FluentResults.Result ApplyConfigProfile(ContentPackage package, string internalName);
FluentResults.Result SaveConfigValue(ISettingBase setting);
FluentResults.Result DisposePackageData(ContentPackage package);
FluentResults.Result DisposeAllPackageData();

View File

@@ -0,0 +1,11 @@
using System;
namespace Barotrauma.LuaCs;
public interface IConsoleCommandsService : IService
{
FluentResults.Result RegisterCommand(string name, string help, Action<string[]> onExecute, Func<string[][]> getValidArgs = null,
bool isCheat = false);
void RemoveCommand(string name);
void RemoveRegisteredCommands();
}