[Milestone] AssemblyLoader completed.

Details:
- Assembly Mgmt Service for loading now a separate interface, not intended for normal use.
- Assembly Loader work; implemented custom dictionary key and table.
- Assembly loading work.
- EventService completed.
- Moved assembly extensions to ModUtils.cs
- Work to event service.
NetworkService work
- Added ImpromptuInterfaces package.
- Networking Service work to support NetVars
- Event Service
- Added assemblies references package for script compilation. Updated Roslyn version for compatibility.
- Package Loading work.
Swap Harmony to HarmonyX
- More refactor conversion to FluentResults.
- Updated StylesService to return Results.
- Refactor of PackageService partially complete.
- Made IService.Reset() required to return a Result.
- Moved plugin/assembly related code to their own folder (same namespace).
- Updated interfaces to reflect the use of Result<T>.
- Partial refactor, incomplete.
- Added 'FluentResults' so we can stop using cursed Exception-based flow control in loading code.
- Added 'OneOf' nuget package: https://github.com/mcintyre321/OneOf
for the implementation of the Optional<T> pattern and complex discrete return types instead of cursed enums (see current AssemblyManager.cs).
- Reapplied old branch changes.
This commit is contained in:
MapleWheels
2024-11-04 02:33:31 -05:00
committed by Maplewheels
parent 01cc1d331b
commit 6880e5e9ee
97 changed files with 4100 additions and 1512 deletions
@@ -2,15 +2,17 @@ using Microsoft.Xna.Framework;
namespace Barotrauma.LuaCs.Configuration;
public class DisplayableData : IDisplayableData
public record DisplayableData : IDisplayableData
{
public string Name { get; private set; }
public string ModName { get; private set; }
public string DisplayName { get; private set; }
public string DisplayModName { get; private set; }
public string DisplayCategory { get; private set; }
public string Tooltip { get; private set; }
public string ImageIcon { get; private set; }
public Point IconResolution { get; private set; }
public bool ShowWhenNotLoaded { get; private set; }
public string InternalName { get; init; }
public ContentPackage OwnerPackage { get; init; }
public string FallbackPackageName { get; init; }
public string DisplayName { get; init; }
public string DisplayModName { get; init; }
public string DisplayCategory { get; init; }
public string Tooltip { get; init; }
public string ImageIcon { get; init; }
public Point IconResolution { get; init; }
public bool ShowWhenNotLoaded { get; init; }
public string Description { get; init; }
}
@@ -0,0 +1,12 @@
using System;
namespace Barotrauma.LuaCs.Configuration;
public interface IConfigControl : IConfigBase
{
event Action<IConfigControl> OnDown;
KeyOrMouse Value { get; }
bool IsAssignable(KeyOrMouse value);
bool TrySetValue(KeyOrMouse value);
bool IsDown();
}
@@ -1,4 +1,5 @@
using System.Numerics;
using Barotrauma.LuaCs.Data;
using Microsoft.Xna.Framework;
namespace Barotrauma.LuaCs.Configuration;
@@ -6,16 +7,8 @@ namespace Barotrauma.LuaCs.Configuration;
/// <summary>
/// Contains the Display Data for use with Menus.
/// </summary>
public interface IDisplayableData
public interface IDisplayableData : IDataInfo
{
/// <summary>
/// Internal name of the instance.
/// </summary>
string Name { get; }
/// <summary>
/// Internal mod name of the instance. ContentPackage name will be used by default.
/// </summary>
string ModName { get; }
/// <summary>
/// The name to display in GUIs and Menus.
/// </summary>
@@ -44,6 +37,10 @@ public interface IDisplayableData
/// Whether to show the entry in the menu when not loaded.
/// </summary>
bool ShowWhenNotLoaded { get; }
/// <summary>
/// What does this setting do?
/// </summary>
string Description { get; }
}
public interface IDisplayableInitialize
@@ -53,8 +50,8 @@ public interface IDisplayableInitialize
// copy this as needed
/*public void Initialize(IDisplayableData values)
{
this.Name = values.Name;
this.ModName = values.ModName;
this.InternalName = values.InternalName;
this.OwnerPackage = values.OwnerPackage;
this.DisplayName = values.DisplayName;
this.DisplayModName = values.DisplayModName;
this.DisplayCategory = values.DisplayCategory;
@@ -17,5 +17,6 @@ public record StylesResourceInfo : IStylesResourceInfo
public bool Optional { get; init; }
public ImmutableArray<CultureInfo> SupportedCultures { get; init; }
public string InternalName { get; init; }
public ContentPackage OwnerPackage { get; init; }
public ImmutableArray<IPackageDependencyInfo> Dependencies { get; init; }
}
@@ -4,7 +4,7 @@ namespace Barotrauma.LuaCs.Data;
public partial interface IModConfigInfo : IStylesResourcesInfo { }
public interface IStylesResourceInfo : IResourceInfo, IResourceCultureInfo, ILoadableResourceInfo, IPackageDependenciesInfo { }
public interface IStylesResourceInfo : IResourceInfo, IResourceCultureInfo, IDataInfo, IPackageDependenciesInfo { }
public interface IStylesResourcesInfo
{
@@ -0,0 +1,8 @@
using Barotrauma.Networking;
namespace Barotrauma.LuaCs.Services.Compatibility;
internal partial interface ILuaCsNetworking : ILuaCsShim
{
}
@@ -1,6 +1,6 @@
namespace Barotrauma.LuaCs.Services;
public interface IClientLoggerService : IService
public interface IClientLoggerService : IReusableService
{
void AddToGUIUpdateList();
void ShowErrorOverlay(string message, float time = 5f, float duration = 1.5f);
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Barotrauma.LuaCs.Configuration;
using Barotrauma.LuaCs.Networking;
using Barotrauma.Networking;
namespace Barotrauma.LuaCs.Services;
public partial interface IConfigService
{
/*
* Immediate mode
*/
FluentResults.Result<IConfigEntry<T>> AddConfigEntry<T>(IDisplayableData data,
T defaultValue,
NetSync syncMode = NetSync.None,
ClientPermissions permissions = ClientPermissions.None,
Func<T, bool> valueChangePredicate = null,
Action<IConfigEntry<T>> onValueChanged = null) where T : IConvertible, IEquatable<T>;
FluentResults.Result<IConfigList> AddConfigList(IDisplayableData data,
int defaultIndex, IReadOnlyList<string> values,
NetSync syncMode = NetSync.None,
ClientPermissions permissions = ClientPermissions.None,
Func<IConfigList, int, bool> valueChangePredicate = null,
Action<IConfigList, int> onValueChanged = null);
FluentResults.Result<IConfigRangeEntry<T>> AddConfigRangeEntry<T>(IDisplayableData data,
T defaultValue, T minValue, T maxValue,
Func<IConfigRangeEntry<T>, int> getStepCount,
NetSync syncMode = NetSync.None,
ClientPermissions permissions = ClientPermissions.None,
Func<T, bool> valueChangePredicate = null,
Action<IConfigEntry<T>> onValueChanged = null) where T : IConvertible, IEquatable<T>;
}
@@ -4,7 +4,7 @@
/// <summary>
/// Loads XML Style assets from the given content package.
/// </summary>
public interface IStylesService : IService
public interface IStylesService : IReusableService
{
/// <summary>
/// Tries to load the styles file for the given contentpackage and path into a new UIStylesProcessor instance.
@@ -12,11 +12,11 @@ public interface IStylesService : IService
/// <param name="package"></param>
/// <param name="path"></param>
/// <returns></returns>
bool TryLoadStylesFile(ContentPackage package, ContentPath path);
FluentResults.Result LoadStylesFile(ContentPackage package, ContentPath path);
/// <summary>
/// Unloads all styles assets and UIStyleProcessor instances.
/// </summary>
void UnloadAllStyles();
FluentResults.Result UnloadAllStyles();
/// <summary>
/// Tries to the get the font asset by xml asset name, returns null on failure.
@@ -0,0 +1,135 @@
using Barotrauma.LuaCs.Services;
using Barotrauma.Networking;
using System;
using System.Collections.Generic;
namespace Barotrauma.LuaCs.Networking;
partial class NetworkingService
{
private Dictionary<ushort, Queue<IReadMessage>> receiveQueue = new Dictionary<ushort, Queue<IReadMessage>>();
public void SendSyncMessage()
{
if (GameMain.Client == null) { return; }
WriteOnlyMessage message = new WriteOnlyMessage();
message.WriteByte((byte)ClientPacketHeader.LUA_NET_MESSAGE);
message.WriteByte((byte)LuaCsClientToServer.RequestAllIds);
GameMain.Client.ClientPeer.Send(message, DeliveryMethod.Reliable);
}
public void NetMessageReceived(IReadMessage netMessage, ServerPacketHeader header, Client client = null)
{
if (header != ServerPacketHeader.LUA_NET_MESSAGE)
{
return;
}
LuaCsServerToClient luaCsHeader = (LuaCsServerToClient)netMessage.ReadByte();
switch (luaCsHeader)
{
case LuaCsServerToClient.NetMessageString:
HandleNetMessageString(netMessage);
break;
case LuaCsServerToClient.NetMessageId:
HandleNetMessageId(netMessage);
break;
case LuaCsServerToClient.ReceiveIds:
ReadIds(netMessage);
break;
}
}
public INetWriteMessage Start(Guid netId)
{
var message = new WriteOnlyMessage();
message.WriteByte((byte)ClientPacketHeader.LUA_NET_MESSAGE);
if (idToPacket.ContainsKey(netId))
{
message.WriteByte((byte)LuaCsClientToServer.NetMessageId);
message.WriteUInt16(idToPacket[netId]);
}
else
{
message.WriteByte((byte)LuaCsClientToServer.NetMessageString);
message.WriteBytes(netId.ToByteArray(), 0, 16);
}
return message.ToNetWriteMessage();
}
public void RequestId(Guid netId)
{
if (idToPacket.ContainsKey(netId)) { return; }
if (GameMain.Client == null) { return; }
WriteOnlyMessage message = new WriteOnlyMessage();
message.WriteByte((byte)ClientPacketHeader.LUA_NET_MESSAGE);
message.WriteByte((byte)LuaCsClientToServer.RequestSingleId);
message.WriteBytes(netId.ToByteArray(), 0, 16);
Send(message, DeliveryMethod.Reliable);
}
public void Send(IWriteMessage netMessage, DeliveryMethod deliveryMethod = DeliveryMethod.Reliable)
{
GameMain.Client.ClientPeer.Send(netMessage, deliveryMethod);
}
private void HandleNetMessageId(IReadMessage netMessage, Client client = null)
{
ushort id = netMessage.ReadUInt16();
if (packetToId.ContainsKey(id))
{
HandleNetMessage(netMessage, packetToId[id], client);
}
else
{
if (!receiveQueue.ContainsKey(id)) { receiveQueue[id] = new Queue<IReadMessage>(); }
receiveQueue[id].Enqueue(netMessage);
if (GameSettings.CurrentConfig.VerboseLogging)
{
LuaCsLogger.LogMessage($"Received NetMessage with unknown id {id} from server, storing in queue in case we receive the id later.");
}
}
}
private void ReadIds(IReadMessage netMessage)
{
ushort size = netMessage.ReadUInt16();
for (int i = 0; i < size; i++)
{
ushort packetId = netMessage.ReadUInt16();
Guid netId = new Guid(netMessage.ReadBytes(16));
packetToId[packetId] = netId;
idToPacket[netId] = packetId;
if (!receiveQueue.ContainsKey(packetId))
{
continue;
}
// We could have received messages before receiving the sync message, so we need to process them now
while (receiveQueue[packetId].TryDequeue(out var queueMessage))
{
if (netReceives.ContainsKey(netId))
{
netReceives[netId](queueMessage);
}
}
}
}
}
@@ -9,10 +9,10 @@ namespace Barotrauma.LuaCs.Services;
public partial class PackageService : IStylesResourcesInfo
{
private readonly Lazy<IStylesService> _stylesService;
public IStylesService Styles => _stylesService.Value;
public PackageService(
Lazy<IXmlModConfigConverterService> converterService,
Lazy<ILegacyConfigService> legacyConfigService,
Lazy<IModConfigParserService> configParserService,
Lazy<ILuaScriptService> luaScriptService,
Lazy<ILocalizationService> localizationService,
Lazy<IPluginService> pluginService,
@@ -22,8 +22,7 @@ public partial class PackageService : IStylesResourcesInfo
IStorageService storageService,
ILoggerService loggerService)
{
_modConfigConverterService = converterService;
_legacyConfigService = legacyConfigService;
_configParserService = configParserService;
_luaScriptService = luaScriptService;
_localizationService = localizationService;
_pluginService = pluginService;
@@ -36,7 +35,7 @@ public partial class PackageService : IStylesResourcesInfo
public ImmutableArray<IStylesResourceInfo> StylesResourceInfos => ModConfigInfo?.StylesResourceInfos ?? ImmutableArray<IStylesResourceInfo>.Empty;
public void LoadStyles([NotNull]IStylesResourcesInfo stylesInfo)
public FluentResults.Result LoadStyles([NotNull]IStylesResourcesInfo stylesInfo)
{
throw new NotImplementedException();
}
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using FluentResults;
using FluentResults.LuaCs;
namespace Barotrauma.LuaCs.Services;
@@ -18,44 +20,53 @@ public class StylesService : IStylesService
_loggerService = loggerService;
}
public bool TryLoadStylesFile(ContentPackage package, ContentPath path)
public FluentResults.Result LoadStylesFile(ContentPackage package, ContentPath path)
{
//check if file already in dict
if (_loadedProcessors.ContainsKey(path.FullPath))
{
return true;
return FluentResults.Result.Ok();
}
//check if file exists
if (_storageService.FileExists(path.FullPath))
if (_storageService.FileExists(path.FullPath) is {} result
&& result.IsFailed | (result.IsSuccess & result.Value == false))
{
try
{
var styleProcessor = new UIStyleProcessor(package, path);
styleProcessor.LoadFile();
_loadedProcessors.Add(path.FullPath, styleProcessor);
}
catch (InvalidDataException exception)
{
_loggerService.LogError($"XmlAssetService.TryLoadStylesFile failed for ContentPackage {package.Name}: Exception: {exception.Message}");
return false;
}
return true;
return FluentResults.Result.Fail(result.Errors)
.WithError(new Error($"{nameof(StylesService)}.{nameof(LoadStylesFile)} file does not exist!")
.WithMetadata(MetadataType.ExceptionObject, this)
.WithMetadata(MetadataType.RootObject, package));
}
return false;
try
{
var styleProcessor = new UIStyleProcessor(package, path);
styleProcessor.LoadFile();
_loadedProcessors.Add(path.FullPath, styleProcessor);
}
catch (InvalidDataException exception)
{
return FluentResults.Result.Fail(new Error($"{nameof(StylesService)}.{nameof(LoadStylesFile)} failed for ContentPackage {package.Name}: Exception: {exception.Message}")
.WithMetadata(MetadataType.ExceptionDetails, exception.Message)
.WithMetadata(MetadataType.ExceptionObject, this)
.WithMetadata(MetadataType.RootObject, package)
.WithMetadata(MetadataType.StackTrace, exception.StackTrace));
}
return FluentResults.Result.Ok();
}
public void UnloadAllStyles()
public FluentResults.Result UnloadAllStyles()
{
if (NoProcessorsLoaded)
return;
return FluentResults.Result.Fail(new Error($"{nameof(StylesService)}.{nameof(UnloadAllStyles)}: No processors have been loaded.")
.WithMetadata(MetadataType.ExceptionObject, this));
foreach (var processor in _loadedProcessors)
{
processor.Value.UnloadFile();
}
_loadedProcessors.Clear();
return FluentResults.Result.Ok();
}
public GUIFont GetFont(string fontName)
@@ -131,8 +142,8 @@ public class StylesService : IStylesService
GC.SuppressFinalize(this);
}
public void Reset()
public FluentResults.Result Reset()
{
UnloadAllStyles();
return UnloadAllStyles();
}
}
@@ -603,7 +603,7 @@ namespace Barotrauma.Networking
{
ServerPacketHeader header = (ServerPacketHeader)inc.ReadByte();
GameMain.LuaCs.Networking.NetMessageReceived(inc, header);
GameMain.LuaCs.NetworkingService.NetMessageReceived(inc, header);
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize
&& header is not (