-- Squash:

- In progress implementation of services model.
This commit is contained in:
MapleWheels
2024-09-18 20:54:56 -04:00
committed by Maplewheels
parent 9e957a75b0
commit 01cc1d331b
68 changed files with 3083 additions and 152 deletions
@@ -0,0 +1,16 @@
using Microsoft.Xna.Framework;
namespace Barotrauma.LuaCs.Configuration;
public class 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; }
}
@@ -0,0 +1,6 @@
using Barotrauma.LuaCs.Configuration;
using Barotrauma.LuaCs.Data;
namespace Barotrauma.LuaCs.Configuration;
public partial interface IConfigBase : IDisplayableData, IDisplayableInitialize { }
@@ -0,0 +1,66 @@
using System.Numerics;
using Microsoft.Xna.Framework;
namespace Barotrauma.LuaCs.Configuration;
/// <summary>
/// Contains the Display Data for use with Menus.
/// </summary>
public interface IDisplayableData
{
/// <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>
string DisplayName { get; }
/// <summary>
/// The mod name to display in GUIs and Menus.
/// </summary>
string DisplayModName { get; }
/// <summary>
/// Category this instance falls under. Used by menus when filtering by category.
/// </summary>
string DisplayCategory { get; }
/// <summary>
/// The tooltip shown on hover.
/// </summary>
string Tooltip { get; }
/// <summary>
/// The fully qualified filepath to the image icon for this config.
/// </summary>
string ImageIcon { get; }
/// <summary>
/// Required if ImageIcon is set. X,Y resolution of the image.
/// </summary>
Point IconResolution { get; }
/// <summary>
/// Whether to show the entry in the menu when not loaded.
/// </summary>
bool ShowWhenNotLoaded { get; }
}
public interface IDisplayableInitialize
{
void Initialize(IDisplayableData values);
// copy this as needed
/*public void Initialize(IDisplayableData values)
{
this.Name = values.Name;
this.ModName = values.ModName;
this.DisplayName = values.DisplayName;
this.DisplayModName = values.DisplayModName;
this.DisplayCategory = values.DisplayCategory;
this.Tooltip = values.Tooltip;
this.ImageIcon = values.ImageIcon;
this.IconResolution = values.IconResolution;
this.ShowWhenNotLoaded = values.ShowWhenNotLoaded;
}*/
}
@@ -0,0 +1,21 @@
using System.Collections.Immutable;
using System.Globalization;
namespace Barotrauma.LuaCs.Data;
public partial record ModConfigInfo : IModConfigInfo
{
public ImmutableArray<IStylesResourceInfo> StylesResourceInfos { get; init; }
}
public record StylesResourceInfo : IStylesResourceInfo
{
public Platform SupportedPlatforms { get; init; }
public Target SupportedTargets { get; init; }
public int LoadPriority { get; init; }
public ImmutableArray<string> FilePaths { get; init; }
public bool Optional { get; init; }
public ImmutableArray<CultureInfo> SupportedCultures { get; init; }
public string InternalName { get; init; }
public ImmutableArray<IPackageDependencyInfo> Dependencies { get; init; }
}
@@ -0,0 +1,5 @@
using Barotrauma.LuaCs.Configuration;
namespace Barotrauma.LuaCs.Data;
public partial interface IConfigInfo : IDisplayableData { }
@@ -0,0 +1,15 @@
using System.Collections.Immutable;
namespace Barotrauma.LuaCs.Data;
public partial interface IModConfigInfo : IStylesResourcesInfo { }
public interface IStylesResourceInfo : IResourceInfo, IResourceCultureInfo, ILoadableResourceInfo, IPackageDependenciesInfo { }
public interface IStylesResourcesInfo
{
/// <summary>
/// Collection of loadable styles data.
/// </summary>
ImmutableArray<IStylesResourceInfo> StylesResourceInfos { get; }
}
@@ -0,0 +1,6 @@
namespace Barotrauma.LuaCs.Data;
public interface IStylesInfo
{
}
@@ -0,0 +1,7 @@
namespace Barotrauma.LuaCs.Services;
public interface IClientLoggerService : IService
{
void AddToGUIUpdateList();
void ShowErrorOverlay(string message, float time = 5f, float duration = 1.5f);
}
@@ -0,0 +1,51 @@
namespace Barotrauma.LuaCs.Services;
// TODO: Rework interface to support resource infos.
/// <summary>
/// Loads XML Style assets from the given content package.
/// </summary>
public interface IStylesService : IService
{
/// <summary>
/// Tries to load the styles file for the given contentpackage and path into a new UIStylesProcessor instance.
/// </summary>
/// <param name="package"></param>
/// <param name="path"></param>
/// <returns></returns>
bool TryLoadStylesFile(ContentPackage package, ContentPath path);
/// <summary>
/// Unloads all styles assets and UIStyleProcessor instances.
/// </summary>
void UnloadAllStyles();
/// <summary>
/// Tries to the get the font asset by xml asset name, returns null on failure.
/// </summary>
/// <param name="fontName">XML Name of the asset.</param>
/// <returns>The asset or null if none are found.</returns>
GUIFont GetFont(string fontName);
/// <summary>
/// Tries to the get the sprite asset by xml asset name, returns null on failure.
/// </summary>
/// <param name="spriteName">XML Name of the asset.</param>
/// <returns>The asset or null if none are found.</returns>
GUISprite GetSprite(string spriteName);
/// <summary>
/// Tries to the get the sprite sheet asset by xml asset name, returns null on failure.
/// </summary>
/// <param name="spriteSheetName">XML Name of the asset.</param>
/// <returns>The asset or null if none are found.</returns>
GUISpriteSheet GetSpriteSheet(string spriteSheetName);
/// <summary>
/// Tries to the get the cursor asset by xml asset name, returns null on failure.
/// </summary>
/// <param name="cursorName">XML Name of the asset.</param>
/// <returns>The asset or null if none are found.</returns>
GUICursor GetCursor(string cursorName);
/// <summary>
/// Tries to the get the color asset by xml asset name, returns null on failure.
/// </summary>
/// <param name="colorName">XML Name of the asset.</param>
/// <returns>The asset or null if none are found.</returns>
GUIColor GetColor(string colorName);
}
@@ -0,0 +1,50 @@
using Microsoft.Xna.Framework;
namespace Barotrauma.LuaCs.Services;
public partial class LoggerService : ILoggerService, IClientLoggerService
{
private GUIFrame _overlayFrame;
private GUITextBlock _textBlock;
private double _showTimer = 0;
private void CreateOverlay(string message)
{
_overlayFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.03f), null), null, new Color(50, 50, 50, 100))
{
CanBeFocused = false
};
GUILayoutGroup layout =
new GUILayoutGroup(
new RectTransform(new Vector2(0.8f, 0.8f), _overlayFrame.RectTransform, Anchor.CenterLeft), false,
Anchor.Center);
_textBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0f), layout.RectTransform), message);
_overlayFrame.RectTransform.MinSize = new Point((int)(_textBlock.TextSize.X * 1.2), 0);
layout.Recalculate();
}
public void AddToGUIUpdateList()
{
if (_overlayFrame != null && Timing.TotalTime <= _showTimer)
{
_overlayFrame.AddToGUIUpdateList();
}
}
public void ShowErrorOverlay(string message, float time = 5f, float duration = 1.5f)
{
if (Timing.TotalTime <= _showTimer)
{
return;
}
CreateOverlay(message);
_overlayFrame.Flash(Color.Red, duration, true);
_showTimer = Timing.TotalTime + time;
}
}
@@ -0,0 +1,43 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using Barotrauma.LuaCs.Data;
using Barotrauma.LuaCs.Services.Processing;
namespace Barotrauma.LuaCs.Services;
public partial class PackageService : IStylesResourcesInfo
{
private readonly Lazy<IStylesService> _stylesService;
public PackageService(
Lazy<IXmlModConfigConverterService> converterService,
Lazy<ILegacyConfigService> legacyConfigService,
Lazy<ILuaScriptService> luaScriptService,
Lazy<ILocalizationService> localizationService,
Lazy<IPluginService> pluginService,
Lazy<IStylesService> stylesService,
Lazy<IConfigService> configService,
IPackageManagementService packageManagementService,
IStorageService storageService,
ILoggerService loggerService)
{
_modConfigConverterService = converterService;
_legacyConfigService = legacyConfigService;
_luaScriptService = luaScriptService;
_localizationService = localizationService;
_pluginService = pluginService;
_stylesService = stylesService;
_configService = configService;
_packageManagementService = packageManagementService;
_storageService = storageService;
_loggerService = loggerService;
}
public ImmutableArray<IStylesResourceInfo> StylesResourceInfos => ModConfigInfo?.StylesResourceInfos ?? ImmutableArray<IStylesResourceInfo>.Empty;
public void LoadStyles([NotNull]IStylesResourcesInfo stylesInfo)
{
throw new NotImplementedException();
}
}
@@ -0,0 +1,9 @@
using System.Xml.Linq;
using Barotrauma.LuaCs.Data;
namespace Barotrauma.LuaCs.Services.Processing;
#region XmlToResourceParsers
public interface IXmlStylesToResConverterService : IXmlResourceConverterService<IStylesResourceInfo> { }
#endregion
@@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.LuaCs.Services;
public class StylesService : IStylesService
{
private readonly Dictionary<string, UIStyleProcessor> _loadedProcessors = new();
private readonly IStorageService _storageService;
private readonly ILoggerService _loggerService;
public StylesService(IStorageService storageService, ILoggerService loggerService)
{
_storageService = storageService;
_loggerService = loggerService;
}
public bool TryLoadStylesFile(ContentPackage package, ContentPath path)
{
//check if file already in dict
if (_loadedProcessors.ContainsKey(path.FullPath))
{
return true;
}
//check if file exists
if (_storageService.FileExists(path.FullPath))
{
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 false;
}
public void UnloadAllStyles()
{
if (NoProcessorsLoaded)
return;
foreach (var processor in _loadedProcessors)
{
processor.Value.UnloadFile();
}
_loadedProcessors.Clear();
}
public GUIFont GetFont(string fontName)
{
if (NoProcessorsLoaded)
return null;
foreach (var processor in _loadedProcessors.Values)
{
if (processor.Fonts.TryGetValue(fontName, out var asset))
return asset;
}
return null;
}
public GUISprite GetSprite(string spriteName)
{
if (NoProcessorsLoaded)
return null;
foreach (var processor in _loadedProcessors.Values)
{
if (processor.Sprites.TryGetValue(spriteName, out var asset))
return asset;
}
return null;
}
public GUISpriteSheet GetSpriteSheet(string spriteSheetName)
{
if (NoProcessorsLoaded)
return null;
foreach (var processor in _loadedProcessors.Values)
{
if (processor.SpriteSheets.TryGetValue(spriteSheetName, out var asset))
return asset;
}
return null;
}
public GUICursor GetCursor(string cursorName)
{
if (NoProcessorsLoaded)
return null;
foreach (var processor in _loadedProcessors.Values)
{
if (processor.Cursors.TryGetValue(cursorName, out var asset))
return asset;
}
return null;
}
public GUIColor GetColor(string colorName)
{
if (NoProcessorsLoaded)
return null;
foreach (var processor in _loadedProcessors.Values)
{
if (processor.Colors.TryGetValue(colorName, out var asset))
return asset;
}
return null;
}
private bool NoProcessorsLoaded => _loadedProcessors.Count < 1;
public void Dispose()
{
UnloadAllStyles();
GC.SuppressFinalize(this);
}
public void Reset()
{
UnloadAllStyles();
}
}
@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma.LuaCs.Services;
public class UIStyleProcessor : HashlessFile
{
private readonly UIStyleFile _fake;
public readonly Dictionary<string, GUIFont> Fonts = new();
public readonly Dictionary<string, GUISprite> Sprites = new();
public readonly Dictionary<string, GUISpriteSheet> SpriteSheets = new();
public readonly Dictionary<string, GUICursor> Cursors = new();
public readonly Dictionary<string, GUIColor> Colors = new();
public UIStyleProcessor(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path)
{
_fake = new UIStyleFile(contentPackage, path);
}
public override void LoadFile()
{
var element = XMLExtensions.TryLoadXml(path: Path)?.Root?.FromPackage(ContentPackage);
if (element is null)
throw new InvalidDataException($"UIStyleProcessor: Failed to load UI style file: {Path}");
var styleElement = element.Name.LocalName.ToLowerInvariant() == "style" ? element : element.GetChildElement("style");
if (styleElement is null)
throw new InvalidDataException($"UIStyleProcessor: no 'style' XmlElement found in file: {Path}");
var childElements = styleElement.GetChildElements("Font");
if (childElements is not null)
AddToList<GUIFont, GUIFontPrefab>(Fonts, childElements, _fake);
childElements = styleElement.GetChildElements("Sprite");
if (childElements is not null)
AddToList<GUISprite, GUISpritePrefab>(Sprites, childElements, _fake);
childElements = styleElement.GetChildElements("Spritesheet");
if (childElements is not null)
AddToList<GUISpriteSheet, GUISpriteSheetPrefab>(SpriteSheets, childElements, _fake);
childElements = styleElement.GetChildElements("Cursor");
if (childElements is not null)
AddToList<GUICursor, GUICursorPrefab>(Cursors, childElements, _fake);
childElements = styleElement.GetChildElements("Color");
if (childElements is not null)
AddToList<GUIColor, GUIColorPrefab>(Colors, childElements, _fake);
void AddToList<T1, T2>(Dictionary<string, T1> dict, IEnumerable<ContentXElement> ele, UIStyleFile file) where T1 : GUISelector<T2> where T2 : GUIPrefab
{
foreach (ContentXElement prefabElement in ele)
{
string name = prefabElement.GetAttributeString("name", string.Empty);
if (name != string.Empty)
{
var prefab = (T2)Activator.CreateInstance(typeof(T2), new object[]{ prefabElement, file })!;
if (!dict.ContainsKey(name))
dict[name] = (T1)Activator.CreateInstance(typeof(T1), new object[] { name })!;
dict[name].Prefabs.Add(prefab, false);
}
}
}
}
public override void UnloadFile()
{
Fonts.Values.ForEach(p => p.Prefabs.RemoveByFile(_fake));
Sprites.Values.ForEach(p => p.Prefabs.RemoveByFile(_fake));
SpriteSheets.Values.ForEach(p => p.Prefabs.RemoveByFile(_fake));
Cursors.Values.ForEach(p => p.Prefabs.RemoveByFile(_fake));
Colors.Values.ForEach(p => p.Prefabs.RemoveByFile(_fake));
Fonts.Clear();
Sprites.Clear();
SpriteSheets.Clear();
Cursors.Clear();
Colors.Clear();
}
public override void Sort()
{
Fonts.Values.ForEach(p => p.Prefabs.Sort());
Sprites.Values.ForEach(p => p.Prefabs.Sort());
SpriteSheets.Values.ForEach(p => p.Prefabs.Sort());
Cursors.Values.ForEach(p => p.Prefabs.Sort());
Colors.Values.ForEach(p => p.Prefabs.Sort());
}
}