From 616d46bf5f509c5ae9d1e405bfe1419c490966c9 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 14 Feb 2026 14:01:53 +0100 Subject: [PATCH 01/41] report parsing errors of xml file list --- .../GameObjects/GameObjectTypeGameManager.cs | 43 ++++++++++++++++--- .../Xml/Parsers/XmlContainerContentParser.cs | 13 +++--- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 407d9c5..7ba43d9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -17,18 +17,49 @@ protected override async Task InitializeCoreAsync(CancellationToken token) var contentParser = new XmlContainerContentParser(ServiceProvider, ErrorReporter); - await Task.Run(() => contentParser.ParseEntriesFromFileListXml( - "DATA\\XML\\GAMEOBJECTFILES.XML", - GameRepository, - ".\\DATA\\XML", - NamedEntries, - VerifyFilePathLength), token); + contentParser.XmlParseError += OnParseError; + + try + { + await Task.Run(() => contentParser.ParseEntriesFromFileListXml( + "DATA\\XML\\GAMEOBJECTFILES.XML", + GameRepository, + ".\\DATA\\XML\\", + NamedEntries, + VerifyFilePathLength), token); + } + finally + { + contentParser.XmlParseError -= OnParseError; + } + } + + private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) + { + if (e.ErrorInXmlFileList) + { + e.Continue = false; + ErrorReporter.Report(new InitializationError + { + GameManager = ToString(), + Message = GetMessage(e) + }); + } + } + + private static string GetMessage(XmlContainerParserErrorEventArgs errorEventArgs) + { + if (errorEventArgs.HasException) + return $"Error while parsing XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; + return "Could not find GameObjectFiles.xml"; } private void VerifyFilePathLength(string filePath) { if (filePath.Length > PGConstants.MaxGameObjectDatabaseFileName) { + // Technically this is an assert in the engine, but in Release Mode, the game CTDs. + // Thus, we rank this as an initialization error. ErrorReporter.Report(new InitializationError { GameManager = ToString(), diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs index 00f4f61..63735d7 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs @@ -45,7 +45,7 @@ public void ParseEntriesFromFileListXml( _reporter?.Report(this, XmlParseErrorEventArgs.FromMissingFile(xmlFile)); Logger.LogWarning("Could not find XML file '{XmlFile}'", xmlFile); - var args = new XmlContainerParserErrorEventArgs(xmlFile, null, true) + var args = new XmlContainerParserErrorEventArgs(xmlFile, isXmlFileList: true) { // No reason to continue Continue = false @@ -65,7 +65,10 @@ public void ParseEntriesFromFileListXml( } catch (XmlException e) { - var args = new XmlContainerParserErrorEventArgs(xmlFile, e, true) + _reporter?.Report(this, + new XmlParseErrorEventArgs(new XmlLocationInfo(xmlFile, e.LineNumber), XmlParseErrorKind.Unknown, e.Message)); + + var args = new XmlContainerParserErrorEventArgs(xmlFile, e, isXmlFileList: true) { // No reason to continue Continue = false @@ -78,7 +81,7 @@ public void ParseEntriesFromFileListXml( var xmlFiles = container.Files.Select(x => FileSystem.Path.Combine(lookupPath, x)).ToList(); var parser = _fileParserFactory.CreateFileParser(_reporter); - + foreach (var file in xmlFiles) { if (onFileParseAction is not null) @@ -91,7 +94,7 @@ public void ParseEntriesFromFileListXml( _reporter?.Report(parser, XmlParseErrorEventArgs.FromMissingFile(file)); Logger.LogWarning("Could not find XML file '{File}'", file); - var args = new XmlContainerParserErrorEventArgs(file); + var args = new XmlContainerParserErrorEventArgs(file, isXmlFileList: false); XmlParseError?.Invoke(this, args); if (args.Continue) @@ -109,7 +112,7 @@ public void ParseEntriesFromFileListXml( { _reporter?.Report(parser, new XmlParseErrorEventArgs(new XmlLocationInfo(file, 0), XmlParseErrorKind.Unknown, e.Message)); - var args = new XmlContainerParserErrorEventArgs(file, e); + var args = new XmlContainerParserErrorEventArgs(file, e, isXmlFileList: false); XmlParseError?.Invoke(this, args); if (!args.Continue) From 4f46bcc9904d89e1125d3514a75600255a677f67 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 14 Feb 2026 14:20:32 +0100 Subject: [PATCH 02/41] rename types --- .../ErrorReporting/GameEngineErrorReporterWrapper.cs | 2 +- .../PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs | 2 +- .../Xml/Parsers/XmlContainerContentParser.cs | 4 ++-- .../PG.StarWarsGame.Files.XML/Data/XmlFileList.cs | 8 ++++++++ .../Data/XmlFileListContainer.cs | 8 -------- .../ErrorHandling/IXmlParserErrorReporter.cs | 2 +- .../ErrorHandling/PrimitiveXmlErrorReporter.cs | 2 +- .../ErrorHandling/XmlErrorEventHandler.cs | 2 +- .../ErrorHandling/XmlErrorReporter.cs | 4 ++-- .../Parsers/Base/IPetroglyphXmlElementParser.cs | 2 +- .../Parsers/Base/IPetroglyphXmlFileContainerParser.cs | 2 +- .../Parsers/Base/IPetroglyphXmlFileParser.cs | 2 +- ...PetroglyphXmlParser.cs => IPetroglyphXmlParserInfo.cs} | 2 +- .../Parsers/Base/PetroglyphXmlParserBase.cs | 2 +- .../Parsers/XmlFileListParser.cs | 7 ++++--- 15 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileListContainer.cs rename src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/{IPetroglyphXmlParser.cs => IPetroglyphXmlParserInfo.cs} (64%) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs index a636aba..adf715a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs @@ -33,7 +33,7 @@ public void Assert(EngineAssert assert) _errorReporter?.Assert(assert); } - public override void Report(IPetroglyphXmlParser parser, XmlParseErrorEventArgs error) + public override void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) { if (_errorReporter is null) return; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs index 83e6e9f..e6124ec 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs @@ -9,7 +9,7 @@ public sealed class XmlError { public required XmlLocationInfo FileLocation { get; init; } - public required IPetroglyphXmlParser Parser { get; init; } + public required IPetroglyphXmlParserInfo Parser { get; init; } public XElement? Element { get; init; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs index 63735d7..e640c53 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs @@ -14,7 +14,7 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; -internal sealed class XmlContainerContentParser : ServiceBase, IPetroglyphXmlParser +internal sealed class XmlContainerContentParser : ServiceBase, IPetroglyphXmlParserInfo { public event EventHandler? XmlParseError; @@ -54,7 +54,7 @@ public void ParseEntriesFromFileListXml( return; } - XmlFileListContainer? container; + XmlFileList? container; try { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs new file mode 100644 index 0000000..8553f33 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace PG.StarWarsGame.Files.XML.Data; + +public class XmlFileList(IReadOnlyList files) +{ + public IReadOnlyList Files { get; } = files; +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileListContainer.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileListContainer.cs deleted file mode 100644 index 31a16cc..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileListContainer.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; - -namespace PG.StarWarsGame.Files.XML.Data; - -public class XmlFileListContainer(IList files) -{ - public IList Files { get; } = files; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs index 6bb14c1..d1dceed 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs @@ -4,5 +4,5 @@ namespace PG.StarWarsGame.Files.XML.ErrorHandling; public interface IXmlParserErrorReporter { - void Report(IPetroglyphXmlParser parser, XmlParseErrorEventArgs error); + void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs index 39de0e6..fda7012 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs @@ -15,7 +15,7 @@ private PrimitiveXmlErrorReporter() { } - public void Report(IPetroglyphXmlParser parser, XmlParseErrorEventArgs error) + public void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) { XmlParseError?.Invoke(parser, error); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs index 69962e3..9e4821c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs @@ -2,4 +2,4 @@ namespace PG.StarWarsGame.Files.XML.ErrorHandling; -public delegate void XmlErrorEventHandler(IPetroglyphXmlParser parser, XmlParseErrorEventArgs error); \ No newline at end of file +public delegate void XmlErrorEventHandler(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error); \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs index 8234729..5369633 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs @@ -12,7 +12,7 @@ public XmlErrorReporter() PrimitiveXmlErrorReporter.Instance.XmlParseError += OnPrimitiveError; } - public virtual void Report(IPetroglyphXmlParser parser, XmlParseErrorEventArgs error) + public virtual void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) { XmlParseError?.Invoke(parser, error); } @@ -22,7 +22,7 @@ protected override void DisposeResources() PrimitiveXmlErrorReporter.Instance.XmlParseError -= OnPrimitiveError; } - private void OnPrimitiveError(IPetroglyphXmlParser parser, XmlParseErrorEventArgs error) + private void OnPrimitiveError(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) { Report(parser, error); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs index 14a8aa1..f5a6e95 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs @@ -2,7 +2,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public interface IPetroglyphXmlElementParser : IPetroglyphXmlParser where T : notnull +public interface IPetroglyphXmlElementParser : IPetroglyphXmlParserInfo where T : notnull { T Parse(XElement element); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs index cd21e00..34dbd77 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs @@ -4,7 +4,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public interface IPetroglyphXmlFileContainerParser : IPetroglyphXmlParser where T : notnull +public interface IPetroglyphXmlFileContainerParser : IPetroglyphXmlParserInfo where T : notnull { void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs index 5f9c4b4..31aa052 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs @@ -2,7 +2,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public interface IPetroglyphXmlFileParser : IPetroglyphXmlParser where T : notnull +public interface IPetroglyphXmlFileParser : IPetroglyphXmlParserInfo where T : notnull { T? ParseFile(Stream xmlStream); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlParserInfo.cs similarity index 64% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlParserInfo.cs index fdf5fd5..6ba0ebf 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlParserInfo.cs @@ -1,6 +1,6 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public interface IPetroglyphXmlParser +public interface IPetroglyphXmlParserInfo { string Name { get; } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs index 7395eb6..698ccb2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs @@ -4,7 +4,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public abstract class PetroglyphXmlParserBase : IPetroglyphXmlParser +public abstract class PetroglyphXmlParserBase : IPetroglyphXmlParserInfo { protected readonly IXmlParserErrorReporter? ErrorReporter; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs index 380ea3f..c148da2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Xml.Linq; using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; @@ -7,11 +8,11 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public sealed class XmlFileListParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : - PetroglyphXmlFileParser(serviceProvider, errorReporter) + PetroglyphXmlFileParser(serviceProvider, errorReporter) { protected override bool LoadLineInfo => false; - protected override XmlFileListContainer Parse(XElement element, string fileName) + protected override XmlFileList Parse(XElement element, string fileName) { var files = new List(); foreach (var child in element.Elements()) @@ -33,6 +34,6 @@ protected override XmlFileListContainer Parse(XElement element, string fileName) $"Tag '<{tagName}>' is not supported. Only '' is supported.")); } } - return new XmlFileListContainer(files); + return new XmlFileList(new ReadOnlyCollection(files)); } } \ No newline at end of file From c13b08a70281abf7caf674f05d8f52513e0901eb Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 11:32:02 +0100 Subject: [PATCH 03/41] start refactoring xml parsers --- src/ModVerify.CliApp/Program.cs | 2 +- .../Properties/launchSettings.json | 2 +- src/ModVerify/DefaultGameVerifiersProvider.cs | 9 +- .../Audio/Sfx/SfxEventGameManager.cs | 7 +- .../CommandBar/CommandBarGameManager.cs | 7 +- .../GameObjects/GameObjectTypeGameManager.cs | 71 +++- .../GuiDialogGameManager_Initialization.cs | 2 +- .../Xml/IPetroglyphXmlFileParserFactory.cs | 2 +- .../Xml/ParserNotFoundException.cs | 2 +- .../Parsers/Data/CommandBarComponentParser.cs | 35 +- .../Xml/Parsers/Data/GameObjectParser.cs | 28 +- .../Xml/Parsers/Data/SfxEventParser.cs | 37 +- .../Xml/Parsers/EngineXmlParser.cs | 321 ++++++++++++++++++ ...gs.cs => EngineXmlParserErrorEventArgs.cs} | 2 +- .../File/CommandBarComponentFileParser.cs | 31 -- .../{Data => File}/GameConstantsParser.cs | 2 +- .../Xml/Parsers/File/GameObjectFileParser.cs | 25 -- .../Xml/Parsers/File/SfxEventFileParser.cs | 32 -- .../Xml/Parsers/XmlContainerContentParser.cs | 123 ------- .../Xml/Parsers/XmlObjectParser.cs | 107 +++--- .../Xml/PetroglyphXmlParserFactory.cs | 22 +- .../Data/XmlFileList.cs | 2 + .../Base/IPetroglyphXmlFileContainerParser.cs | 4 +- .../Parsers/Base/IPetroglyphXmlFileParser.cs | 2 +- .../Base/PetroglyphXmlFileParserBase.cs | 12 +- .../IPetroglyphXmlNamedElementParser.cs | 10 + .../PetroglyphXmlFileContainerParser.cs | 33 +- .../Parsers/PetroglyphXmlFileParser.cs | 10 +- .../CommaSeparatedStringKeyValueListParser.cs | 5 +- .../PetroglyphPrimitiveXmlParser.cs | 7 +- .../Primitives/PetroglyphXmlBooleanParser.cs | 5 +- .../Primitives/PetroglyphXmlByteParser.cs | 7 +- .../Primitives/PetroglyphXmlFloatParser.cs | 10 +- .../Primitives/PetroglyphXmlIntegerParser.cs | 16 +- .../PetroglyphXmlLooseStringListParser.cs | 4 +- .../PetroglyphXmlMax100ByteParser.cs | 7 +- .../PetroglyphXmlRgbaColorParser.cs | 2 +- .../Primitives/PetroglyphXmlStringParser.cs | 7 +- .../PetroglyphXmlUnsignedIntegerParser.cs | 7 +- .../Primitives/PetroglyphXmlVector2FParser.cs | 5 +- .../XmlFileConstants.cs | 10 + 41 files changed, 616 insertions(+), 418 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{XmlContainerParserErrorEventArgs.cs => EngineXmlParserErrorEventArgs.cs} (82%) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/CommandBarComponentFileParser.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{Data => File}/GameConstantsParser.cs (90%) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameObjectFileParser.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/SfxEventFileParser.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/XmlFileConstants.cs diff --git a/src/ModVerify.CliApp/Program.cs b/src/ModVerify.CliApp/Program.cs index 68056a4..fd698cc 100644 --- a/src/ModVerify.CliApp/Program.cs +++ b/src/ModVerify.CliApp/Program.cs @@ -51,7 +51,7 @@ private static Task Main(string[] args) internal class Program : SelfUpdateableAppLifecycle { - private static readonly string EngineParserNamespace = typeof(XmlObjectParser<>).Namespace!; + private static readonly string EngineParserNamespace = typeof(EngineXmlParser).Namespace!; private static readonly string ParserNamespace = typeof(PetroglyphXmlFileParser<>).Namespace!; private static readonly string ModVerifyRootNameSpace = typeof(Program).Namespace!; private static readonly CompiledExpression PrintToConsoleExpression = SerilogExpression.Compile($"EventId.Id = {ModVerifyConstants.ConsoleEventIdValue}"); diff --git a/src/ModVerify.CliApp/Properties/launchSettings.json b/src/ModVerify.CliApp/Properties/launchSettings.json index 299ce46..128bcdd 100644 --- a/src/ModVerify.CliApp/Properties/launchSettings.json +++ b/src/ModVerify.CliApp/Properties/launchSettings.json @@ -10,7 +10,7 @@ }, "Verify (Automatic Target Selection)": { "commandName": "Project", - "commandLineArgs": "verify -o verifyResults --path \"C:\\Program Files (x86)\\Steam\\steamapps\\common\\Star Wars Empire at War\\corruption\"" + "commandLineArgs": "verify --offline -o verifyResults --path \"C:/Program Files (x86)/Steam/steamapps/common/Star Wars Empire at War/corruption/Mods/Test\"" }, "Create Baseline Interactive": { "commandName": "Project", diff --git a/src/ModVerify/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs index c9982b7..e4bb0cd 100644 --- a/src/ModVerify/DefaultGameVerifiersProvider.cs +++ b/src/ModVerify/DefaultGameVerifiersProvider.cs @@ -14,10 +14,11 @@ public IEnumerable GetVerifiers( GameVerifySettings settings, IServiceProvider serviceProvider) { - yield return new ReferencedModelsVerifier(database, settings, serviceProvider); - yield return new DuplicateNameFinder(database, settings, serviceProvider); - yield return new AudioFilesVerifier(database, settings, serviceProvider); - yield return new GuiDialogsVerifier(database, settings, serviceProvider); + yield break; + //yield return new ReferencedModelsVerifier(database, settings, serviceProvider); + //yield return new DuplicateNameFinder(database, settings, serviceProvider); + //yield return new AudioFilesVerifier(database, settings, serviceProvider); + //yield return new GuiDialogsVerifier(database, settings, serviceProvider); //yield return new CommandBarVerifier(database, settings, serviceProvider); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs index b037939..72fecbb 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs @@ -24,13 +24,12 @@ protected override async Task InitializeCoreAsync(CancellationToken token) Logger?.LogInformation("Parsing SFXEvents..."); - var contentParser = new XmlContainerContentParser(ServiceProvider, ErrorReporter); + var contentParser = new EngineXmlParser(GameRepository, ServiceProvider, ErrorReporter); contentParser.XmlParseError += OnParseError; try { await Task.Run(() => contentParser.ParseEntriesFromFileListXml( "DATA\\XML\\SFXEventFiles.XML", - GameRepository, "DATA\\XML", NamedEntries, VerifyFilePathLength), @@ -42,7 +41,7 @@ await Task.Run(() => contentParser.ParseEntriesFromFileListXml( } } - private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) + private void OnParseError(object sender, EngineXmlParserErrorEventArgs e) { if (e.ErrorInXmlFileList || e.HasException) { @@ -55,7 +54,7 @@ private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) } } - private static string GetMessage(XmlContainerParserErrorEventArgs errorEventArgs) + private static string GetMessage(EngineXmlParserErrorEventArgs errorEventArgs) { if (errorEventArgs.HasException) return $"Error while parsing SFXEvent XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 0b8687e..4af4a86 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -74,7 +74,7 @@ protected override async Task InitializeCoreAsync(CancellationToken token) { Logger?.LogInformation("Creating command bar components..."); - var contentParser = new XmlContainerContentParser(ServiceProvider, ErrorReporter); + var contentParser = new EngineXmlParser(GameRepository, ServiceProvider, ErrorReporter); contentParser.XmlParseError += OnParseError; var parsedCommandBarComponents = new FrugalValueListDictionary(); @@ -83,7 +83,6 @@ protected override async Task InitializeCoreAsync(CancellationToken token) { await Task.Run(() => contentParser.ParseEntriesFromFileListXml( "DATA\\XML\\CommandBarComponentFiles.XML", - GameRepository, ".\\DATA\\XML", parsedCommandBarComponents, VerifyFilePathLength), @@ -259,7 +258,7 @@ private void SetComponentGroup(IEnumerable components) } } - private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) + private void OnParseError(object sender, EngineXmlParserErrorEventArgs e) { if (e.ErrorInXmlFileList || e.HasException) { @@ -272,7 +271,7 @@ private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) } } - private static string GetMessage(XmlContainerParserErrorEventArgs errorEventArgs) + private static string GetMessage(EngineXmlParserErrorEventArgs errorEventArgs) { if (errorEventArgs.HasException) return $"Error while parsing CommandBar XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 7ba43d9..7650185 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -1,10 +1,11 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO.Repositories; using PG.StarWarsGame.Engine.Xml.Parsers; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace PG.StarWarsGame.Engine.GameObjects; @@ -14,31 +15,67 @@ internal class GameObjectTypeGameManager(GameRepository repository, GameEngineEr protected override async Task InitializeCoreAsync(CancellationToken token) { Logger?.LogInformation("Parsing GameObjects..."); + await Task.Run(ParseGameObjectDatabases, token); + } - var contentParser = new XmlContainerContentParser(ServiceProvider, ErrorReporter); - - contentParser.XmlParseError += OnParseError; + private void ParseGameObjectDatabases() + { + var parser = new EngineXmlParser(GameRepository, ServiceProvider, ErrorReporter); + parser.XmlParseError += OnParseError; try { - await Task.Run(() => contentParser.ParseEntriesFromFileListXml( - "DATA\\XML\\GAMEOBJECTFILES.XML", - GameRepository, - ".\\DATA\\XML\\", - NamedEntries, - VerifyFilePathLength), token); + var xmlFileList = parser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files + .Select(x => + { + var filePath = FileSystem.Path.Combine(@".\DATA\XML\", x); + VerifyFilePathLength(filePath); + return filePath; + }).ToList(); + + + //var gameObjectFileParser = new GameObjectFileParser(serviceProvider, errorReporter); + + var allLoaded = false; + for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++) + { + foreach (var gameObjectXmlFile in xmlFileList) + { + if (passNumber == 0) + { + //ParseSingleGameObjectFile(gameObjectXmlFile, parser, gameObjectFileParser); + } + else + { + } + } + + + + //GameObjectTypeClass::Static_Post_Load_Fixup(); + //SFXEventReferenceClass::Static_Post_Load_Fixup(); + //SpeechEventReferenceClass::Static_Post_Load_Fixup(); + //MusicEventReferenceClass::Static_Post_Load_Fixup(); + //FactionReferenceClass::Static_Post_Load_Fixup(); + //... + } } finally { - contentParser.XmlParseError -= OnParseError; + parser.XmlParseError -= OnParseError; } } - private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) + //private void ParseSingleGameObjectFile(string file, EngineXmlParser engineParser, GameObjectFileParser gameObjectFileParser) + //{ + // engineParser.ParseEntriesFromContainerFile(gameObjectFileParser, file, NamedEntries); + //} + + + private void OnParseError(object sender, EngineXmlParserErrorEventArgs e) { if (e.ErrorInXmlFileList) { - e.Continue = false; ErrorReporter.Report(new InitializationError { GameManager = ToString(), @@ -47,7 +84,7 @@ private void OnParseError(object sender, XmlContainerParserErrorEventArgs e) } } - private static string GetMessage(XmlContainerParserErrorEventArgs errorEventArgs) + private static string GetMessage(EngineXmlParserErrorEventArgs errorEventArgs) { if (errorEventArgs.HasException) return $"Error while parsing XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs index c3814ea..68fdabf 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs @@ -14,7 +14,7 @@ namespace PG.StarWarsGame.Engine.GuiDialog; -partial class GuiDialogGameManager +internal partial class GuiDialogGameManager { public const int MegaTextureMaxFilePathLength = 255; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs index 4532365..b3cf950 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs @@ -5,5 +5,5 @@ namespace PG.StarWarsGame.Engine.Xml; public interface IPetroglyphXmlFileParserFactory { - IPetroglyphXmlFileContainerParser CreateFileParser(IXmlParserErrorReporter? errorReporter) where T : notnull; + IPetroglyphXmlFileContainerParser CreateFileContainerParser(IXmlParserErrorReporter? errorReporter) where T : XmlObject; } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs index 19bc797..fd4fba3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs @@ -2,7 +2,7 @@ namespace PG.StarWarsGame.Engine.Xml; -public sealed class ParserNotFoundException : Exception +internal sealed class ParserNotFoundException : Exception { public override string Message { get; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs index 297b474..e8f2cd2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs @@ -1,33 +1,26 @@ -using System; -using System.Collections.ObjectModel; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; +using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.CommandBar.Xml; using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Collections.ObjectModel; +using System.Xml.Linq; +using Crc32 = PG.Commons.Hashing.Crc32; namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; -public sealed class CommandBarComponentParser( - IReadOnlyFrugalValueListDictionary parsedElements, - IServiceProvider serviceProvider, - IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParser(parsedElements, serviceProvider, errorReporter) +internal class CommandBarComponentParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) + : NamedXmlObjectParser(serviceProvider, errorReporter) { - public override CommandBarComponentData Parse(XElement element, out Crc32 crc32) + + protected override CommandBarComponentData CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) { - var name = GetXmlObjectName(element, out crc32, true); - var component = new CommandBarComponentData(name, crc32, XmlLocationInfo.FromElement(element)); - Parse(component, element, default); - ValidateValues(component, element); - component.CoerceValues(); - return component; + return new CommandBarComponentData(name, nameCrc, location); } - - protected override bool ParseTag(XElement tag, CommandBarComponentData componentData) + + protected override bool ParseTag(XElement tag, CommandBarComponentData componentData, in IReadOnlyFrugalValueListDictionary parseState) { switch (tag.Name.LocalName) { @@ -352,7 +345,7 @@ protected override bool ParseTag(XElement tag, CommandBarComponentData component } } - private void ValidateValues(CommandBarComponentData xmlData, XElement element) + protected override void ValidateValues(CommandBarComponentData xmlData, XElement element) { if (xmlData.Name.Length > PGConstants.MaxCommandBarComponentName) { @@ -360,6 +353,4 @@ private void ValidateValues(CommandBarComponentData xmlData, XElement element) $"CommandbarComponent name '{xmlData.Name}' is too long.")); } } - - public override CommandBarComponentData Parse(XElement element) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs index 5cac3e2..2b9126b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs @@ -1,11 +1,11 @@ -using System; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; +using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.GameObjects; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Xml.Linq; +using Crc32 = PG.Commons.Hashing.Crc32; namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; @@ -25,25 +25,17 @@ public static class GameObjectXmlTags public const string DamagedSmokeAssetName = "Damaged_Smoke_Asset_Name"; } -public sealed class GameObjectParser( - IReadOnlyFrugalValueListDictionary parsedElements, - IServiceProvider serviceProvider, - IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParser(parsedElements, serviceProvider, errorReporter) +internal class GameObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) + : NamedXmlObjectParser(serviceProvider, errorReporter) { - public override GameObject Parse(XElement element, out Crc32 crc32) + protected override GameObject CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) { - var name = GetXmlObjectName(element, out crc32, true); var type = GetTagName(element); var objectType = EstimateType(type); - var gameObject = new GameObject(type, name, crc32, objectType, XmlLocationInfo.FromElement(element)); - - Parse(gameObject, element, default); - - return gameObject; + return new GameObject(type, name, nameCrc, objectType, location); } - protected override bool ParseTag(XElement tag, GameObject xmlObject) + protected override bool ParseTag(XElement tag, GameObject xmlObject, in IReadOnlyFrugalValueListDictionary parseState) { switch (tag.Name.LocalName) { @@ -143,6 +135,4 @@ private static GameObjectType EstimateType(string tagName) _ => GameObjectType.Unknown }; } - - public override GameObject Parse(XElement element) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs index bc3439f..c59bc40 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs @@ -1,33 +1,28 @@ -using System; -using System.Collections.ObjectModel; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; +using AnakinRaW.CommonUtilities.Collections; +using Microsoft.Extensions.DependencyInjection; using PG.Commons.Hashing; using PG.StarWarsGame.Engine.Audio.Sfx; using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities; namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; -public sealed class SfxEventParser( - IReadOnlyFrugalValueListDictionary parsedElements, - IServiceProvider serviceProvider, - IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParser(parsedElements, serviceProvider, errorReporter) -{ - public override SfxEvent Parse(XElement element, out Crc32 crc32) +internal class SfxEventParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) + : NamedXmlObjectParser(serviceProvider, errorReporter) +{ + protected override SfxEvent CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) { - var name = GetXmlObjectName(element, out crc32, true); - var sfxEvent = new SfxEvent(name, crc32, XmlLocationInfo.FromElement(element)); - Parse(sfxEvent, element, default); - ValidateValues(sfxEvent, element); - sfxEvent.CoerceValues(); - return sfxEvent; + return new SfxEvent(name, nameCrc, location); } - private void ValidateValues(SfxEvent sfxEvent, XElement element) + protected override void ValidateValues(SfxEvent sfxEvent, XElement element) { if (sfxEvent.Name.Length > PGConstants.MaxSFXEventName) { @@ -72,7 +67,7 @@ private void ValidateValues(SfxEvent sfxEvent, XElement element) } } - protected override bool ParseTag(XElement tag, SfxEvent sfxEvent) + protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, in IReadOnlyFrugalValueListDictionary parsedEntries) { switch (tag.Name.LocalName) { @@ -86,7 +81,7 @@ protected override bool ParseTag(XElement tag, SfxEvent sfxEvent) { var presetName = PetroglyphXmlStringParser.Instance.Parse(tag); var presetNameCrc = HashingService.GetCrc32Upper(presetName.AsSpan(), PGConstants.DefaultPGEncoding); - if (presetNameCrc != default && ParsedElements.TryGetFirstValue(presetNameCrc, out var preset)) + if (presetNameCrc != default && parsedEntries.TryGetFirstValue(presetNameCrc, out var preset)) sfxEvent.ApplyPreset(preset); else { @@ -199,6 +194,4 @@ protected override bool ParseTag(XElement tag, SfxEvent sfxEvent) default: return false; } } - - public override SfxEvent Parse(XElement element) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs new file mode 100644 index 0000000..c93c773 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs @@ -0,0 +1,321 @@ +using AnakinRaW.CommonUtilities; +using AnakinRaW.CommonUtilities.Collections; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using PG.Commons.Hashing; +using PG.Commons.Services; +using PG.StarWarsGame.Engine.Audio.Sfx; +using PG.StarWarsGame.Engine.IO; +using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace PG.StarWarsGame.Engine.Xml.Parsers; + +public sealed class EngineXmlParser : ServiceBase, IPetroglyphXmlParserInfo +{ + public event EventHandler? XmlParseError; + + private readonly IGameRepository _gameRepository; + private readonly IXmlParserErrorReporter? _reporter; + private readonly IPetroglyphXmlFileParserFactory _fileParserFactory; + + public EngineXmlParser(IGameRepository gameRepository, IServiceProvider serviceProvider, IXmlParserErrorReporter? reporter) + : base(serviceProvider) + { + _gameRepository = gameRepository; + _reporter = reporter; + _fileParserFactory = serviceProvider.GetRequiredService(); + Name = GetType().FullName!; + } + + public string Name { get; } + + public XmlFileList ParseFileList(string xmlFile) + { + Logger.LogDebug("Parsing container data '{XmlFile}'", xmlFile); + + using var containerStream = _gameRepository.TryOpenFile(xmlFile); + if (containerStream == null) + { + _reporter?.Report(this, XmlParseErrorEventArgs.FromMissingFile(xmlFile)); + Logger.LogWarning("Could not find XML file '{XmlFile}'", xmlFile); + + var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: true); + XmlParseError?.Invoke(this, args); + return XmlFileList.Empty; + } + + XmlFileList? container; + var containerParser = new XmlFileListParser(Services, _reporter); + + try + { + container = containerParser.ParseFile(containerStream); + if (container is null) + throw new XmlException($"Unable to parse XML container file '{xmlFile}'."); + } + catch (XmlException e) + { + _reporter?.Report(containerParser, new XmlParseErrorEventArgs(new XmlLocationInfo(xmlFile, e.LineNumber), + XmlParseErrorKind.Unknown, e.Message)); + var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: true); + XmlParseError?.Invoke(this, args); + return XmlFileList.Empty; + } + + return container; + } + + public void ParseEntriesFromFileListXml( + string xmlFile, + string lookupPath, + FrugalValueListDictionary entries, + Action? onFileParseAction = null) where T : XmlObject + { + var container = ParseFileList(xmlFile); + + var xmlFiles = container.Files.Select(x => FileSystem.Path.Combine(lookupPath, x)).ToList(); + + var parser = _fileParserFactory.CreateFileContainerParser(_reporter); + + foreach (var file in xmlFiles) + { + onFileParseAction?.Invoke(file); + if (!ParseEntriesFromContainerFile(file, parser, entries)) + return; + } + } + + public bool ParseEntriesFromContainerFile( + string xmlFile, + IPetroglyphXmlFileContainerParser parser, + IFrugalValueListDictionary entries) where T : notnull + { + using var fileStream = _gameRepository.TryOpenFile(xmlFile); + + if (fileStream is null) + { + _reporter?.Report(this, XmlParseErrorEventArgs.FromMissingFile(xmlFile)); + Logger.LogWarning("Could not find XML file '{File}'", xmlFile); + + var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: false); + XmlParseError?.Invoke(this, args); + return args.Continue; + } + + Logger.LogDebug("Parsing File '{File}'", xmlFile); + + try + { + parser.ParseFile(fileStream, entries); + return true; + } + catch (XmlException e) + { + _reporter?.Report(parser, + new XmlParseErrorEventArgs(new XmlLocationInfo(xmlFile, 0), XmlParseErrorKind.Unknown, e.Message)); + + var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: false); + XmlParseError?.Invoke(this, args); + return args.Continue; + } + } +} + + +internal partial class XmlTagMapperDatabase +{ + private readonly IServiceProvider _serviceProvider; + + public XmlTagMapperDatabase(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + SfxEventMap = CreateSfxEventMap(); + } +} + +internal partial class XmlTagMapperDatabase +{ + private XmlTagMapper CreateSfxEventMap() + { + return new SfxEventXmlTagMapper(_serviceProvider); + } + + private sealed class SfxEventXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) + { + protected override void BuildMappings() + { + AddMapping( + "OverlapTestName", + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.OverlapTestName = val); + } + } +} + + +internal partial class XmlTagMapperDatabase +{ + public XmlTagMapper SfxEventMap { get; } +} + +internal abstract class XmlTagMapper where TClass : notnull +{ + private const int MaxTagLength = 256; + + private delegate void ParserValueAction(TClass target, XElement element); + + private readonly Dictionary _tagMappings = new(); + private readonly ICrc32HashingService _crcService; + + protected XmlTagMapper(IServiceProvider serviceProvider) + { + if (serviceProvider == null) + throw new ArgumentNullException(nameof(serviceProvider)); + _crcService = serviceProvider.GetRequiredService(); + + // ReSharper disable once VirtualMemberCallInConstructor + BuildMappings(); + } + + protected abstract void BuildMappings(); + + protected void AddMapping(string tagName, Func parser, Action setter) + { + ThrowHelper.ThrowIfNullOrEmpty(tagName); + if (tagName.Length >= MaxTagLength) + throw new ArgumentOutOfRangeException( + $"Tag name '{tagName}' exceeds maximum length of {MaxTagLength} characters", nameof(tagName)); + + if (parser == null) + throw new ArgumentNullException(nameof(parser)); + if (setter == null) + throw new ArgumentNullException(nameof(setter)); + + var crc = GetCrc32(tagName); + + _tagMappings[crc] = (target, element) => + { + var value = parser(element); + setter(target, value); + }; + } + + public bool TryParseEntry(XElement element, TClass target) + { + var tagName = element.Name.LocalName; + if (tagName.Length >= MaxTagLength) + return false; + + var crc = GetCrc32(tagName); + + if (!_tagMappings.TryGetValue(crc, out var mapping)) + return false; + + mapping(target, element); + return true; + } + + private Crc32 GetCrc32(string tagName) + { + return _crcService.GetCrc32Upper(tagName, PGConstants.DefaultPGEncoding); + } +} + +enum XmlDataType +{ + DB_DATA_TYPE_BOOL = 0x0, + DB_DATA_TYPE_DWORD = 0x1, + DB_DATA_TYPE_UNSIGNED_CHAR = 0x2, + DB_DATA_TYPE_SIGNED_CHAR = 0x3, + DB_DATA_TYPE_UNSIGNED_CHAR_PERCENT = 0x4, + DB_DATA_TYPE_UNSIGNED_INT = 0x5, + DB_DATA_TYPE_SIGNED_INT = 0x6, + DB_DATA_TYPE_UNSIGNED_INT_PERCENT = 0x7, + DB_DATA_TYPE_FLOAT = 0x8, + DB_DATA_TYPE_UNIT_FLOAT = 0x9, + DB_DATA_TYPE_DOUBLE = 0xa, + DB_DATA_TYPE_UNIT_DOUBLE = 0xb, + DB_DATA_TYPE_SIGNED_INT_HEX = 0xc, + DB_DATA_TYPE_DWORD_HEX = 0xd, + DB_DATA_TYPE_CONVERSION = 0xe, + DB_DATA_TYPE_VECTOR2 = 0xf, + DB_DATA_TYPE_VECTOR3 = 0x10, + DB_DATA_TYPE_VECTOR4 = 0x11, + DB_DATA_TYPE_DYN_VECTOR_INT = 0x12, + DB_DATA_TYPE_DYN_VECTOR_FLOAT = 0x13, + DB_DATA_TYPE_DYN_VECTOR_VECTOR3 = 0x14, + DB_DATA_TYPE_DYN_VECTOR_VECTOR2 = 0x15, + DB_DATA_TYPE_RGBA = 0x16, + DB_DATA_TYPE_STL_STRING = 0x17, + DB_DATA_TYPE_STL_LIST_STL_STRINGS = 0x18, + DB_DATA_TYPE_STL_VECTOR_DWORDS = 0x19, + DB_DATA_TYPE_STL_VECTOR_DWORDS_HEX = 0x1a, + DB_DATA_TYPE_STL_VECTOR_STL_STRINGS = 0x1b, + DB_DATA_TYPE_STL_STRING_UPPER = 0x1c, + DB_DATA_TYPE_OBJECT_REFERENCE = 0x1d, + DB_DATA_TYPE_MULTI_OBJECT_REFERENCE = 0x1e, + DB_DATA_TYPE_SFX_EVENT = 0x1f, + DB_DATA_TYPE_SPEECH_EVENT = 0x20, + DB_DATA_TYPE_MUSIC_EVENT = 0x21, + DB_DATA_TYPE_SFXEVENT_OVERRIDE_LIST_ENTRY = 0x22, + DB_DATA_TYPE_WEATHER_SFXEVENT_LOOP_LIST_ENTRY = 0x23, + DB_DATA_TYPE_WEATHER_SFXEVENT_INTERMITTENT_LIST_ENTRY = 0x24, + DB_DATA_TYPE_WEATHER_SFX_EVENT_PAIR_ARRAY_ENTRY = 0x25, + DB_DATA_TYPE_AMBIENT_SFXEVENT_INTERMITTENT_LIST_ENTRY = 0x26, + DB_DATA_TYPE_DYN_VECTOR_SFX_EVENT_ENTRY = 0x27, + DB_DATA_TYPE_TRIPLE_OBJ_TYPE_AND_SPEECH_EVENT_ENTRY = 0x28, + DB_DATA_TYPE_DYN_VECTOR_FACTION_AND_MUSIC_EVENT_PAIR_ENTRY = 0x29, + DB_DATA_TYPE_DYN_VECTOR_STL_STRINGS = 0x2a, + DB_DATA_TYPE_FACTION_DATA_OVERRIDE_UINT = 0x2b, + DB_DATA_TYPE_FACTION_DATA_OVERRIDE_FLOAT = 0x2c, + DB_DATA_TYPE_FACTION_DATA_OVERRIDE_NAMEREF = 0x2d, + DB_DATA_TYPE_QUADRATIC = 0x2e, + DB_DATA_TYPE_SPLINE = 0x2f, + DB_DATA_TYPE_LINEAR = 0x30, + DB_DATA_TYPE_PARABOLIC = 0x31, + DB_DATA_TYPE_SHIPCLASS = 0x32, + DB_DATA_TYPE_SCRIPT_VARIABLE = 0x33, + DB_DATA_TYPE_CONVERSION_STRING_PAIR_VECTOR = 0x34, + DB_DATA_TYPE_CONVERSION_OBJECT_REF_VECTOR = 0x35, + DB_DATA_TYPE_STL_VECTOR_OBJECT_REFERENCE_STRING_PAIR = 0x36, + DB_DATA_TYPE_STARTING_FORCE_DEFINITION = 0x37, + DB_DATA_TYPE_STL_VECTOR_ABILITIES = 0x38, + DB_DATA_TYPE_STL_VECTOR_ABILITIES_DATA = 0x39, + DB_DATA_TYPE_STL_VECTOR_ACTIONS = 0x3a, + DB_DATA_TYPE_STL_HASHMAP_DAMAGE_TO_DEATH_CLONE = 0x3b, + DB_DATA_TYPE_STL_VECTOR_STRING_INT_PAIR = 0x3c, + DB_DATA_TYPE_LIST_GAME_OBJECT_CATEGORY_FLOAT_PAIR = 0x3d, + DB_DATA_TYPE_DAMAGE_TO_ARMOR_MOD_ENTRY = 0x3e, + DB_DATA_QUOTED_STRING_DYN_VECTOR_ENTRY = 0x3f, + DB_DATA_TYPE_LANGUAGE_STL_STRING_ARRAY_ENTRY = 0x40, + DB_DATA_TYPE_HARD_POINT_TYPE_ARRAY_OF_DYN_VECTOR_STL_STRINGS = 0x41, + DB_DATA_TYPE_HARD_POINT_TYPE_ARRAY_OF_SFXEVENTS = 0x42, + DB_DATA_TYPE_FACTION = 0x43, + DB_DATA_TYPE_WEIGHTED_TYPE_LIST = 0x44, + DB_DATA_TYPE_STL_VECTOR_CONVERSION = 0x45, + DB_DATA_TYPE_STL_VECTOR_OBJECT_REFERENCE_INT_PAIR = 0x46, + DB_DATA_TYPE_DISCRETE_DISTRIBUTION_NAME_REFERENCE = 0x47, + DB_DATA_TYPE_STL_HASHMAP_CONVERSION_TO_FLOAT = 0x48, + DB_DATA_TYPE_UNIT_ABILITY = 0x49, + DB_TYPE_PROJECTILE_CATEGORY = 0x4a, + DB_DATA_TYPE_RENDER_MODE = 0x4b, + DB_DATA_TYPE_NON_HERO_ABILITIES_SFX_EVENT_PAIR = 0x4c, + DB_DATA_TYPE_UNIT_MODE_MULTIPLIER_MOD = 0x4d, + DB_DATA_TYPE_UNIT_MODE_FLAG_MOD = 0x4e, + DB_DATA_TYPE_STRING_INT_PAIR = 0x4f, + DB_DATA_TYPE_BIT_BOOL = 0x50, + DB_DATA_TYPE_STL_VECTOR_PROJECTILE_CATEGORIES = 0x51, + DB_DATA_TYPE_COMBAT_MOD = 0x52, + DB_DATA_TYPE_MULTI_OBJECT_REFERENCE_WITH_OR = 0x53, + DB_DATA_TYPE_CONVERSION_PTR = 0x54, + DB_DATA_TYPE_CONVERSION_OBJECT_REF_VECTOR_PTR = 0x55, + DB_DATA_TYPE_CONVERSION_64 = 0x56 +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerParserErrorEventArgs.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParserErrorEventArgs.cs similarity index 82% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerParserErrorEventArgs.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParserErrorEventArgs.cs index 87ccce1..d8ff77b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerParserErrorEventArgs.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParserErrorEventArgs.cs @@ -3,7 +3,7 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; -internal class XmlContainerParserErrorEventArgs(string file, XmlException? exception = null, bool isXmlFileList = false) +public class EngineXmlParserErrorEventArgs(string file, XmlException? exception = null, bool isXmlFileList = false) { public bool Continue { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/CommandBarComponentFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/CommandBarComponentFileParser.cs deleted file mode 100644 index 763d244..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/CommandBarComponentFileParser.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; -using PG.StarWarsGame.Engine.CommandBar.Xml; -using PG.StarWarsGame.Engine.Xml.Parsers.Data; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.Xml.Parsers.File; - -internal class CommandBarComponentFileParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : PetroglyphXmlFileContainerParser(serviceProvider, errorReporter) -{ - protected override void Parse(XElement element, IFrugalValueListDictionary parsedElements, string fileName) - { - var parser = new CommandBarComponentParser(parsedElements, ServiceProvider, ErrorReporter); - - if (!element.HasElements) - { - OnParseError(XmlParseErrorEventArgs.FromEmptyRoot(element)); - return; - } - - foreach (var xElement in element.Elements()) - { - var commandBarComponent = parser.Parse(xElement, out var nameCrc); - parsedElements.Add(nameCrc, commandBarComponent); - } - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameConstantsParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameConstantsParser.cs similarity index 90% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameConstantsParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameConstantsParser.cs index 64de5ec..8f2806f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameConstantsParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameConstantsParser.cs @@ -4,7 +4,7 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; +namespace PG.StarWarsGame.Engine.Xml.Parsers.File; internal class GameConstantsParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : PetroglyphXmlFileParser(serviceProvider, errorReporter) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameObjectFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameObjectFileParser.cs deleted file mode 100644 index ffeafff..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameObjectFileParser.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; -using PG.StarWarsGame.Engine.GameObjects; -using PG.StarWarsGame.Engine.Xml.Parsers.Data; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.Xml.Parsers.File; - -internal class GameObjectFileParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : PetroglyphXmlFileContainerParser(serviceProvider, errorReporter) -{ - protected override void Parse(XElement element, IFrugalValueListDictionary parsedElements, string fileName) - { - var parser = new GameObjectParser(parsedElements, ServiceProvider, ErrorReporter); - - foreach (var xElement in element.Elements()) - { - var gameObject = parser.Parse(xElement, out var nameCrc); - parsedElements.Add(nameCrc, gameObject); - } - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/SfxEventFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/SfxEventFileParser.cs deleted file mode 100644 index 841d805..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/SfxEventFileParser.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; -using PG.StarWarsGame.Engine.Audio.Sfx; -using PG.StarWarsGame.Engine.Xml.Parsers.Data; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.Xml.Parsers.File; - -internal class SfxEventFileParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : PetroglyphXmlFileContainerParser(serviceProvider, errorReporter) -{ - protected override void Parse(XElement element, IFrugalValueListDictionary parsedElements, string fileName) - { - var parser = new SfxEventParser(parsedElements, ServiceProvider, ErrorReporter); - - if (!element.HasElements) - { - OnParseError(XmlParseErrorEventArgs.FromEmptyRoot(element)); - return; - } - - foreach (var xElement in element.Elements()) - { - var sfxEvent = parser.Parse(xElement, out var nameCrc); - parsedElements.Add(nameCrc, sfxEvent); - } - - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs deleted file mode 100644 index e640c53..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlContainerContentParser.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Linq; -using System.Xml; -using AnakinRaW.CommonUtilities.Collections; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using PG.Commons.Hashing; -using PG.Commons.Services; -using PG.StarWarsGame.Engine.IO; -using PG.StarWarsGame.Files.XML; -using PG.StarWarsGame.Files.XML.Data; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.Xml.Parsers; - -internal sealed class XmlContainerContentParser : ServiceBase, IPetroglyphXmlParserInfo -{ - public event EventHandler? XmlParseError; - - private readonly IXmlParserErrorReporter? _reporter; - private readonly IPetroglyphXmlFileParserFactory _fileParserFactory; - - public XmlContainerContentParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? reporter) : base(serviceProvider) - { - _reporter = reporter; - _fileParserFactory = serviceProvider.GetRequiredService(); - Name = GetType().FullName!; - } - - public string Name { get; } - - public void ParseEntriesFromFileListXml( - string xmlFile, - IGameRepository gameRepository, - string lookupPath, - FrugalValueListDictionary entries, - Action? onFileParseAction = null) where T : notnull - { - Logger.LogDebug("Parsing container data '{XmlFile}'", xmlFile); - - using var containerStream = gameRepository.TryOpenFile(xmlFile); - if (containerStream == null) - { - _reporter?.Report(this, XmlParseErrorEventArgs.FromMissingFile(xmlFile)); - Logger.LogWarning("Could not find XML file '{XmlFile}'", xmlFile); - - var args = new XmlContainerParserErrorEventArgs(xmlFile, isXmlFileList: true) - { - // No reason to continue - Continue = false - }; - XmlParseError?.Invoke(this, args); - return; - } - - XmlFileList? container; - - try - { - var containerParser = new XmlFileListParser(Services, _reporter); - container = containerParser.ParseFile(containerStream); - if (container is null) - throw new XmlException($"Unable to parse XML container file '{xmlFile}'."); - } - catch (XmlException e) - { - _reporter?.Report(this, - new XmlParseErrorEventArgs(new XmlLocationInfo(xmlFile, e.LineNumber), XmlParseErrorKind.Unknown, e.Message)); - - var args = new XmlContainerParserErrorEventArgs(xmlFile, e, isXmlFileList: true) - { - // No reason to continue - Continue = false - }; - XmlParseError?.Invoke(this, args); - return; - } - - - var xmlFiles = container.Files.Select(x => FileSystem.Path.Combine(lookupPath, x)).ToList(); - - var parser = _fileParserFactory.CreateFileParser(_reporter); - - foreach (var file in xmlFiles) - { - if (onFileParseAction is not null) - onFileParseAction(file); - - using var fileStream = gameRepository.TryOpenFile(file); - - if (fileStream is null) - { - _reporter?.Report(parser, XmlParseErrorEventArgs.FromMissingFile(file)); - Logger.LogWarning("Could not find XML file '{File}'", file); - - var args = new XmlContainerParserErrorEventArgs(file, isXmlFileList: false); - XmlParseError?.Invoke(this, args); - - if (args.Continue) - continue; - return; - } - - Logger.LogDebug("Parsing File '{File}'", file); - - try - { - parser.ParseFile(fileStream, entries); - } - catch (XmlException e) - { - _reporter?.Report(parser, new XmlParseErrorEventArgs(new XmlLocationInfo(file, 0), XmlParseErrorKind.Unknown, e.Message)); - - var args = new XmlContainerParserErrorEventArgs(file, e, isXmlFileList: false); - XmlParseError?.Invoke(this, args); - - if (!args.Continue) - return; - } - } - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs index 1565e9e..1e3ea3a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs @@ -1,51 +1,24 @@ -using System; +using AnakinRaW.CommonUtilities.Collections; +using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Text; using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; using Microsoft.Extensions.DependencyInjection; using PG.Commons.Hashing; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; +using Crc32 = PG.Commons.Hashing.Crc32; namespace PG.StarWarsGame.Engine.Xml.Parsers; -public abstract class XmlObjectParser( - IReadOnlyFrugalValueListDictionary parsedElements, - IServiceProvider serviceProvider, - IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParser(parsedElements, serviceProvider, errorReporter) where TObject : XmlObject +internal abstract class XmlObjectParserBase(IXmlParserErrorReporter? errorReporter) + : PetroglyphXmlParserBase(errorReporter) + where TObject : XmlObject { - protected void Parse(TObject xmlObject, XElement element) - { - Parse(xmlObject, element, EmptyParseState.Instance); - } - - protected sealed override bool ParseTag(XElement tag, TObject xmlObject, in EmptyParseState parseState) + protected virtual void ValidateValues(TObject namedXmlObject, XElement element) { - return ParseTag(tag, xmlObject); } - protected abstract bool ParseTag(XElement tag, TObject xmlObject); -} - -public readonly struct EmptyParseState -{ - public static readonly EmptyParseState Instance = new(); -} - - -public abstract class XmlObjectParser( - IReadOnlyFrugalValueListDictionary parsedElements, - IServiceProvider serviceProvider, - IXmlParserErrorReporter? errorReporter = null) - : PetroglyphXmlElementParser(errorReporter) where TObject : XmlObject -{ - protected IReadOnlyFrugalValueListDictionary ParsedElements { get; } = - parsedElements ?? throw new ArgumentNullException(nameof(parsedElements)); - - protected ICrc32HashingService HashingService { get; } = serviceProvider.GetRequiredService(); - - public abstract TObject Parse(XElement element, out Crc32 crc32); - protected void Parse(TObject xmlObject, XElement element, in TParseState state) { foreach (var tag in element.Elements()) @@ -54,26 +27,74 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) { OnParseError(new XmlParseErrorEventArgs(tag, XmlParseErrorKind.UnknownNode, $"The node '{tag.Name}' is not supported.")); - break; } } } protected abstract bool ParseTag(XElement tag, TObject xmlObject, in TParseState parseState); +} + - protected string GetXmlObjectName(XElement element, out Crc32 crc32, bool uppercaseName) +internal abstract class NamedXmlObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter) + : XmlObjectParserBase>(errorReporter), + IPetroglyphXmlNamedElementParser + where TObject : NamedXmlObject +{ + protected readonly ICrc32HashingService HashingService = serviceProvider.GetRequiredService(); + + public TObject Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) + { + var name = GetXmlObjectName(element, true, out nameCrc); + var namedXmlObject = CreateXmlObject(name, nameCrc, element, XmlLocationInfo.FromElement(element)); + Parse(namedXmlObject, element, parsedEntries); + ValidateValues(namedXmlObject, element); + namedXmlObject.CoerceValues(); + return namedXmlObject; + } + + protected abstract TObject CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location); + + protected string GetXmlObjectName(XElement element, bool uppercaseName, out Crc32 crc32) { GetNameAttributeValue(element, out var name); crc32 = uppercaseName - ? HashingService.GetCrc32Upper(name.AsSpan(), PGConstants.DefaultPGEncoding) - : HashingService.GetCrc32(name.AsSpan(), PGConstants.DefaultPGEncoding); + ? HashingService.GetCrc32Upper(name.AsSpan(), Encoding.ASCII) + : HashingService.GetCrc32(name.AsSpan(), Encoding.ASCII); if (crc32 == default) { OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Name for XmlObject cannot be empty.")); + "Name for XmlObject cannot be empty.")); } return name; } +} + +internal abstract class XmlObjectParser(IXmlParserErrorReporter? errorReporter = null) + : XmlObjectParserBase(errorReporter), IPetroglyphXmlElementParser + where TObject : XmlObject +{ + public TObject Parse(XElement element) + { + var xmlObject = CreateXmlObject(XmlLocationInfo.FromElement(element)); + Parse(xmlObject, element, EmptyParseState.Instance); + ValidateValues(xmlObject, element); + xmlObject.CoerceValues(); + return xmlObject; + } + + protected abstract TObject CreateXmlObject(XmlLocationInfo location); + + protected sealed override bool ParseTag(XElement tag, TObject xmlObject, in EmptyParseState parseState) + { + return ParseTag(tag, xmlObject); + } + + protected abstract bool ParseTag(XElement tag, TObject xmlObject); +} + +internal readonly struct EmptyParseState +{ + public static readonly EmptyParseState Instance = new(); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs index 550f459..0817892 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs @@ -1,27 +1,33 @@ -using System; -using PG.StarWarsGame.Engine.Audio.Sfx; +using PG.StarWarsGame.Engine.Audio.Sfx; using PG.StarWarsGame.Engine.CommandBar.Xml; using PG.StarWarsGame.Engine.GameObjects; -using PG.StarWarsGame.Engine.Xml.Parsers.File; +using PG.StarWarsGame.Engine.Xml.Parsers.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; namespace PG.StarWarsGame.Engine.Xml; internal sealed class PetroglyphXmlFileParserFactory(IServiceProvider serviceProvider) : IPetroglyphXmlFileParserFactory { - public IPetroglyphXmlFileContainerParser CreateFileParser(IXmlParserErrorReporter? errorReporter) where T : notnull + public IPetroglyphXmlFileContainerParser CreateFileContainerParser(IXmlParserErrorReporter? errorReporter) where T : XmlObject { if (typeof(T) == typeof(SfxEvent)) - return (IPetroglyphXmlFileContainerParser) new SfxEventFileParser(serviceProvider, errorReporter); + return new PetroglyphXmlFileContainerParser( + serviceProvider, (IPetroglyphXmlNamedElementParser)new SfxEventParser(serviceProvider, errorReporter), + errorReporter); if (typeof(T) == typeof(CommandBarComponentData)) - return (IPetroglyphXmlFileContainerParser)new CommandBarComponentFileParser(serviceProvider, errorReporter); + return new PetroglyphXmlFileContainerParser( + serviceProvider, (IPetroglyphXmlNamedElementParser)new CommandBarComponentParser(serviceProvider, errorReporter), + errorReporter); if (typeof(T) == typeof(GameObject)) - return (IPetroglyphXmlFileContainerParser)new GameObjectFileParser(serviceProvider, errorReporter); + return new PetroglyphXmlFileContainerParser( + serviceProvider, (IPetroglyphXmlNamedElementParser)new GameObjectParser(serviceProvider, errorReporter), + errorReporter); - throw new NotImplementedException($"Unable to get parser for type {typeof(T)}"); + throw new ParserNotFoundException(typeof(T)); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs index 8553f33..9ea4b34 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs @@ -4,5 +4,7 @@ namespace PG.StarWarsGame.Files.XML.Data; public class XmlFileList(IReadOnlyList files) { + public static readonly XmlFileList Empty = new([]); + public IReadOnlyList Files { get; } = files; } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs index 34dbd77..690bb0c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs @@ -4,7 +4,9 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public interface IPetroglyphXmlFileContainerParser : IPetroglyphXmlParserInfo where T : notnull +public interface IPetroglyphXmlFileContainerParser : IPetroglyphXmlParserInfo where T : notnull { + IPetroglyphXmlNamedElementParser ElementParser { get; } + void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs index 31aa052..51850de 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs @@ -4,5 +4,5 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public interface IPetroglyphXmlFileParser : IPetroglyphXmlParserInfo where T : notnull { - T? ParseFile(Stream xmlStream); + T ParseFile(Stream xmlStream); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs index 6ffba48..bf8de55 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs @@ -23,7 +23,7 @@ public abstract class PetroglyphXmlFileParserBase(IServiceProvider serviceProvid protected virtual bool LoadLineInfo => true; - protected XElement? GetRootElement(Stream xmlStream, out string fileName) + protected XElement GetRootElement(Stream xmlStream, out string fileName) { fileName = GetStrippedFileName(xmlStream.GetFilePath()); @@ -32,11 +32,13 @@ public abstract class PetroglyphXmlFileParserBase(IServiceProvider serviceProvid SkipLeadingWhiteSpace(fileName, xmlStream); - var xmlReader = XmlReader.Create(xmlStream, new XmlReaderSettings + var asciiStreamReader = new StreamReader(xmlStream, XmlFileConstants.XmlEncoding, false, 1024, leaveOpen: true); + using var xmlReader = XmlReader.Create(asciiStreamReader, new XmlReaderSettings { IgnoreWhitespace = true, IgnoreComments = true, - IgnoreProcessingInstructions = true + IgnoreProcessingInstructions = true, + CloseInput = true }, fileName); var options = LoadOptions.SetBaseUri; @@ -44,7 +46,7 @@ public abstract class PetroglyphXmlFileParserBase(IServiceProvider serviceProvid options |= LoadOptions.SetLineInfo; var doc = XDocument.Load(xmlReader, options); - return doc.Root; + return doc.Root ?? throw new XmlException("No root node found."); } private string GetStrippedFileName(string filePath) @@ -63,7 +65,7 @@ private string GetStrippedFileName(string filePath) private void SkipLeadingWhiteSpace(string fileName, Stream stream) { - using var r = new StreamReader(stream, Encoding.ASCII, false, 10, true); + using var r = new StreamReader(stream, XmlFileConstants.XmlEncoding, false, 10, true); var count = 0; while (true) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs new file mode 100644 index 0000000..faec508 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs @@ -0,0 +1,10 @@ +using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; +using PG.Commons.Hashing; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public interface IPetroglyphXmlNamedElementParser : IPetroglyphXmlParserInfo where T : notnull +{ + T Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc); +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs index d2b862a..af67fa4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs @@ -1,21 +1,34 @@ -using System; -using System.IO; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; +using AnakinRaW.CommonUtilities.Collections; using PG.Commons.Hashing; using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; +using System.IO; namespace PG.StarWarsGame.Files.XML.Parsers; -public abstract class PetroglyphXmlFileContainerParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? listener = null) +public sealed class PetroglyphXmlFileContainerParser( + IServiceProvider serviceProvider, + IPetroglyphXmlNamedElementParser elementParser, + IXmlParserErrorReporter? listener = null) : PetroglyphXmlFileParserBase(serviceProvider, listener), IPetroglyphXmlFileContainerParser where T : notnull { + public IPetroglyphXmlNamedElementParser ElementParser { get; } = + elementParser ?? throw new ArgumentNullException(nameof(elementParser)); + public void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries) { - var root = GetRootElement(xmlStream, out var fileName); - if (root is not null) - Parse(root, parsedEntries, fileName); - } + var root = GetRootElement(xmlStream, out _); + + if (!root.HasElements) + { + OnParseError(XmlParseErrorEventArgs.FromEmptyRoot(root)); + return; + } - protected abstract void Parse(XElement element, IFrugalValueListDictionary parsedElements, string fileName); + foreach (var xElement in root.Elements()) + { + var parsedElement = ElementParser.Parse(xElement, parsedEntries, out var entryCrc); + parsedEntries.Add(entryCrc, parsedElement); + } + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs index 986cfef..7a5e581 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs @@ -8,16 +8,10 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public abstract class PetroglyphXmlFileParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : PetroglyphXmlFileParserBase(serviceProvider, errorReporter), IPetroglyphXmlFileParser where T : notnull { - public T? ParseFile(Stream xmlStream) + public T ParseFile(Stream xmlStream) { var root = GetRootElement(xmlStream, out var fileName); - if (root is null) - { - var location = new XmlLocationInfo(fileName, 0); - OnParseError(new XmlParseErrorEventArgs(location, XmlParseErrorKind.EmptyRoot, - "Unable to get root node from XML file.")); - } - return root is null ? default : Parse(root, fileName); + return Parse(root, fileName); } protected abstract T Parse(XElement element, string fileName); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs index 1d2a5b3..34e5317 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -17,7 +18,7 @@ private CommaSeparatedStringKeyValueListParser() private protected override IList<(string key, string value)> DefaultValue => []; - protected internal override IList<(string key, string value)> ParseCore(string trimmedValue, XElement element) + protected internal override IList<(string key, string value)> ParseCore(ReadOnlySpan trimmedValue, XElement element) { var values = element.Value.Split(','); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs index 0fd6fc1..8551867 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs @@ -1,4 +1,5 @@ -using System.Xml.Linq; +using System; +using System.Xml.Linq; using PG.StarWarsGame.Files.XML.ErrorHandling; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -22,9 +23,9 @@ public sealed override T Parse(XElement element) if (tagName.Length >= 256) ErrorReporter?.Report(this, new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, "A tag name cannot be null or empty.")); - var value = element.Value.Trim(); + var value = element.Value.AsSpan().Trim(); return value.Length == 0 ? DefaultValue : ParseCore(value, element); } - protected internal abstract T ParseCore(string trimmedValue, XElement element); + protected internal abstract T ParseCore(ReadOnlySpan trimmedValue, XElement element); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs index 8672d1b..e2d5a7a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs @@ -1,4 +1,5 @@ -using System.Xml.Linq; +using System; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -12,7 +13,7 @@ private PetroglyphXmlBooleanParser() private protected override bool DefaultValue => false; - protected internal override bool ParseCore(string trimmedValue, XElement element) + protected internal override bool ParseCore(ReadOnlySpan trimmedValue, XElement element) { // Yes! The engine only checks if the values is exact 1 or starts with Tt or Yy // At least it's efficient, I guess... diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs index aa7ba4b..7bab7ff 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs @@ -1,5 +1,6 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -13,7 +14,7 @@ private PetroglyphXmlByteParser() private protected override byte DefaultValue => 0; - protected internal override byte ParseCore(string trimmedValue, XElement element) + protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XElement element) { var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs index d3b4e85..ecad15f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs @@ -28,13 +28,17 @@ public float ParseAtLeast(XElement element, float minValue) return corrected; } - protected internal override float ParseCore(string trimmedValue, XElement element) + protected internal override float ParseCore(ReadOnlySpan trimmedValue, XElement element) { // The engine always loads FP numbers a long double and then converts that result to float - if (!double.TryParse(trimmedValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var doubleValue)) + if (!double.TryParse(trimmedValue +#if NETSTANDARD2_0 + .ToString() +#endif + , NumberStyles.Any, CultureInfo.InvariantCulture, out var doubleValue)) { OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.MalformedValue, - $"Expected double but got value '{trimmedValue}'.")); + $"Expected double but got value '{trimmedValue.ToString()}'.")); return 0.0f; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs index fd0c0ec..8dcf79f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs @@ -1,6 +1,7 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Utilities; +using System; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -14,15 +15,20 @@ private PetroglyphXmlIntegerParser() { } - protected internal override int ParseCore(string trimmedValue, XElement element) + protected internal override int ParseCore(ReadOnlySpan trimmedValue, XElement element) { // The engines uses the C++ function std::atoi which is a little more loose. // For example the value '123d' get parsed to 123, // whereas in C# int.TryParse returns (false, 0) - if (!int.TryParse(trimmedValue, out var i)) + if (!int.TryParse(trimmedValue +#if NETSTANDARD2_0 + .ToString() +#endif + + , out var i)) { OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.MalformedValue, - $"Expected integer but got '{trimmedValue}'.")); + $"Expected integer but got '{trimmedValue.ToString()}'.")); return 0; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs index d06f660..00be8f9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs @@ -25,7 +25,7 @@ private PetroglyphXmlLooseStringListParser() { } - protected internal override IList ParseCore(string trimmedValue, XElement element) + protected internal override IList ParseCore(ReadOnlySpan trimmedValue, XElement element) { if (trimmedValue.Length > 0x2000) { @@ -34,7 +34,7 @@ protected internal override IList ParseCore(string trimmedValue, XElemen return DefaultValue; } - var entries = trimmedValue.Split(Separators, StringSplitOptions.RemoveEmptyEntries); + var entries = trimmedValue.ToString().Split(Separators, StringSplitOptions.RemoveEmptyEntries); return entries; } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs index ede64a3..8241164 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs @@ -1,6 +1,7 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Utilities; +using System; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -14,7 +15,7 @@ private PetroglyphXmlMax100ByteParser() { } - protected internal override byte ParseCore(string trimmedValue, XElement element) + protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XElement element) { var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs index 1ecf10a..8f32e50 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs @@ -14,7 +14,7 @@ private PetroglyphXmlRgbaColorParser() { } - protected internal override Vector4Int ParseCore(string trimmedValue, XElement element) + protected internal override Vector4Int ParseCore(ReadOnlySpan trimmedValue, XElement element) { var values = PetroglyphXmlLooseStringListParser.Instance.ParseCore(trimmedValue, element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs index dcca294..a0dde7f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs @@ -1,4 +1,5 @@ -using System.Xml.Linq; +using System; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -12,8 +13,8 @@ private PetroglyphXmlStringParser() private protected override string DefaultValue => string.Empty; - protected internal override string ParseCore(string trimmedValue, XElement element) + protected internal override string ParseCore(ReadOnlySpan trimmedValue, XElement element) { - return trimmedValue; + return trimmedValue.ToString(); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs index 7061cca..02b9f2f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs @@ -1,5 +1,6 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -13,7 +14,7 @@ private PetroglyphXmlUnsignedIntegerParser() { } - protected internal override uint ParseCore(string trimmedValue, XElement element) + protected internal override uint ParseCore(ReadOnlySpan trimmedValue, XElement element) { var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs index 94900b7..da22a09 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System; +using System.Numerics; using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -17,7 +18,7 @@ private PetroglyphXmlVector2FParser() private protected override Vector2 DefaultValue => default; - protected internal override Vector2 ParseCore(string trimmedValue, XElement element) + protected internal override Vector2 ParseCore(ReadOnlySpan trimmedValue, XElement element) { var listOfValues = LooseStringListParser.Parse(element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/XmlFileConstants.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/XmlFileConstants.cs new file mode 100644 index 0000000..fb0de39 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/XmlFileConstants.cs @@ -0,0 +1,10 @@ +using System.Text; + +namespace PG.StarWarsGame.Files.XML; + +public static class XmlFileConstants +{ + public const int MaxTagNameLength = 255; + + public static readonly Encoding XmlEncoding = Encoding.ASCII; +} \ No newline at end of file From f3da8f84e32919f2f36a9a70484db901b02aa4c6 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 12:43:17 +0100 Subject: [PATCH 04/41] started reorganization --- src/ModVerify.CliApp/Program.cs | 2 +- .../Audio/Sfx/SfxEventGameManager.cs | 2 +- .../CommandBar/CommandBarGameManager.cs | 1 + .../GameObjects/GameObjectTypeGameManager.cs | 1 + .../GuiDialogGameManager_Initialization.cs | 2 +- .../PG.StarWarsGame.Engine.csproj.DotSettings | 4 +- .../PetroglyphEngineServiceContribution.cs | 1 + .../Xml/{Parsers => }/EngineXmlParser.cs | 83 +++++++------------ .../EngineXmlParserErrorEventArgs.cs | 2 +- .../Xml/IPetroglyphXmlFileParserFactory.cs | 9 -- .../Xml/NamedXmlObject.cs | 3 +- .../GameConstantsParser.cs | 2 +- .../{File => FileObjects}/GuiDialogParser.cs | 2 +- .../IPetroglyphXmlFileParserFactory.cs | 8 ++ .../CommandBarComponentParser.cs | 21 +++-- .../GameObjectParser.cs | 17 ++-- .../{Data => NamedObjects}/SfxEventParser.cs | 26 ++++-- .../{ => Parsers}/ParserNotFoundException.cs | 2 +- .../Xml/Parsers/PetroglyphXmlParserFactory.cs | 28 +++++++ .../Tags/CommandBarComponentTags.cs | 0 .../Tags/ComponentTextureKeyExtensions.cs | 0 .../Xml/{ => Parsers}/Tags/SfxEventXmlTags.cs | 0 .../Xml/PetroglyphXmlParserFactory.cs | 33 -------- .../Xml/{Parsers => }/XmlObjectParser.cs | 22 +++-- .../Base/PetroglyphXmlFileParserBase.cs | 1 - 25 files changed, 138 insertions(+), 134 deletions(-) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{Parsers => }/EngineXmlParser.cs (86%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{Parsers => }/EngineXmlParserErrorEventArgs.cs (93%) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{File => FileObjects}/GameConstantsParser.cs (90%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{File => FileObjects}/GuiDialogParser.cs (97%) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{Data => NamedObjects}/CommandBarComponentParser.cs (97%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{Data => NamedObjects}/GameObjectParser.cs (94%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{Data => NamedObjects}/SfxEventParser.cs (94%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{ => Parsers}/ParserNotFoundException.cs (89%) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{ => Parsers}/Tags/CommandBarComponentTags.cs (100%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{ => Parsers}/Tags/ComponentTextureKeyExtensions.cs (100%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{ => Parsers}/Tags/SfxEventXmlTags.cs (100%) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{Parsers => }/XmlObjectParser.cs (77%) diff --git a/src/ModVerify.CliApp/Program.cs b/src/ModVerify.CliApp/Program.cs index fd698cc..788d784 100644 --- a/src/ModVerify.CliApp/Program.cs +++ b/src/ModVerify.CliApp/Program.cs @@ -15,7 +15,6 @@ using Microsoft.Extensions.Logging; using PG.Commons; using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Engine.Xml.Parsers; using PG.StarWarsGame.Files.ALO; using PG.StarWarsGame.Files.MEG; using PG.StarWarsGame.Files.MTD; @@ -35,6 +34,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using AET.ModVerify.App.Reporting; +using PG.StarWarsGame.Engine.Xml; using Testably.Abstractions; using ILogger = Serilog.ILogger; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs index 72fecbb..89645d4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs @@ -7,7 +7,7 @@ using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO.Repositories; using PG.StarWarsGame.Engine.Localization; -using PG.StarWarsGame.Engine.Xml.Parsers; +using PG.StarWarsGame.Engine.Xml; namespace PG.StarWarsGame.Engine.Audio.Sfx; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 4af4a86..b9e5848 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -18,6 +18,7 @@ using System.Threading; using System.Threading.Tasks; using AnakinRaW.CommonUtilities.Collections; +using PG.StarWarsGame.Engine.Xml; namespace PG.StarWarsGame.Engine.CommandBar; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 7650185..aed5848 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO.Repositories; +using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Engine.Xml.Parsers; using System; using System.Linq; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs index 68fdabf..f4b3267 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.GuiDialog.Xml; -using PG.StarWarsGame.Engine.Xml.Parsers.File; +using PG.StarWarsGame.Engine.Xml.Parsers; using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.Binary; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj.DotSettings b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj.DotSettings index 57b1fa3..89ac95d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj.DotSettings +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj.DotSettings @@ -4,4 +4,6 @@ True True True - True \ No newline at end of file + True + True + True \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs index 0132d10..69ce035 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs @@ -2,6 +2,7 @@ using PG.StarWarsGame.Engine.IO; using PG.StarWarsGame.Engine.Localization; using PG.StarWarsGame.Engine.Xml; +using PG.StarWarsGame.Engine.Xml.Parsers; namespace PG.StarWarsGame.Engine; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs similarity index 86% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs index c93c773..4353d74 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs @@ -1,22 +1,31 @@ -using AnakinRaW.CommonUtilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities; using AnakinRaW.CommonUtilities.Collections; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using PG.Commons.Hashing; using PG.Commons.Services; -using PG.StarWarsGame.Engine.Audio.Sfx; using PG.StarWarsGame.Engine.IO; +using PG.StarWarsGame.Engine.Xml.Parsers; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using System.Xml.Linq; -namespace PG.StarWarsGame.Engine.Xml.Parsers; +namespace PG.StarWarsGame.Engine.Xml; + + +public sealed record EngineXmlParseSettings +{ + public bool InvalidFilesListXmlFailsInitialization { get; init; } = true; + + public bool InvalidContainerXmlFailsInitialization { get; init; } = false; +} + public sealed class EngineXmlParser : ServiceBase, IPetroglyphXmlParserInfo { @@ -26,7 +35,12 @@ public sealed class EngineXmlParser : ServiceBase, IPetroglyphXmlParserInfo private readonly IXmlParserErrorReporter? _reporter; private readonly IPetroglyphXmlFileParserFactory _fileParserFactory; - public EngineXmlParser(IGameRepository gameRepository, IServiceProvider serviceProvider, IXmlParserErrorReporter? reporter) + public string Name { get; } + + public EngineXmlParser( + IGameRepository gameRepository, + IServiceProvider serviceProvider, + IXmlParserErrorReporter? reporter) : base(serviceProvider) { _gameRepository = gameRepository; @@ -35,8 +49,6 @@ public EngineXmlParser(IGameRepository gameRepository, IServiceProvider serviceP Name = GetType().FullName!; } - public string Name { get; } - public XmlFileList ParseFileList(string xmlFile) { Logger.LogDebug("Parsing container data '{XmlFile}'", xmlFile); @@ -77,13 +89,14 @@ public void ParseEntriesFromFileListXml( string xmlFile, string lookupPath, FrugalValueListDictionary entries, - Action? onFileParseAction = null) where T : XmlObject + Action? onFileParseAction = null) where T : NamedXmlObject { var container = ParseFileList(xmlFile); var xmlFiles = container.Files.Select(x => FileSystem.Path.Combine(lookupPath, x)).ToList(); - var parser = _fileParserFactory.CreateFileContainerParser(_reporter); + var parser = new PetroglyphXmlFileContainerParser(Services, + _fileParserFactory.CreateNamedXmlObjectParser(_reporter), _reporter); foreach (var file in xmlFiles) { @@ -129,48 +142,16 @@ public bool ParseEntriesFromContainerFile( } } - -internal partial class XmlTagMapperDatabase -{ - private readonly IServiceProvider _serviceProvider; - - public XmlTagMapperDatabase(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - SfxEventMap = CreateSfxEventMap(); - } -} - -internal partial class XmlTagMapperDatabase -{ - private XmlTagMapper CreateSfxEventMap() - { - return new SfxEventXmlTagMapper(_serviceProvider); - } - - private sealed class SfxEventXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) - { - protected override void BuildMappings() - { - AddMapping( - "OverlapTestName", - PetroglyphXmlStringParser.Instance.Parse, - (obj, val) => obj.OverlapTestName = val); - } - } -} - - -internal partial class XmlTagMapperDatabase +public interface IXmlTagMapper where TObject : XmlObject { - public XmlTagMapper SfxEventMap { get; } + bool TryParseEntry(XElement element, TObject target); } -internal abstract class XmlTagMapper where TClass : notnull +public abstract class XmlTagMapper : IXmlTagMapper where TObject : XmlObject { private const int MaxTagLength = 256; - private delegate void ParserValueAction(TClass target, XElement element); + private delegate void ParserValueAction(TObject target, XElement element); private readonly Dictionary _tagMappings = new(); private readonly ICrc32HashingService _crcService; @@ -187,7 +168,7 @@ protected XmlTagMapper(IServiceProvider serviceProvider) protected abstract void BuildMappings(); - protected void AddMapping(string tagName, Func parser, Action setter) + protected void AddMapping(string tagName, Func parser, Action setter) { ThrowHelper.ThrowIfNullOrEmpty(tagName); if (tagName.Length >= MaxTagLength) @@ -208,7 +189,7 @@ protected void AddMapping(string tagName, Func parser, }; } - public bool TryParseEntry(XElement element, TClass target) + public bool TryParseEntry(XElement element, TObject target) { var tagName = element.Name.LocalName; if (tagName.Length >= MaxTagLength) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParserErrorEventArgs.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs similarity index 93% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParserErrorEventArgs.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs index d8ff77b..8026804 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/EngineXmlParserErrorEventArgs.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Xml; -namespace PG.StarWarsGame.Engine.Xml.Parsers; +namespace PG.StarWarsGame.Engine.Xml; public class EngineXmlParserErrorEventArgs(string file, XmlException? exception = null, bool isXmlFileList = false) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs deleted file mode 100644 index b3cf950..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.Xml; - -public interface IPetroglyphXmlFileParserFactory -{ - IPetroglyphXmlFileContainerParser CreateFileContainerParser(IXmlParserErrorReporter? errorReporter) where T : XmlObject; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs index 7cf9c4e..6118f99 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs @@ -1,11 +1,10 @@ using System; -using PG.Commons.Data; using PG.Commons.Hashing; using PG.StarWarsGame.Files.XML; namespace PG.StarWarsGame.Engine.Xml; -public abstract class NamedXmlObject(string name, Crc32 nameCrc, XmlLocationInfo location) : XmlObject(location), IHasCrc32 +public abstract class NamedXmlObject(string name, Crc32 nameCrc, XmlLocationInfo location) : XmlObject(location) { public Crc32 Crc32 { get; } = nameCrc; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameConstantsParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs similarity index 90% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameConstantsParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs index 8f2806f..8100e2e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GameConstantsParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs @@ -4,7 +4,7 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -namespace PG.StarWarsGame.Engine.Xml.Parsers.File; +namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class GameConstantsParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : PetroglyphXmlFileParser(serviceProvider, errorReporter) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GuiDialogParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs similarity index 97% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GuiDialogParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs index 851aa9f..d8c1191 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/File/GuiDialogParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs @@ -7,7 +7,7 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -namespace PG.StarWarsGame.Engine.Xml.Parsers.File; +namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class GuiDialogParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : PetroglyphXmlFileParser(serviceProvider, errorReporter) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs new file mode 100644 index 0000000..c821e46 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs @@ -0,0 +1,8 @@ +using PG.StarWarsGame.Files.XML.ErrorHandling; + +namespace PG.StarWarsGame.Engine.Xml.Parsers; + +internal interface IPetroglyphXmlFileParserFactory +{ + NamedXmlObjectParser CreateNamedXmlObjectParser(IXmlParserErrorReporter? errorReporter) where T : NamedXmlObject; +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs similarity index 97% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index e8f2cd2..8d4a285 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -1,20 +1,19 @@ -using AnakinRaW.CommonUtilities.Collections; +using System; +using System.Collections.ObjectModel; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.CommandBar.Xml; using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -using System; -using System.Collections.ObjectModel; -using System.Xml.Linq; using Crc32 = PG.Commons.Hashing.Crc32; -namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; +namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class CommandBarComponentParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : NamedXmlObjectParser(serviceProvider, errorReporter) + : NamedXmlObjectParser(serviceProvider, new CommandBarComponentDataXmlTagMapper(serviceProvider), errorReporter) { - protected override CommandBarComponentData CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) { return new CommandBarComponentData(name, nameCrc, location); @@ -353,4 +352,12 @@ protected override void ValidateValues(CommandBarComponentData xmlData, XElement $"CommandbarComponent name '{xmlData.Name}' is too long.")); } } + + private sealed class CommandBarComponentDataXmlTagMapper(IServiceProvider serviceProvider) + : XmlTagMapper(serviceProvider) + { + protected override void BuildMappings() + { + } + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs similarity index 94% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index 2b9126b..e28ff37 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -1,13 +1,13 @@ -using AnakinRaW.CommonUtilities.Collections; +using System; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.GameObjects; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -using System; -using System.Xml.Linq; using Crc32 = PG.Commons.Hashing.Crc32; -namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; +namespace PG.StarWarsGame.Engine.Xml.Parsers; public static class GameObjectXmlTags { @@ -26,7 +26,7 @@ public static class GameObjectXmlTags } internal class GameObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : NamedXmlObjectParser(serviceProvider, errorReporter) + : NamedXmlObjectParser(serviceProvider, new GameObjectXmlTagMapper(serviceProvider), errorReporter) { protected override GameObject CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) { @@ -135,4 +135,11 @@ private static GameObjectType EstimateType(string tagName) _ => GameObjectType.Unknown }; } + + private sealed class GameObjectXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) + { + protected override void BuildMappings() + { + } + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs similarity index 94% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs index c59bc40..0d78cef 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Data/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs @@ -1,21 +1,18 @@ -using AnakinRaW.CommonUtilities.Collections; -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.ObjectModel; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; using PG.Commons.Hashing; using PG.StarWarsGame.Engine.Audio.Sfx; using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities; -namespace PG.StarWarsGame.Engine.Xml.Parsers.Data; +namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class SfxEventParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : NamedXmlObjectParser(serviceProvider, errorReporter) + : NamedXmlObjectParser(serviceProvider, new SfxEventXmlTagMapper(serviceProvider), errorReporter) { protected override SfxEvent CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) { @@ -194,4 +191,15 @@ protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, in IReadOnlyFr default: return false; } } + + private sealed class SfxEventXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) + { + protected override void BuildMappings() + { + AddMapping( + "OverlapTestName", + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.OverlapTestName = val); + } + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/ParserNotFoundException.cs similarity index 89% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/ParserNotFoundException.cs index fd4fba3..79b5d0c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/ParserNotFoundException.cs @@ -1,6 +1,6 @@ using System; -namespace PG.StarWarsGame.Engine.Xml; +namespace PG.StarWarsGame.Engine.Xml.Parsers; internal sealed class ParserNotFoundException : Exception { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs new file mode 100644 index 0000000..152617f --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs @@ -0,0 +1,28 @@ +using PG.StarWarsGame.Engine.Audio.Sfx; +using PG.StarWarsGame.Engine.CommandBar.Xml; +using PG.StarWarsGame.Engine.GameObjects; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; + +namespace PG.StarWarsGame.Engine.Xml.Parsers; + +internal sealed class PetroglyphXmlFileParserFactory(IServiceProvider serviceProvider) : IPetroglyphXmlFileParserFactory +{ + public NamedXmlObjectParser CreateNamedXmlObjectParser(IXmlParserErrorReporter? errorReporter) where T : NamedXmlObject + { + if (typeof(T) == typeof(SfxEvent)) + return ChangeType(new SfxEventParser(serviceProvider, errorReporter)); + if (typeof(T) == typeof(CommandBarComponentData)) + return ChangeType(new CommandBarComponentParser(serviceProvider, errorReporter)); + if (typeof(T) == typeof(GameObject)) + return ChangeType(new GameObjectParser(serviceProvider, errorReporter)); + + + throw new ParserNotFoundException(typeof(T)); + } + + private static NamedXmlObjectParser ChangeType(object obj) where T : NamedXmlObject + { + return (NamedXmlObjectParser) obj; + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Tags/CommandBarComponentTags.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/CommandBarComponentTags.cs similarity index 100% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Tags/CommandBarComponentTags.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/CommandBarComponentTags.cs diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Tags/ComponentTextureKeyExtensions.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/ComponentTextureKeyExtensions.cs similarity index 100% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Tags/ComponentTextureKeyExtensions.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/ComponentTextureKeyExtensions.cs diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Tags/SfxEventXmlTags.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/SfxEventXmlTags.cs similarity index 100% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Tags/SfxEventXmlTags.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/SfxEventXmlTags.cs diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs deleted file mode 100644 index 0817892..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphXmlParserFactory.cs +++ /dev/null @@ -1,33 +0,0 @@ -using PG.StarWarsGame.Engine.Audio.Sfx; -using PG.StarWarsGame.Engine.CommandBar.Xml; -using PG.StarWarsGame.Engine.GameObjects; -using PG.StarWarsGame.Engine.Xml.Parsers.Data; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; -using System; - -namespace PG.StarWarsGame.Engine.Xml; - -internal sealed class PetroglyphXmlFileParserFactory(IServiceProvider serviceProvider) : IPetroglyphXmlFileParserFactory -{ - public IPetroglyphXmlFileContainerParser CreateFileContainerParser(IXmlParserErrorReporter? errorReporter) where T : XmlObject - { - if (typeof(T) == typeof(SfxEvent)) - return new PetroglyphXmlFileContainerParser( - serviceProvider, (IPetroglyphXmlNamedElementParser)new SfxEventParser(serviceProvider, errorReporter), - errorReporter); - - if (typeof(T) == typeof(CommandBarComponentData)) - return new PetroglyphXmlFileContainerParser( - serviceProvider, (IPetroglyphXmlNamedElementParser)new CommandBarComponentParser(serviceProvider, errorReporter), - errorReporter); - - if (typeof(T) == typeof(GameObject)) - return new PetroglyphXmlFileContainerParser( - serviceProvider, (IPetroglyphXmlNamedElementParser)new GameObjectParser(serviceProvider, errorReporter), - errorReporter); - - - throw new ParserNotFoundException(typeof(T)); - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs similarity index 77% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs index 1e3ea3a..9e6f045 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs @@ -9,12 +9,13 @@ using PG.Commons.Hashing; using Crc32 = PG.Commons.Hashing.Crc32; -namespace PG.StarWarsGame.Engine.Xml.Parsers; +namespace PG.StarWarsGame.Engine.Xml; -internal abstract class XmlObjectParserBase(IXmlParserErrorReporter? errorReporter) - : PetroglyphXmlParserBase(errorReporter) - where TObject : XmlObject +public abstract class XmlObjectParserBase(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter) + : PetroglyphXmlParserBase(errorReporter) where TObject : XmlObject { + protected readonly IXmlTagMapper TagMapper = tagMapper ?? throw new ArgumentNullException(nameof(tagMapper)); + protected virtual void ValidateValues(TObject namedXmlObject, XElement element) { } @@ -35,8 +36,11 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) } -internal abstract class NamedXmlObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter) - : XmlObjectParserBase>(errorReporter), +public abstract class NamedXmlObjectParser( + IServiceProvider serviceProvider, + IXmlTagMapper tagMapper, + IXmlParserErrorReporter? errorReporter) + : XmlObjectParserBase>(tagMapper, errorReporter), IPetroglyphXmlNamedElementParser where TObject : NamedXmlObject { @@ -71,8 +75,8 @@ protected string GetXmlObjectName(XElement element, bool uppercaseName, out Crc3 } } -internal abstract class XmlObjectParser(IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParserBase(errorReporter), IPetroglyphXmlElementParser +public abstract class XmlObjectParser(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter = null) + : XmlObjectParserBase(tagMapper, errorReporter), IPetroglyphXmlElementParser where TObject : XmlObject { public TObject Parse(XElement element) @@ -94,7 +98,7 @@ protected sealed override bool ParseTag(XElement tag, TObject xmlObject, in Empt protected abstract bool ParseTag(XElement tag, TObject xmlObject); } -internal readonly struct EmptyParseState +public readonly struct EmptyParseState { public static readonly EmptyParseState Instance = new(); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs index bf8de55..875341c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.IO.Abstractions; -using System.Text; using System.Xml; using System.Xml.Linq; using Microsoft.Extensions.DependencyInjection; From 3217a58952fc7d8c7619f8c3addcbf0e9b07889c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 14:21:54 +0100 Subject: [PATCH 05/41] new xml error reporting --- .../Engine/GameEngineErrorCollection.cs | 3 +- .../Engine/IGameEngineErrorCollection.cs | 1 + .../Reporting/Engine/XmlParseErrorReporter.cs | 1 - .../GameEngineErrorReporterWrapper.cs | 18 +--- .../IGameEngineErrorReporter.cs | 8 +- .../ErrorReporting/XmlError.cs | 19 ---- .../PetroglyphStarWarsGameEngineService.cs | 1 + .../Xml/EngineXmlParser.cs | 28 ++++-- .../Parsers/FileObjects/GuiDialogParser.cs | 16 +++- .../NamedObjects/CommandBarComponentParser.cs | 7 +- .../Parsers/NamedObjects/SfxEventParser.cs | 89 ++++++++++--------- .../Xml/XmlObjectParser.cs | 14 ++- .../ErrorHandling/IXmlParserErrorProvider.cs | 6 -- .../ErrorHandling/IXmlParserErrorReporter.cs | 6 +- .../PrimitiveXmlErrorReporter.cs | 13 +-- .../ErrorHandling/XmlError.cs | 21 +++++ .../ErrorHandling/XmlErrorEventHandler.cs | 5 -- .../ErrorHandling/XmlErrorReporter.cs | 16 ++-- .../ErrorHandling/XmlParseErrorEventArgs.cs | 42 --------- .../Base/PetroglyphXmlFileParserBase.cs | 25 +++++- .../Parsers/Base/PetroglyphXmlParserBase.cs | 14 +-- .../PetroglyphXmlFileContainerParser.cs | 6 -- .../PetroglyphPrimitiveXmlParser.cs | 18 +++- .../Primitives/PetroglyphXmlByteParser.cs | 7 +- .../Primitives/PetroglyphXmlFloatParser.cs | 14 ++- .../Primitives/PetroglyphXmlIntegerParser.cs | 14 ++- .../PetroglyphXmlLooseStringListParser.cs | 7 +- .../PetroglyphXmlMax100ByteParser.cs | 29 ++++-- .../PetroglyphXmlUnsignedIntegerParser.cs | 7 +- .../Parsers/XmlFileListParser.cs | 17 +++- 30 files changed, 251 insertions(+), 221 deletions(-) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorProvider.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlError.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorEventArgs.cs diff --git a/src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs b/src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs index ba0abf5..8cb67c0 100644 --- a/src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs +++ b/src/ModVerify/Reporting/Engine/GameEngineErrorCollection.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Files.XML.ErrorHandling; namespace AET.ModVerify.Reporting.Engine; @@ -17,7 +18,7 @@ public sealed class GameEngineErrorCollection : IGameEngineErrorCollection, IGam public IEnumerable Asserts => _asserts.ToList(); - void IGameEngineErrorReporter.Report(XmlError error) + void IXmlParserErrorReporter.Report(XmlError error) { _xmlErrors.Add(error); } diff --git a/src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs b/src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs index adf734d..286d047 100644 --- a/src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs +++ b/src/ModVerify/Reporting/Engine/IGameEngineErrorCollection.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Files.XML.ErrorHandling; namespace AET.ModVerify.Reporting.Engine; diff --git a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs index 2629f26..b29fce0 100644 --- a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs +++ b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs @@ -4,7 +4,6 @@ using AET.ModVerify.Utilities; using AET.ModVerify.Verifiers; using Microsoft.Extensions.DependencyInjection; -using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO; using PG.StarWarsGame.Files.XML.ErrorHandling; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs index adf715a..320a2c7 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs @@ -1,6 +1,5 @@ using System; using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; namespace PG.StarWarsGame.Engine.ErrorReporting; @@ -17,7 +16,7 @@ public GameEngineErrorReporterWrapper(IGameEngineErrorReporter? errorReporter) _errorReporter = errorReporter; } - public void Report(XmlError error) + public override void Report(XmlError error) { _errorReporter?.Report(error); } @@ -32,19 +31,4 @@ public void Assert(EngineAssert assert) { _errorReporter?.Assert(assert); } - - public override void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) - { - if (_errorReporter is null) - return; - - Report(new XmlError - { - FileLocation = error.Location, - Parser = parser, - Message = error.Message, - ErrorKind = error.ErrorKind, - Element = error.Element - }); - } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/IGameEngineErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/IGameEngineErrorReporter.cs index 1294fd1..933d3b5 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/IGameEngineErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/IGameEngineErrorReporter.cs @@ -1,9 +1,9 @@ -namespace PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Files.XML.ErrorHandling; -public interface IGameEngineErrorReporter -{ - void Report(XmlError error); +namespace PG.StarWarsGame.Engine.ErrorReporting; +public interface IGameEngineErrorReporter : IXmlParserErrorReporter +{ void Report(InitializationError error); void Assert(EngineAssert assert); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs deleted file mode 100644 index e6124ec..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/XmlError.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.ErrorReporting; - -public sealed class XmlError -{ - public required XmlLocationInfo FileLocation { get; init; } - - public required IPetroglyphXmlParserInfo Parser { get; init; } - - public XElement? Element { get; init; } - - public required XmlParseErrorKind ErrorKind { get; init; } - - public required string Message { get; init; } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs index 02a8d9f..42a2416 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs @@ -51,6 +51,7 @@ public async Task InitializeAsync( void OnInitializationError(object sender, InitializationError e) { + _logger?.LogWarning("Engine initialization failed for {Manager}: {Message}", e.GameManager, e.Message); if (cancelOnInitializationError) cts.Cancel(); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs index 4353d74..b37a5f7 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs @@ -56,7 +56,11 @@ public XmlFileList ParseFileList(string xmlFile) using var containerStream = _gameRepository.TryOpenFile(xmlFile); if (containerStream == null) { - _reporter?.Report(this, XmlParseErrorEventArgs.FromMissingFile(xmlFile)); + _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) + { + Message = "Xml file not found", + ErrorKind = XmlParseErrorKind.MissingFile + }); Logger.LogWarning("Could not find XML file '{XmlFile}'", xmlFile); var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: true); @@ -75,8 +79,12 @@ public XmlFileList ParseFileList(string xmlFile) } catch (XmlException e) { - _reporter?.Report(containerParser, new XmlParseErrorEventArgs(new XmlLocationInfo(xmlFile, e.LineNumber), - XmlParseErrorKind.Unknown, e.Message)); + _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) + { + ErrorKind = XmlParseErrorKind.Unknown, + Message = e.Message, + }); + var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: true); XmlParseError?.Invoke(this, args); return XmlFileList.Empty; @@ -115,7 +123,11 @@ public bool ParseEntriesFromContainerFile( if (fileStream is null) { - _reporter?.Report(this, XmlParseErrorEventArgs.FromMissingFile(xmlFile)); + _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) + { + Message = "Xml file not found", + ErrorKind = XmlParseErrorKind.MissingFile + }); Logger.LogWarning("Could not find XML file '{File}'", xmlFile); var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: false); @@ -132,9 +144,11 @@ public bool ParseEntriesFromContainerFile( } catch (XmlException e) { - _reporter?.Report(parser, - new XmlParseErrorEventArgs(new XmlLocationInfo(xmlFile, 0), XmlParseErrorKind.Unknown, e.Message)); - + _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) + { + ErrorKind = XmlParseErrorKind.Unknown, + Message = e.Message, + }); var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: false); XmlParseError?.Invoke(this, args); return args.Continue; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs index d8c1191..4c59922 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs @@ -22,8 +22,11 @@ private GuiDialogsXmlTextureData ParseTextures(XElement? element, string fileNam { if (element is null) { - OnParseError(new XmlParseErrorEventArgs(new XmlLocationInfo(fileName, null), XmlParseErrorKind.MissingNode, - "Expected node is missing.")); + ErrorReporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(fileName, null)) + { + ErrorKind = XmlParseErrorKind.MissingNode, + Message = "Expected node is missing." + }); return new GuiDialogsXmlTextureData([], new XmlLocationInfo(fileName, null)); } @@ -36,8 +39,13 @@ private GuiDialogsXmlTextureData ParseTextures(XElement? element, string fileNam textures.Add(ParseTexture(texture)); if (textures.Count == 0) - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.MissingNode, - "Textures must contain at least one child node.")); + { + ErrorReporter?.Report(new XmlError(this, element) + { + Message = "Textures must contain at least one child node.", + ErrorKind = XmlParseErrorKind.MissingNode + }); + } return new GuiDialogsXmlTextureData(textures, XmlLocationInfo.FromElement(element)) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index 8d4a285..2c74d99 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -348,8 +348,11 @@ protected override void ValidateValues(CommandBarComponentData xmlData, XElement { if (xmlData.Name.Length > PGConstants.MaxCommandBarComponentName) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, - $"CommandbarComponent name '{xmlData.Name}' is too long.")); + ErrorReporter?.Report(new XmlError(this, element) + { + Message = $"CommandbarComponent name '{xmlData.Name}' is too long.", + ErrorKind = XmlParseErrorKind.TooLongData + }); } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs index 0d78cef..e59ef80 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs @@ -21,47 +21,47 @@ protected override SfxEvent CreateXmlObject(string name, Crc32 nameCrc, XElement protected override void ValidateValues(SfxEvent sfxEvent, XElement element) { - if (sfxEvent.Name.Length > PGConstants.MaxSFXEventName) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, - $"SFXEvent name '{sfxEvent.Name}' is too long.")); - } - - if (sfxEvent is { Is2D: true, Is3D: true }) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"SFXEvent '{sfxEvent.Name}' is defined as 2D and 3D.")); - } - - if (sfxEvent.MinVolume > sfxEvent.MaxVolume) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"{SfxEventXmlTags.MinVolume} should not be higher than {SfxEventXmlTags.MaxVolume} for SFXEvent '{sfxEvent.Name}'")); - } - - if (sfxEvent.MinPitch > sfxEvent.MaxPitch) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"{SfxEventXmlTags.MinPitch} should not be higher than {SfxEventXmlTags.MaxPitch} for SFXEvent '{sfxEvent.Name}'")); - } - - if (sfxEvent.MinPan2D > sfxEvent.MaxPan2D) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"{SfxEventXmlTags.MinPan2D} should not be higher than {SfxEventXmlTags.MaxPan2D} for SFXEvent '{sfxEvent.Name}'")); - } - - if (sfxEvent.MinPredelay > sfxEvent.MaxPredelay) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"{SfxEventXmlTags.MinPredelay} should not be higher than {SfxEventXmlTags.MaxPredelay} for SFXEvent '{sfxEvent.Name}'")); - } - - if (sfxEvent.MinPostdelay > sfxEvent.MaxPostdelay) - { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"{SfxEventXmlTags.MinPostdelay} should not be higher than {SfxEventXmlTags.MaxPostdelay} for SFXEvent '{sfxEvent.Name}'")); - } + //if (sfxEvent.Name.Length > PGConstants.MaxSFXEventName) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, + // $"SFXEvent name '{sfxEvent.Name}' is too long.")); + //} + + //if (sfxEvent is { Is2D: true, Is3D: true }) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, + // $"SFXEvent '{sfxEvent.Name}' is defined as 2D and 3D.")); + //} + + //if (sfxEvent.MinVolume > sfxEvent.MaxVolume) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, + // $"{SfxEventXmlTags.MinVolume} should not be higher than {SfxEventXmlTags.MaxVolume} for SFXEvent '{sfxEvent.Name}'")); + //} + + //if (sfxEvent.MinPitch > sfxEvent.MaxPitch) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, + // $"{SfxEventXmlTags.MinPitch} should not be higher than {SfxEventXmlTags.MaxPitch} for SFXEvent '{sfxEvent.Name}'")); + //} + + //if (sfxEvent.MinPan2D > sfxEvent.MaxPan2D) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, + // $"{SfxEventXmlTags.MinPan2D} should not be higher than {SfxEventXmlTags.MaxPan2D} for SFXEvent '{sfxEvent.Name}'")); + //} + + //if (sfxEvent.MinPredelay > sfxEvent.MaxPredelay) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, + // $"{SfxEventXmlTags.MinPredelay} should not be higher than {SfxEventXmlTags.MaxPredelay} for SFXEvent '{sfxEvent.Name}'")); + //} + + //if (sfxEvent.MinPostdelay > sfxEvent.MaxPostdelay) + //{ + // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, + // $"{SfxEventXmlTags.MinPostdelay} should not be higher than {SfxEventXmlTags.MaxPostdelay} for SFXEvent '{sfxEvent.Name}'")); + //} } protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, in IReadOnlyFrugalValueListDictionary parsedEntries) @@ -82,8 +82,11 @@ protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, in IReadOnlyFr sfxEvent.ApplyPreset(preset); else { - OnParseError(new XmlParseErrorEventArgs(tag, - XmlParseErrorKind.MissingReference, $"Cannot to find preset '{presetName}' for SFXEvent '{sfxEvent.Name}'")); + ErrorReporter?.Report(new XmlError(this, tag) + { + Message = $"Cannot to find preset '{presetName}' for SFXEvent '{sfxEvent.Name}'", + ErrorKind = XmlParseErrorKind.MissingReference + }); } return true; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs index 9e6f045..158f15c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs @@ -26,8 +26,11 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) { if (!ParseTag(tag, xmlObject, state)) { - OnParseError(new XmlParseErrorEventArgs(tag, XmlParseErrorKind.UnknownNode, - $"The node '{tag.Name}' is not supported.")); + ErrorReporter?.Report(new XmlError(this, element) + { + Message = $"The node '{tag.Name}' is not supported.", + ErrorKind = XmlParseErrorKind.UnknownNode + }); } } } @@ -67,8 +70,11 @@ protected string GetXmlObjectName(XElement element, bool uppercaseName, out Crc3 if (crc32 == default) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - "Name for XmlObject cannot be empty.")); + ErrorReporter?.Report(new XmlError(this, element) + { + Message = "Name for XmlObject cannot be empty.", + ErrorKind = XmlParseErrorKind.InvalidValue + }); } return name; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorProvider.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorProvider.cs deleted file mode 100644 index 2470187..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PG.StarWarsGame.Files.XML.ErrorHandling; - -public interface IXmlParserErrorProvider -{ - event XmlErrorEventHandler XmlParseError; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs index d1dceed..bddb691 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/IXmlParserErrorReporter.cs @@ -1,8 +1,6 @@ -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Files.XML.ErrorHandling; +namespace PG.StarWarsGame.Files.XML.ErrorHandling; public interface IXmlParserErrorReporter { - void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error); + void Report(XmlError error); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs index fda7012..4d4bce2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/PrimitiveXmlErrorReporter.cs @@ -1,13 +1,14 @@ using System; -using PG.StarWarsGame.Files.XML.Parsers; namespace PG.StarWarsGame.Files.XML.ErrorHandling; -internal sealed class PrimitiveXmlErrorReporter : IXmlParserErrorReporter, IXmlParserErrorProvider +internal sealed class PrimitiveXmlErrorReporter : IXmlParserErrorReporter { - public event XmlErrorEventHandler? XmlParseError; + internal delegate void XmlErrorEventHandler(XmlError error); - private static readonly Lazy LazyInstance = new(() => new PrimitiveXmlErrorReporter()); + public event XmlErrorEventHandler? PrimitiveParseError; + + private static readonly Lazy LazyInstance = new(() => new PrimitiveXmlErrorReporter(), true); public static PrimitiveXmlErrorReporter Instance => LazyInstance.Value; @@ -15,8 +16,8 @@ private PrimitiveXmlErrorReporter() { } - public void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) + public void Report(XmlError error) { - XmlParseError?.Invoke(parser, error); + PrimitiveParseError?.Invoke(error); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlError.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlError.cs new file mode 100644 index 0000000..bcdac81 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlError.cs @@ -0,0 +1,21 @@ +using System; +using System.Xml.Linq; +using PG.StarWarsGame.Files.XML.Parsers; + +namespace PG.StarWarsGame.Files.XML.ErrorHandling; + +public sealed class XmlError( + IPetroglyphXmlParserInfo parser, + XElement? element = null, + XmlLocationInfo? locationInfo = null) +{ + public XmlLocationInfo FileLocation { get; } = locationInfo ?? (element is not null ? XmlLocationInfo.FromElement(element) : default); + + public IPetroglyphXmlParserInfo Parser { get; } = parser ?? throw new ArgumentNullException(nameof(parser)); + + public XElement? Element { get; } = element; + + public required XmlParseErrorKind ErrorKind { get; init; } + + public required string Message { get; init; } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs deleted file mode 100644 index 9e4821c..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorEventHandler.cs +++ /dev/null @@ -1,5 +0,0 @@ -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Files.XML.ErrorHandling; - -public delegate void XmlErrorEventHandler(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error); \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs index 5369633..dd8734b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlErrorReporter.cs @@ -1,29 +1,25 @@ using AnakinRaW.CommonUtilities; -using PG.StarWarsGame.Files.XML.Parsers; namespace PG.StarWarsGame.Files.XML.ErrorHandling; -public class XmlErrorReporter : DisposableObject, IXmlParserErrorReporter, IXmlParserErrorProvider +public class XmlErrorReporter : DisposableObject, IXmlParserErrorReporter { - public event XmlErrorEventHandler? XmlParseError; - public XmlErrorReporter() { - PrimitiveXmlErrorReporter.Instance.XmlParseError += OnPrimitiveError; + PrimitiveXmlErrorReporter.Instance.PrimitiveParseError += OnPrimitiveError; } - public virtual void Report(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) + public virtual void Report(XmlError error) { - XmlParseError?.Invoke(parser, error); } protected override void DisposeResources() { - PrimitiveXmlErrorReporter.Instance.XmlParseError -= OnPrimitiveError; + PrimitiveXmlErrorReporter.Instance.PrimitiveParseError -= OnPrimitiveError; } - private void OnPrimitiveError(IPetroglyphXmlParserInfo parser, XmlParseErrorEventArgs error) + private void OnPrimitiveError(XmlError error) { - Report(parser, error); + Report(error); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorEventArgs.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorEventArgs.cs deleted file mode 100644 index afaa2ce..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorEventArgs.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities; - -namespace PG.StarWarsGame.Files.XML.ErrorHandling; - -public class XmlParseErrorEventArgs : EventArgs -{ - public XmlLocationInfo Location { get; } - - public XElement? Element { get; } - - public XmlParseErrorKind ErrorKind { get; } - - public string Message { get; } - - public XmlParseErrorEventArgs(XElement element, XmlParseErrorKind errorKind, string message) - { - Element = element ?? throw new ArgumentNullException(nameof(element)); - Location = XmlLocationInfo.FromElement(element); - ErrorKind = errorKind; - Message = message; - } - - public XmlParseErrorEventArgs(XmlLocationInfo location, XmlParseErrorKind errorKind, string message) - { - Location = location; - Message = message; - ErrorKind = errorKind; - } - - public static XmlParseErrorEventArgs FromMissingFile(string file) - { - ThrowHelper.ThrowIfNullOrEmpty(file); - return new XmlParseErrorEventArgs(new XmlLocationInfo(file, null), XmlParseErrorKind.MissingFile, "XML file not found."); - } - - public static XmlParseErrorEventArgs FromEmptyRoot(XElement element) - { - return new XmlParseErrorEventArgs(element, XmlParseErrorKind.EmptyRoot, "XML file has an empty root node."); - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs index 875341c..178fece 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs @@ -45,7 +45,22 @@ protected XElement GetRootElement(Stream xmlStream, out string fileName) options |= LoadOptions.SetLineInfo; var doc = XDocument.Load(xmlReader, options); - return doc.Root ?? throw new XmlException("No root node found."); + + var root = doc.Root; + + if (root is null) + throw new XmlException("No root node found."); + + if (!root.HasElements) + { + ErrorReporter?.Report(new XmlError(this, root) + { + ErrorKind = XmlParseErrorKind.EmptyRoot, + Message = "XML file has an empty root node.", + }); + } + + return root; } private string GetStrippedFileName(string filePath) @@ -77,8 +92,12 @@ private void SkipLeadingWhiteSpace(string fileName, Stream stream) if (count != 0) { - OnParseError(new XmlParseErrorEventArgs(new XmlLocationInfo(fileName, 0), - XmlParseErrorKind.DataBeforeHeader, $"XML header is not the first entry of the XML file."));} + ErrorReporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(fileName, 0)) + { + ErrorKind = XmlParseErrorKind.DataBeforeHeader, + Message = "XML header is not the first entry of the XML file.", + }); + } stream.Position = count; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs index 698ccb2..4e05ac1 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs @@ -40,22 +40,22 @@ protected bool GetNameAttributeValue(XElement element, out string value) protected bool GetAttributeValue(XElement element, string attribute, out string? value, string? defaultValue = null) { + // In this engine, this is actually case-sensitive var nameAttribute = element.Attributes() .FirstOrDefault(a => a.Name.LocalName == attribute); - + if (nameAttribute is null) { value = defaultValue; - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.MissingAttribute, $"Missing attribute '{attribute}'")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.MissingAttribute, + Message = $"Missing attribute '{attribute}'", + }); return false; } value = nameAttribute.Value; return true; } - - protected virtual void OnParseError(XmlParseErrorEventArgs error) - { - ErrorReporter?.Report(this, error); - } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs index af67fa4..9441c6f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs @@ -19,12 +19,6 @@ public void ParseFile(Stream xmlStream, IFrugalValueListDictionary par { var root = GetRootElement(xmlStream, out _); - if (!root.HasElements) - { - OnParseError(XmlParseErrorEventArgs.FromEmptyRoot(root)); - return; - } - foreach (var xElement in root.Elements()) { var parsedElement = ElementParser.Parse(xElement, parsedEntries, out var entryCrc); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs index 8551867..198b4de 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs @@ -17,11 +17,23 @@ public sealed override T Parse(XElement element) var tagName = element.Name.LocalName; if (string.IsNullOrEmpty(tagName)) { - ErrorReporter?.Report(this, new XmlParseErrorEventArgs(element, XmlParseErrorKind.EmptyNodeName, "A tag name cannot be null or empty.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.EmptyNodeName, + Message = "A tag name cannot be null or empty.", + }); + return DefaultValue; + } + + if (tagName.Length > XmlFileConstants.MaxTagNameLength) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.TooLongData, + Message = $"A tag name can be only {XmlFileConstants.MaxTagNameLength} chars long.", + }); return DefaultValue; } - if (tagName.Length >= 256) - ErrorReporter?.Report(this, new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, "A tag name cannot be null or empty.")); var value = element.Value.AsSpan().Trim(); return value.Length == 0 ? DefaultValue : ParseCore(value, element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs index 7bab7ff..2be5d48 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs @@ -21,8 +21,11 @@ protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XEle var asByte = (byte)intValue; if (intValue != asByte) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected a byte value (0 - 255) but got value '{intValue}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected a byte value (0 - 255) but got value '{intValue}'.", + }); } return asByte; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs index ecad15f..86ef413 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs @@ -21,8 +21,11 @@ public float ParseAtLeast(XElement element, float minValue) var corrected = Math.Max(value, minValue); if (corrected != value) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected float to be at least {minValue} but got value '{value}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected float to be at least {minValue} but got value '{value}'.", + }); } return corrected; @@ -37,8 +40,11 @@ protected internal override float ParseCore(ReadOnlySpan trimmedValue, XEl #endif , NumberStyles.Any, CultureInfo.InvariantCulture, out var doubleValue)) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.MalformedValue, - $"Expected double but got value '{trimmedValue.ToString()}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.MalformedValue, + Message = $"Expected double but got value '{trimmedValue.ToString()}'.", + }); return 0.0f; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs index 8dcf79f..9faf905 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs @@ -27,8 +27,11 @@ protected internal override int ParseCore(ReadOnlySpan trimmedValue, XElem , out var i)) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.MalformedValue, - $"Expected integer but got '{trimmedValue.ToString()}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.MalformedValue, + Message = $"Expected integer but got '{trimmedValue.ToString()}'.", + }); return 0; } @@ -41,8 +44,11 @@ public int ParseWithRange(XElement element, int minValue, int maxValue) var clamped = PGMath.Clamp(value, minValue, maxValue); if (value != clamped) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected integer between {minValue} and {maxValue} but got value '{value}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected integer between {minValue} and {maxValue} but got value '{value}'.", + }); } return clamped; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs index 00be8f9..d6f1e3e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs @@ -29,8 +29,11 @@ protected internal override IList ParseCore(ReadOnlySpan trimmedVa { if (trimmedValue.Length > 0x2000) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, - $"Input value is too long '{trimmedValue.Length}' at {XmlLocationInfo.FromElement(element)}")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.TooLongData, + Message = $"Input value is too long '{trimmedValue.Length}' at {XmlLocationInfo.FromElement(element)}", + }); return DefaultValue; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs index 8241164..5d23e6d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs @@ -25,15 +25,21 @@ protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XEle var asByte = (byte)intValue; if (intValue != asByte) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected a byte value (0 - 255) but got value '{intValue}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected a byte value (0 - 255) but got value '{intValue}'.", + }); } // Add additional check, cause the PG implementation is broken, but we need to stay "bug-compatible". if (asByte > 100) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected a byte value (0 - 100) but got value '{asByte}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected a byte value (0 - 100) but got value '{asByte}'.", + }); } return asByte; @@ -43,9 +49,11 @@ public byte ParseWithRange(XElement element, byte minValue, byte maxValue) { if (maxValue > 100) { - OnParseError(new XmlParseErrorEventArgs( - element, XmlParseErrorKind.InvalidValue, - $"The provided maxValue '{maxValue}' is above 100.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"The provided maxValue '{maxValue}' is above 100.", + }); } // TODO: Do we need to coerce maxValue??? @@ -55,8 +63,11 @@ public byte ParseWithRange(XElement element, byte minValue, byte maxValue) var clamped = PGMath.Clamp(value, minValue, maxValue); if (value != clamped) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected byte between {minValue} and {maxValue} but got value '{value}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected byte between {minValue} and {maxValue} but got value '{value}'.", + }); } return clamped; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs index 02b9f2f..6c63f7e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs @@ -21,8 +21,11 @@ protected internal override uint ParseCore(ReadOnlySpan trimmedValue, XEle var asUint = (uint)intValue; if (intValue != asUint) { - OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - $"Expected unsigned integer but got '{intValue}'.")); + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected unsigned integer but got '{intValue}'.", + }); } return asUint; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs index c148da2..311bd8c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs @@ -7,6 +7,9 @@ namespace PG.StarWarsGame.Files.XML.Parsers; + +// TODO: To XmlObjectParser + public sealed class XmlFileListParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : PetroglyphXmlFileParser(serviceProvider, errorReporter) { @@ -23,15 +26,21 @@ protected override XmlFileList Parse(XElement element, string fileName) var file = PetroglyphXmlStringParser.Instance.Parse(child); if (file.Length == 0) { - ErrorReporter?.Report(this, - new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, "Empty value in tag.")); + ErrorReporter?.Report(new XmlError(this, child) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = "Empty value in tag", + }); } files.Add(file); } else { - ErrorReporter?.Report(this, new XmlParseErrorEventArgs(child, XmlParseErrorKind.UnknownNode, - $"Tag '<{tagName}>' is not supported. Only '' is supported.")); + ErrorReporter?.Report(new XmlError(this, child) + { + ErrorKind = XmlParseErrorKind.UnknownNode, + Message = $"Tag '<{tagName}>' is not supported. Only '' is supported.", + }); } } return new XmlFileList(new ReadOnlyCollection(files)); From e0ca66e75324ef96f20d8894a9b9485d4eac2c0c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 15:47:11 +0100 Subject: [PATCH 06/41] refactor xml lib --- src/ModVerify.CliApp/Program.cs | 2 +- src/ModVerify/DefaultGameVerifiersProvider.cs | 10 +- .../Verifiers/DuplicateNameFinder.cs | 1 + .../Audio/Sfx/SfxEvent.cs | 4 +- .../CommandBar/Xml/CommandBarComponentData.cs | 4 +- .../GameConstants/GameConstantsXml.cs | 7 +- .../GameObjects/GameObject.cs | 1 + .../GuiDialog/Xml/GuiDialogsXml.cs | 1 + .../GuiDialog/Xml/GuiDialogsXmlTextureData.cs | 2 +- .../GuiDialog/Xml/XmlComponentTextureData.cs | 2 +- .../Xml/EngineXmlParser.cs | 81 +------------ .../FileObjects/GameConstantsParser.cs | 7 +- .../Parsers/FileObjects/GuiDialogParser.cs | 4 +- .../IPetroglyphXmlFileParserFactory.cs | 4 +- .../Xml/Parsers/PetroglyphXmlParserFactory.cs | 2 + .../Xml/XmlObjectParser.cs | 110 ------------------ .../Data}/NamedXmlObject.cs | 3 +- .../Data/XmlFileList.cs | 7 +- .../Data}/XmlObject.cs | 6 +- .../Base/IPetroglyphXmlElementParser.cs | 8 -- .../Base/IPetroglyphXmlFileContainerParser.cs | 12 -- .../Parsers/Base/IPetroglyphXmlFileParser.cs | 8 -- .../Parsers/Base/IXmlTagMapper.cs | 9 ++ .../Parsers/Base/XmlObjectParserBase.cs | 36 ++++++ .../Parsers/EmptyParseState.cs | 6 + .../IPetroglyphXmlNamedElementParser.cs | 10 -- .../Parsers/NamedXmlObjectParser.cs | 53 +++++++++ .../Parsers/PetroglyphXmlElementParser.cs | 10 -- .../PetroglyphPrimitiveXmlParser.cs | 4 +- ...nerParser.cs => XmlContainerFileParser.cs} | 9 +- .../Parsers/XmlFileListParser.cs | 13 +-- ...glyphXmlFileParser.cs => XmlFileParser.cs} | 13 ++- .../Parsers/XmlObjectParser.cs | 31 +++++ .../Parsers/XmlTagMapper.cs | 70 +++++++++++ 34 files changed, 267 insertions(+), 283 deletions(-) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs rename src/PetroglyphTools/{PG.StarWarsGame.Engine/Xml => PG.StarWarsGame.Files.XML/Data}/NamedXmlObject.cs (80%) rename src/PetroglyphTools/{PG.StarWarsGame.Engine/Xml => PG.StarWarsGame.Files.XML/Data}/XmlObject.cs (53%) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlElementParser.cs rename src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/{PetroglyphXmlFileContainerParser.cs => XmlContainerFileParser.cs} (71%) rename src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/{PetroglyphXmlFileParser.cs => XmlFileParser.cs} (50%) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs diff --git a/src/ModVerify.CliApp/Program.cs b/src/ModVerify.CliApp/Program.cs index 788d784..ba5bd31 100644 --- a/src/ModVerify.CliApp/Program.cs +++ b/src/ModVerify.CliApp/Program.cs @@ -52,7 +52,7 @@ private static Task Main(string[] args) internal class Program : SelfUpdateableAppLifecycle { private static readonly string EngineParserNamespace = typeof(EngineXmlParser).Namespace!; - private static readonly string ParserNamespace = typeof(PetroglyphXmlFileParser<>).Namespace!; + private static readonly string ParserNamespace = typeof(XmlFileParser<>).Namespace!; private static readonly string ModVerifyRootNameSpace = typeof(Program).Namespace!; private static readonly CompiledExpression PrintToConsoleExpression = SerilogExpression.Compile($"EventId.Id = {ModVerifyConstants.ConsoleEventIdValue}"); diff --git a/src/ModVerify/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs index e4bb0cd..b84ff87 100644 --- a/src/ModVerify/DefaultGameVerifiersProvider.cs +++ b/src/ModVerify/DefaultGameVerifiersProvider.cs @@ -15,10 +15,10 @@ public IEnumerable GetVerifiers( IServiceProvider serviceProvider) { yield break; - //yield return new ReferencedModelsVerifier(database, settings, serviceProvider); - //yield return new DuplicateNameFinder(database, settings, serviceProvider); - //yield return new AudioFilesVerifier(database, settings, serviceProvider); - //yield return new GuiDialogsVerifier(database, settings, serviceProvider); - //yield return new CommandBarVerifier(database, settings, serviceProvider); + yield return new ReferencedModelsVerifier(database, settings, serviceProvider); + yield return new DuplicateNameFinder(database, settings, serviceProvider); + yield return new AudioFilesVerifier(database, settings, serviceProvider); + yield return new GuiDialogsVerifier(database, settings, serviceProvider); + yield return new CommandBarVerifier(database, settings, serviceProvider); } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/DuplicateNameFinder.cs b/src/ModVerify/Verifiers/DuplicateNameFinder.cs index 0b3b585..600f090 100644 --- a/src/ModVerify/Verifiers/DuplicateNameFinder.cs +++ b/src/ModVerify/Verifiers/DuplicateNameFinder.cs @@ -10,6 +10,7 @@ using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.MTD.Data; using PG.StarWarsGame.Files.MTD.Files; +using PG.StarWarsGame.Files.XML.Data; namespace AET.ModVerify.Verifiers; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs index aed53f2..b9d32a0 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; using PG.Commons.Hashing; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.Audio.Sfx; @@ -163,7 +163,7 @@ internal SfxEvent(string name, Crc32 nameCrc, XmlLocationInfo location) { } - internal override void CoerceValues() + public override void CoerceValues() { AdjustMinMaxValues(ref _minVolume, ref _maxVolume); AdjustMinMaxValues(ref _minPitch, ref _maxPitch); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs index 057745e..40ab0c9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs @@ -4,8 +4,8 @@ using System.Numerics; using PG.Commons.Hashing; using PG.Commons.Numerics; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.CommandBar.Xml; @@ -128,7 +128,7 @@ public sealed class CommandBarComponentData(string name, Crc32 crc, XmlLocationI public Vector4Int? TextColor2 { get; internal set; } public Vector4Int? MaxBarColor { get; internal set; } = WhiteColor; - internal override void CoerceValues() + public override void CoerceValues() { base.CoerceValues(); if (AlternateFontNames.Count == 0) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstantsXml.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstantsXml.cs index e98ed52..5eae395 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstantsXml.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstantsXml.cs @@ -1,3 +1,6 @@ -namespace PG.StarWarsGame.Engine.GameConstants; +using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; -public class GameConstantsXml; \ No newline at end of file +namespace PG.StarWarsGame.Engine.GameConstants; + +public class GameConstantsXml(XmlLocationInfo location) : XmlObject(location); \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index de7ed01..f531df4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -4,6 +4,7 @@ using PG.Commons.Hashing; using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.GameObjects; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs index 72cc5a0..7621c15 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs @@ -1,5 +1,6 @@ using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.GuiDialog.Xml; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXmlTextureData.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXmlTextureData.cs index 6496417..c5e56b8 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXmlTextureData.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXmlTextureData.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.GuiDialog.Xml; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/XmlComponentTextureData.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/XmlComponentTextureData.cs index f102457..6b91547 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/XmlComponentTextureData.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/XmlComponentTextureData.cs @@ -1,7 +1,7 @@ using System; using AnakinRaW.CommonUtilities.Collections; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.GuiDialog.Xml; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs index b37a5f7..1dc4ce1 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Xml; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities; using AnakinRaW.CommonUtilities.Collections; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -65,7 +62,7 @@ public XmlFileList ParseFileList(string xmlFile) var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: true); XmlParseError?.Invoke(this, args); - return XmlFileList.Empty; + return XmlFileList.Empty(new XmlLocationInfo(xmlFile, null)); } XmlFileList? container; @@ -87,7 +84,7 @@ public XmlFileList ParseFileList(string xmlFile) var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: true); XmlParseError?.Invoke(this, args); - return XmlFileList.Empty; + return XmlFileList.Empty(new XmlLocationInfo(xmlFile, null)); } return container; @@ -103,7 +100,7 @@ public void ParseEntriesFromFileListXml( var xmlFiles = container.Files.Select(x => FileSystem.Path.Combine(lookupPath, x)).ToList(); - var parser = new PetroglyphXmlFileContainerParser(Services, + var parser = new XmlContainerFileParser(Services, _fileParserFactory.CreateNamedXmlObjectParser(_reporter), _reporter); foreach (var file in xmlFiles) @@ -116,8 +113,8 @@ public void ParseEntriesFromFileListXml( public bool ParseEntriesFromContainerFile( string xmlFile, - IPetroglyphXmlFileContainerParser parser, - IFrugalValueListDictionary entries) where T : notnull + XmlContainerFileParser parser, + IFrugalValueListDictionary entries) where T : NamedXmlObject { using var fileStream = _gameRepository.TryOpenFile(xmlFile); @@ -156,74 +153,6 @@ public bool ParseEntriesFromContainerFile( } } -public interface IXmlTagMapper where TObject : XmlObject -{ - bool TryParseEntry(XElement element, TObject target); -} - -public abstract class XmlTagMapper : IXmlTagMapper where TObject : XmlObject -{ - private const int MaxTagLength = 256; - - private delegate void ParserValueAction(TObject target, XElement element); - - private readonly Dictionary _tagMappings = new(); - private readonly ICrc32HashingService _crcService; - - protected XmlTagMapper(IServiceProvider serviceProvider) - { - if (serviceProvider == null) - throw new ArgumentNullException(nameof(serviceProvider)); - _crcService = serviceProvider.GetRequiredService(); - - // ReSharper disable once VirtualMemberCallInConstructor - BuildMappings(); - } - - protected abstract void BuildMappings(); - - protected void AddMapping(string tagName, Func parser, Action setter) - { - ThrowHelper.ThrowIfNullOrEmpty(tagName); - if (tagName.Length >= MaxTagLength) - throw new ArgumentOutOfRangeException( - $"Tag name '{tagName}' exceeds maximum length of {MaxTagLength} characters", nameof(tagName)); - - if (parser == null) - throw new ArgumentNullException(nameof(parser)); - if (setter == null) - throw new ArgumentNullException(nameof(setter)); - - var crc = GetCrc32(tagName); - - _tagMappings[crc] = (target, element) => - { - var value = parser(element); - setter(target, value); - }; - } - - public bool TryParseEntry(XElement element, TObject target) - { - var tagName = element.Name.LocalName; - if (tagName.Length >= MaxTagLength) - return false; - - var crc = GetCrc32(tagName); - - if (!_tagMappings.TryGetValue(crc, out var mapping)) - return false; - - mapping(target, element); - return true; - } - - private Crc32 GetCrc32(string tagName) - { - return _crcService.GetCrc32Upper(tagName, PGConstants.DefaultPGEncoding); - } -} - enum XmlDataType { DB_DATA_TYPE_BOOL = 0x0, diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs index 8100e2e..4c7e0d9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GameConstantsParser.cs @@ -1,16 +1,17 @@ using System; using System.Xml.Linq; using PG.StarWarsGame.Engine.GameConstants; +using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class GameConstantsParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : - PetroglyphXmlFileParser(serviceProvider, errorReporter) + XmlFileParser(serviceProvider, errorReporter) { - protected override GameConstantsXml Parse(XElement element, string fileName) + protected override GameConstantsXml ParseRoot(XElement element, string fileName) { - return new GameConstantsXml(); + return new GameConstantsXml(new XmlLocationInfo(fileName, null)); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs index 4c59922..e735dc3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs @@ -10,9 +10,9 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class GuiDialogParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : - PetroglyphXmlFileParser(serviceProvider, errorReporter) + XmlFileParser(serviceProvider, errorReporter) { - protected override GuiDialogsXml Parse(XElement element, string fileName) + protected override GuiDialogsXml ParseRoot(XElement element, string fileName) { var textures = ParseTextures(element.Element("Textures"), fileName); return new GuiDialogsXml(textures, XmlLocationInfo.FromElement(element)); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs index c821e46..c940274 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs @@ -1,4 +1,6 @@ -using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Parsers; namespace PG.StarWarsGame.Engine.Xml.Parsers; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs index 152617f..736b729 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs @@ -3,6 +3,8 @@ using PG.StarWarsGame.Engine.GameObjects; using PG.StarWarsGame.Files.XML.ErrorHandling; using System; +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.Parsers; namespace PG.StarWarsGame.Engine.Xml.Parsers; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs deleted file mode 100644 index 158f15c..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs +++ /dev/null @@ -1,110 +0,0 @@ -using AnakinRaW.CommonUtilities.Collections; -using PG.StarWarsGame.Files.XML; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; -using System; -using System.Text; -using System.Xml.Linq; -using Microsoft.Extensions.DependencyInjection; -using PG.Commons.Hashing; -using Crc32 = PG.Commons.Hashing.Crc32; - -namespace PG.StarWarsGame.Engine.Xml; - -public abstract class XmlObjectParserBase(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter) - : PetroglyphXmlParserBase(errorReporter) where TObject : XmlObject -{ - protected readonly IXmlTagMapper TagMapper = tagMapper ?? throw new ArgumentNullException(nameof(tagMapper)); - - protected virtual void ValidateValues(TObject namedXmlObject, XElement element) - { - } - - protected void Parse(TObject xmlObject, XElement element, in TParseState state) - { - foreach (var tag in element.Elements()) - { - if (!ParseTag(tag, xmlObject, state)) - { - ErrorReporter?.Report(new XmlError(this, element) - { - Message = $"The node '{tag.Name}' is not supported.", - ErrorKind = XmlParseErrorKind.UnknownNode - }); - } - } - } - - protected abstract bool ParseTag(XElement tag, TObject xmlObject, in TParseState parseState); -} - - -public abstract class NamedXmlObjectParser( - IServiceProvider serviceProvider, - IXmlTagMapper tagMapper, - IXmlParserErrorReporter? errorReporter) - : XmlObjectParserBase>(tagMapper, errorReporter), - IPetroglyphXmlNamedElementParser - where TObject : NamedXmlObject -{ - protected readonly ICrc32HashingService HashingService = serviceProvider.GetRequiredService(); - - public TObject Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) - { - var name = GetXmlObjectName(element, true, out nameCrc); - var namedXmlObject = CreateXmlObject(name, nameCrc, element, XmlLocationInfo.FromElement(element)); - Parse(namedXmlObject, element, parsedEntries); - ValidateValues(namedXmlObject, element); - namedXmlObject.CoerceValues(); - return namedXmlObject; - } - - protected abstract TObject CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location); - - protected string GetXmlObjectName(XElement element, bool uppercaseName, out Crc32 crc32) - { - GetNameAttributeValue(element, out var name); - crc32 = uppercaseName - ? HashingService.GetCrc32Upper(name.AsSpan(), Encoding.ASCII) - : HashingService.GetCrc32(name.AsSpan(), Encoding.ASCII); - - if (crc32 == default) - { - ErrorReporter?.Report(new XmlError(this, element) - { - Message = "Name for XmlObject cannot be empty.", - ErrorKind = XmlParseErrorKind.InvalidValue - }); - } - - return name; - } -} - -public abstract class XmlObjectParser(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParserBase(tagMapper, errorReporter), IPetroglyphXmlElementParser - where TObject : XmlObject -{ - public TObject Parse(XElement element) - { - var xmlObject = CreateXmlObject(XmlLocationInfo.FromElement(element)); - Parse(xmlObject, element, EmptyParseState.Instance); - ValidateValues(xmlObject, element); - xmlObject.CoerceValues(); - return xmlObject; - } - - protected abstract TObject CreateXmlObject(XmlLocationInfo location); - - protected sealed override bool ParseTag(XElement tag, TObject xmlObject, in EmptyParseState parseState) - { - return ParseTag(tag, xmlObject); - } - - protected abstract bool ParseTag(XElement tag, TObject xmlObject); -} - -public readonly struct EmptyParseState -{ - public static readonly EmptyParseState Instance = new(); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/NamedXmlObject.cs similarity index 80% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs rename to src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/NamedXmlObject.cs index 6118f99..2222633 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/NamedXmlObject.cs @@ -1,8 +1,7 @@ using System; using PG.Commons.Hashing; -using PG.StarWarsGame.Files.XML; -namespace PG.StarWarsGame.Engine.Xml; +namespace PG.StarWarsGame.Files.XML.Data; public abstract class NamedXmlObject(string name, Crc32 nameCrc, XmlLocationInfo location) : XmlObject(location) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs index 9ea4b34..aef7f43 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlFileList.cs @@ -2,9 +2,12 @@ namespace PG.StarWarsGame.Files.XML.Data; -public class XmlFileList(IReadOnlyList files) +public class XmlFileList(IReadOnlyList files, XmlLocationInfo location) : XmlObject(location) { - public static readonly XmlFileList Empty = new([]); + public static XmlFileList Empty(XmlLocationInfo location) + { + return new XmlFileList([], location); + } public IReadOnlyList Files { get; } = files; } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs similarity index 53% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObject.cs rename to src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs index 71840fe..090d4d9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs @@ -1,12 +1,10 @@ -using PG.StarWarsGame.Files.XML; - -namespace PG.StarWarsGame.Engine.Xml; +namespace PG.StarWarsGame.Files.XML.Data; public abstract class XmlObject(XmlLocationInfo location) { public XmlLocationInfo Location { get; } = location; - internal virtual void CoerceValues() + public virtual void CoerceValues() { } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs deleted file mode 100644 index f5a6e95..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlElementParser.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Xml.Linq; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public interface IPetroglyphXmlElementParser : IPetroglyphXmlParserInfo where T : notnull -{ - T Parse(XElement element); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs deleted file mode 100644 index 690bb0c..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileContainerParser.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.IO; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public interface IPetroglyphXmlFileContainerParser : IPetroglyphXmlParserInfo where T : notnull -{ - IPetroglyphXmlNamedElementParser ElementParser { get; } - - void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs deleted file mode 100644 index 51850de..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IPetroglyphXmlFileParser.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.IO; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public interface IPetroglyphXmlFileParser : IPetroglyphXmlParserInfo where T : notnull -{ - T ParseFile(Stream xmlStream); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs new file mode 100644 index 0000000..5db7353 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs @@ -0,0 +1,9 @@ +using System.Xml.Linq; +using PG.StarWarsGame.Files.XML.Data; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public interface IXmlTagMapper where T : XmlObject +{ + bool TryParseEntry(XElement element, T target); +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs new file mode 100644 index 0000000..877ceab --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs @@ -0,0 +1,36 @@ +using System; +using System.Xml.Linq; +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public abstract class XmlObjectParserBase(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter) + : PetroglyphXmlParserBase(errorReporter) where TObject : XmlObject +{ + protected readonly IXmlTagMapper XmlTagMapper = tagMapper ?? throw new ArgumentNullException(nameof(tagMapper)); + + protected virtual void ValidateValues(TObject namedXmlObject, XElement element) + { + } + + protected void Parse(TObject xmlObject, XElement element, in TParseState state) + { + foreach (var tag in element.Elements()) + { + if (!ParseTag(tag, xmlObject, state)) + { + ErrorReporter?.Report(new XmlError(this, element) + { + Message = $"The node '{tag.Name}' is not supported.", + ErrorKind = XmlParseErrorKind.UnknownNode + }); + } + } + } + + protected virtual bool ParseTag(XElement tag, TObject xmlObject, in TParseState parseState) + { + return XmlTagMapper.TryParseEntry(tag, xmlObject); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs new file mode 100644 index 0000000..c8eac60 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs @@ -0,0 +1,6 @@ +namespace PG.StarWarsGame.Files.XML.Parsers; + +public readonly struct EmptyParseState +{ + public static readonly EmptyParseState Instance = new(); +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs deleted file mode 100644 index faec508..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IPetroglyphXmlNamedElementParser.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public interface IPetroglyphXmlNamedElementParser : IPetroglyphXmlParserInfo where T : notnull -{ - T Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs new file mode 100644 index 0000000..4b206af --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs @@ -0,0 +1,53 @@ +using System; +using System.Text; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; +using Microsoft.Extensions.DependencyInjection; +using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public abstract class NamedXmlObjectParser( + IServiceProvider serviceProvider, + IXmlTagMapper tagMapper, + IXmlParserErrorReporter? errorReporter) + : XmlObjectParserBase>(tagMapper, errorReporter) + where TObject : NamedXmlObject +{ + protected virtual bool UpperCaseNameForCrc => true; + + protected readonly ICrc32HashingService HashingService = serviceProvider.GetRequiredService(); + + public TObject Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) + { + var name = GetXmlObjectName(element, out nameCrc); + var namedXmlObject = CreateXmlObject(name, nameCrc, element, XmlLocationInfo.FromElement(element)); + Parse(namedXmlObject, element, parsedEntries); + ValidateValues(namedXmlObject, element); + namedXmlObject.CoerceValues(); + return namedXmlObject; + } + + protected abstract TObject CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location); + + private string GetXmlObjectName(XElement element, out Crc32 crc32) + { + GetNameAttributeValue(element, out var name); + crc32 = UpperCaseNameForCrc + ? HashingService.GetCrc32Upper(name.AsSpan(), Encoding.ASCII) + : HashingService.GetCrc32(name.AsSpan(), Encoding.ASCII); + + if (crc32 == default) + { + ErrorReporter?.Report(new XmlError(this, element) + { + Message = $"Name for XML object of type {typeof(TObject).Name} cannot be empty.", + ErrorKind = XmlParseErrorKind.InvalidValue + }); + } + + return name; + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlElementParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlElementParser.cs deleted file mode 100644 index 5fa2c6d..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlElementParser.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public abstract class PetroglyphXmlElementParser(IXmlParserErrorReporter? errorReporter = null) - : PetroglyphXmlParserBase(errorReporter), IPetroglyphXmlElementParser where T : notnull -{ - public abstract T Parse(XElement element); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs index 198b4de..ddd3b24 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs @@ -4,7 +4,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public abstract class PetroglyphPrimitiveXmlParser : PetroglyphXmlElementParser where T : notnull +public abstract class PetroglyphPrimitiveXmlParser : PetroglyphXmlParserBase where T : notnull { private protected abstract T DefaultValue { get; } @@ -12,7 +12,7 @@ private protected PetroglyphPrimitiveXmlParser() : base(PrimitiveXmlErrorReporte { } - public sealed override T Parse(XElement element) + public T Parse(XElement element) { var tagName = element.Name.LocalName; if (string.IsNullOrEmpty(tagName)) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs similarity index 71% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs index 9441c6f..12f0f5d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileContainerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs @@ -3,16 +3,17 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; using System; using System.IO; +using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Files.XML.Parsers; -public sealed class PetroglyphXmlFileContainerParser( +public sealed class XmlContainerFileParser( IServiceProvider serviceProvider, - IPetroglyphXmlNamedElementParser elementParser, + NamedXmlObjectParser elementParser, IXmlParserErrorReporter? listener = null) - : PetroglyphXmlFileParserBase(serviceProvider, listener), IPetroglyphXmlFileContainerParser where T : notnull + : PetroglyphXmlFileParserBase(serviceProvider, listener) where T : NamedXmlObject { - public IPetroglyphXmlNamedElementParser ElementParser { get; } = + public NamedXmlObjectParser ElementParser { get; } = elementParser ?? throw new ArgumentNullException(nameof(elementParser)); public void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs index 311bd8c..d96d497 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs @@ -7,15 +7,10 @@ namespace PG.StarWarsGame.Files.XML.Parsers; - -// TODO: To XmlObjectParser - public sealed class XmlFileListParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : - PetroglyphXmlFileParser(serviceProvider, errorReporter) -{ - protected override bool LoadLineInfo => false; - - protected override XmlFileList Parse(XElement element, string fileName) + XmlFileParser(serviceProvider, errorReporter) +{ + protected override XmlFileList ParseRoot(XElement element, string fileName) { var files = new List(); foreach (var child in element.Elements()) @@ -43,6 +38,6 @@ protected override XmlFileList Parse(XElement element, string fileName) }); } } - return new XmlFileList(new ReadOnlyCollection(files)); + return new XmlFileList(new ReadOnlyCollection(files), new XmlLocationInfo(fileName, null)); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileParser.cs similarity index 50% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileParser.cs index 7a5e581..8890a61 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileParser.cs @@ -1,18 +1,19 @@ -using System; +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; using System.IO; using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; namespace PG.StarWarsGame.Files.XML.Parsers; -public abstract class PetroglyphXmlFileParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : PetroglyphXmlFileParserBase(serviceProvider, errorReporter), IPetroglyphXmlFileParser where T : notnull +public abstract class XmlFileParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) + : PetroglyphXmlFileParserBase(serviceProvider, errorReporter) where T : XmlObject { public T ParseFile(Stream xmlStream) { var root = GetRootElement(xmlStream, out var fileName); - return Parse(root, fileName); + return ParseRoot(root, fileName); } - protected abstract T Parse(XElement element, string fileName); + protected abstract T ParseRoot(XElement element, string fileName); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs new file mode 100644 index 0000000..c716a6e --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs @@ -0,0 +1,31 @@ +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System.Xml.Linq; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public abstract class XmlObjectParser(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter = null) + : XmlObjectParserBase(tagMapper, errorReporter) + where TObject : XmlObject +{ + public TObject Parse(XElement element) + { + var xmlObject = CreateXmlObject(XmlLocationInfo.FromElement(element)); + Parse(xmlObject, element, EmptyParseState.Instance); + ValidateValues(xmlObject, element); + xmlObject.CoerceValues(); + return xmlObject; + } + + protected abstract TObject CreateXmlObject(XmlLocationInfo location); + + protected sealed override bool ParseTag(XElement tag, TObject xmlObject, in EmptyParseState parseState) + { + return ParseTag(tag, xmlObject); + } + + protected virtual bool ParseTag(XElement tag, TObject xmlObject) + { + return XmlTagMapper.TryParseEntry(tag, xmlObject); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs new file mode 100644 index 0000000..366ccaf --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using AnakinRaW.CommonUtilities; +using Microsoft.Extensions.DependencyInjection; +using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML.Data; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public abstract class XmlTagMapper : IXmlTagMapper where TObject : XmlObject +{ + private delegate void ParserValueAction(TObject target, XElement element); + + private readonly Dictionary _tagMappings = new(); + private readonly ICrc32HashingService _crcService; + + protected XmlTagMapper(IServiceProvider serviceProvider) + { + if (serviceProvider == null) + throw new ArgumentNullException(nameof(serviceProvider)); + _crcService = serviceProvider.GetRequiredService(); + + // ReSharper disable once VirtualMemberCallInConstructor + BuildMappings(); + } + + protected abstract void BuildMappings(); + + protected void AddMapping(string tagName, Func parser, Action setter) + { + ThrowHelper.ThrowIfNullOrEmpty(tagName); + if (tagName.Length >= XmlFileConstants.MaxTagNameLength) + throw new ArgumentOutOfRangeException( + $"Tag name '{tagName}' exceeds maximum length of {XmlFileConstants.MaxTagNameLength} characters", nameof(tagName)); + + if (parser == null) + throw new ArgumentNullException(nameof(parser)); + if (setter == null) + throw new ArgumentNullException(nameof(setter)); + + var crc = GetCrc32(tagName); + + _tagMappings[crc] = (target, element) => + { + var value = parser(element); + setter(target, value); + }; + } + + public bool TryParseEntry(XElement element, TObject target) + { + var tagName = element.Name.LocalName; + if (tagName.Length >= XmlFileConstants.MaxTagNameLength) + return false; + + var crc = GetCrc32(tagName); + + if (!_tagMappings.TryGetValue(crc, out var mapping)) + return false; + + mapping(target, element); + return true; + } + + private Crc32 GetCrc32(string tagName) + { + return _crcService.GetCrc32Upper(tagName, XmlFileConstants.XmlEncoding); + } +} \ No newline at end of file From 37353f8bd2ff1e1bc69140c791838852b3d04c6c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 16:16:56 +0100 Subject: [PATCH 07/41] refactor --- .../Audio/Sfx/SfxEventGameManager.cs | 45 +++------ .../CommandBar/CommandBarGameManager.cs | 48 +++------- .../GameEngineErrorReporterWrapper.cs | 18 +--- .../GameObjects/GameObjectTypeGameManager.cs | 87 +++++++---------- .../Xml/EngineXmlParserErrorEventArgs.cs | 25 ----- .../PetroglyphStarWarsGameXmlParseSettings.cs | 10 ++ ....cs => PetroglyphStarWarsGameXmlParser.cs} | 93 ++++++++++++------- 7 files changed, 131 insertions(+), 195 deletions(-) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{EngineXmlParser.cs => PetroglyphStarWarsGameXmlParser.cs} (75%) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs index 89645d4..46741bc 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs @@ -24,41 +24,20 @@ protected override async Task InitializeCoreAsync(CancellationToken token) Logger?.LogInformation("Parsing SFXEvents..."); - var contentParser = new EngineXmlParser(GameRepository, ServiceProvider, ErrorReporter); - contentParser.XmlParseError += OnParseError; - try - { - await Task.Run(() => contentParser.ParseEntriesFromFileListXml( - "DATA\\XML\\SFXEventFiles.XML", - "DATA\\XML", - NamedEntries, - VerifyFilePathLength), - token); - } - finally - { - contentParser.XmlParseError -= OnParseError; - } - } - - private void OnParseError(object sender, EngineXmlParserErrorEventArgs e) - { - if (e.ErrorInXmlFileList || e.HasException) - { - e.Continue = false; - ErrorReporter.Report(new InitializationError + var contentParser = new PetroglyphStarWarsGameXmlParser(GameRepository, + new PetroglyphStarWarsGameXmlParseSettings { GameManager = ToString(), - Message = GetMessage(e) - }); - } - } - - private static string GetMessage(EngineXmlParserErrorEventArgs errorEventArgs) - { - if (errorEventArgs.HasException) - return $"Error while parsing SFXEvent XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; - return "Could not find SFXEventFiles.xml"; + InvalidContainerXmlFailsInitialization = true, + InvalidFilesListXmlFailsInitialization = true + }, ServiceProvider, ErrorReporter); + + await Task.Run(() => contentParser.ParseEntriesFromFileListXml( + "DATA\\XML\\SFXEventFiles.XML", + "DATA\\XML", + NamedEntries, + VerifyFilePathLength), + token); } private void VerifyFilePathLength(string filePath) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index b9e5848..4ad531f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -8,7 +8,6 @@ using PG.StarWarsGame.Engine.IO.Repositories; using PG.StarWarsGame.Engine.Rendering; using PG.StarWarsGame.Engine.Rendering.Font; -using PG.StarWarsGame.Engine.Xml.Parsers; using PG.StarWarsGame.Files.Binary; using PG.StarWarsGame.Files.MTD.Files; using PG.StarWarsGame.Files.MTD.Services; @@ -75,24 +74,21 @@ protected override async Task InitializeCoreAsync(CancellationToken token) { Logger?.LogInformation("Creating command bar components..."); - var contentParser = new EngineXmlParser(GameRepository, ServiceProvider, ErrorReporter); - contentParser.XmlParseError += OnParseError; + var contentParser = new PetroglyphStarWarsGameXmlParser(GameRepository, new PetroglyphStarWarsGameXmlParseSettings + { + GameManager = ToString(), + InvalidContainerXmlFailsInitialization = true, + InvalidFilesListXmlFailsInitialization = true + }, ServiceProvider, ErrorReporter); var parsedCommandBarComponents = new FrugalValueListDictionary(); - try - { - await Task.Run(() => contentParser.ParseEntriesFromFileListXml( - "DATA\\XML\\CommandBarComponentFiles.XML", - ".\\DATA\\XML", - parsedCommandBarComponents, - VerifyFilePathLength), - token); - } - finally - { - contentParser.XmlParseError -= OnParseError; - } + await Task.Run(() => contentParser.ParseEntriesFromFileListXml( + "DATA\\XML\\CommandBarComponentFiles.XML", + ".\\DATA\\XML", + parsedCommandBarComponents, + VerifyFilePathLength), + token); // Create Scene // Create Camera @@ -259,26 +255,6 @@ private void SetComponentGroup(IEnumerable components) } } - private void OnParseError(object sender, EngineXmlParserErrorEventArgs e) - { - if (e.ErrorInXmlFileList || e.HasException) - { - e.Continue = false; - ErrorReporter.Report(new InitializationError - { - GameManager = ToString(), - Message = GetMessage(e) - }); - } - } - - private static string GetMessage(EngineXmlParserErrorEventArgs errorEventArgs) - { - if (errorEventArgs.HasException) - return $"Error while parsing CommandBar XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; - return "Could not find CommandBarComponentFiles.xml"; - } - private void VerifyFilePathLength(string filePath) { if (filePath.Length > PGConstants.MaxCommandBarDatabaseFileName) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs index 320a2c7..a8280cc 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/GameEngineErrorReporterWrapper.cs @@ -3,32 +3,24 @@ namespace PG.StarWarsGame.Engine.ErrorReporting; -internal sealed class GameEngineErrorReporterWrapper : XmlErrorReporter, IGameEngineErrorReporter +internal sealed class GameEngineErrorReporterWrapper(IGameEngineErrorReporter? errorReporter) + : XmlErrorReporter, IGameEngineErrorReporter { internal event EventHandler? InitializationError; - private readonly IGameEngineErrorReporter? _errorReporter; - - public GameEngineErrorReporterWrapper(IGameEngineErrorReporter? errorReporter) - { - if (errorReporter is null) - return; - _errorReporter = errorReporter; - } - public override void Report(XmlError error) { - _errorReporter?.Report(error); + errorReporter?.Report(error); } public void Report(InitializationError error) { InitializationError?.Invoke(this, error); - _errorReporter?.Report(error); + errorReporter?.Report(error); } public void Assert(EngineAssert assert) { - _errorReporter?.Assert(assert); + errorReporter?.Assert(assert); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index aed5848..7652704 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -22,48 +22,47 @@ protected override async Task InitializeCoreAsync(CancellationToken token) private void ParseGameObjectDatabases() { - var parser = new EngineXmlParser(GameRepository, ServiceProvider, ErrorReporter); - parser.XmlParseError += OnParseError; - try - { - var xmlFileList = parser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files - .Select(x => - { - var filePath = FileSystem.Path.Combine(@".\DATA\XML\", x); - VerifyFilePathLength(filePath); - return filePath; - }).ToList(); + var parser = new PetroglyphStarWarsGameXmlParser(GameRepository, + new PetroglyphStarWarsGameXmlParseSettings + { + GameManager = ToString(), + InvalidFilesListXmlFailsInitialization = true, + InvalidContainerXmlFailsInitialization = false, + }, ServiceProvider, ErrorReporter); + + var xmlFileList = parser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files + .Select(x => + { + var filePath = FileSystem.Path.Combine(@".\DATA\XML\", x); + VerifyFilePathLength(filePath); + return filePath; + }).ToList(); + + //var gameObjectFileParser = new GameObjectFileParser(serviceProvider, errorReporter); - //var gameObjectFileParser = new GameObjectFileParser(serviceProvider, errorReporter); - - var allLoaded = false; - for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++) + var allLoaded = false; + for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++) + { + foreach (var gameObjectXmlFile in xmlFileList) { - foreach (var gameObjectXmlFile in xmlFileList) + if (passNumber == 0) + { + //ParseSingleGameObjectFile(gameObjectXmlFile, parser, gameObjectFileParser); + } + else { - if (passNumber == 0) - { - //ParseSingleGameObjectFile(gameObjectXmlFile, parser, gameObjectFileParser); - } - else - { - } } + } - //GameObjectTypeClass::Static_Post_Load_Fixup(); - //SFXEventReferenceClass::Static_Post_Load_Fixup(); - //SpeechEventReferenceClass::Static_Post_Load_Fixup(); - //MusicEventReferenceClass::Static_Post_Load_Fixup(); - //FactionReferenceClass::Static_Post_Load_Fixup(); - //... - } - } - finally - { - parser.XmlParseError -= OnParseError; + //GameObjectTypeClass::Static_Post_Load_Fixup(); + //SFXEventReferenceClass::Static_Post_Load_Fixup(); + //SpeechEventReferenceClass::Static_Post_Load_Fixup(); + //MusicEventReferenceClass::Static_Post_Load_Fixup(); + //FactionReferenceClass::Static_Post_Load_Fixup(); + //... } } @@ -72,26 +71,6 @@ private void ParseGameObjectDatabases() // engineParser.ParseEntriesFromContainerFile(gameObjectFileParser, file, NamedEntries); //} - - private void OnParseError(object sender, EngineXmlParserErrorEventArgs e) - { - if (e.ErrorInXmlFileList) - { - ErrorReporter.Report(new InitializationError - { - GameManager = ToString(), - Message = GetMessage(e) - }); - } - } - - private static string GetMessage(EngineXmlParserErrorEventArgs errorEventArgs) - { - if (errorEventArgs.HasException) - return $"Error while parsing XML file '{errorEventArgs.File}': {errorEventArgs.Exception.Message}"; - return "Could not find GameObjectFiles.xml"; - } - private void VerifyFilePathLength(string filePath) { if (filePath.Length > PGConstants.MaxGameObjectDatabaseFileName) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs deleted file mode 100644 index 8026804..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParserErrorEventArgs.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Xml; - -namespace PG.StarWarsGame.Engine.Xml; - -public class EngineXmlParserErrorEventArgs(string file, XmlException? exception = null, bool isXmlFileList = false) -{ - public bool Continue - { - get; - // Once this is set to false, there is no way back. - set => field &= value; - } = true; - - public bool ErrorInXmlFileList { get; } = isXmlFileList; - - public string File { get; } = file; - - [MemberNotNullWhen(true, nameof(Exception))] - public bool HasException => Exception is not null; - - public bool IsFileNotFound => !HasException; - - public XmlException? Exception { get; } = exception; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs new file mode 100644 index 0000000..c3827fa --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs @@ -0,0 +1,10 @@ +namespace PG.StarWarsGame.Engine.Xml; + +public sealed record PetroglyphStarWarsGameXmlParseSettings +{ + public required string GameManager { get; init; } + + public bool InvalidFilesListXmlFailsInitialization { get; init; } = true; + + public bool InvalidContainerXmlFailsInitialization { get; init; } = false; +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs similarity index 75% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs index 1dc4ce1..7e27965 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EngineXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using PG.Commons.Hashing; using PG.Commons.Services; +using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO; using PG.StarWarsGame.Engine.Xml.Parsers; using PG.StarWarsGame.Files.XML; @@ -15,32 +16,24 @@ namespace PG.StarWarsGame.Engine.Xml; - -public sealed record EngineXmlParseSettings +public sealed class PetroglyphStarWarsGameXmlParser : ServiceBase, IPetroglyphXmlParserInfo { - public bool InvalidFilesListXmlFailsInitialization { get; init; } = true; - - public bool InvalidContainerXmlFailsInitialization { get; init; } = false; -} - - -public sealed class EngineXmlParser : ServiceBase, IPetroglyphXmlParserInfo -{ - public event EventHandler? XmlParseError; - private readonly IGameRepository _gameRepository; - private readonly IXmlParserErrorReporter? _reporter; + private readonly PetroglyphStarWarsGameXmlParseSettings _settings; + private readonly IGameEngineErrorReporter _reporter; private readonly IPetroglyphXmlFileParserFactory _fileParserFactory; public string Name { get; } - public EngineXmlParser( - IGameRepository gameRepository, + public PetroglyphStarWarsGameXmlParser( + IGameRepository gameRepository, + PetroglyphStarWarsGameXmlParseSettings settings, IServiceProvider serviceProvider, - IXmlParserErrorReporter? reporter) + IGameEngineErrorReporter reporter) : base(serviceProvider) { _gameRepository = gameRepository; + _settings = settings; _reporter = reporter; _fileParserFactory = serviceProvider.GetRequiredService(); Name = GetType().FullName!; @@ -53,15 +46,25 @@ public XmlFileList ParseFileList(string xmlFile) using var containerStream = _gameRepository.TryOpenFile(xmlFile); if (containerStream == null) { - _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) + var message = $"Could not find XML file '{xmlFile}'"; + + Logger.LogWarning(message); + + _reporter.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) { - Message = "Xml file not found", + Message = message, ErrorKind = XmlParseErrorKind.MissingFile }); - Logger.LogWarning("Could not find XML file '{XmlFile}'", xmlFile); + + if (_settings.InvalidFilesListXmlFailsInitialization) + { + _reporter.Report(new InitializationError + { + GameManager = _settings.GameManager, + Message = message, + }); + } - var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: true); - XmlParseError?.Invoke(this, args); return XmlFileList.Empty(new XmlLocationInfo(xmlFile, null)); } @@ -76,14 +79,21 @@ public XmlFileList ParseFileList(string xmlFile) } catch (XmlException e) { - _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) + _reporter.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) { ErrorKind = XmlParseErrorKind.Unknown, Message = e.Message, }); - var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: true); - XmlParseError?.Invoke(this, args); + if (_settings.InvalidFilesListXmlFailsInitialization) + { + _reporter.Report(new InitializationError + { + GameManager = _settings.GameManager, + Message = e.Message, + }); + } + return XmlFileList.Empty(new XmlLocationInfo(xmlFile, null)); } @@ -120,16 +130,25 @@ public bool ParseEntriesFromContainerFile( if (fileStream is null) { - _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) + var message = $"Could not find XML file '{xmlFile}'"; + Logger.LogWarning(message); + + _reporter.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) { - Message = "Xml file not found", + Message = message, ErrorKind = XmlParseErrorKind.MissingFile }); - Logger.LogWarning("Could not find XML file '{File}'", xmlFile); + + if (_settings.InvalidContainerXmlFailsInitialization) + { + _reporter.Report(new InitializationError + { + GameManager = _settings.GameManager, + Message = message, + }); + } - var args = new EngineXmlParserErrorEventArgs(xmlFile, isXmlFileList: false); - XmlParseError?.Invoke(this, args); - return args.Continue; + return _settings.InvalidContainerXmlFailsInitialization; } Logger.LogDebug("Parsing File '{File}'", xmlFile); @@ -141,14 +160,20 @@ public bool ParseEntriesFromContainerFile( } catch (XmlException e) { - _reporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) + _reporter.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) { ErrorKind = XmlParseErrorKind.Unknown, Message = e.Message, }); - var args = new EngineXmlParserErrorEventArgs(xmlFile, e, isXmlFileList: false); - XmlParseError?.Invoke(this, args); - return args.Continue; + if (_settings.InvalidContainerXmlFailsInitialization) + { + _reporter.Report(new InitializationError + { + GameManager = _settings.GameManager, + Message = e.Message, + }); + } + return _settings.InvalidContainerXmlFailsInitialization; } } } From 5b44a6878f083641db844a5c7e64e1c3882390be Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 16:17:07 +0100 Subject: [PATCH 08/41] improve error reports --- src/ModVerify.CliApp/Program.cs | 2 +- src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ModVerify.CliApp/Program.cs b/src/ModVerify.CliApp/Program.cs index ba5bd31..e5316f4 100644 --- a/src/ModVerify.CliApp/Program.cs +++ b/src/ModVerify.CliApp/Program.cs @@ -51,7 +51,7 @@ private static Task Main(string[] args) internal class Program : SelfUpdateableAppLifecycle { - private static readonly string EngineParserNamespace = typeof(EngineXmlParser).Namespace!; + private static readonly string EngineParserNamespace = typeof(PetroglyphStarWarsGameXmlParser).Namespace!; private static readonly string ParserNamespace = typeof(XmlFileParser<>).Namespace!; private static readonly string ModVerifyRootNameSpace = typeof(Program).Namespace!; private static readonly CompiledExpression PrintToConsoleExpression = SerilogExpression.Compile($"EventId.Id = {ModVerifyConstants.ConsoleEventIdValue}"); diff --git a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs index b29fce0..9607cf1 100644 --- a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs +++ b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs @@ -28,7 +28,8 @@ protected override ErrorData CreateError(XmlError error) var context = new List { - strippedFileName + $"Parser: {error.Parser.Name}", + $"File: {strippedFileName}" }; var xmlElement = error.Element; From 572787518d78088cdb193dd0ac8a8b1b06df657c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 16:47:25 +0100 Subject: [PATCH 09/41] unify checks and filelist parser behaves like engine --- .../GameObjects/GameObjectTypeGameManager.cs | 1 - .../Parsers/Base/PetroglyphXmlParserBase.cs | 26 +++++++++++++++++ .../Parsers/Base/XmlObjectParserBase.cs | 2 +- .../PetroglyphPrimitiveXmlParser.cs | 21 +------------- .../Parsers/XmlFileListParser.cs | 29 ++++++++++--------- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 7652704..5830262 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -2,7 +2,6 @@ using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO.Repositories; using PG.StarWarsGame.Engine.Xml; -using PG.StarWarsGame.Engine.Xml.Parsers; using System; using System.Linq; using System.Threading; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs index 4e05ac1..2a6a1e2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs @@ -15,6 +15,32 @@ public override string ToString() return Name; } + protected bool IsTagValid(XElement element) + { + var tagName = element.Name.LocalName; + if (string.IsNullOrEmpty(tagName)) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.EmptyNodeName, + Message = "A tag name cannot be null or empty.", + }); + return false; + } + + if (tagName.Length > XmlFileConstants.MaxTagNameLength) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.TooLongData, + Message = $"A tag name can be only {XmlFileConstants.MaxTagNameLength} chars long.", + }); + return false; + } + + return true; + } + protected PetroglyphXmlParserBase(IXmlParserErrorReporter? errorReporter) { Name = GetType().FullName!; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs index 877ceab..ff59d8a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs @@ -31,6 +31,6 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) protected virtual bool ParseTag(XElement tag, TObject xmlObject, in TParseState parseState) { - return XmlTagMapper.TryParseEntry(tag, xmlObject); + return IsTagValid(tag) && XmlTagMapper.TryParseEntry(tag, xmlObject); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs index ddd3b24..4df9467 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs @@ -14,27 +14,8 @@ private protected PetroglyphPrimitiveXmlParser() : base(PrimitiveXmlErrorReporte public T Parse(XElement element) { - var tagName = element.Name.LocalName; - if (string.IsNullOrEmpty(tagName)) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.EmptyNodeName, - Message = "A tag name cannot be null or empty.", - }); + if (IsTagValid(element)) return DefaultValue; - } - - if (tagName.Length > XmlFileConstants.MaxTagNameLength) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.TooLongData, - Message = $"A tag name can be only {XmlFileConstants.MaxTagNameLength} chars long.", - }); - return DefaultValue; - } - var value = element.Value.AsSpan().Trim(); return value.Length == 0 ? DefaultValue : ParseCore(value, element); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs index d96d497..641f59e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs @@ -16,27 +16,30 @@ protected override XmlFileList ParseRoot(XElement element, string fileName) foreach (var child in element.Elements()) { var tagName = GetTagName(child); - if (tagName == "File") + if (tagName != "File") { - var file = PetroglyphXmlStringParser.Instance.Parse(child); - if (file.Length == 0) + ErrorReporter?.Report(new XmlError(this, child) { - ErrorReporter?.Report(new XmlError(this, child) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = "Empty value in tag", - }); - } - files.Add(file); + ErrorKind = XmlParseErrorKind.UnknownNode, + Message = $"Tag '<{tagName}>' is not supported. Only '' is supported.", + }); } - else + + // NB: There intentionally is not else branch here, because that's how the engine behaves. + // It checks whether the tag is called "File" and reports an assert if not. + // However, it still consumes the value and treats it as file. + + var file = PetroglyphXmlStringParser.Instance.Parse(child); + if (file.Length == 0) { ErrorReporter?.Report(new XmlError(this, child) { - ErrorKind = XmlParseErrorKind.UnknownNode, - Message = $"Tag '<{tagName}>' is not supported. Only '' is supported.", + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = "Empty value in tag", }); } + + files.Add(file); } return new XmlFileList(new ReadOnlyCollection(files), new XmlLocationInfo(fileName, null)); } From 6696329355904f9dae0a1b32d8a9c5d48d56e4c5 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 17:42:57 +0100 Subject: [PATCH 10/41] fix parsers --- .../Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs index 4df9467..2cece9c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs @@ -14,7 +14,7 @@ private protected PetroglyphPrimitiveXmlParser() : base(PrimitiveXmlErrorReporte public T Parse(XElement element) { - if (IsTagValid(element)) + if (!IsTagValid(element)) return DefaultValue; var value = element.Value.AsSpan().Trim(); return value.Length == 0 ? DefaultValue : ParseCore(value, element); From be101eefb9b942246b8806d345b31de64097fa7c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Feb 2026 18:57:59 +0100 Subject: [PATCH 11/41] support tags with child nodes --- .../Reporting/Engine/XmlParseErrorReporter.cs | 2 ++ src/ModVerify/Verifiers/DuplicateNameFinder.cs | 1 - src/ModVerify/Verifiers/VerifierErrorCodes.cs | 1 + .../ErrorHandling/XmlParseErrorKind.cs | 6 +++++- .../Parsers/Base/PetroglyphXmlParserBase.cs | 9 +++++++++ .../Parsers/Base/XmlObjectParserBase.cs | 8 ++++++++ .../Parsers/NamedXmlObjectParser.cs | 14 +++++++------- 7 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs index 9607cf1..83c3bbe 100644 --- a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs +++ b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs @@ -75,6 +75,7 @@ private static VerificationSeverity GetSeverityFromError(XmlParseErrorKind xmlEr XmlParseErrorKind.DataBeforeHeader => VerificationSeverity.Information, XmlParseErrorKind.MissingNode => VerificationSeverity.Critical, XmlParseErrorKind.UnknownNode => VerificationSeverity.Information, + XmlParseErrorKind.TagHasElements => VerificationSeverity.Warning, _ => VerificationSeverity.Warning }; } @@ -94,6 +95,7 @@ private static string GetIdFromError(XmlParseErrorKind xmlErrorErrorKind) XmlParseErrorKind.DataBeforeHeader => VerifierErrorCodes.XmlDataBeforeHeader, XmlParseErrorKind.MissingNode => VerifierErrorCodes.XmlMissingNode, XmlParseErrorKind.UnknownNode => VerifierErrorCodes.XmlUnsupportedTag, + XmlParseErrorKind.TagHasElements => VerifierErrorCodes.XmlElementsInTag, _ => throw new ArgumentOutOfRangeException(nameof(xmlErrorErrorKind), xmlErrorErrorKind, null) }; } diff --git a/src/ModVerify/Verifiers/DuplicateNameFinder.cs b/src/ModVerify/Verifiers/DuplicateNameFinder.cs index 600f090..c6b3089 100644 --- a/src/ModVerify/Verifiers/DuplicateNameFinder.cs +++ b/src/ModVerify/Verifiers/DuplicateNameFinder.cs @@ -7,7 +7,6 @@ using AnakinRaW.CommonUtilities.Collections; using PG.Commons.Hashing; using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.MTD.Data; using PG.StarWarsGame.Files.MTD.Files; using PG.StarWarsGame.Files.XML.Data; diff --git a/src/ModVerify/Verifiers/VerifierErrorCodes.cs b/src/ModVerify/Verifiers/VerifierErrorCodes.cs index 57d3209..fdb4d2b 100644 --- a/src/ModVerify/Verifiers/VerifierErrorCodes.cs +++ b/src/ModVerify/Verifiers/VerifierErrorCodes.cs @@ -36,4 +36,5 @@ public static class VerifierErrorCodes public const string XmlDataBeforeHeader = "XML08"; public const string XmlMissingNode = "XML09"; public const string XmlUnsupportedTag = "XML10"; + public const string XmlElementsInTag = "XML11"; } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs index aa3f8d2..861e441 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs @@ -50,5 +50,9 @@ public enum XmlParseErrorKind /// /// The XML tag name is null or empty. /// - EmptyNodeName + EmptyNodeName = 11, + /// + /// The XML tag has child elements. + /// + TagHasElements = 12 } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs index 2a6a1e2..af9fdb1 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs @@ -17,6 +17,15 @@ public override string ToString() protected bool IsTagValid(XElement element) { + if (element.HasElements) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.TagHasElements, + Message = "A tag cannot have elements.", + }); + return false; + } var tagName = element.Name.LocalName; if (string.IsNullOrEmpty(tagName)) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs index ff59d8a..f4eb0af 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs @@ -10,6 +10,8 @@ public abstract class XmlObjectParserBase(IXmlTagMapper XmlTagMapper = tagMapper ?? throw new ArgumentNullException(nameof(tagMapper)); + protected virtual bool IgnoreEmptyValue => true; + protected virtual void ValidateValues(TObject namedXmlObject, XElement element) { } @@ -18,6 +20,12 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) { foreach (var tag in element.Elements()) { + if (string.IsNullOrEmpty(tag.Value) && IgnoreEmptyValue) + continue; + + if (tag.HasElements) + Parse(xmlObject, tag, in state); + if (!ParseTag(tag, xmlObject, state)) { ErrorReporter?.Report(new XmlError(this, element) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs index 4b206af..a31f2aa 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs @@ -9,18 +9,18 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public abstract class NamedXmlObjectParser( +public abstract class NamedXmlObjectParser( IServiceProvider serviceProvider, - IXmlTagMapper tagMapper, + IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter) - : XmlObjectParserBase>(tagMapper, errorReporter) - where TObject : NamedXmlObject + : XmlObjectParserBase>(tagMapper, errorReporter) + where T : NamedXmlObject { protected virtual bool UpperCaseNameForCrc => true; protected readonly ICrc32HashingService HashingService = serviceProvider.GetRequiredService(); - public TObject Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) + public T Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) { var name = GetXmlObjectName(element, out nameCrc); var namedXmlObject = CreateXmlObject(name, nameCrc, element, XmlLocationInfo.FromElement(element)); @@ -30,7 +30,7 @@ public TObject Parse(XElement element, IReadOnlyFrugalValueListDictionary Date: Sat, 21 Feb 2026 10:28:14 +0100 Subject: [PATCH 12/41] huge parser refactoring --- src/ModVerify/ModVerify.csproj | 2 +- .../Reporting/Engine/XmlParseErrorReporter.cs | 2 + .../GuiDialogs/GuiDialogsVerifier.cs | 2 + src/ModVerify/Verifiers/VerifierErrorCodes.cs | 1 + .../Audio/Sfx/SfxEvent.cs | 16 +- .../Audio/Sfx/SfxEventGameManager.cs | 2 +- .../CommandBar/CommandBarGameManager.cs | 2 +- .../CommandBar/Xml/CommandBarComponentData.cs | 3 +- .../PG.StarWarsGame.Engine/GameManagerBase.cs | 1 + .../GameObjects/GameObject.cs | 1 - .../GameObjects/GameObjectTypeGameManager.cs | 2 +- .../GuiDialog/GuiDialogGameManager.cs | 39 +- .../GuiDialogGameManager_Initialization.cs | 87 ++-- .../Xml/EnumConversionDictionary.cs | 58 +++ .../Parsers/FileObjects/GuiDialogParser.cs | 135 +++++- .../NamedObjects/CommandBarComponentParser.cs | 112 ++++- .../Parsers/NamedObjects/SfxEventParser.cs | 431 +++++++++++------- .../Parsers/Tags/CommandBarComponentTags.cs | 108 ----- .../Tags/ComponentTextureKeyExtensions.cs | 114 ----- .../Xml/Parsers/Tags/SfxEventXmlTags.cs | 41 -- .../PetroglyphStarWarsGameXmlParseSettings.cs | 2 +- .../Xml/PetroglyphStarWarsGameXmlParser.cs | 103 ++--- .../PG.StarWarsGame.Files.ALO.csproj | 2 +- .../PG.StarWarsGame.Files.ChunkFiles.csproj | 2 +- .../Data/XmlObject.cs | 4 - .../ErrorHandling/XmlParseErrorKind.cs | 6 +- .../PG.StarWarsGame.Files.XML.csproj | 2 +- .../Parsers/Base/XmlObjectParserBase.cs | 28 +- .../Parsers/NamedXmlObjectParser.cs | 8 +- .../CommaSeparatedStringKeyValueListParser.cs | 3 +- .../Primitives/PetroglyphNumberParser.cs | 88 ++++ .../PetroglyphPrimitiveXmlParser.cs | 8 +- .../Primitives/PetroglyphXmlBooleanParser.cs | 6 +- .../Primitives/PetroglyphXmlByteParser.cs | 14 +- .../PetroglyphXmlBytePercentParser.cs | 45 ++ .../Primitives/PetroglyphXmlFloatParser.cs | 32 +- .../Primitives/PetroglyphXmlIntegerParser.cs | 28 +- .../PetroglyphXmlLooseStringListParser.cs | 1 + .../PetroglyphXmlMax100ByteParser.cs | 74 --- .../PetroglyphXmlRgbaColorParser.cs | 1 + .../Primitives/PetroglyphXmlSByteParser.cs | 41 ++ .../Primitives/PetroglyphXmlStringParser.cs | 6 +- .../PetroglyphXmlUnsignedIntegerParser.cs | 10 +- .../Primitives/PetroglyphXmlVector2FParser.cs | 6 +- .../Parsers/XmlFileListParser.cs | 4 +- .../Parsers/XmlObjectParser.cs | 3 +- .../Utilities/PGMath.cs | 58 ++- .../XElementExtensions.cs | 15 + 48 files changed, 1025 insertions(+), 734 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EnumConversionDictionary.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/CommandBarComponentTags.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/ComponentTextureKeyExtensions.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/SfxEventXmlTags.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphNumberParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBytePercentParser.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlSByteParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/XElementExtensions.cs diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj index aecf306..948719f 100644 --- a/src/ModVerify/ModVerify.csproj +++ b/src/ModVerify/ModVerify.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net10.0 AlamoEngineTools.ModVerify AET.ModVerify AET.ModVerify diff --git a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs index 83c3bbe..9548ad4 100644 --- a/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs +++ b/src/ModVerify/Reporting/Engine/XmlParseErrorReporter.cs @@ -76,6 +76,7 @@ private static VerificationSeverity GetSeverityFromError(XmlParseErrorKind xmlEr XmlParseErrorKind.MissingNode => VerificationSeverity.Critical, XmlParseErrorKind.UnknownNode => VerificationSeverity.Information, XmlParseErrorKind.TagHasElements => VerificationSeverity.Warning, + XmlParseErrorKind.UnexceptedElementName => VerificationSeverity.Information, _ => VerificationSeverity.Warning }; } @@ -96,6 +97,7 @@ private static string GetIdFromError(XmlParseErrorKind xmlErrorErrorKind) XmlParseErrorKind.MissingNode => VerifierErrorCodes.XmlMissingNode, XmlParseErrorKind.UnknownNode => VerifierErrorCodes.XmlUnsupportedTag, XmlParseErrorKind.TagHasElements => VerifierErrorCodes.XmlElementsInTag, + XmlParseErrorKind.UnexceptedElementName => VerifierErrorCodes.XmlUnexceptedElementName, _ => throw new ArgumentOutOfRangeException(nameof(xmlErrorErrorKind), xmlErrorErrorKind, null) }; } diff --git a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs index 435c5de..320815e 100644 --- a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs +++ b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs @@ -52,6 +52,8 @@ private void VerifyGuiTextures() }; components.AddRange(GameEngine.GuiDialogManager.Components); + // TODO: Verify no double definitions for textures and components exit + foreach (var component in components) VerifyGuiComponentTexturesExist(component); diff --git a/src/ModVerify/Verifiers/VerifierErrorCodes.cs b/src/ModVerify/Verifiers/VerifierErrorCodes.cs index fdb4d2b..a526715 100644 --- a/src/ModVerify/Verifiers/VerifierErrorCodes.cs +++ b/src/ModVerify/Verifiers/VerifierErrorCodes.cs @@ -37,4 +37,5 @@ public static class VerifierErrorCodes public const string XmlMissingNode = "XML09"; public const string XmlUnsupportedTag = "XML10"; public const string XmlElementsInTag = "XML11"; + public const string XmlUnexceptedElementName = "XML12"; } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs index b9d32a0..d384007 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs @@ -25,11 +25,11 @@ public sealed class SfxEvent : NamedXmlObject public const byte MaxPan2dValue = 100; public const byte MinPriorityValue = 1; public const byte MaxPriorityValue = 5; - public const byte MaxProbability = 100; - public const sbyte MinMaxInstances = 0; - public const sbyte InfinitivePlayCount = -1; - public const float MinLoopSeconds = 0.0f; - public const float MinVolumeSaturation = 0.0f; + public const byte MaxProbabilityValue = 100; + public const sbyte MinMaxInstancesValue = 0; + public const sbyte InfinitivePlayCountValue = -1; + public const float MinLoopSecondsValue = 0.0f; + public const float MinVolumeSaturationValue = 0.0f; // Default values which are not the default value of the type public const byte DefaultPriority = 3; @@ -163,7 +163,7 @@ internal SfxEvent(string name, Crc32 nameCrc, XmlLocationInfo location) { } - public override void CoerceValues() + internal void FixupValues() { AdjustMinMaxValues(ref _minVolume, ref _maxVolume); AdjustMinMaxValues(ref _minPitch, ref _maxPitch); @@ -187,6 +187,8 @@ public override void CoerceValues() */ public void ApplyPreset(SfxEvent preset) { + Preset = preset; + Is3D = preset.Is3D; Is2D = preset.Is2D; IsGui = preset.IsGui; @@ -194,8 +196,6 @@ public void ApplyPreset(SfxEvent preset) IsUnitResponseVo = preset.IsUnitResponseVo; IsAmbientVo = preset.IsAmbientVo; IsLocalized = preset.IsLocalized; - Preset = preset; - UsePresetName = preset.Name; PlaySequentially = preset.PlaySequentially; PreSamples = preset.PreSamples; Samples = preset.Samples; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs index 46741bc..a9034ef 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs @@ -28,7 +28,7 @@ protected override async Task InitializeCoreAsync(CancellationToken token) new PetroglyphStarWarsGameXmlParseSettings { GameManager = ToString(), - InvalidContainerXmlFailsInitialization = true, + InvalidObjectXmlFailsInitialization = true, InvalidFilesListXmlFailsInitialization = true }, ServiceProvider, ErrorReporter); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 4ad531f..8b5d175 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -77,7 +77,7 @@ protected override async Task InitializeCoreAsync(CancellationToken token) var contentParser = new PetroglyphStarWarsGameXmlParser(GameRepository, new PetroglyphStarWarsGameXmlParseSettings { GameManager = ToString(), - InvalidContainerXmlFailsInitialization = true, + InvalidObjectXmlFailsInitialization = true, InvalidFilesListXmlFailsInitialization = true }, ServiceProvider, ErrorReporter); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs index 40ab0c9..82168a3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs @@ -128,9 +128,8 @@ public sealed class CommandBarComponentData(string name, Crc32 crc, XmlLocationI public Vector4Int? TextColor2 { get; internal set; } public Vector4Int? MaxBarColor { get; internal set; } = WhiteColor; - public override void CoerceValues() + internal void FixupValues() { - base.CoerceValues(); if (AlternateFontNames.Count == 0) return; var newFontNames = new string[AlternateFontNames.Count]; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs index 607121d..c49438b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using System.Threading; using System.Threading.Tasks; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index f531df4..1d05bdd 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using PG.Commons.Hashing; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 5830262..e82bb02 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -26,7 +26,7 @@ private void ParseGameObjectDatabases() { GameManager = ToString(), InvalidFilesListXmlFailsInitialization = true, - InvalidContainerXmlFailsInitialization = false, + InvalidObjectXmlFailsInitialization = false, }, ServiceProvider, ErrorReporter); var xmlFileList = parser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs index 879c16f..5b96451 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using PG.Commons.Hashing; @@ -19,15 +20,24 @@ internal partial class GuiDialogGameManager(GameRepository repository, GameEngin private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService(); - // Unlike other strings for this game, the component's (aka gadget) name is case-sensitive. - private readonly Dictionary> _perComponentTextures = new(StringComparer.Ordinal); - private readonly Dictionary _defaultTextures = new(); - private ReadOnlyDictionary _defaultTexturesRo = null!; - private bool _megaTextureExists; private string? _megaTextureFileName; - + [field: MaybeNull, AllowNull] + private ReadOnlyDictionary> PerComponentTextures + { + get + { + ThrowIfNotInitialized(); + return field!; + } + set + { + ThrowIfAlreadyInitialized(); + field = value; + } + } + public IMtdFile? MtdFile { get @@ -61,7 +71,7 @@ public IReadOnlyCollection Components get { ThrowIfNotInitialized(); - return _perComponentTextures.Keys; + return PerComponentTextures.Keys!; } } @@ -70,14 +80,19 @@ public IReadOnlyDictionary DefaultTextu get { ThrowIfNotInitialized(); - return _defaultTexturesRo; + return field!; + } + internal set + { + ThrowIfAlreadyInitialized(); + field = value; } } public IReadOnlyDictionary GetTextureEntries(string component, out bool componentExist) { - if (!_perComponentTextures.TryGetValue(component, out var textures)) + if (!PerComponentTextures.TryGetValue(component, out var textures)) { Logger?.LogDebug("The component '{Component}' has no overrides. Using default textures.", component); componentExist = false; @@ -85,15 +100,15 @@ public IReadOnlyDictionary GetTextureEn } componentExist = true; - return new ReadOnlyDictionary(textures); + return textures; } public bool TryGetTextureEntry(string component, GuiComponentType key, out ComponentTextureEntry texture) { - if (!_perComponentTextures.TryGetValue(component, out var textures)) + if (!PerComponentTextures.TryGetValue(component, out var textures)) { Logger?.LogDebug("The component '{Component}' has no overrides. Using default textures.", component); - textures = _defaultTextures; + textures = DefaultTextureEntries; } return textures.TryGetValue(key, out texture); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs index f4b3267..2bac738 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager_Initialization.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading; @@ -8,8 +7,8 @@ using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.GuiDialog.Xml; +using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Engine.Xml.Parsers; -using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.Binary; namespace PG.StarWarsGame.Engine.GuiDialog; @@ -22,24 +21,14 @@ protected override Task InitializeCoreAsync(CancellationToken token) { return Task.Run(() => { - var guiDialogParser = new GuiDialogParser(ServiceProvider, ErrorReporter); - - _defaultTexturesRo = new ReadOnlyDictionary(_defaultTextures); - - Logger?.LogInformation("Parsing GuiDialogs..."); - using var fileStream = GameRepository.TryOpenFile("DATA\\XML\\GUIDIALOGS.XML"); - - if (fileStream is null) - { - ErrorReporter.Report(new InitializationError + var engineParser = new PetroglyphStarWarsGameXmlParser(GameRepository, + new PetroglyphStarWarsGameXmlParseSettings { GameManager = ToString(), - Message = "Unable to find GuiDialogs.xml" - }); - return; - } + InvalidObjectXmlFailsInitialization = true + }, ServiceProvider, ErrorReporter); - var guiDialogs = guiDialogParser.ParseFile(fileStream); + var guiDialogs = engineParser.ParseFile("DATA\\XML\\GUIDIALOGS.XML", new GuiDialogParser(ServiceProvider, ErrorReporter)); if (guiDialogs is null) { ErrorReporter.Report(new InitializationError @@ -50,10 +39,8 @@ protected override Task InitializeCoreAsync(CancellationToken token) return; } - GuiDialogsXml = guiDialogs; - InitializeTextures(guiDialogs.TextureData); - + GuiDialogsXml = guiDialogs; }, token); } @@ -62,7 +49,8 @@ private void InitializeTextures(GuiDialogsXmlTextureData textureData) InitializeMegaTextures(textureData); var textures = textureData.Textures; - + + IReadOnlyDictionary defaultTextures; if (textures.Count == 0) { ErrorReporter.Report(new InitializationError @@ -70,47 +58,70 @@ private void InitializeTextures(GuiDialogsXmlTextureData textureData) GameManager = ToString(), Message = "No Textures defined in GuiDialogs.xml" }); + + defaultTextures = new ReadOnlyDictionary( + new Dictionary()); } else { - var defaultCandidate = textures.First(); - // Regardless of its name, the game treats the first entry as default. - var defaultTextures = InitializeComponentTextures(defaultCandidate, true, out var invalidKeys); - foreach (var entry in defaultTextures) - _defaultTextures.Add(entry.Key, entry.Value); + var defaultCandidate = textures.First(); + defaultTextures = InitializeComponentTextures(defaultCandidate, null, out var invalidKeys); + ReportInvalidComponent(in invalidKeys); } + var perComponentTextures = new Dictionary>(); + foreach (var componentTextureData in textures.Skip(1)) { // The game only uses the *first* entry. - if (_perComponentTextures.ContainsKey(componentTextureData.Component)) + if (perComponentTextures.ContainsKey(componentTextureData.Component)) continue; - _perComponentTextures.Add(componentTextureData.Component, InitializeComponentTextures(componentTextureData, false, out var invalidKeys)); + perComponentTextures.Add( + componentTextureData.Component, + InitializeComponentTextures(componentTextureData, defaultTextures, out var invalidKeys)); + ReportInvalidComponent(in invalidKeys); } + + DefaultTextureEntries = defaultTextures; + PerComponentTextures = + new ReadOnlyDictionary>( + perComponentTextures); } - private Dictionary InitializeComponentTextures(XmlComponentTextureData textureData, bool isDefaultComponent, out FrugalList invalidKeys) + private ReadOnlyDictionary InitializeComponentTextures( + XmlComponentTextureData textureData, + IReadOnlyDictionary? defaultTextures, + out FrugalList invalidKeys) { - invalidKeys = new FrugalList(); + invalidKeys = []; var result = new Dictionary(); + var isDefaultComponent = defaultTextures is null; + if (!isDefaultComponent) { - // This assumes that _defaultTextures is already filled - foreach (var key in _defaultTextures.Keys) - result.Add(key, _defaultTextures[key]); + foreach (var key in defaultTextures!.Keys) + result.Add(key, defaultTextures[key]); } - + if (textureData.Textures.Count == 0) + { + ErrorReporter.Report(new InitializationError + { + GameManager = ToString(), + Message = $"No Textures defined for component '{textureData.Component}' in GuiDialogs.xml" + }); + } + foreach (var keyText in textureData.Textures.Keys) { - if (!ComponentTextureKeyExtensions.TryConvertToKey(keyText.AsSpan(), out var key)) + if (!GuiDialogParser.ComponentTypeDictionary.TryStringToEnum(keyText, out var key)) { invalidKeys.Add(keyText); continue; @@ -119,8 +130,8 @@ private Dictionary InitializeComponentT var textureValue = textureData.Textures.GetLastValue(keyText); result[key] = new ComponentTextureEntry(key, textureValue, !isDefaultComponent); } - - return result; + + return new ReadOnlyDictionary(result); } private void InitializeMegaTextures(GuiDialogsXmlTextureData guiDialogs) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EnumConversionDictionary.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EnumConversionDictionary.cs new file mode 100644 index 0000000..275fea8 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/EnumConversionDictionary.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace PG.StarWarsGame.Engine.Xml; + +public sealed class EnumConversionDictionary : IReadOnlyCollection> where T : struct, Enum +{ + // This is the value the engine would give you. + internal const string StringNotFoundDummy = "-BAD VALUE-"; + + // Most consumers call the method TryStringToEnum. Thus, we optimize the class for this case + // and accept performance penalties for the EnumToString case. + private readonly IReadOnlyDictionary _dictionary; + + public int Count => _dictionary.Count; + + public EnumConversionDictionary(IEnumerable> entries) + { + var dictionary = new Dictionary(); + var values = dictionary.Values; + foreach (var entry in entries) + { + if (values.Contains(entry.Value)) + throw new InvalidOperationException($"Enum value {entry.Value} already exists!"); + dictionary.Add(entry.Key.ToUpperInvariant(), entry.Value); + } + _dictionary = dictionary; + } + + public bool TryStringToEnum(string key, out T enumValue) + { + key = key.ToUpperInvariant(); + return _dictionary.TryGetValue(key, out enumValue); + } + + public string EnumToString(T enumValue) + { + foreach (var keyValuePair in _dictionary) + { + if (EqualityComparer.Default.Equals(enumValue, keyValuePair.Value)) + return keyValuePair.Key; + } + + return StringNotFoundDummy; + } + + public IEnumerator> GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs index e735dc3..152ec83 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/FileObjects/GuiDialogParser.cs @@ -1,11 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; +using AnakinRaW.CommonUtilities.Collections; +using PG.StarWarsGame.Engine.GuiDialog; using PG.StarWarsGame.Engine.GuiDialog.Xml; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Collections.Generic; +using System.Xml.Linq; namespace PG.StarWarsGame.Engine.Xml.Parsers; @@ -14,7 +15,14 @@ internal class GuiDialogParser(IServiceProvider serviceProvider, IXmlParserError { protected override GuiDialogsXml ParseRoot(XElement element, string fileName) { - var textures = ParseTextures(element.Element("Textures"), fileName); + using var elementsEnumerator = element.Elements().GetEnumerator(); + + var texturesExist = elementsEnumerator.MoveNext(); + var textures = ParseTextures(texturesExist + ? elementsEnumerator.Current + : null!, + fileName); + return new GuiDialogsXml(textures, XmlLocationInfo.FromElement(element)); } @@ -24,12 +32,21 @@ private GuiDialogsXmlTextureData ParseTextures(XElement? element, string fileNam { ErrorReporter?.Report(new XmlError(this, locationInfo: new XmlLocationInfo(fileName, null)) { - ErrorKind = XmlParseErrorKind.MissingNode, - Message = "Expected node is missing." + ErrorKind = XmlParseErrorKind.MissingNode, + Message = "Unable to read textures for GUI." }); return new GuiDialogsXmlTextureData([], new XmlLocationInfo(fileName, null)); } + if (element.Name != "Textures") + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.UnexceptedElementName, + Message = "Unable to read textures for GUI." + }); + } + var textures = new List(); GetAttributeValue(element, "File", out var megaTexture); @@ -42,7 +59,7 @@ private GuiDialogsXmlTextureData ParseTextures(XElement? element, string fileNam { ErrorReporter?.Report(new XmlError(this, element) { - Message = "Textures must contain at least one child node.", + Message = "Missing default texture specifications in GUI XML file!", ErrorKind = XmlParseErrorKind.MissingNode }); } @@ -64,4 +81,106 @@ private XmlComponentTextureData ParseTexture(XElement texture) return new XmlComponentTextureData(componentId, textures, XmlLocationInfo.FromElement(texture)); } + + + internal static readonly EnumConversionDictionary ComponentTypeDictionary = new([ + new("Button_Left", GuiComponentType.ButtonLeft), + new("Button_Middle", GuiComponentType.ButtonMiddle), + new("Button_Right", GuiComponentType.ButtonRight), + new("Button_Left_Mouse_Over", GuiComponentType.ButtonLeftMouseOver), + new("Button_Middle_Mouse_Over", GuiComponentType.ButtonMiddleMouseOver), + new("Button_Right_Mouse_Over", GuiComponentType.ButtonRightMouseOver), + new("Button_Left_Pressed", GuiComponentType.ButtonLeftPressed), + new("Button_Middle_Pressed", GuiComponentType.ButtonMiddlePressed), + new("Button_Right_Pressed", GuiComponentType.ButtonRightPressed), + new("Button_Left_Disabled", GuiComponentType.ButtonLeftDisabled), + new("Button_Middle_Disabled", GuiComponentType.ButtonMiddleDisabled), + new("Button_Right_Disabled", GuiComponentType.ButtonRightDisabled), + + new("Check_Off", GuiComponentType.CheckOff), + new("Check_On", GuiComponentType.CheckOn), + + new("Dial_Left", GuiComponentType.DialLeft), + new("Dial_Middle", GuiComponentType.DialMiddle), + new("Dial_Right", GuiComponentType.DialRight), + new("Dial_Plus", GuiComponentType.DialPlus), + new("Dial_Plus_Mouse_Over", GuiComponentType.DialPlusMouseOver), + new("Dial_Plus_Pressed", GuiComponentType.DialPlusPressed), + new("Dial_Minus", GuiComponentType.DialMinus), + new("Dial_Minus_Mouse_Over", GuiComponentType.DialMinusMouseOver), + new("Dial_Minus_Pressed", GuiComponentType.DialMinusPressed), + new("Dial_Tab", GuiComponentType.DialTab), + + new("Frame_Bottom", GuiComponentType.FrameBottom), + new("Frame_Bottom_Left", GuiComponentType.FrameBottomLeft), + new("Frame_Bottom_Right", GuiComponentType.FrameBottomRight), + new("Frame_Background", GuiComponentType.FrameBackground), + new("Frame_Left", GuiComponentType.FrameLeft), + new("Frame_Right", GuiComponentType.FrameRight), + new("Frame_Top", GuiComponentType.FrameTop), + new("Frame_Top_Left", GuiComponentType.FrameTopLeft), + new("Frame_Top_Right", GuiComponentType.FrameTopRight), + new("Frame_Top_Transition_Left", GuiComponentType.FrameTopTransitionLeft), + new("Frame_Top_Transition_Right", GuiComponentType.FrameTopTransitionRight), + new("Frame_Bottom_Transition_Left", GuiComponentType.FrameBottomTransitionLeft), + new("Frame_Bottom_Transition_Right", GuiComponentType.FrameBottomTransitionRight), + new("Frame_Left_Transition_Top", GuiComponentType.FrameLeftTransitionTop), + new("Frame_Left_Transition_Bottom", GuiComponentType.FrameLeftTransitionBottom), + new("Frame_Right_Transition_Top", GuiComponentType.FrameRightTransitionTop), + new("Frame_Right_Transition_Bottom", GuiComponentType.FrameRightTransitionBottom), + + new("Radio_Off", GuiComponentType.RadioOff), + new("Radio_On", GuiComponentType.RadioOn), + new("Radio_Disabled", GuiComponentType.RadioDisabled), + new("Radio_Mouse_Over", GuiComponentType.RadioMouseOver), + + new("Scroll_Down_Button", GuiComponentType.ScrollDownButton), + new("Scroll_Down_Button_Pressed", GuiComponentType.ScrollDownButtonPressed), + new("Scroll_Down_Button_Mouse_Over", GuiComponentType.ScrollDownButtonMouseOver), + new("Scroll_Down_Button_Disabled", GuiComponentType.ScrollDownButtonDisabled), + new("Scroll_Middle", GuiComponentType.ScrollMiddle), + new("Scroll_Middle_Disabled", GuiComponentType.ScrollMiddleDisabled), + new("Scroll_Tab", GuiComponentType.ScrollTab), + new("Scroll_Tab_Disabled", GuiComponentType.ScrollTabDisabled), + new("Scroll_Up_Button", GuiComponentType.ScrollUpButton), + new("Scroll_Up_Button_Pressed", GuiComponentType.ScrollUpButtonPressed), + new("Scroll_Up_Button_Mouse_Over", GuiComponentType.ScrollUpButtonMouseOver), + new("Scroll_Up_Button_Disabled", GuiComponentType.ScrollUpButtonDisabled), + + new("Trackbar_Scroll_Down_Button", GuiComponentType.TrackbarScrollDownButton), + new("Trackbar_Scroll_Down_Button_Pressed", GuiComponentType.TrackbarScrollDownButtonPressed), + new("Trackbar_Scroll_Down_Button_Mouse_Over", GuiComponentType.TrackbarScrollDownButtonMouseOver), + new("Trackbar_Scroll_Down_Button_Disabled", GuiComponentType.TrackbarScrollDownButtonDisabled), + new("Trackbar_Scroll_Middle", GuiComponentType.TrackbarScrollMiddle), + new("Trackbar_Scroll_Middle_Disabled", GuiComponentType.TrackbarScrollMiddleDisabled), + new("Trackbar_Scroll_Tab", GuiComponentType.TrackbarScrollTab), + new("Trackbar_Scroll_Tab_Disabled", GuiComponentType.TrackbarScrollTabDisabled), + new("Trackbar_Scroll_Up_Button", GuiComponentType.TrackbarScrollUpButton), + new("Trackbar_Scroll_Up_Button_Pressed", GuiComponentType.TrackbarScrollUpButtonPressed), + new("Trackbar_Scroll_Up_Button_Mouse_Over", GuiComponentType.TrackbarScrollUpButtonMouseOver), + new("Trackbar_Scroll_Up_Button_Disabled", GuiComponentType.TrackbarScrollUpButtonDisabled), + + new("Small_Frame_Bottom", GuiComponentType.SmallFrameBottom), + new("Small_Frame_Bottom_Left", GuiComponentType.SmallFrameBottomLeft), + new("Small_Frame_Bottom_Right", GuiComponentType.SmallFrameBottomRight), + new("Small_Frame_Left", GuiComponentType.SmallFrameMiddleLeft), + new("Small_Frame_Right", GuiComponentType.SmallFrameMiddleRight), + new("Small_Frame_Top", GuiComponentType.SmallFrameTop), + new("Small_Frame_Top_Left", GuiComponentType.SmallFrameTopLeft), + new("Small_Frame_Top_Right", GuiComponentType.SmallFrameTopRight), + new("Small_Frame_Background", GuiComponentType.SmallFrameBackground), + + new("Combo_Box_Popdown_Button", GuiComponentType.ComboboxPopdown), + new("Combo_Box_Popdown_Button_Pressed", GuiComponentType.ComboboxPopdownPressed), + new("Combo_Box_Popdown_Button_Mouse_Over", GuiComponentType.ComboboxPopdownMouseOver), + new("Combo_Box_Text_Box", GuiComponentType.ComboboxTextBox), + new("Combo_Box_Left_Cap", GuiComponentType.ComboboxLeftCap), + + new("Progress_Bar_Left", GuiComponentType.ProgressLeft), + new("Progress_Bar_Middle_Off", GuiComponentType.ProgressMiddleOff), + new("Progress_Bar_Middle_On", GuiComponentType.ProgressMiddleOn), + new("Progress_Bar_Right", GuiComponentType.ProgressRight), + + new("Scanlines", GuiComponentType.Scanlines), + ]); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index 2c74d99..be3dcc0 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -3,7 +3,6 @@ using System.Xml.Linq; using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.CommandBar.Xml; -using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; @@ -344,7 +343,7 @@ protected override bool ParseTag(XElement tag, CommandBarComponentData component } } - protected override void ValidateValues(CommandBarComponentData xmlData, XElement element) + protected override void ValidateAndFixupValues(CommandBarComponentData xmlData, XElement element) { if (xmlData.Name.Length > PGConstants.MaxCommandBarComponentName) { @@ -354,6 +353,8 @@ protected override void ValidateValues(CommandBarComponentData xmlData, XElement ErrorKind = XmlParseErrorKind.TooLongData }); } + + xmlData.FixupValues(); } private sealed class CommandBarComponentDataXmlTagMapper(IServiceProvider serviceProvider) @@ -363,4 +364,111 @@ protected override void BuildMappings() { } } + + internal static class CommandBarComponentTags + { + public const string SelectedTextureName = "Selected_Texture_Name"; + public const string BlankTextureName = "Blank_Texture_Name"; + public const string IconTextureName = "Icon_Texture_Name"; + public const string IconAlternateTextureName = "Icon_Alternate_Texture_Name"; + public const string MouseOverTextureName = "Mouse_Over_Texture_Name"; + public const string DisabledTextureName = "Disabled_Texture_Name"; + public const string FlashTextureName = "Flash_Texture_Name"; + public const string BarTextureName = "Bar_Texture_Name"; + public const string BarOverlayName = "Bar_Overlay_Name"; + public const string BuildTextureName = "Build_Texture_Name"; + public const string ModelName = "Model_Name"; + public const string BoneName = "Bone_Name"; + public const string CursorTextureName = "Cursor_Texture_Name"; + public const string FontName = "Font_Name"; + public const string AlternateFontName = "Alternate_Font_Name"; + public const string TooltipText = "Tooltip_Text"; + public const string ClickSfx = "Click_SFX"; + public const string MouseOverSfx = "Mouse_Over_SFX"; + public const string LowerEffectTextureName = "Lower_Effect_Texture_Name"; + public const string UpperEffectTextureName = "Upper_Effect_Texture_Name"; + public const string OverlayTextureName = "Overlay_Texture_Name"; + public const string Overlay2TextureName = "Overlay2_Texture_Name"; + public const string RightClickSfx = "Right_Click_SFX"; + public const string Type = "Type"; + public const string Group = "Group"; + public const string DragAndDrop = "Drag_And_Drop"; + public const string DragSelect = "Drag_Select"; + public const string Receptor = "Receptor"; + public const string Toggle = "Toggle"; + public const string Tab = "Tab"; + public const string AssociatedText = "Associated_Text"; + public const string Hidden = "Hidden"; + public const string Scale = "Scale"; + public const string Color = "Color"; + public const string TextColor = "Text_Color"; + public const string TextColor2 = "Text_Color2"; + public const string Size = "Size"; + public const string ClearColor = "Clear_Color"; + public const string Disabled = "Disabled"; + public const string SwapTexture = "Swap_Texture"; + public const string BaseLayer = "Base_Layer"; + public const string DrawAdditive = "Draw_Additive"; + public const string TextOffset = "Text_Offset"; + public const string TextOffset2 = "Text_Offset2"; + public const string Offset = "Offset"; + public const string DefaultOffset = "Default_Offset"; + public const string DefaultOffsetWidescreen = "Default_Offset_Widescreen"; + public const string IconOffset = "Icon_Offset"; + public const string MouseOverOffset = "Mouse_Over_Offset"; + public const string DisabledOffset = "Disabled_Offset"; + public const string BuildDialOffset = "Build_Dial_Offset"; + public const string BuildDial2Offset = "Build_Dial2_Offset"; + public const string LowerEffectOffset = "Lower_Effect_Offset"; + public const string UpperEffectOffset = "Upper_Effect_Offset"; + public const string OverlayOffset = "Overlay_Offset"; + public const string Overlay2Offset = "Overlay2_Offset"; + public const string Editable = "Editable"; + public const string MaxTextLength = "Max_Text_Length"; + public const string BlinkRate = "Blink_Rate"; + public const string FontPointSize = "Font_Point_Size"; + public const string TextOutline = "Text_Outline"; + public const string MaxTextWidth = "Max_Text_Width"; + public const string Stackable = "Stackable"; + public const string ModelOffsetX = "Model_Offset_X"; + public const string ModelOffsetY = "Model_Offset_Y"; + public const string ScaleModelX = "Scale_Model_X"; + public const string ScaleModelY = "Scale_Model_Y"; + public const string Collideable = "Collideable"; + public const string TextEmboss = "Text_Emboss"; + public const string ShouldGhost = "Should_Ghost"; + public const string GhostBaseOnly = "Ghost_Base_Only"; + public const string MaxBarLevel = "Max_Bar_Level"; + public const string MaxBarColor = "Max_Bar_Color"; + public const string CrossFade = "Cross_Fade"; + public const string LeftJustified = "Left_Justified"; + public const string RightJustified = "Right_Justified"; + public const string NoShell = "No_Shell"; + public const string SnapDrag = "Snap_Drag"; + public const string SnapLocation = "Snap_Location"; + public const string BlinkDuration = "Blink_Duration"; + public const string ScaleDuration = "Scale_Duration"; + public const string OffsetRender = "Offset_Render"; + public const string BlinkFade = "Blink_Fade"; + public const string NoHiddenCollision = "No_Hidden_Collision"; + public const string ManualOffset = "Manual_Offset"; + public const string SelectedAlpha = "Selected_Alpha"; + public const string PixelAlign = "Pixel_Align"; + public const string CanDragStack = "Can_Drag_Stack"; + public const string CanAnimate = "Can_Animate"; + public const string AnimFps = "Anim_FPS"; + public const string LoopAnim = "Loop_Anim"; + public const string SmoothBar = "Smooth_Bar"; + public const string OutlinedBar = "Outlined_Bar"; + public const string DragBack = "Drag_Back"; + public const string LowerEffectAdditive = "Lower_Effect_Additive"; + public const string UpperEffectAdditive = "Upper_Effect_Additive"; + public const string ClickShift = "Click_Shift"; + public const string TutorialScene = "Tutorial_Scene"; + public const string DialogScene = "Dialog_Scene"; + public const string ShouldRenderAtDragPos = "Should_Render_At_Drag_Pos"; + public const string DisableDarken = "Disable_Darken"; + public const string AnimateBack = "Animate_Back"; + public const string AnimateUpperEffect = "Animate_Upper_Effect"; + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs index e59ef80..484b075 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs @@ -1,10 +1,10 @@ using System; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Xml.Linq; using AnakinRaW.CommonUtilities.Collections; using PG.Commons.Hashing; using PG.StarWarsGame.Engine.Audio.Sfx; -using PG.StarWarsGame.Engine.Xml.Tags; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; @@ -19,190 +19,287 @@ protected override SfxEvent CreateXmlObject(string name, Crc32 nameCrc, XElement return new SfxEvent(name, nameCrc, location); } - protected override void ValidateValues(SfxEvent sfxEvent, XElement element) + protected override void ValidateAndFixupValues(SfxEvent sfxEvent, XElement element) { - //if (sfxEvent.Name.Length > PGConstants.MaxSFXEventName) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.TooLongData, - // $"SFXEvent name '{sfxEvent.Name}' is too long.")); - //} - - //if (sfxEvent is { Is2D: true, Is3D: true }) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - // $"SFXEvent '{sfxEvent.Name}' is defined as 2D and 3D.")); - //} - - //if (sfxEvent.MinVolume > sfxEvent.MaxVolume) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - // $"{SfxEventXmlTags.MinVolume} should not be higher than {SfxEventXmlTags.MaxVolume} for SFXEvent '{sfxEvent.Name}'")); - //} - - //if (sfxEvent.MinPitch > sfxEvent.MaxPitch) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - // $"{SfxEventXmlTags.MinPitch} should not be higher than {SfxEventXmlTags.MaxPitch} for SFXEvent '{sfxEvent.Name}'")); - //} - - //if (sfxEvent.MinPan2D > sfxEvent.MaxPan2D) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - // $"{SfxEventXmlTags.MinPan2D} should not be higher than {SfxEventXmlTags.MaxPan2D} for SFXEvent '{sfxEvent.Name}'")); - //} - - //if (sfxEvent.MinPredelay > sfxEvent.MaxPredelay) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - // $"{SfxEventXmlTags.MinPredelay} should not be higher than {SfxEventXmlTags.MaxPredelay} for SFXEvent '{sfxEvent.Name}'")); - //} - - //if (sfxEvent.MinPostdelay > sfxEvent.MaxPostdelay) - //{ - // OnParseError(new XmlParseErrorEventArgs(element, XmlParseErrorKind.InvalidValue, - // $"{SfxEventXmlTags.MinPostdelay} should not be higher than {SfxEventXmlTags.MaxPostdelay} for SFXEvent '{sfxEvent.Name}'")); - //} + if (sfxEvent.Name.Length > PGConstants.MaxSFXEventName) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.TooLongData, + Message = $"SFXEvent name '{sfxEvent.Name}' is too long." + }); + } + + if (sfxEvent.Is2D == sfxEvent.Is3D) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"SFXEvent '{sfxEvent.Name}' has the same value for is2D and is3D." + }); + } + + if (sfxEvent.MinVolume > sfxEvent.MaxVolume) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"{SfxEventXmlTags.MinVolume} should not be higher than {SfxEventXmlTags.MaxVolume} for SFXEvent '{sfxEvent.Name}'" + }); + } + + if (sfxEvent.MinPitch > sfxEvent.MaxPitch) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"{SfxEventXmlTags.MinPitch} should not be higher than {SfxEventXmlTags.MaxPitch} for SFXEvent '{sfxEvent.Name}'" + }); + } + + if (sfxEvent.MinPan2D > sfxEvent.MaxPan2D) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"{SfxEventXmlTags.MinPan2D} should not be higher than {SfxEventXmlTags.MaxPan2D} for SFXEvent '{sfxEvent.Name}'" + }); + } + + if (sfxEvent.MinPredelay > sfxEvent.MaxPredelay) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"{SfxEventXmlTags.MinPredelay} should not be higher than {SfxEventXmlTags.MaxPredelay} for SFXEvent '{sfxEvent.Name}'" + }); + } + + if (sfxEvent.MinPostdelay > sfxEvent.MaxPostdelay) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"{SfxEventXmlTags.MinPostdelay} should not be higher than {SfxEventXmlTags.MaxPostdelay} for SFXEvent '{sfxEvent.Name}'" + }); + } + + sfxEvent.FixupValues(); } - protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, in IReadOnlyFrugalValueListDictionary parsedEntries) + protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, + in IReadOnlyFrugalValueListDictionary parsedEntries) { - switch (tag.Name.LocalName) + if (tag.Name.LocalName == SfxEventXmlTags.UsePreset) { - case SfxEventXmlTags.OverlapTest: - sfxEvent.OverlapTestName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.ChainedSfxEvent: - sfxEvent.ChainedSfxEventName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.UsePreset: + var presetName = PetroglyphXmlStringParser.Instance.Parse(tag); + + Debug.Assert(!string.IsNullOrEmpty(presetName)); + + var presetNameCrc = HashingService.GetCrc32Upper(presetName.AsSpan(), PGConstants.DefaultPGEncoding); + if (presetNameCrc != default && parsedEntries.TryGetFirstValue(presetNameCrc, out var preset)) + sfxEvent.ApplyPreset(preset); + else { - var presetName = PetroglyphXmlStringParser.Instance.Parse(tag); - var presetNameCrc = HashingService.GetCrc32Upper(presetName.AsSpan(), PGConstants.DefaultPGEncoding); - if (presetNameCrc != default && parsedEntries.TryGetFirstValue(presetNameCrc, out var preset)) - sfxEvent.ApplyPreset(preset); - else + ErrorReporter?.Report(new XmlError(this, tag) { - ErrorReporter?.Report(new XmlError(this, tag) - { - Message = $"Cannot to find preset '{presetName}' for SFXEvent '{sfxEvent.Name}'", - ErrorKind = XmlParseErrorKind.MissingReference - }); - } - return true; + Message = $"Cannot to find preset '{presetName}' for SFXEvent '{sfxEvent.Name}'", + ErrorKind = XmlParseErrorKind.MissingReference + }); } - case SfxEventXmlTags.IsPreset: - sfxEvent.IsPreset = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.Is3D: - sfxEvent.Is3D = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.Is2D: - sfxEvent.Is2D = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.IsGui: - sfxEvent.IsGui = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.IsHudVo: - sfxEvent.IsHudVo = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.IsUnitResponseVo: - sfxEvent.IsUnitResponseVo = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.IsAmbientVo: - sfxEvent.IsAmbientVo = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.Localize: - sfxEvent.IsLocalized = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.PlaySequentially: - sfxEvent.PlaySequentially = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.KillsPreviousObjectSFX: - sfxEvent.KillsPreviousObjectsSfx = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - - case SfxEventXmlTags.Samples: - sfxEvent.Samples = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case SfxEventXmlTags.PreSamples: - sfxEvent.PreSamples = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case SfxEventXmlTags.PostSamples: - sfxEvent.PostSamples = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case SfxEventXmlTags.TextID: - sfxEvent.LocalizedTextIDs = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - - case SfxEventXmlTags.Priority: - sfxEvent.Priority = (byte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, SfxEvent.MinPriorityValue, SfxEvent.MaxPriorityValue); - return true; - case SfxEventXmlTags.MinPitch: - sfxEvent.MinPitch = (byte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, SfxEvent.MinPitchValue, SfxEvent.MaxPitchValue); - return true; - case SfxEventXmlTags.MaxPitch: - sfxEvent.MaxPitch = (byte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, SfxEvent.MinPitchValue, SfxEvent.MaxPitchValue); - return true; - case SfxEventXmlTags.MinPan2D: - sfxEvent.MinPan2D = (byte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, byte.MinValue, SfxEvent.MaxPan2dValue); - return true; - case SfxEventXmlTags.MaxPan2D: - sfxEvent.MaxPan2D = (byte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, byte.MinValue, SfxEvent.MaxPan2dValue); - return true; - case SfxEventXmlTags.PlayCount: - sfxEvent.PlayCount = (sbyte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, SfxEvent.InfinitivePlayCount, sbyte.MaxValue); - return true; - case SfxEventXmlTags.MaxInstances: - sfxEvent.MaxInstances = (sbyte)PetroglyphXmlIntegerParser.Instance.ParseWithRange(tag, SfxEvent.MinMaxInstances, sbyte.MaxValue); - return true; - - case SfxEventXmlTags.Probability: - sfxEvent.Probability = PetroglyphXmlMax100ByteParser.Instance.ParseWithRange(tag, byte.MinValue, SfxEvent.MaxProbability); - return true; - case SfxEventXmlTags.MinVolume: - sfxEvent.MinVolume = PetroglyphXmlMax100ByteParser.Instance.ParseWithRange(tag, byte.MinValue, SfxEvent.MaxVolumeValue); - return true; - case SfxEventXmlTags.MaxVolume: - sfxEvent.MaxVolume = PetroglyphXmlMax100ByteParser.Instance.ParseWithRange(tag, byte.MinValue, SfxEvent.MaxVolumeValue); - return true; - - case SfxEventXmlTags.MinPredelay: - sfxEvent.MinPredelay = PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.MaxPredelay: - sfxEvent.MaxPredelay = PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.MinPostdelay: - sfxEvent.MinPostdelay = PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - case SfxEventXmlTags.MaxPostdelay: - sfxEvent.MaxPostdelay = PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - - case SfxEventXmlTags.LoopFadeInSeconds: - sfxEvent.LoopFadeInSeconds = PetroglyphXmlFloatParser.Instance.ParseAtLeast(tag, SfxEvent.MinLoopSeconds); - return true; - case SfxEventXmlTags.LoopFadeOutSeconds: - sfxEvent.LoopFadeOutSeconds = PetroglyphXmlFloatParser.Instance.ParseAtLeast(tag, SfxEvent.MinLoopSeconds); - return true; - case SfxEventXmlTags.VolumeSaturationDistance: - // I think it was planned at some time to support -1.0 and >= 0.0, since you don't get a warning when -1.0 is coded - // but the Engine coerces anything < 0.0 to 0.0. - sfxEvent.VolumeSaturationDistance = PetroglyphXmlFloatParser.Instance.ParseAtLeast(tag, SfxEvent.MinVolumeSaturation); - return true; - default: return false; + // Set the preset value regardless whether we found the SFXEvent or not. + sfxEvent.UsePresetName = presetName; + + return true; } + + return base.ParseTag(tag, sfxEvent, parsedEntries); } - private sealed class SfxEventXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) + + internal sealed class SfxEventXmlTagMapper(IServiceProvider serviceProvider) + : XmlTagMapper(serviceProvider) { protected override void BuildMappings() { AddMapping( - "OverlapTestName", + SfxEventXmlTags.IsPreset, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.IsPreset = val); + AddMapping( + SfxEventXmlTags.UsePreset, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.UsePresetName = val); + AddMapping( + SfxEventXmlTags.Samples, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.Samples = new ReadOnlyCollection(val)); + AddMapping( + SfxEventXmlTags.PreSamples, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.PreSamples = new ReadOnlyCollection(val)); + AddMapping( + SfxEventXmlTags.PostSamples, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.PostSamples = new ReadOnlyCollection(val)); + AddMapping( + SfxEventXmlTags.TextID, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.LocalizedTextIDs = new ReadOnlyCollection(val)); + AddMapping( + SfxEventXmlTags.PlaySequentially, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.PlaySequentially = val); + AddMapping( + SfxEventXmlTags.Priority, + x => PetroglyphXmlByteParser.Instance.ParseClamped(x, SfxEvent.MinPriorityValue, SfxEvent.MaxPriorityValue), + (obj, val) => obj.Priority = val); + AddMapping( + SfxEventXmlTags.Probability, + x => PetroglyphXmlBytePercentParser.Instance.ParseAtMost(x, SfxEvent.MaxProbabilityValue), + (obj, val) => obj.Probability = val); + AddMapping( + SfxEventXmlTags.PlayCount, + x => PetroglyphXmlSByteParser.Instance.ParseAtLeast(x, SfxEvent.InfinitivePlayCountValue), + (obj, val) => obj.PlayCount = val); + AddMapping( + SfxEventXmlTags.LoopFadeInSeconds, + x => PetroglyphXmlFloatParser.Instance.ParseAtLeast(x, SfxEvent.MinLoopSecondsValue), + (obj, val) => obj.LoopFadeInSeconds = val); + AddMapping( + SfxEventXmlTags.LoopFadeOutSeconds, + x => PetroglyphXmlFloatParser.Instance.ParseAtLeast(x, SfxEvent.MinLoopSecondsValue), + (obj, val) => obj.LoopFadeOutSeconds = val); + AddMapping( + SfxEventXmlTags.MaxInstances, + x => PetroglyphXmlSByteParser.Instance.ParseAtLeast(x, SfxEvent.MinMaxInstancesValue), + (obj, val) => obj.MaxInstances = val); + AddMapping( + SfxEventXmlTags.MinVolume, + x => PetroglyphXmlBytePercentParser.Instance.ParseAtMost(x, SfxEvent.MaxVolumeValue), + (obj, val) => obj.MinVolume = val); + AddMapping( + SfxEventXmlTags.MaxVolume, + x => PetroglyphXmlBytePercentParser.Instance.ParseAtMost(x, SfxEvent.MaxVolumeValue), + (obj, val) => obj.MaxVolume = val); + AddMapping( + SfxEventXmlTags.MinPitch, + x => PetroglyphXmlByteParser.Instance.ParseClamped(x, SfxEvent.MinPitchValue, SfxEvent.MaxPitchValue), + (obj, val) => obj.MinPitch = val); + AddMapping( + SfxEventXmlTags.MaxPitch, + x => PetroglyphXmlByteParser.Instance.ParseClamped(x, SfxEvent.MinPitchValue, SfxEvent.MaxPitchValue), + (obj, val) => obj.MaxPitch = val); + AddMapping( + SfxEventXmlTags.MinPan2D, + x => PetroglyphXmlByteParser.Instance.ParseAtMost(x, SfxEvent.MaxPan2dValue), + (obj, val) => obj.MinPan2D = val); + AddMapping( + SfxEventXmlTags.MaxPan2D, + x => PetroglyphXmlByteParser.Instance.ParseAtMost(x, SfxEvent.MaxPan2dValue), + (obj, val) => obj.MaxPan2D = val); + AddMapping( + SfxEventXmlTags.MinPredelay, + PetroglyphXmlUnsignedIntegerParser.Instance.Parse, + (obj, val) => obj.MinPredelay = val); + AddMapping( + SfxEventXmlTags.MaxPredelay, + PetroglyphXmlUnsignedIntegerParser.Instance.Parse, + (obj, val) => obj.MaxPredelay = val); + AddMapping( + SfxEventXmlTags.MinPostdelay, + PetroglyphXmlUnsignedIntegerParser.Instance.Parse, + (obj, val) => obj.MinPostdelay = val); + AddMapping( + SfxEventXmlTags.MaxPostdelay, + PetroglyphXmlUnsignedIntegerParser.Instance.Parse, + (obj, val) => obj.MaxPostdelay = val); + AddMapping( + SfxEventXmlTags.VolumeSaturationDistance, + // I think it was planned at some time to support -1.0 and >= 0.0, since you don't get a warning when -1.0 is coded + // but the Engine coerces anything < 0.0 to 0.0. + x => PetroglyphXmlFloatParser.Instance.ParseAtLeast(x, SfxEvent.MinVolumeSaturationValue), + (obj, val) => obj.VolumeSaturationDistance = val); + AddMapping( + SfxEventXmlTags.KillsPreviousObjectSFX, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.KillsPreviousObjectsSfx = val); + AddMapping( + SfxEventXmlTags.OverlapTest, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.OverlapTestName = val); + AddMapping( + SfxEventXmlTags.Localize, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.IsLocalized = val); + AddMapping( + SfxEventXmlTags.Is2D, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Is2D = val); + AddMapping( + SfxEventXmlTags.Is3D, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Is3D = val); + AddMapping( + SfxEventXmlTags.IsGui, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.IsGui = val); + AddMapping( + SfxEventXmlTags.IsHudVo, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.IsHudVo = val); + AddMapping( + SfxEventXmlTags.IsUnitResponseVo, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.IsUnitResponseVo = val); + AddMapping( + SfxEventXmlTags.IsAmbientVo, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.IsAmbientVo = val); + AddMapping( + SfxEventXmlTags.ChainedSfxEvent, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.ChainedSfxEventName = val); } } + + internal static class SfxEventXmlTags + { + internal const string PresetXRef = "XREF_PRESET"; + internal const string IsPreset = "Is_Preset"; + internal const string UsePreset = "Use_Preset"; + internal const string Samples = "Samples"; + internal const string PreSamples = "Pre_Samples"; + internal const string PostSamples = "Post_Samples"; + internal const string TextID = "Text_ID"; + internal const string PlaySequentially = "Play_Sequentially"; + internal const string Priority = "Priority"; + internal const string Probability = "Probability"; + internal const string PlayCount = "Play_Count"; + internal const string LoopFadeInSeconds = "Loop_Fade_In_Seconds"; + internal const string LoopFadeOutSeconds = "Loop_Fade_Out_Seconds"; + internal const string MaxInstances = "Max_Instances"; + internal const string MinVolume = "Min_Volume"; + internal const string MaxVolume = "Max_Volume"; + internal const string MinPitch = "Min_Pitch"; + internal const string MaxPitch = "Max_Pitch"; + internal const string MinPan2D = "Min_Pan2D"; + internal const string MaxPan2D = "Max_Pan2D"; + internal const string MinPredelay = "Min_Predelay"; + internal const string MaxPredelay = "Max_Predelay"; + internal const string MinPostdelay = "Min_Postdelay"; + internal const string MaxPostdelay = "Max_Postdelay"; + internal const string VolumeSaturationDistance = "Volume_Saturation_Distance"; + internal const string KillsPreviousObjectSFX = "Kills_Previous_Object_SFX"; + internal const string OverlapTest = "Overlap_Test"; + internal const string Localize = "Localize"; + internal const string Is2D = "Is_2D"; + internal const string Is3D = "Is_3D"; + internal const string IsGui = "Is_GUI"; + internal const string IsHudVo = "Is_HUD_VO"; + internal const string IsUnitResponseVo = "Is_Unit_Response_VO"; + internal const string IsAmbientVo = "Is_Ambient_VO"; + internal const string ChainedSfxEvent = "Chained_SFXEvent"; + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/CommandBarComponentTags.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/CommandBarComponentTags.cs deleted file mode 100644 index bc5498b..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/CommandBarComponentTags.cs +++ /dev/null @@ -1,108 +0,0 @@ -namespace PG.StarWarsGame.Engine.Xml.Tags; - -public static class CommandBarComponentTags -{ - public const string SelectedTextureName = "Selected_Texture_Name"; - public const string BlankTextureName = "Blank_Texture_Name"; - public const string IconTextureName = "Icon_Texture_Name"; - public const string IconAlternateTextureName = "Icon_Alternate_Texture_Name"; - public const string MouseOverTextureName = "Mouse_Over_Texture_Name"; - public const string DisabledTextureName = "Disabled_Texture_Name"; - public const string FlashTextureName = "Flash_Texture_Name"; - public const string BarTextureName = "Bar_Texture_Name"; - public const string BarOverlayName = "Bar_Overlay_Name"; - public const string BuildTextureName = "Build_Texture_Name"; - public const string ModelName = "Model_Name"; - public const string BoneName = "Bone_Name"; - public const string CursorTextureName = "Cursor_Texture_Name"; - public const string FontName = "Font_Name"; - public const string AlternateFontName = "Alternate_Font_Name"; - public const string TooltipText = "Tooltip_Text"; - public const string ClickSfx = "Click_SFX"; - public const string MouseOverSfx = "Mouse_Over_SFX"; - public const string LowerEffectTextureName = "Lower_Effect_Texture_Name"; - public const string UpperEffectTextureName = "Upper_Effect_Texture_Name"; - public const string OverlayTextureName = "Overlay_Texture_Name"; - public const string Overlay2TextureName = "Overlay2_Texture_Name"; - public const string RightClickSfx = "Right_Click_SFX"; - public const string Type = "Type"; - public const string Group = "Group"; - public const string DragAndDrop = "Drag_And_Drop"; - public const string DragSelect = "Drag_Select"; - public const string Receptor = "Receptor"; - public const string Toggle = "Toggle"; - public const string Tab = "Tab"; - public const string AssociatedText = "Associated_Text"; - public const string Hidden = "Hidden"; - public const string Scale = "Scale"; - public const string Color = "Color"; - public const string TextColor = "Text_Color"; - public const string TextColor2 = "Text_Color2"; - public const string Size = "Size"; - public const string ClearColor = "Clear_Color"; - public const string Disabled = "Disabled"; - public const string SwapTexture = "Swap_Texture"; - public const string BaseLayer = "Base_Layer"; - public const string DrawAdditive = "Draw_Additive"; - public const string TextOffset = "Text_Offset"; - public const string TextOffset2 = "Text_Offset2"; - public const string Offset = "Offset"; - public const string DefaultOffset = "Default_Offset"; - public const string DefaultOffsetWidescreen = "Default_Offset_Widescreen"; - public const string IconOffset = "Icon_Offset"; - public const string MouseOverOffset = "Mouse_Over_Offset"; - public const string DisabledOffset = "Disabled_Offset"; - public const string BuildDialOffset = "Build_Dial_Offset"; - public const string BuildDial2Offset = "Build_Dial2_Offset"; - public const string LowerEffectOffset = "Lower_Effect_Offset"; - public const string UpperEffectOffset = "Upper_Effect_Offset"; - public const string OverlayOffset = "Overlay_Offset"; - public const string Overlay2Offset = "Overlay2_Offset"; - public const string Editable = "Editable"; - public const string MaxTextLength = "Max_Text_Length"; - public const string BlinkRate = "Blink_Rate"; - public const string FontPointSize = "Font_Point_Size"; - public const string TextOutline = "Text_Outline"; - public const string MaxTextWidth = "Max_Text_Width"; - public const string Stackable = "Stackable"; - public const string ModelOffsetX = "Model_Offset_X"; - public const string ModelOffsetY = "Model_Offset_Y"; - public const string ScaleModelX = "Scale_Model_X"; - public const string ScaleModelY = "Scale_Model_Y"; - public const string Collideable = "Collideable"; - public const string TextEmboss = "Text_Emboss"; - public const string ShouldGhost = "Should_Ghost"; - public const string GhostBaseOnly = "Ghost_Base_Only"; - public const string MaxBarLevel = "Max_Bar_Level"; - public const string MaxBarColor = "Max_Bar_Color"; - public const string CrossFade = "Cross_Fade"; - public const string LeftJustified = "Left_Justified"; - public const string RightJustified = "Right_Justified"; - public const string NoShell = "No_Shell"; - public const string SnapDrag = "Snap_Drag"; - public const string SnapLocation = "Snap_Location"; - public const string BlinkDuration = "Blink_Duration"; - public const string ScaleDuration = "Scale_Duration"; - public const string OffsetRender = "Offset_Render"; - public const string BlinkFade = "Blink_Fade"; - public const string NoHiddenCollision = "No_Hidden_Collision"; - public const string ManualOffset = "Manual_Offset"; - public const string SelectedAlpha = "Selected_Alpha"; - public const string PixelAlign = "Pixel_Align"; - public const string CanDragStack = "Can_Drag_Stack"; - public const string CanAnimate = "Can_Animate"; - public const string AnimFps = "Anim_FPS"; - public const string LoopAnim = "Loop_Anim"; - public const string SmoothBar = "Smooth_Bar"; - public const string OutlinedBar = "Outlined_Bar"; - public const string DragBack = "Drag_Back"; - public const string LowerEffectAdditive = "Lower_Effect_Additive"; - public const string UpperEffectAdditive = "Upper_Effect_Additive"; - public const string ClickShift = "Click_Shift"; - public const string TutorialScene = "Tutorial_Scene"; - public const string DialogScene = "Dialog_Scene"; - public const string ShouldRenderAtDragPos = "Should_Render_At_Drag_Pos"; - public const string DisableDarken = "Disable_Darken"; - public const string AnimateBack = "Animate_Back"; - public const string AnimateUpperEffect = "Animate_Upper_Effect"; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/ComponentTextureKeyExtensions.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/ComponentTextureKeyExtensions.cs deleted file mode 100644 index c072c90..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/ComponentTextureKeyExtensions.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using PG.StarWarsGame.Engine.GuiDialog; - -namespace PG.StarWarsGame.Engine.Xml.Tags; - -internal static class ComponentTextureKeyExtensions -{ - public static bool TryConvertToKey(ReadOnlySpan keyValue, out GuiComponentType key) - { - key = keyValue switch - { - "Button_Left" => GuiComponentType.ButtonLeft, - "Button_Middle" => GuiComponentType.ButtonMiddle, - "Button_Right" => GuiComponentType.ButtonRight, - "Button_Left_Mouse_Over" => GuiComponentType.ButtonLeftMouseOver, - "Button_Middle_Mouse_Over" => GuiComponentType.ButtonMiddleMouseOver, - "Button_Right_Mouse_Over" => GuiComponentType.ButtonRightMouseOver, - "Button_Left_Pressed" => GuiComponentType.ButtonLeftPressed, - "Button_Middle_Pressed" => GuiComponentType.ButtonMiddlePressed, - "Button_Right_Pressed" => GuiComponentType.ButtonRightPressed, - "Button_Left_Disabled" => GuiComponentType.ButtonLeftDisabled, - "Button_Middle_Disabled" => GuiComponentType.ButtonMiddleDisabled, - "Button_Right_Disabled" => GuiComponentType.ButtonRightDisabled, - - "Check_Off" => GuiComponentType.CheckOff, - "Check_On" => GuiComponentType.CheckOn, - - "Dial_Left" => GuiComponentType.DialLeft, - "Dial_Middle" => GuiComponentType.DialMiddle, - "Dial_Right" => GuiComponentType.DialRight, - "Dial_Plus" => GuiComponentType.DialPlus, - "Dial_Plus_Mouse_Over" => GuiComponentType.DialPlusMouseOver, - "Dial_Plus_Pressed" => GuiComponentType.DialPlusPressed, - "Dial_Minus" => GuiComponentType.DialMinus, - "Dial_Minus_Mouse_Over" => GuiComponentType.DialMinusMouseOver, - "Dial_Minus_Pressed" => GuiComponentType.DialMinusPressed, - "Dial_Tab" => GuiComponentType.DialTab, - - "Frame_Bottom" => GuiComponentType.FrameBottom, - "Frame_Bottom_Left" => GuiComponentType.FrameBottomLeft, - "Frame_Bottom_Right" => GuiComponentType.FrameBottomRight, - "Frame_Background" => GuiComponentType.FrameBackground, - "Frame_Left" => GuiComponentType.FrameLeft, - "Frame_Right" => GuiComponentType.FrameRight, - "Frame_Top" => GuiComponentType.FrameTop, - "Frame_Top_Left" => GuiComponentType.FrameTopLeft, - "Frame_Top_Right" => GuiComponentType.FrameTopRight, - "Frame_Top_Transition_Left" => GuiComponentType.FrameTopTransitionLeft, - "Frame_Top_Transition_Right" => GuiComponentType.FrameTopTransitionRight, - "Frame_Bottom_Transition_Left" => GuiComponentType.FrameBottomTransitionLeft, - "Frame_Bottom_Transition_Right" => GuiComponentType.FrameBottomTransitionRight, - "Frame_Left_Transition_Top" => GuiComponentType.FrameLeftTransitionTop, - "Frame_Left_Transition_Bottom" => GuiComponentType.FrameLeftTransitionBottom, - "Frame_Right_Transition_Top" => GuiComponentType.FrameRightTransitionTop, - "Frame_Right_Transition_Bottom" => GuiComponentType.FrameRightTransitionBottom, - - "Radio_Off" => GuiComponentType.RadioOff, - "Radio_On" => GuiComponentType.RadioOn, - "Radio_Disabled" => GuiComponentType.RadioDisabled, - "Radio_Mouse_Over" => GuiComponentType.RadioMouseOver, - - "Scroll_Down_Button" => GuiComponentType.ScrollDownButton, - "Scroll_Down_Button_Pressed" => GuiComponentType.ScrollDownButtonPressed, - "Scroll_Down_Button_Mouse_Over" => GuiComponentType.ScrollDownButtonMouseOver, - "Scroll_Down_Button_Disabled" => GuiComponentType.ScrollDownButtonDisabled, - "Scroll_Middle" => GuiComponentType.ScrollMiddle, - "Scroll_Middle_Disabled" => GuiComponentType.ScrollMiddleDisabled, - "Scroll_Tab" => GuiComponentType.ScrollTab, - "Scroll_Tab_Disabled" => GuiComponentType.ScrollTabDisabled, - "Scroll_Up_Button" => GuiComponentType.ScrollUpButton, - "Scroll_Up_Button_Pressed" => GuiComponentType.ScrollUpButtonPressed, - "Scroll_Up_Button_Mouse_Over" => GuiComponentType.ScrollUpButtonMouseOver, - "Scroll_Up_Button_Disabled" => GuiComponentType.ScrollUpButtonDisabled, - - "Trackbar_Scroll_Down_Button" => GuiComponentType.TrackbarScrollDownButton, - "Trackbar_Scroll_Down_Button_Pressed" => GuiComponentType.TrackbarScrollDownButtonPressed, - "Trackbar_Scroll_Down_Button_Mouse_Over" => GuiComponentType.TrackbarScrollDownButtonMouseOver, - "Trackbar_Scroll_Down_Button_Disabled" => GuiComponentType.TrackbarScrollDownButtonDisabled, - "Trackbar_Scroll_Middle" => GuiComponentType.TrackbarScrollMiddle, - "Trackbar_Scroll_Middle_Disabled" => GuiComponentType.TrackbarScrollMiddleDisabled, - "Trackbar_Scroll_Tab" => GuiComponentType.TrackbarScrollTab, - "Trackbar_Scroll_Tab_Disabled" => GuiComponentType.TrackbarScrollTabDisabled, - "Trackbar_Scroll_Up_Button" => GuiComponentType.TrackbarScrollUpButton, - "Trackbar_Scroll_Up_Button_Pressed" => GuiComponentType.TrackbarScrollUpButtonPressed, - "Trackbar_Scroll_Up_Button_Mouse_Over" => GuiComponentType.TrackbarScrollUpButtonMouseOver, - "Trackbar_Scroll_Up_Button_Disabled" => GuiComponentType.TrackbarScrollUpButtonDisabled, - - "Small_Frame_Bottom" => GuiComponentType.SmallFrameBottom, - "Small_Frame_Bottom_Left" => GuiComponentType.SmallFrameBottomLeft, - "Small_Frame_Bottom_Right" => GuiComponentType.SmallFrameBottomRight, - "Small_Frame_Left" => GuiComponentType.SmallFrameMiddleLeft, - "Small_Frame_Right" => GuiComponentType.SmallFrameMiddleRight, - "Small_Frame_Top" => GuiComponentType.SmallFrameTop, - "Small_Frame_Top_Left" => GuiComponentType.SmallFrameTopLeft, - "Small_Frame_Top_Right" => GuiComponentType.SmallFrameTopRight, - "Small_Frame_Background" => GuiComponentType.SmallFrameBackground, - - "Combo_Box_Popdown_Button" => GuiComponentType.ComboboxPopdown, - "Combo_Box_Popdown_Button_Pressed" => GuiComponentType.ComboboxPopdownPressed, - "Combo_Box_Popdown_Button_Mouse_Over" => GuiComponentType.ComboboxPopdownMouseOver, - "Combo_Box_Text_Box" => GuiComponentType.ComboboxTextBox, - "Combo_Box_Left_Cap" => GuiComponentType.ComboboxLeftCap, - - "Progress_Bar_Left" => GuiComponentType.ProgressLeft, - "Progress_Bar_Middle_Off" => GuiComponentType.ProgressMiddleOff, - "Progress_Bar_Middle_On" => GuiComponentType.ProgressMiddleOn, - "Progress_Bar_Right" => GuiComponentType.ProgressRight, - - "Scanlines" => GuiComponentType.Scanlines, - _ => (GuiComponentType)int.MaxValue - }; - return (int)key != int.MaxValue; - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/SfxEventXmlTags.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/SfxEventXmlTags.cs deleted file mode 100644 index 959da6b..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/Tags/SfxEventXmlTags.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace PG.StarWarsGame.Engine.Xml.Tags; - -public static class SfxEventXmlTags -{ - internal const string PresetXRef = "XREF_PRESET"; - - public const string IsPreset = "Is_Preset"; - public const string UsePreset = "Use_Preset"; - public const string Samples = "Samples"; - public const string PreSamples = "Pre_Samples"; - public const string PostSamples = "Post_Samples"; - public const string TextID = "Text_ID"; - public const string PlaySequentially = "Play_Sequentially"; - public const string Priority = "Priority"; - public const string Probability = "Probability"; - public const string PlayCount = "Play_Count"; - public const string LoopFadeInSeconds = "Loop_Fade_In_Seconds"; - public const string LoopFadeOutSeconds = "Loop_Fade_Out_Seconds"; - public const string MaxInstances = "Max_Instances"; - public const string MinVolume = "Min_Volume"; - public const string MaxVolume = "Max_Volume"; - public const string MinPitch = "Min_Pitch"; - public const string MaxPitch = "Max_Pitch"; - public const string MinPan2D = "Min_Pan2D"; - public const string MaxPan2D = "Max_Pan2D"; - public const string MinPredelay = "Min_Predelay"; - public const string MaxPredelay = "Max_Predelay"; - public const string MinPostdelay = "Min_Postdelay"; - public const string MaxPostdelay = "Max_Postdelay"; - public const string VolumeSaturationDistance = "Volume_Saturation_Distance"; - public const string KillsPreviousObjectSFX = "Kills_Previous_Object_SFX"; - public const string OverlapTest = "Overlap_Test"; - public const string Localize = "Localize"; - public const string Is2D = "Is_2D"; - public const string Is3D = "Is_3D"; - public const string IsGui = "Is_GUI"; - public const string IsHudVo = "Is_HUD_VO"; - public const string IsUnitResponseVo = "Is_Unit_Response_VO"; - public const string IsAmbientVo = "Is_Ambient_VO"; - public const string ChainedSfxEvent = "Chained_SFXEvent"; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs index c3827fa..3952f25 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParseSettings.cs @@ -6,5 +6,5 @@ public sealed record PetroglyphStarWarsGameXmlParseSettings public bool InvalidFilesListXmlFailsInitialization { get; init; } = true; - public bool InvalidContainerXmlFailsInitialization { get; init; } = false; + public bool InvalidObjectXmlFailsInitialization { get; init; } = false; } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs index 7e27965..7beb801 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Xml; using AnakinRaW.CommonUtilities.Collections; @@ -39,72 +40,23 @@ public PetroglyphStarWarsGameXmlParser( Name = GetType().FullName!; } - public XmlFileList ParseFileList(string xmlFile) + public T? ParseFile(string xmlFile, XmlFileParser parser) where T : XmlObject { - Logger.LogDebug("Parsing container data '{XmlFile}'", xmlFile); - - using var containerStream = _gameRepository.TryOpenFile(xmlFile); - if (containerStream == null) - { - var message = $"Could not find XML file '{xmlFile}'"; - - Logger.LogWarning(message); - - _reporter.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, null)) - { - Message = message, - ErrorKind = XmlParseErrorKind.MissingFile - }); - - if (_settings.InvalidFilesListXmlFailsInitialization) - { - _reporter.Report(new InitializationError - { - GameManager = _settings.GameManager, - Message = message, - }); - } - - return XmlFileList.Empty(new XmlLocationInfo(xmlFile, null)); - } - - XmlFileList? container; - var containerParser = new XmlFileListParser(Services, _reporter); - - try - { - container = containerParser.ParseFile(containerStream); - if (container is null) - throw new XmlException($"Unable to parse XML container file '{xmlFile}'."); - } - catch (XmlException e) - { - _reporter.Report(new XmlError(this, locationInfo: new XmlLocationInfo(xmlFile, e.LineNumber)) - { - ErrorKind = XmlParseErrorKind.Unknown, - Message = e.Message, - }); - - if (_settings.InvalidFilesListXmlFailsInitialization) - { - _reporter.Report(new InitializationError - { - GameManager = _settings.GameManager, - Message = e.Message, - }); - } - - return XmlFileList.Empty(new XmlLocationInfo(xmlFile, null)); - } + return ParseCore(xmlFile, parser.ParseFile, () => null); + } - return container; + public XmlFileList ParseFileList(string xmlFile) + { + return ParseCore(xmlFile, + stream => new XmlFileListParser(Services, _reporter).ParseFile(stream), + () => XmlFileList.Empty(new XmlLocationInfo(xmlFile, null))); } public void ParseEntriesFromFileListXml( string xmlFile, string lookupPath, FrugalValueListDictionary entries, - Action? onFileParseAction = null) where T : NamedXmlObject + Action? onParseContainerAction = null) where T : NamedXmlObject { var container = ParseFileList(xmlFile); @@ -115,17 +67,28 @@ public void ParseEntriesFromFileListXml( foreach (var file in xmlFiles) { - onFileParseAction?.Invoke(file); - if (!ParseEntriesFromContainerFile(file, parser, entries)) + onParseContainerAction?.Invoke(file); + if (!ParseObjectsFromContainerFile(file, parser, entries)) return; } } - - public bool ParseEntriesFromContainerFile( + + public bool ParseObjectsFromContainerFile( string xmlFile, XmlContainerFileParser parser, IFrugalValueListDictionary entries) where T : NamedXmlObject { + return ParseCore(xmlFile, stream => + { + parser.ParseFile(stream, entries); + return true; + }, () => _settings.InvalidObjectXmlFailsInitialization); + } + + private T ParseCore(string xmlFile, Func parseAction, Func invalidFileAction) + { + Logger.LogDebug("Parsing file '{XmlFile}'", xmlFile); + using var fileStream = _gameRepository.TryOpenFile(xmlFile); if (fileStream is null) @@ -138,8 +101,8 @@ public bool ParseEntriesFromContainerFile( Message = message, ErrorKind = XmlParseErrorKind.MissingFile }); - - if (_settings.InvalidContainerXmlFailsInitialization) + + if (_settings.InvalidObjectXmlFailsInitialization) { _reporter.Report(new InitializationError { @@ -148,15 +111,12 @@ public bool ParseEntriesFromContainerFile( }); } - return _settings.InvalidContainerXmlFailsInitialization; + return invalidFileAction(); } - Logger.LogDebug("Parsing File '{File}'", xmlFile); - try { - parser.ParseFile(fileStream, entries); - return true; + return parseAction(fileStream); } catch (XmlException e) { @@ -165,7 +125,7 @@ public bool ParseEntriesFromContainerFile( ErrorKind = XmlParseErrorKind.Unknown, Message = e.Message, }); - if (_settings.InvalidContainerXmlFailsInitialization) + if (_settings.InvalidObjectXmlFailsInitialization) { _reporter.Report(new InitializationError { @@ -173,7 +133,8 @@ public bool ParseEntriesFromContainerFile( Message = e.Message, }); } - return _settings.InvalidContainerXmlFailsInitialization; + + return invalidFileAction(); } } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj index 052190c..a92efb1 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.ALO/PG.StarWarsGame.Files.ALO.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net10.0 PG.StarWarsGame.Files.ALO PG.StarWarsGame.Files.ALO AlamoEngineTools.PG.StarWarsGame.Files.ALO diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj index 5328887..9fe818c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net10.0 PG.StarWarsGame.Files.ChunkFiles PG.StarWarsGame.Files.ChunkFiles AlamoEngineTools.PG.StarWarsGame.Files.ChunkFiles diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs index 090d4d9..41cde2c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Data/XmlObject.cs @@ -3,8 +3,4 @@ public abstract class XmlObject(XmlLocationInfo location) { public XmlLocationInfo Location { get; } = location; - - public virtual void CoerceValues() - { - } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs index 861e441..6308a74 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/ErrorHandling/XmlParseErrorKind.cs @@ -54,5 +54,9 @@ public enum XmlParseErrorKind /// /// The XML tag has child elements. /// - TagHasElements = 12 + TagHasElements = 12, + /// + /// The name of the XML Element (not the value of the attribute "Name") has an unexpected name. + /// + UnexceptedElementName = 13, } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj index 5feadba..961034b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netstandard2.1 + netstandard2.0;netstandard2.1;net10.0 PG.StarWarsGame.Files.XML PG.StarWarsGame.Files.XML AlamoEngineTools.PG.StarWarsGame.Files.XML diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs index f4eb0af..dd9ac3d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs @@ -12,7 +12,7 @@ public abstract class XmlObjectParserBase(IXmlTagMapper true; - protected virtual void ValidateValues(TObject namedXmlObject, XElement element) + protected virtual void ValidateAndFixupValues(TObject namedXmlObject, XElement element) { } @@ -20,19 +20,23 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) { foreach (var tag in element.Elements()) { - if (string.IsNullOrEmpty(tag.Value) && IgnoreEmptyValue) - continue; - - if (tag.HasElements) - Parse(xmlObject, tag, in state); - - if (!ParseTag(tag, xmlObject, state)) + if (!tag.HasElements) { - ErrorReporter?.Report(new XmlError(this, element) + if (string.IsNullOrEmpty(tag.PGValue) && IgnoreEmptyValue) + continue; + + if (!ParseTag(tag, xmlObject, state)) { - Message = $"The node '{tag.Name}' is not supported.", - ErrorKind = XmlParseErrorKind.UnknownNode - }); + ErrorReporter?.Report(new XmlError(this, tag) + { + Message = $"The node '{tag.Name}' is not supported.", + ErrorKind = XmlParseErrorKind.UnknownNode + }); + } + } + else + { + Parse(xmlObject, tag, in state); } } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs index a31f2aa..140dcd0 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs @@ -1,5 +1,4 @@ using System; -using System.Text; using System.Xml.Linq; using AnakinRaW.CommonUtilities.Collections; using Microsoft.Extensions.DependencyInjection; @@ -25,8 +24,7 @@ public T Parse(XElement element, IReadOnlyFrugalValueListDictionary pa var name = GetXmlObjectName(element, out nameCrc); var namedXmlObject = CreateXmlObject(name, nameCrc, element, XmlLocationInfo.FromElement(element)); Parse(namedXmlObject, element, parsedEntries); - ValidateValues(namedXmlObject, element); - namedXmlObject.CoerceValues(); + ValidateAndFixupValues(namedXmlObject, element); return namedXmlObject; } @@ -36,8 +34,8 @@ private string GetXmlObjectName(XElement element, out Crc32 crc32) { GetNameAttributeValue(element, out var name); crc32 = UpperCaseNameForCrc - ? HashingService.GetCrc32Upper(name.AsSpan(), Encoding.ASCII) - : HashingService.GetCrc32(name.AsSpan(), Encoding.ASCII); + ? HashingService.GetCrc32Upper(name.AsSpan(), XmlFileConstants.XmlEncoding) + : HashingService.GetCrc32(name.AsSpan(), XmlFileConstants.XmlEncoding); if (crc32 == default) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs index 34e5317..ff175ed 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs @@ -17,10 +17,11 @@ private CommaSeparatedStringKeyValueListParser() } private protected override IList<(string key, string value)> DefaultValue => []; + internal override int EngineDataTypeId => throw new NotImplementedException(); protected internal override IList<(string key, string value)> ParseCore(ReadOnlySpan trimmedValue, XElement element) { - var values = element.Value.Split(','); + var values = element.PGValue.Split(','); // Cases: Empty tag or invalid value (e.g, terrain only, wrong separator, etc.) if (values.Length <= 1) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphNumberParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphNumberParser.cs new file mode 100644 index 0000000..e93b0a6 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphNumberParser.cs @@ -0,0 +1,88 @@ +using System; +using System.Xml.Linq; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Utilities; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public abstract class PetroglyphNumberParser : PetroglyphPrimitiveXmlParser where T : struct, IEquatable, IComparable +#if NET10_0_OR_GREATER + , INumber, IMinMaxValue +#endif +{ + +#if NET7_0_OR_GREATER + protected virtual T MaxValue => T.MaxValue; + + protected virtual T MinValue => T.MinValue; +#else + protected abstract T MaxValue { get; } + + protected abstract T MinValue { get; } + +#endif + + public T ParseAtLeast(XElement element, T minValue) + { + if (minValue.CompareTo(MinValue) < 0 || minValue.CompareTo(MaxValue) > 0) + throw new ArgumentOutOfRangeException(nameof(minValue), "minValue is out of range."); + + var value = Parse(element); + var corrected = PGMath.Max(value, minValue); + if (!corrected.Equals(value)) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected value to be at least {minValue} but got value '{value}'.", + }); + } + + return corrected; + } + + public T ParseAtMost(XElement element, T maxValue) + { + if (maxValue.CompareTo(MinValue) < 0 || maxValue.CompareTo(MaxValue) > 0) + throw new ArgumentOutOfRangeException(nameof(maxValue), "maxValue is out of range."); + + var value = Parse(element); + var corrected = PGMath.Min(value, maxValue); + if (!corrected.Equals(value)) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected value to be at least {maxValue} but got value '{value}'.", + }); + } + + return corrected; + } + + + public T ParseClamped(XElement element, T minValue, T maxValue) + { + if (minValue.CompareTo(MinValue) < 0 || minValue.CompareTo(MaxValue) > 0) + throw new ArgumentOutOfRangeException(nameof(minValue), "minValue is out of range."); + if (maxValue.CompareTo(MinValue) < 0 || maxValue.CompareTo(MaxValue) > 0) + throw new ArgumentOutOfRangeException(nameof(maxValue), "maxValue is out of range."); + if (minValue.CompareTo(maxValue) > 0) + throw new ArgumentException("minValue must be less than or equal to maxValue."); + + var value = Parse(element); + var clamped = PGMath.Clamp(value, minValue, maxValue); + if (!value.Equals(clamped)) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected integer between {minValue} and {maxValue} but got value '{value}'.", + }); + } + return clamped; + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs index 2cece9c..48c53c3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphPrimitiveXmlParser.cs @@ -1,6 +1,6 @@ -using System; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -8,6 +8,8 @@ public abstract class PetroglyphPrimitiveXmlParser : PetroglyphXmlParserBase { private protected abstract T DefaultValue { get; } + internal abstract int EngineDataTypeId { get; } + private protected PetroglyphPrimitiveXmlParser() : base(PrimitiveXmlErrorReporter.Instance) { } @@ -16,7 +18,7 @@ public T Parse(XElement element) { if (!IsTagValid(element)) return DefaultValue; - var value = element.Value.AsSpan().Trim(); + var value = element.PGValue.AsSpan().Trim(); return value.Length == 0 ? DefaultValue : ParseCore(value, element); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs index e2d5a7a..b52554d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs @@ -7,12 +7,14 @@ public sealed class PetroglyphXmlBooleanParser : PetroglyphPrimitiveXmlParser false; + + internal override int EngineDataTypeId => 0x0; + private PetroglyphXmlBooleanParser() { } - private protected override bool DefaultValue => false; - protected internal override bool ParseCore(ReadOnlySpan trimmedValue, XElement element) { // Yes! The engine only checks if the values is exact 1 or starts with Tt or Yy diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs index 2be5d48..56bcb5c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlByteParser.cs @@ -4,16 +4,24 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public sealed class PetroglyphXmlByteParser : PetroglyphPrimitiveXmlParser +public sealed class PetroglyphXmlByteParser : PetroglyphNumberParser { public static readonly PetroglyphXmlByteParser Instance = new(); + private protected override byte DefaultValue => 0; + + internal override int EngineDataTypeId => 0x2; + +#if !NET7_0_OR_GREATER + protected override byte MaxValue => byte.MaxValue; + + protected override byte MinValue => byte.MinValue; +#endif + private PetroglyphXmlByteParser() { } - private protected override byte DefaultValue => 0; - protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XElement element) { var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBytePercentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBytePercentParser.cs new file mode 100644 index 0000000..e419da4 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBytePercentParser.cs @@ -0,0 +1,45 @@ +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; +using System.Xml.Linq; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public sealed class PetroglyphXmlBytePercentParser : PetroglyphNumberParser +{ + public static readonly PetroglyphXmlBytePercentParser Instance = new(); + + private protected override byte DefaultValue => 0; + + internal override int EngineDataTypeId => 0x4; + + protected override byte MaxValue => 100; + +#if !NET7_0_OR_GREATER + protected override byte MinValue => byte.MinValue; +#endif + + private PetroglyphXmlBytePercentParser() + { + } + + protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XElement element) + { + var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); + + if (intValue > MaxValue) + intValue = MaxValue; + + var asByte = (byte)intValue; + // Add additional check (> 100), cause the PG implementation is broken, but we need to stay "bug-compatible". + if (intValue != asByte) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected a byte value (0 - 100) but got value '{asByte}'.", + }); + } + + return asByte; + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs index 86ef413..c8d0335 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlFloatParser.cs @@ -1,36 +1,28 @@ -using System; +using PG.StarWarsGame.Files.XML.ErrorHandling; +using System; using System.Globalization; using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.ErrorHandling; namespace PG.StarWarsGame.Files.XML.Parsers; -public sealed class PetroglyphXmlFloatParser : PetroglyphPrimitiveXmlParser +public sealed class PetroglyphXmlFloatParser : PetroglyphNumberParser { public static readonly PetroglyphXmlFloatParser Instance = new(); private protected override float DefaultValue => 0.0f; - private PetroglyphXmlFloatParser() - { - } + internal override int EngineDataTypeId => 0x8; - public float ParseAtLeast(XElement element, float minValue) - { - var value = Parse(element); - var corrected = Math.Max(value, minValue); - if (corrected != value) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = $"Expected float to be at least {minValue} but got value '{value}'.", - }); - } +#if !NET7_0_OR_GREATER + protected override float MaxValue => float.MaxValue; - return corrected; - } + protected override float MinValue => float.MinValue; +#endif + private PetroglyphXmlFloatParser() + { + } + protected internal override float ParseCore(ReadOnlySpan trimmedValue, XElement element) { // The engine always loads FP numbers a long double and then converts that result to float diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs index 9faf905..485c89f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlIntegerParser.cs @@ -1,16 +1,23 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Utilities; using System; using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; -public sealed class PetroglyphXmlIntegerParser : PetroglyphPrimitiveXmlParser +public sealed class PetroglyphXmlIntegerParser : PetroglyphNumberParser { public static readonly PetroglyphXmlIntegerParser Instance = new(); private protected override int DefaultValue => 0; + internal override int EngineDataTypeId => 0x6; + +#if !NET7_0_OR_GREATER + protected override int MaxValue => int.MaxValue; + + protected override int MinValue => int.MinValue; +#endif + private PetroglyphXmlIntegerParser() { } @@ -32,24 +39,9 @@ protected internal override int ParseCore(ReadOnlySpan trimmedValue, XElem ErrorKind = XmlParseErrorKind.MalformedValue, Message = $"Expected integer but got '{trimmedValue.ToString()}'.", }); - return 0; + return DefaultValue; } return i; } - - public int ParseWithRange(XElement element, int minValue, int maxValue) - { - var value = Parse(element); - var clamped = PGMath.Clamp(value, minValue, maxValue); - if (value != clamped) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = $"Expected integer between {minValue} and {maxValue} but got value '{value}'.", - }); - } - return clamped; - } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs index d6f1e3e..47a0603 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs @@ -20,6 +20,7 @@ public sealed class PetroglyphXmlLooseStringListParser : PetroglyphPrimitiveXmlP public static readonly PetroglyphXmlLooseStringListParser Instance = new(); private protected override IList DefaultValue => []; + internal override int EngineDataTypeId => 0x18; private PetroglyphXmlLooseStringListParser() { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs deleted file mode 100644 index 5d23e6d..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlMax100ByteParser.cs +++ /dev/null @@ -1,74 +0,0 @@ -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Utilities; -using System; -using System.Xml.Linq; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public sealed class PetroglyphXmlMax100ByteParser : PetroglyphPrimitiveXmlParser -{ - public static readonly PetroglyphXmlMax100ByteParser Instance = new(); - - private protected override byte DefaultValue => 0; - - private PetroglyphXmlMax100ByteParser() - { - } - - protected internal override byte ParseCore(ReadOnlySpan trimmedValue, XElement element) - { - var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); - - if (intValue > 100) - intValue = 100; - - var asByte = (byte)intValue; - if (intValue != asByte) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = $"Expected a byte value (0 - 255) but got value '{intValue}'.", - }); - } - - // Add additional check, cause the PG implementation is broken, but we need to stay "bug-compatible". - if (asByte > 100) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = $"Expected a byte value (0 - 100) but got value '{asByte}'.", - }); - } - - return asByte; - } - - public byte ParseWithRange(XElement element, byte minValue, byte maxValue) - { - if (maxValue > 100) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = $"The provided maxValue '{maxValue}' is above 100.", - }); - } - - // TODO: Do we need to coerce maxValue??? - - var value = Parse(element); - - var clamped = PGMath.Clamp(value, minValue, maxValue); - if (value != clamped) - { - ErrorReporter?.Report(new XmlError(this, element) - { - ErrorKind = XmlParseErrorKind.InvalidValue, - Message = $"Expected byte between {minValue} and {maxValue} but got value '{value}'.", - }); - } - return clamped; - } -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs index 8f32e50..e040aaf 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlRgbaColorParser.cs @@ -9,6 +9,7 @@ public sealed class PetroglyphXmlRgbaColorParser : PetroglyphPrimitiveXmlParser< public static readonly PetroglyphXmlRgbaColorParser Instance = new(); private protected override Vector4Int DefaultValue => default; + internal override int EngineDataTypeId => 0x16; private PetroglyphXmlRgbaColorParser() { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlSByteParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlSByteParser.cs new file mode 100644 index 0000000..234b6ae --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlSByteParser.cs @@ -0,0 +1,41 @@ +using System; +using System.Xml.Linq; +using PG.StarWarsGame.Files.XML.ErrorHandling; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public sealed class PetroglyphXmlSByteParser : PetroglyphNumberParser +{ + public static readonly PetroglyphXmlSByteParser Instance = new(); + + private protected override sbyte DefaultValue => 0; + + internal override int EngineDataTypeId => 0x3; + +#if !NET7_0_OR_GREATER + protected override sbyte MaxValue => sbyte.MaxValue; + + protected override sbyte MinValue => sbyte.MinValue; +#endif + + private PetroglyphXmlSByteParser() + { + } + + protected internal override sbyte ParseCore(ReadOnlySpan trimmedValue, XElement element) + { + var intValue = PetroglyphXmlIntegerParser.Instance.ParseCore(trimmedValue, element); + + var asSByte = (sbyte)intValue; + if (intValue != asSByte) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.InvalidValue, + Message = $"Expected a byte value (0 - 255) but got value '{intValue}'.", + }); + } + + return asSByte; + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs index a0dde7f..13cce7e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs @@ -7,12 +7,14 @@ public sealed class PetroglyphXmlStringParser : PetroglyphPrimitiveXmlParser string.Empty; + + internal override int EngineDataTypeId => 0x17; + private PetroglyphXmlStringParser() { } - private protected override string DefaultValue => string.Empty; - protected internal override string ParseCore(ReadOnlySpan trimmedValue, XElement element) { return trimmedValue.ToString(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs index 6c63f7e..420f21d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlUnsignedIntegerParser.cs @@ -4,12 +4,20 @@ namespace PG.StarWarsGame.Files.XML.Parsers; -public sealed class PetroglyphXmlUnsignedIntegerParser : PetroglyphPrimitiveXmlParser +public sealed class PetroglyphXmlUnsignedIntegerParser : PetroglyphNumberParser { public static readonly PetroglyphXmlUnsignedIntegerParser Instance = new(); private protected override uint DefaultValue => 0; + internal override int EngineDataTypeId => 0x5; + +#if !NET7_0_OR_GREATER + protected override uint MaxValue => uint.MaxValue; + + protected override uint MinValue => uint.MinValue; +#endif + private PetroglyphXmlUnsignedIntegerParser() { } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs index da22a09..c35e5b8 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs @@ -12,12 +12,14 @@ public sealed class PetroglyphXmlVector2FParser : PetroglyphPrimitiveXmlParser default; + + internal override int EngineDataTypeId => throw new NotImplementedException(); + private PetroglyphXmlVector2FParser() { } - private protected override Vector2 DefaultValue => default; - protected internal override Vector2 ParseCore(ReadOnlySpan trimmedValue, XElement element) { var listOfValues = LooseStringListParser.Parse(element); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs index 641f59e..0718ac4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlFileListParser.cs @@ -20,8 +20,8 @@ protected override XmlFileList ParseRoot(XElement element, string fileName) { ErrorReporter?.Report(new XmlError(this, child) { - ErrorKind = XmlParseErrorKind.UnknownNode, - Message = $"Tag '<{tagName}>' is not supported. Only '' is supported.", + ErrorKind = XmlParseErrorKind.UnexceptedElementName, + Message = $"Tag '<{tagName}>' should not be used. Use '' only.", }); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs index c716a6e..039867c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs @@ -12,8 +12,7 @@ public TObject Parse(XElement element) { var xmlObject = CreateXmlObject(XmlLocationInfo.FromElement(element)); Parse(xmlObject, element, EmptyParseState.Instance); - ValidateValues(xmlObject, element); - xmlObject.CoerceValues(); + ValidateAndFixupValues(xmlObject, element); ; return xmlObject; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs index bc40317..96e7c7e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; using System.Runtime.CompilerServices; namespace PG.StarWarsGame.Files.XML.Utilities; @@ -8,8 +9,11 @@ internal static class PGMath [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(int value, int min, int max) { +#if NETSTANDARD2_1_OR_GREATER || NET + return Math.Clamp(value, min, max); +#endif if (min > max) - throw new ArgumentException("min cannot be larger than max."); + throw new ArgumentException($"'{max}' cannot be greater than {min}."); if (value < min) return min; return value > max ? max : value; @@ -18,10 +22,60 @@ public static int Clamp(int value, int min, int max) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte Clamp(byte value, byte min, byte max) { +#if NETSTANDARD2_1_OR_GREATER || NET + return Math.Clamp(value, min, max); +#endif if (min > max) - throw new ArgumentException("min cannot be larger than max."); + throw new ArgumentException($"'{max}' cannot be greater than {min}."); if (value < min) return min; return value > max ? max : value; } + +#if NET7_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Clamp(T value, T min, T max) where T : INumber + { + if (min > max) + throw new ArgumentException($"'{max}' cannot be greater than {min}."); + if (value < min) + return min; + return value > max ? max : value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Max(T val1, T val2) where T : INumber + { + return (val1 >= val2) ? val1 : val2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Min(T val1, T val2) where T : INumber + { + return (val1 <= val2) ? val1 : val2; + } +# else + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Clamp(T value, T min, T max) where T : struct, IEquatable, IComparable + { + if (min.CompareTo(max) > 0) + throw new ArgumentException($"'{max}' cannot be greater than {min}."); + if (value.CompareTo(min) < 0) + return min; + return value.CompareTo(max) > 0 ? max : value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Max(T val1, T val2) where T : struct, IEquatable, IComparable + { + return val1.CompareTo(val2) >= 0 ? val1 : val2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Min(T val1, T val2) where T : struct, IEquatable, IComparable + { + return val1.CompareTo(val2) <= 0 ? val1 : val2; + } +#endif } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/XElementExtensions.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/XElementExtensions.cs new file mode 100644 index 0000000..eb7a6c0 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/XElementExtensions.cs @@ -0,0 +1,15 @@ +using System.Xml.Linq; + +namespace PG.StarWarsGame.Files.XML; + +public static class XElementExtensions +{ + extension(XElement element) + { + /// + /// Gets the value of the element as the Petroglyph engine would parse it. + /// That is, if the element has child elements, it returns an empty string, otherwise it returns the value of the element. + /// + public string PGValue => element.HasElements ? string.Empty : element.Value; + } +} \ No newline at end of file From bd68f7738183cc9e2db765a68a563918419a336a Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 21 Feb 2026 13:13:31 +0100 Subject: [PATCH 13/41] simplified animation type code --- .../PG.StarWarsGame.Engine/GameManagerBase.cs | 1 - .../GuiDialog/Xml/GuiDialogsXml.cs | 3 +- .../PetroglyphEngineServiceContribution.cs | 1 - .../Animations/EawModelAnimationTypes.cs | 109 ------ .../Animations/FocModelAnimationTypes.cs | 124 ------ .../Animations/ModelAnimationType.cs | 170 +++++--- .../SupportedModelAnimationTypes.cs | 365 +++++++----------- .../Rendering/Font/FontManager.cs | 9 +- .../Rendering/Font/WindowsFontManager.cs | 3 +- 9 files changed, 270 insertions(+), 515 deletions(-) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/EawModelAnimationTypes.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/FocModelAnimationTypes.cs diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs index c49438b..607121d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; using System.Threading; using System.Threading.Tasks; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs index 7621c15..dbaaed6 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/Xml/GuiDialogsXml.cs @@ -1,5 +1,4 @@ -using PG.StarWarsGame.Engine.Xml; -using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.GuiDialog.Xml; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs index 69ce035..c8b8380 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine.IO; using PG.StarWarsGame.Engine.Localization; -using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Engine.Xml.Parsers; namespace PG.StarWarsGame.Engine; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/EawModelAnimationTypes.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/EawModelAnimationTypes.cs deleted file mode 100644 index f1a89c3..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/EawModelAnimationTypes.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace PG.StarWarsGame.Engine.Rendering.Animations; - -public static class EawModelAnimationTypes -{ - public static readonly ModelAnimationType Idle = new(GameEngineType.Eaw, 0x0); - public static readonly ModelAnimationType SpaceIdle = new(GameEngineType.Eaw, 0x1); - public static readonly ModelAnimationType Move = new(GameEngineType.Eaw, 0x2); - public static readonly ModelAnimationType TurnLeft = new(GameEngineType.Eaw, 0x3); - public static readonly ModelAnimationType TurnRight = new(GameEngineType.Eaw, 0x4); - public static readonly ModelAnimationType Attack = new(GameEngineType.Eaw, 0x5); - public static readonly ModelAnimationType AttackIdle = new(GameEngineType.Eaw, 0x6); - public static readonly ModelAnimationType Die = new(GameEngineType.Eaw, 0x7); - public static readonly ModelAnimationType Rotate = new(GameEngineType.Eaw, 0x8); - public static readonly ModelAnimationType SpecialA = new(GameEngineType.Eaw, 0x9); - public static readonly ModelAnimationType SpecialB = new(GameEngineType.Eaw, 0xa); - public static readonly ModelAnimationType SpecialC = new(GameEngineType.Eaw, 0xb); - public static readonly ModelAnimationType TransitionToLeftTurn = new(GameEngineType.Eaw, 0xc); - public static readonly ModelAnimationType TransitionFromLeftTurn = new(GameEngineType.Eaw, 0xd); - public static readonly ModelAnimationType TransitionToRightTurn = new(GameEngineType.Eaw, 0xe); - public static readonly ModelAnimationType TransitionFromRightTurn = new(GameEngineType.Eaw, 0xf); - public static readonly ModelAnimationType TransitionToMove = new(GameEngineType.Eaw, 0x10); - public static readonly ModelAnimationType TransitionFromMoveFrame0 = new(GameEngineType.Eaw, 0x11); - public static readonly ModelAnimationType TransitionFromMoveFrame40 = new(GameEngineType.Eaw, 0x12); - public static readonly ModelAnimationType TransitionFromMoveFrame80 = new(GameEngineType.Eaw, 0x13); - public static readonly ModelAnimationType TransitionFromMoveFrame120 = new(GameEngineType.Eaw, 0x14); - public static readonly ModelAnimationType TurnLeftHalf = new(GameEngineType.Eaw, 0x15); - public static readonly ModelAnimationType TurnLeftQuarter = new(GameEngineType.Eaw, 0x16); - public static readonly ModelAnimationType TurnRightHalf = new(GameEngineType.Eaw, 0x17); - public static readonly ModelAnimationType TurnRightQuarter = new(GameEngineType.Eaw, 0x18); - public static readonly ModelAnimationType Deploy = new(GameEngineType.Eaw, 0x19); - public static readonly ModelAnimationType Undeploy = new(GameEngineType.Eaw, 0x1a); - public static readonly ModelAnimationType Cinematic = new(GameEngineType.Eaw, 0x1b); - public static readonly ModelAnimationType BlockBlaster = new(GameEngineType.Eaw, 0x1c); - public static readonly ModelAnimationType RedirectBlaster = new(GameEngineType.Eaw, 0x1d); - public static readonly ModelAnimationType IdleBlockBlaster = new(GameEngineType.Eaw, 0x1e); - public static readonly ModelAnimationType ForceWhirlwindAttack = new(GameEngineType.Eaw, 0x1f); - public static readonly ModelAnimationType ForceWhirlwindDie = new(GameEngineType.Eaw, 0x20); - public static readonly ModelAnimationType ForceTelekinesisAttack = new(GameEngineType.Eaw, 0x21); - public static readonly ModelAnimationType ForceTelekinesisHold = new(GameEngineType.Eaw, 0x22); - public static readonly ModelAnimationType ForceTelekinesisRelease = new(GameEngineType.Eaw, 0x23); - public static readonly ModelAnimationType ForceTelekinesisDie = new(GameEngineType.Eaw, 0x24); - public static readonly ModelAnimationType EarthquakeAttack = new(GameEngineType.Eaw, 0x25); - public static readonly ModelAnimationType EarthquakeHold = new(GameEngineType.Eaw, 0x26); - public static readonly ModelAnimationType EarthquakeRelease = new(GameEngineType.Eaw, 0x27); - public static readonly ModelAnimationType ForceLightningAttack = new(GameEngineType.Eaw, 0x28); - public static readonly ModelAnimationType ForceLightningDie = new(GameEngineType.Eaw, 0x29); - public static readonly ModelAnimationType ForceRun = new(GameEngineType.Eaw, 0x2a); - public static readonly ModelAnimationType TransportLanding = new(GameEngineType.Eaw, 0x2b); - public static readonly ModelAnimationType TransportLeaving = new(GameEngineType.Eaw, 0x2c); - public static readonly ModelAnimationType FlameAttack = new(GameEngineType.Eaw, 0x2d); - public static readonly ModelAnimationType Demolition = new(GameEngineType.Eaw, 0x2e); - public static readonly ModelAnimationType BombToss = new(GameEngineType.Eaw, 0x2f); - public static readonly ModelAnimationType Jump = new(GameEngineType.Eaw, 0x30); - public static readonly ModelAnimationType FlyIdle = new(GameEngineType.Eaw, 0x31); - public static readonly ModelAnimationType FlyLand = new(GameEngineType.Eaw, 0x32); - public static readonly ModelAnimationType LandIdle = new(GameEngineType.Eaw, 0x33); - public static readonly ModelAnimationType Land = new(GameEngineType.Eaw, 0x34); - public static readonly ModelAnimationType HcWin = new(GameEngineType.Eaw, 0x35); - public static readonly ModelAnimationType HcLose = new(GameEngineType.Eaw, 0x36); - public static readonly ModelAnimationType HcDraw = new(GameEngineType.Eaw, 0x37); - public static readonly ModelAnimationType ShieldOn = new(GameEngineType.Eaw, 0x38); - public static readonly ModelAnimationType ShieldOff = new(GameEngineType.Eaw, 0x39); - public static readonly ModelAnimationType CableAttackDie = new(GameEngineType.Eaw, 0x3a); - public static readonly ModelAnimationType DeployedCableAttackDie = new(GameEngineType.Eaw, 0x3b); - public static readonly ModelAnimationType DeployedDie = new(GameEngineType.Eaw, 0x3c); - public static readonly ModelAnimationType RunAroundOnFire = new(GameEngineType.Eaw, 0x3d); - public static readonly ModelAnimationType FireDie = new(GameEngineType.Eaw, 0x3e); - public static readonly ModelAnimationType PoundAttack = new(GameEngineType.Eaw, 0x3f); - public static readonly ModelAnimationType EatAttack = new(GameEngineType.Eaw, 0x40); - public static readonly ModelAnimationType EatDie = new(GameEngineType.Eaw, 0x41); - public static readonly ModelAnimationType MoveWalk = new(GameEngineType.Eaw, 0x42); - public static readonly ModelAnimationType MoveCrouch = new(GameEngineType.Eaw, 0x43); - public static readonly ModelAnimationType StructureOpen = new(GameEngineType.Eaw, 0x44); - public static readonly ModelAnimationType StructureHold = new(GameEngineType.Eaw, 0x45); - public static readonly ModelAnimationType StructureClose = new(GameEngineType.Eaw, 0x46); - public static readonly ModelAnimationType IdleCrouch = new(GameEngineType.Eaw, 0x47); - public static readonly ModelAnimationType TurnLeftCrouch = new(GameEngineType.Eaw, 0x48); - public static readonly ModelAnimationType TurnRightCrouch = new(GameEngineType.Eaw, 0x49); - public static readonly ModelAnimationType Build = new(GameEngineType.Eaw, 0x4a); - public static readonly ModelAnimationType TransitionOwnership = new(GameEngineType.Eaw, 0x4b); - public static readonly ModelAnimationType SelfDestruct = new(GameEngineType.Eaw, 0x4c); - public static readonly ModelAnimationType Attention = new(GameEngineType.Eaw, 0x4d); - public static readonly ModelAnimationType Celebrate = new(GameEngineType.Eaw, 0x4e); - public static readonly ModelAnimationType FlinchLeft = new(GameEngineType.Eaw, 0x4f); - public static readonly ModelAnimationType FlinchRight = new(GameEngineType.Eaw, 0x50); - public static readonly ModelAnimationType FlinchFront = new(GameEngineType.Eaw, 0x51); - public static readonly ModelAnimationType FlinchBack = new(GameEngineType.Eaw, 0x52); - public static readonly ModelAnimationType AttackFlinchLeft = new(GameEngineType.Eaw, 0x53); - public static readonly ModelAnimationType AttackFlinchRight = new(GameEngineType.Eaw, 0x54); - public static readonly ModelAnimationType AttackFlinchFront = new(GameEngineType.Eaw, 0x55); - public static readonly ModelAnimationType AttackFlinchBack = new(GameEngineType.Eaw, 0x56); - public static readonly ModelAnimationType Talk = new(GameEngineType.Eaw, 0x57); - public static readonly ModelAnimationType TalkGesture = new(GameEngineType.Eaw, 0x58); - public static readonly ModelAnimationType TalkQuestion = new(GameEngineType.Eaw, 0x59); - public static readonly ModelAnimationType Hacking = new(GameEngineType.Eaw, 0x5a); - public static readonly ModelAnimationType Repairing = new(GameEngineType.Eaw, 0x5b); - public static readonly ModelAnimationType Choke = new(GameEngineType.Eaw, 0x5c); - public static readonly ModelAnimationType ChokeDie = new(GameEngineType.Eaw, 0x5d); - public static readonly ModelAnimationType DropTroopers = new(GameEngineType.Eaw, 0x5e); - public static readonly ModelAnimationType RopeSlide = new(GameEngineType.Eaw, 0x5f); - public static readonly ModelAnimationType RopeLand = new(GameEngineType.Eaw, 0x60); - public static readonly ModelAnimationType RopeDrop = new(GameEngineType.Eaw, 0x61); - public static readonly ModelAnimationType RopeLift = new(GameEngineType.Eaw, 0x62); - public static readonly ModelAnimationType Alarm = new(GameEngineType.Eaw, 0x63); - public static readonly ModelAnimationType Warning = new(GameEngineType.Eaw, 0x64); - public static readonly ModelAnimationType Crushed = new(GameEngineType.Eaw, 0x65); - public static readonly ModelAnimationType PowerDown = new(GameEngineType.Eaw, 0x66); - public static readonly ModelAnimationType PowerUp = new(GameEngineType.Eaw, 0x67); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/FocModelAnimationTypes.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/FocModelAnimationTypes.cs deleted file mode 100644 index 743491a..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/FocModelAnimationTypes.cs +++ /dev/null @@ -1,124 +0,0 @@ -namespace PG.StarWarsGame.Engine.Rendering.Animations; - -public static class FocModelAnimationTypes -{ - public static readonly ModelAnimationType Idle = new(GameEngineType.Foc, 0x0); - public static readonly ModelAnimationType SpaceIdle = new(GameEngineType.Foc, 0x1); - public static readonly ModelAnimationType Move = new(GameEngineType.Foc, 0x2); - public static readonly ModelAnimationType TurnLeft = new(GameEngineType.Foc, 0x3); - public static readonly ModelAnimationType TurnRight = new(GameEngineType.Foc, 0x4); - public static readonly ModelAnimationType Attack = new(GameEngineType.Foc, 0x5); - public static readonly ModelAnimationType AttackIdle = new(GameEngineType.Foc, 0x6); - public static readonly ModelAnimationType Die = new(GameEngineType.Foc, 0x7); - public static readonly ModelAnimationType Rotate = new(GameEngineType.Foc, 0x8); - public static readonly ModelAnimationType SpecialA = new(GameEngineType.Foc, 0x9); - public static readonly ModelAnimationType SpecialB = new(GameEngineType.Foc, 0xa); - public static readonly ModelAnimationType SpecialC = new(GameEngineType.Foc, 0xb); - public static readonly ModelAnimationType TransitionToLeftTurn = new(GameEngineType.Foc, 0xc); - public static readonly ModelAnimationType TransitionFromLeftTurn = new(GameEngineType.Foc, 0xd); - public static readonly ModelAnimationType TransitionToRightTurn = new(GameEngineType.Foc, 0xe); - public static readonly ModelAnimationType TransitionFromRightTurn = new(GameEngineType.Foc, 0xf); - public static readonly ModelAnimationType TransitionToMove = new(GameEngineType.Foc, 0x10); - public static readonly ModelAnimationType TransitionFromMoveFrame0 = new(GameEngineType.Foc, 0x11); - public static readonly ModelAnimationType TransitionFromMoveFrame40 = new(GameEngineType.Foc, 0x12); - public static readonly ModelAnimationType TransitionFromMoveFrame80 = new(GameEngineType.Foc, 0x13); - public static readonly ModelAnimationType TransitionFromMoveFrame120 = new(GameEngineType.Foc, 0x14); - public static readonly ModelAnimationType TurnLeftHalf = new(GameEngineType.Foc, 0x15); - public static readonly ModelAnimationType TurnLeftQuarter = new(GameEngineType.Foc, 0x16); - public static readonly ModelAnimationType TurnRightHalf = new(GameEngineType.Foc, 0x17); - public static readonly ModelAnimationType TurnRightQuarter = new(GameEngineType.Foc, 0x18); - public static readonly ModelAnimationType Deploy = new(GameEngineType.Foc, 0x19); - public static readonly ModelAnimationType Undeploy = new(GameEngineType.Foc, 0x1a); - public static readonly ModelAnimationType Cinematic = new(GameEngineType.Foc, 0x1b); - public static readonly ModelAnimationType BlockBlaster = new(GameEngineType.Foc, 0x1c); - public static readonly ModelAnimationType RedirectBlaster = new(GameEngineType.Foc, 0x1d); - public static readonly ModelAnimationType IdleBlockBlaster = new(GameEngineType.Foc, 0x1e); - public static readonly ModelAnimationType ForceWhirlwindAttack = new(GameEngineType.Foc, 0x1f); - public static readonly ModelAnimationType ForceWhirlwindDie = new(GameEngineType.Foc, 0x20); - public static readonly ModelAnimationType ForceTelekinesisAttack = new(GameEngineType.Foc, 0x21); - public static readonly ModelAnimationType ForceTelekinesisHold = new(GameEngineType.Foc, 0x22); - public static readonly ModelAnimationType ForceTelekinesisRelease = new(GameEngineType.Foc, 0x23); - public static readonly ModelAnimationType ForceTelekinesisDie = new(GameEngineType.Foc, 0x24); - public static readonly ModelAnimationType EarthquakeAttack = new(GameEngineType.Foc, 0x25); - public static readonly ModelAnimationType EarthquakeHold = new(GameEngineType.Foc, 0x26); - public static readonly ModelAnimationType EarthquakeRelease = new(GameEngineType.Foc, 0x27); - public static readonly ModelAnimationType ForceLightningAttack = new(GameEngineType.Foc, 0x28); - public static readonly ModelAnimationType ForceLightningDie = new(GameEngineType.Foc, 0x29); - public static readonly ModelAnimationType ForceRun = new(GameEngineType.Foc, 0x2a); - public static readonly ModelAnimationType TransportLanding = new(GameEngineType.Foc, 0x2b); - public static readonly ModelAnimationType TransportLeaving = new(GameEngineType.Foc, 0x2c); - public static readonly ModelAnimationType FlameAttack = new(GameEngineType.Foc, 0x2d); - public static readonly ModelAnimationType Demolition = new(GameEngineType.Foc, 0x2e); - public static readonly ModelAnimationType BombToss = new(GameEngineType.Foc, 0x2f); - public static readonly ModelAnimationType Jump = new(GameEngineType.Foc, 0x30); - public static readonly ModelAnimationType FlyIdle = new(GameEngineType.Foc, 0x31); - public static readonly ModelAnimationType FlyLand = new(GameEngineType.Foc, 0x32); - public static readonly ModelAnimationType LandIdle = new(GameEngineType.Foc, 0x33); - public static readonly ModelAnimationType Land = new(GameEngineType.Foc, 0x34); - public static readonly ModelAnimationType HcWin = new(GameEngineType.Foc, 0x35); - public static readonly ModelAnimationType HcLose = new(GameEngineType.Foc, 0x36); - public static readonly ModelAnimationType HcDraw = new(GameEngineType.Foc, 0x37); - public static readonly ModelAnimationType ShieldOn = new(GameEngineType.Foc, 0x38); - public static readonly ModelAnimationType ShieldOff = new(GameEngineType.Foc, 0x39); - public static readonly ModelAnimationType CableAttackDie = new(GameEngineType.Foc, 0x3a); - public static readonly ModelAnimationType DeployedCableAttackDie = new(GameEngineType.Foc, 0x3b); - public static readonly ModelAnimationType DeployedDie = new(GameEngineType.Foc, 0x3c); - public static readonly ModelAnimationType RunAroundOnFire = new(GameEngineType.Foc, 0x3d); - public static readonly ModelAnimationType FireDie = new(GameEngineType.Foc, 0x3e); - public static readonly ModelAnimationType PoundAttack = new(GameEngineType.Foc, 0x3f); - public static readonly ModelAnimationType EatAttack = new(GameEngineType.Foc, 0x40); - public static readonly ModelAnimationType EatDie = new(GameEngineType.Foc, 0x41); - public static readonly ModelAnimationType MoveWalk = new(GameEngineType.Foc, 0x42); - public static readonly ModelAnimationType MoveCrouch = new(GameEngineType.Foc, 0x43); - public static readonly ModelAnimationType StructureOpen = new(GameEngineType.Foc, 0x44); - public static readonly ModelAnimationType StructureHold = new(GameEngineType.Foc, 0x45); - public static readonly ModelAnimationType StructureClose = new(GameEngineType.Foc, 0x46); - public static readonly ModelAnimationType IdleCrouch = new(GameEngineType.Foc, 0x47); - public static readonly ModelAnimationType TurnLeftCrouch = new(GameEngineType.Foc, 0x48); - public static readonly ModelAnimationType TurnRightCrouch = new(GameEngineType.Foc, 0x49); - public static readonly ModelAnimationType Build = new(GameEngineType.Foc, 0x4a); - public static readonly ModelAnimationType TransitionOwnership = new(GameEngineType.Foc, 0x4b); - public static readonly ModelAnimationType SelfDestruct = new(GameEngineType.Foc, 0x4c); - public static readonly ModelAnimationType Attention = new(GameEngineType.Foc, 0x4d); - public static readonly ModelAnimationType Celebrate = new(GameEngineType.Foc, 0x4e); - public static readonly ModelAnimationType FlinchLeft = new(GameEngineType.Foc, 0x4f); - public static readonly ModelAnimationType FlinchRight = new(GameEngineType.Foc, 0x50); - public static readonly ModelAnimationType FlinchFront = new(GameEngineType.Foc, 0x51); - public static readonly ModelAnimationType FlinchBack = new(GameEngineType.Foc, 0x52); - public static readonly ModelAnimationType AttackFlinchLeft = new(GameEngineType.Foc, 0x53); - public static readonly ModelAnimationType AttackFlinchRight = new(GameEngineType.Foc, 0x54); - public static readonly ModelAnimationType AttackFlinchFront = new(GameEngineType.Foc, 0x55); - public static readonly ModelAnimationType AttackFlinchBack = new(GameEngineType.Foc, 0x56); - public static readonly ModelAnimationType Talk = new(GameEngineType.Foc, 0x57); - public static readonly ModelAnimationType TalkGesture = new(GameEngineType.Foc, 0x58); - public static readonly ModelAnimationType TalkQuestion = new(GameEngineType.Foc, 0x59); - public static readonly ModelAnimationType Hacking = new(GameEngineType.Foc, 0x5a); - public static readonly ModelAnimationType Repairing = new(GameEngineType.Foc, 0x5b); - public static readonly ModelAnimationType Choke = new(GameEngineType.Foc, 0x5c); - public static readonly ModelAnimationType ChokeDie = new(GameEngineType.Foc, 0x5d); - public static readonly ModelAnimationType DropTroopers = new(GameEngineType.Foc, 0x5e); - public static readonly ModelAnimationType RopeSlide = new(GameEngineType.Foc, 0x5f); - public static readonly ModelAnimationType RopeLand = new(GameEngineType.Foc, 0x60); - public static readonly ModelAnimationType RopeDrop = new(GameEngineType.Foc, 0x61); - public static readonly ModelAnimationType RopeLift = new(GameEngineType.Foc, 0x62); - public static readonly ModelAnimationType Alarm = new(GameEngineType.Foc, 0x63); - public static readonly ModelAnimationType Warning = new(GameEngineType.Foc, 0x64); - public static readonly ModelAnimationType Crushed = new(GameEngineType.Foc, 0x65); - public static readonly ModelAnimationType PowerDown = new(GameEngineType.Foc, 0x66); - public static readonly ModelAnimationType PowerUp = new(GameEngineType.Foc, 0x67); - public static readonly ModelAnimationType SpinMove = new(GameEngineType.Foc, 0x68); - public static readonly ModelAnimationType ForceRevealBegin = new(GameEngineType.Foc, 0x69); - public static readonly ModelAnimationType ForceRevealLoop = new(GameEngineType.Foc, 0x6a); - public static readonly ModelAnimationType ForceRevealEnd = new(GameEngineType.Foc, 0x6b); - public static readonly ModelAnimationType SaberThrow = new(GameEngineType.Foc, 0x6c); - public static readonly ModelAnimationType SaberControl = new(GameEngineType.Foc, 0x6d); - public static readonly ModelAnimationType SaberCatch = new(GameEngineType.Foc, 0x6e); - public static readonly ModelAnimationType SaberSpin = new(GameEngineType.Foc, 0x6f); - public static readonly ModelAnimationType ContaminateAttack = new(GameEngineType.Foc, 0x70); - public static readonly ModelAnimationType ContaminateLoop = new(GameEngineType.Foc, 0x71); - public static readonly ModelAnimationType ContaminateRelease = new(GameEngineType.Foc, 0x72); - public static readonly ModelAnimationType DeployedWalk = new(GameEngineType.Foc, 0x73); - public static readonly ModelAnimationType PadBuild = new(GameEngineType.Foc, 0x74); - public static readonly ModelAnimationType PadSell = new(GameEngineType.Foc, 0x75); - public static readonly ModelAnimationType Heal = new(GameEngineType.Foc, 0x76); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/ModelAnimationType.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/ModelAnimationType.cs index 867ba08..31ecb22 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/ModelAnimationType.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/ModelAnimationType.cs @@ -1,47 +1,127 @@ -using System; +namespace PG.StarWarsGame.Engine.Rendering.Animations; -namespace PG.StarWarsGame.Engine.Rendering.Animations; - -public readonly struct ModelAnimationType : IEquatable +public enum ModelAnimationType { - public GameEngineType TargetEngine { get; } - - public int Value { get; } - - internal ModelAnimationType(GameEngineType engine, int value) - { - TargetEngine = engine; - Value = value; - } - - public override string ToString() - { - var nameLookup = SupportedModelAnimationTypes.GetAnimationTypesForEngine(TargetEngine); - return $"'{nameLookup[this]}' ({Value})"; - } - - public bool Equals(ModelAnimationType other) - { - return TargetEngine == other.TargetEngine && Value == other.Value; - } - - public override bool Equals(object? obj) - { - return obj is ModelAnimationType other && Equals(other); - } - - public override int GetHashCode() - { - return HashCode.Combine((int)TargetEngine, Value); - } - - public static bool operator ==(ModelAnimationType left, ModelAnimationType right) - { - return left.Equals(right); - } - - public static bool operator !=(ModelAnimationType left, ModelAnimationType right) - { - return !(left == right); - } -} \ No newline at end of file + Invalid = -1, + None = -1, + Idle = 0x0, + SpaceIdle = 0x1, + Move = 0x2, + TurnLeft = 0x3, + TurnRight = 0x4, + Attack = 0x5, + AttackIdle = 0x6, + Die = 0x7, + Rotate = 0x8, + SpecialA = 0x9, + SpecialB = 0xa, + SpecialC = 0xb, + TransitionToLeftTurn = 0xc, + TransitionFromLeftTurn = 0xd, + TransitionToRightTurn = 0xe, + TransitionFromRightTurn = 0xf, + TransitionToMove = 0x10, + TransitionFromMoveFrame0 = 0x11, + TransitionFromMoveFrame40 = 0x12, + TransitionFromMoveFrame80 = 0x13, + TransitionFromMoveFrame120 = 0x14, + TurnLeftHalf = 0x15, + TurnLeftQuarter = 0x16, + TurnRightHalf = 0x17, + TurnRightQuarter = 0x18, + Deploy = 0x19, + Undeploy = 0x1a, + Cinematic = 0x1b, + BlockBlaster = 0x1c, + RedirectBlaster = 0x1d, + IdleBlockBlaster = 0x1e, + ForceWhirlwindAttack = 0x1f, + ForceWhirlwindDie = 0x20, + ForceTelekinesisAttack = 0x21, + ForceTelekinesisHold = 0x22, + ForceTelekinesisRelease = 0x23, + ForceTelekinesisDie = 0x24, + EarthquakeAttack = 0x25, + EarthquakeHold = 0x26, + EarthquakeRelease = 0x27, + ForceLightningAttack = 0x28, + ForceLightningDie = 0x29, + ForceRun = 0x2a, + TransportLanding = 0x2b, + TransportLeaving = 0x2c, + FlameAttack = 0x2d, + Demolition = 0x2e, + BombToss = 0x2f, + Jump = 0x30, + FlyIdle = 0x31, + FlyLand = 0x32, + LandIdle = 0x33, + Land = 0x34, + HcWin = 0x35, + HcLose = 0x36, + HcDraw = 0x37, + ShieldOn = 0x38, + ShieldOff = 0x39, + CableAttackDie = 0x3a, + DeployedCableAttackDie = 0x3b, + DeployedDie = 0x3c, + RunAroundOnFire = 0x3d, + FireDie = 0x3e, + PoundAttack = 0x3f, + EatAttack = 0x40, + EatDie = 0x41, + MoveWalk = 0x42, + MoveCrouch = 0x43, + StructureOpen = 0x44, + StructureHold = 0x45, + StructureClose = 0x46, + IdleCrouch = 0x47, + TurnLeftCrouch = 0x48, + TurnRightCrouch = 0x49, + Build = 0x4a, + TransitionOwnership = 0x4b, + SelfDestruct = 0x4c, + Attention = 0x4d, + Celebrate = 0x4e, + FlinchLeft = 0x4f, + FlinchRight = 0x50, + FlinchFront = 0x51, + FlinchBack = 0x52, + AttackFlinchLeft = 0x53, + AttackFlinchRight = 0x54, + AttackFlinchFront = 0x55, + AttackFlinchBack = 0x56, + Talk = 0x57, + TalkGesture = 0x58, + TalkQuestion = 0x59, + Hacking = 0x5a, + Repairing = 0x5b, + Choke = 0x5c, + ChokeDie = 0x5d, + DropTroopers = 0x5e, + RopeSlide = 0x5f, + RopeLand = 0x60, + RopeDrop = 0x61, + RopeLift = 0x62, + Alarm = 0x63, + Warning = 0x64, + Crushed = 0x65, + PowerDown = 0x66, + PowerUp = 0x67, + // These are exclusive to FoC + SpinMove = 0x68, + ForceRevealBegin = 0x69, + ForceRevealLoop = 0x6a, + ForceRevealEnd = 0x6b, + SaberThrow = 0x6c, + SaberControl = 0x6d, + SaberCatch = 0x6e, + SaberSpin = 0x6f, + ContaminateAttack = 0x70, + ContaminateLoop = 0x71, + ContaminateRelease = 0x72, + DeployedWalk = 0x73, + PadBuild = 0x74, + PadSell = 0x75, + Heal = 0x76, +}; \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/SupportedModelAnimationTypes.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/SupportedModelAnimationTypes.cs index 2a7aa3f..302c2fb 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/SupportedModelAnimationTypes.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Animations/SupportedModelAnimationTypes.cs @@ -1,11 +1,16 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace PG.StarWarsGame.Engine.Rendering.Animations; public static class SupportedModelAnimationTypes { + // NB: The games uses two different string mappings for animations. + // The strings here are used to identify the animation file name. + // These strings have an underscore '_' as delimiter, + // while the animation names for the LUA functions (Play_Animation("ANIM NAME")) use a space ' ' as delimiter. + public static IReadOnlyDictionary GetAnimationTypesForEngine(GameEngineType engineType) { return engineType switch @@ -15,237 +20,135 @@ public static IReadOnlyDictionary GetAnimationTypesF _ => throw new NotSupportedException() }; } - - [SuppressMessage("ReSharper", "StringLiteralTypo")] - private static readonly Dictionary FocSupportedAnimations = new() - { - { FocModelAnimationTypes.Idle, "IDLE"}, - { FocModelAnimationTypes.SpaceIdle, "SPACE_IDLE"}, - { FocModelAnimationTypes.Move, "MOVE"}, - { FocModelAnimationTypes.TurnLeft, "TURNL"}, - { FocModelAnimationTypes.TurnRight, "TURNR"}, - { FocModelAnimationTypes.Attack, "ATTACK"}, - { FocModelAnimationTypes.AttackIdle, "ATTACKIDLE"}, - { FocModelAnimationTypes.Die, "DIE"}, - { FocModelAnimationTypes.Rotate, "ROTATE"}, - { FocModelAnimationTypes.SpecialA, "SPECIAL_A"}, - { FocModelAnimationTypes.SpecialB, "SPECIAL_B"}, - { FocModelAnimationTypes.SpecialC, "SPECIAL_C"}, - { FocModelAnimationTypes.TransitionToLeftTurn, "TURNL_BEGIN"}, - { FocModelAnimationTypes.TransitionFromLeftTurn, "TURNL_END"}, - { FocModelAnimationTypes.TransitionToRightTurn, "TURNR_BEGIN"}, - { FocModelAnimationTypes.TransitionFromRightTurn, "TURNR_END"}, - { FocModelAnimationTypes.TransitionToMove, "MOVESTART"}, - { FocModelAnimationTypes.TransitionFromMoveFrame0, "MOVE_ENDONE"}, - { FocModelAnimationTypes.TransitionFromMoveFrame40, "MOVE_ENDTWO"}, - { FocModelAnimationTypes.TransitionFromMoveFrame80, "MOVE_ENDTHREE"}, - { FocModelAnimationTypes.TransitionFromMoveFrame120, "MOVE_ENDFOUR"}, - { FocModelAnimationTypes.TurnLeftHalf, "TURNL_HALF"}, - { FocModelAnimationTypes.TurnLeftQuarter, "TURNL_QUARTER"}, - { FocModelAnimationTypes.TurnRightHalf, "TURNR_HALF"}, - { FocModelAnimationTypes.TurnRightQuarter, "TURNR_QUARTER"}, - { FocModelAnimationTypes.Deploy, "DEPLOY"}, - { FocModelAnimationTypes.Undeploy, "UNDEPLOY"}, - { FocModelAnimationTypes.Cinematic, "CINEMATIC"}, - { FocModelAnimationTypes.BlockBlaster, "BLOCK_BLASTER"}, - { FocModelAnimationTypes.RedirectBlaster, "REDIRECT_BLASTER"}, - { FocModelAnimationTypes.IdleBlockBlaster, "IDLE_BLOCKBLASTER"}, - { FocModelAnimationTypes.ForceWhirlwindAttack, "FW_ATTACK"}, - { FocModelAnimationTypes.ForceWhirlwindDie, "FW_DIE"}, - { FocModelAnimationTypes.ForceTelekinesisAttack, "FTK_ATTACK"}, - { FocModelAnimationTypes.ForceTelekinesisHold, "FTK_HOLD"}, - { FocModelAnimationTypes.ForceTelekinesisRelease, "FTK_RELEASE"}, - { FocModelAnimationTypes.ForceTelekinesisDie, "FTK_DIE"}, - { FocModelAnimationTypes.EarthquakeAttack, "FB_ATTACK"}, - { FocModelAnimationTypes.EarthquakeHold, "FB_HOLD"}, - { FocModelAnimationTypes.EarthquakeRelease, "FB_RELEASE"}, - { FocModelAnimationTypes.ForceLightningAttack, "FL_ATTACK"}, - { FocModelAnimationTypes.ForceLightningDie, "FL_DIE"}, - { FocModelAnimationTypes.ForceRun, "FORCE_RUN"}, - { FocModelAnimationTypes.TransportLanding, "LAND"}, - { FocModelAnimationTypes.TransportLeaving, "TAKEOFF"}, - { FocModelAnimationTypes.FlameAttack, "FLAME_ATTACK"}, - { FocModelAnimationTypes.Demolition, "DEMOLITION"}, - { FocModelAnimationTypes.BombToss, "BOMBTOSS"}, - { FocModelAnimationTypes.Jump, "JUMP"}, - { FocModelAnimationTypes.FlyIdle, "FLYIDLE"}, - { FocModelAnimationTypes.FlyLand, "FLYLAND"}, - { FocModelAnimationTypes.LandIdle, "FLYLANDIDLE"}, - { FocModelAnimationTypes.Land, "FLYLANDDROP"}, - { FocModelAnimationTypes.HcWin, "HC_WIN"}, - { FocModelAnimationTypes.HcLose, "HC_LOSE"}, - { FocModelAnimationTypes.HcDraw, "HC_DRAW"}, - { FocModelAnimationTypes.ShieldOn, "SHIELD_ON"}, - { FocModelAnimationTypes.ShieldOff, "SHIELD_OFF"}, - { FocModelAnimationTypes.CableAttackDie, "CA_DIE"}, - { FocModelAnimationTypes.DeployedCableAttackDie, "DEPLOYED_CA_DIE"}, - { FocModelAnimationTypes.DeployedDie, "DEPLOYED_DIE"}, - { FocModelAnimationTypes.RunAroundOnFire, "FIRE_MOVE"}, - { FocModelAnimationTypes.FireDie, "FIRE_DIE"}, - { FocModelAnimationTypes.PoundAttack, "POUND_ATTACK"}, - { FocModelAnimationTypes.EatAttack, "EAT_ATTACK"}, - { FocModelAnimationTypes.EatDie, "EATEN_DIE"}, - { FocModelAnimationTypes.MoveWalk, "WALKMOVE"}, - { FocModelAnimationTypes.MoveCrouch, "CROUCHMOVE"}, - { FocModelAnimationTypes.StructureOpen, "OPEN"}, - { FocModelAnimationTypes.StructureHold, "HOLD"}, - { FocModelAnimationTypes.StructureClose, "CLOSE"}, - { FocModelAnimationTypes.IdleCrouch, "CROUCHIDLE"}, - { FocModelAnimationTypes.TurnLeftCrouch, "CROUCHTURNL"}, - { FocModelAnimationTypes.TurnRightCrouch, "CROUCHTURNR"}, - { FocModelAnimationTypes.Build, "BUILD"}, - { FocModelAnimationTypes.TransitionOwnership, "TRANS"}, - { FocModelAnimationTypes.SelfDestruct, "SELF_DESTRUCT"}, - { FocModelAnimationTypes.Attention, "ATTENTION"}, - { FocModelAnimationTypes.Celebrate, "CELEBRATE"}, - { FocModelAnimationTypes.FlinchLeft, "FLINCHL"}, - { FocModelAnimationTypes.FlinchRight, "FLINCHR"}, - { FocModelAnimationTypes.FlinchFront, "FLINCHF"}, - { FocModelAnimationTypes.FlinchBack, "FLINCHB"}, - { FocModelAnimationTypes.AttackFlinchLeft, "ATTACKFLINCHL"}, - { FocModelAnimationTypes.AttackFlinchRight, "ATTACKFLINCHR"}, - { FocModelAnimationTypes.AttackFlinchFront, "ATTACKFLINCHF"}, - { FocModelAnimationTypes.AttackFlinchBack, "ATTACKFLINCHB"}, - { FocModelAnimationTypes.Talk, "TALK"}, - { FocModelAnimationTypes.TalkGesture, "TALKGESTURE"}, - { FocModelAnimationTypes.TalkQuestion, "TALKQUESTION"}, - { FocModelAnimationTypes.Hacking, "HACKING"}, - { FocModelAnimationTypes.Repairing, "REPAIRING"}, - { FocModelAnimationTypes.Choke, "CHOKE"}, - { FocModelAnimationTypes.ChokeDie, "CHOKEDEATH"}, - { FocModelAnimationTypes.DropTroopers, "TROOPDROP"}, - { FocModelAnimationTypes.RopeSlide, "ROPESLIDE"}, - { FocModelAnimationTypes.RopeLand, "ROPELAND"}, - { FocModelAnimationTypes.RopeDrop, "ROPE_DROP"}, - { FocModelAnimationTypes.RopeLift, "ROPE_LIFT"}, - { FocModelAnimationTypes.Alarm, "ALARM"}, - { FocModelAnimationTypes.Warning, "WARNING"}, - { FocModelAnimationTypes.Crushed, "CRUSHED"}, - { FocModelAnimationTypes.PowerDown, "POWERDOWN"}, - { FocModelAnimationTypes.PowerUp, "POWERUP"}, - { FocModelAnimationTypes.SpinMove, "SPINMOVE"}, - { FocModelAnimationTypes.ForceRevealBegin, "FORCE_REVEAL_BEGIN"}, - { FocModelAnimationTypes.ForceRevealLoop, "FORCE_REVEAL_LOOP"}, - { FocModelAnimationTypes.ForceRevealEnd, "FORCE_REVEAL_END"}, - { FocModelAnimationTypes.SaberThrow, "SWORD_THROW"}, - { FocModelAnimationTypes.SaberControl, "SWORD_CONTROL"}, - { FocModelAnimationTypes.SaberCatch, "SWORD_CATCH"}, - { FocModelAnimationTypes.SaberSpin, "SWORDSPIN"}, - { FocModelAnimationTypes.ContaminateAttack, "CONTAMINATE_ATTACK"}, - { FocModelAnimationTypes.ContaminateLoop, "CONTAMINATE_LOOP"}, - { FocModelAnimationTypes.ContaminateRelease, "CONTAMINATE_RELEASE"}, - { FocModelAnimationTypes.DeployedWalk, "WALK"}, - { FocModelAnimationTypes.PadBuild, "PAD_BUILD"}, - { FocModelAnimationTypes.PadSell, "PAD_SELL"}, - { FocModelAnimationTypes.Heal, "HEAL"}, - }; - - [SuppressMessage("ReSharper", "StringLiteralTypo")] + private static readonly Dictionary EawSupportedAnimations = new() { - { EawModelAnimationTypes.Idle, "IDLE"}, - { EawModelAnimationTypes.SpaceIdle, "SPACE_IDLE"}, - { EawModelAnimationTypes.Move, "MOVE"}, - { EawModelAnimationTypes.TurnLeft, "TURNL"}, - { EawModelAnimationTypes.TurnRight, "TURNR"}, - { EawModelAnimationTypes.Attack, "ATTACK"}, - { EawModelAnimationTypes.AttackIdle, "ATTACKIDLE"}, - { EawModelAnimationTypes.Die, "DIE"}, - { EawModelAnimationTypes.Rotate, "ROTATE"}, - { EawModelAnimationTypes.SpecialA, "SPECIAL_A"}, - { EawModelAnimationTypes.SpecialB, "SPECIAL_B"}, - { EawModelAnimationTypes.SpecialC, "SPECIAL_C"}, - { EawModelAnimationTypes.TransitionToLeftTurn, "TURNL_BEGIN"}, - { EawModelAnimationTypes.TransitionFromLeftTurn, "TURNL_END"}, - { EawModelAnimationTypes.TransitionToRightTurn, "TURNR_BEGIN"}, - { EawModelAnimationTypes.TransitionFromRightTurn, "TURNR_END"}, - { EawModelAnimationTypes.TransitionToMove, "MOVESTART"}, - { EawModelAnimationTypes.TransitionFromMoveFrame0, "MOVE_ENDONE"}, - { EawModelAnimationTypes.TransitionFromMoveFrame40, "MOVE_ENDTWO"}, - { EawModelAnimationTypes.TransitionFromMoveFrame80, "MOVE_ENDTHREE"}, - { EawModelAnimationTypes.TransitionFromMoveFrame120, "MOVE_ENDFOUR"}, - { EawModelAnimationTypes.TurnLeftHalf, "TURNL_HALF"}, - { EawModelAnimationTypes.TurnLeftQuarter, "TURNL_QUARTER"}, - { EawModelAnimationTypes.TurnRightHalf, "TURNR_HALF"}, - { EawModelAnimationTypes.TurnRightQuarter, "TURNR_QUARTER"}, - { EawModelAnimationTypes.Deploy, "DEPLOY"}, - { EawModelAnimationTypes.Undeploy, "UNDEPLOY"}, - { EawModelAnimationTypes.Cinematic, "CINEMATIC"}, - { EawModelAnimationTypes.BlockBlaster, "BLOCK_BLASTER"}, - { EawModelAnimationTypes.RedirectBlaster, "REDIRECT_BLASTER"}, - { EawModelAnimationTypes.IdleBlockBlaster, "IDLE_BLOCKBLASTER"}, - { EawModelAnimationTypes.ForceWhirlwindAttack, "FW_ATTACK"}, - { EawModelAnimationTypes.ForceWhirlwindDie, "FW_DIE"}, - { EawModelAnimationTypes.ForceTelekinesisAttack, "FTK_ATTACK"}, - { EawModelAnimationTypes.ForceTelekinesisHold, "FTK_HOLD"}, - { EawModelAnimationTypes.ForceTelekinesisRelease, "FTK_RELEASE"}, - { EawModelAnimationTypes.ForceTelekinesisDie, "FTK_DIE"}, - { EawModelAnimationTypes.EarthquakeAttack, "FB_ATTACK"}, - { EawModelAnimationTypes.EarthquakeHold, "FB_HOLD"}, - { EawModelAnimationTypes.EarthquakeRelease, "FB_RELEASE"}, - { EawModelAnimationTypes.ForceLightningAttack, "FL_ATTACK"}, - { EawModelAnimationTypes.ForceLightningDie, "FL_DIE"}, - { EawModelAnimationTypes.ForceRun, "FORCE_RUN"}, - { EawModelAnimationTypes.TransportLanding, "LAND"}, - { EawModelAnimationTypes.TransportLeaving, "TAKEOFF"}, - { EawModelAnimationTypes.FlameAttack, "FLAME_ATTACK"}, - { EawModelAnimationTypes.Demolition, "DEMOLITION"}, - { EawModelAnimationTypes.BombToss, "BOMBTOSS"}, - { EawModelAnimationTypes.Jump, "JUMP"}, - { EawModelAnimationTypes.FlyIdle, "FLYIDLE"}, - { EawModelAnimationTypes.FlyLand, "FLYLAND"}, - { EawModelAnimationTypes.LandIdle, "FLYLANDIDLE"}, - { EawModelAnimationTypes.Land, "FLYLANDDROP"}, - { EawModelAnimationTypes.HcWin, "HC_WIN"}, - { EawModelAnimationTypes.HcLose, "HC_LOSE"}, - { EawModelAnimationTypes.HcDraw, "HC_DRAW"}, - { EawModelAnimationTypes.ShieldOn, "SHIELD_ON"}, - { EawModelAnimationTypes.ShieldOff, "SHIELD_OFF"}, - { EawModelAnimationTypes.CableAttackDie, "CA_DIE"}, - { EawModelAnimationTypes.DeployedCableAttackDie, "DEPLOYED_CA_DIE"}, - { EawModelAnimationTypes.DeployedDie, "DEPLOYED_DIE"}, - { EawModelAnimationTypes.RunAroundOnFire, "FIRE_MOVE"}, - { EawModelAnimationTypes.FireDie, "FIRE_DIE"}, - { EawModelAnimationTypes.PoundAttack, "POUND_ATTACK"}, - { EawModelAnimationTypes.EatAttack, "EAT_ATTACK"}, - { EawModelAnimationTypes.EatDie, "EATEN_DIE"}, - { EawModelAnimationTypes.MoveWalk, "WALKMOVE"}, - { EawModelAnimationTypes.MoveCrouch, "CROUCHMOVE"}, - { EawModelAnimationTypes.StructureOpen, "OPEN"}, - { EawModelAnimationTypes.StructureHold, "HOLD"}, - { EawModelAnimationTypes.StructureClose, "CLOSE"}, - { EawModelAnimationTypes.IdleCrouch, "CROUCHIDLE"}, - { EawModelAnimationTypes.TurnLeftCrouch, "CROUCHTURNL"}, - { EawModelAnimationTypes.TurnRightCrouch, "CROUCHTURNR"}, - { EawModelAnimationTypes.Build, "BUILD"}, - { EawModelAnimationTypes.TransitionOwnership, "TRANS"}, - { EawModelAnimationTypes.SelfDestruct, "SELF_DESTRUCT"}, - { EawModelAnimationTypes.Attention, "ATTENTION"}, - { EawModelAnimationTypes.Celebrate, "CELEBRATE"}, - { EawModelAnimationTypes.FlinchLeft, "FLINCHL"}, - { EawModelAnimationTypes.FlinchRight, "FLINCHR"}, - { EawModelAnimationTypes.FlinchFront, "FLINCHF"}, - { EawModelAnimationTypes.FlinchBack, "FLINCHB"}, - { EawModelAnimationTypes.AttackFlinchLeft, "ATTACKFLINCHL"}, - { EawModelAnimationTypes.AttackFlinchRight, "ATTACKFLINCHR"}, - { EawModelAnimationTypes.AttackFlinchFront, "ATTACKFLINCHF"}, - { EawModelAnimationTypes.AttackFlinchBack, "ATTACKFLINCHB"}, - { EawModelAnimationTypes.Talk, "TALK"}, - { EawModelAnimationTypes.TalkGesture, "TALKGESTURE"}, - { EawModelAnimationTypes.TalkQuestion, "TALKQUESTION"}, - { EawModelAnimationTypes.Hacking, "HACKING"}, - { EawModelAnimationTypes.Repairing, "REPAIRING"}, - { EawModelAnimationTypes.Choke, "CHOKE"}, - { EawModelAnimationTypes.ChokeDie, "CHOKEDEATH"}, - { EawModelAnimationTypes.DropTroopers, "TROOPDROP"}, - { EawModelAnimationTypes.RopeSlide, "ROPESLIDE"}, - { EawModelAnimationTypes.RopeLand, "ROPELAND"}, - { EawModelAnimationTypes.RopeDrop, "ROPE_DROP"}, - { EawModelAnimationTypes.RopeLift, "ROPE_LIFT"}, - { EawModelAnimationTypes.Alarm, "ALARM"}, - { EawModelAnimationTypes.Warning, "WARNING"}, - { EawModelAnimationTypes.Crushed, "CRUSHED"}, - { EawModelAnimationTypes.PowerDown, "POWERDOWN"}, - { EawModelAnimationTypes.PowerUp, "POWERUP"} + { ModelAnimationType.Idle, "IDLE"}, + { ModelAnimationType.SpaceIdle, "SPACE_IDLE"}, + { ModelAnimationType.Move, "MOVE"}, + { ModelAnimationType.TurnLeft, "TURNL"}, + { ModelAnimationType.TurnRight, "TURNR"}, + { ModelAnimationType.Attack, "ATTACK"}, + { ModelAnimationType.AttackIdle, "ATTACKIDLE"}, + { ModelAnimationType.Die, "DIE"}, + { ModelAnimationType.Rotate, "ROTATE"}, + { ModelAnimationType.SpecialA, "SPECIAL_A"}, + { ModelAnimationType.SpecialB, "SPECIAL_B"}, + { ModelAnimationType.SpecialC, "SPECIAL_C"}, + { ModelAnimationType.TransitionToLeftTurn, "TURNL_BEGIN"}, + { ModelAnimationType.TransitionFromLeftTurn, "TURNL_END"}, + { ModelAnimationType.TransitionToRightTurn, "TURNR_BEGIN"}, + { ModelAnimationType.TransitionFromRightTurn, "TURNR_END"}, + { ModelAnimationType.TransitionToMove, "MOVESTART"}, + { ModelAnimationType.TransitionFromMoveFrame0, "MOVE_ENDONE"}, + { ModelAnimationType.TransitionFromMoveFrame40, "MOVE_ENDTWO"}, + { ModelAnimationType.TransitionFromMoveFrame80, "MOVE_ENDTHREE"}, + { ModelAnimationType.TransitionFromMoveFrame120, "MOVE_ENDFOUR"}, + { ModelAnimationType.TurnLeftHalf, "TURNL_HALF"}, + { ModelAnimationType.TurnLeftQuarter, "TURNL_QUARTER"}, + { ModelAnimationType.TurnRightHalf, "TURNR_HALF"}, + { ModelAnimationType.TurnRightQuarter, "TURNR_QUARTER"}, + { ModelAnimationType.Deploy, "DEPLOY"}, + { ModelAnimationType.Undeploy, "UNDEPLOY"}, + { ModelAnimationType.Cinematic, "CINEMATIC"}, + { ModelAnimationType.BlockBlaster, "BLOCK_BLASTER"}, + { ModelAnimationType.RedirectBlaster, "REDIRECT_BLASTER"}, + { ModelAnimationType.IdleBlockBlaster, "IDLE_BLOCKBLASTER"}, + { ModelAnimationType.ForceWhirlwindAttack, "FW_ATTACK"}, + { ModelAnimationType.ForceWhirlwindDie, "FW_DIE"}, + { ModelAnimationType.ForceTelekinesisAttack, "FTK_ATTACK"}, + { ModelAnimationType.ForceTelekinesisHold, "FTK_HOLD"}, + { ModelAnimationType.ForceTelekinesisRelease, "FTK_RELEASE"}, + { ModelAnimationType.ForceTelekinesisDie, "FTK_DIE"}, + { ModelAnimationType.EarthquakeAttack, "FB_ATTACK"}, + { ModelAnimationType.EarthquakeHold, "FB_HOLD"}, + { ModelAnimationType.EarthquakeRelease, "FB_RELEASE"}, + { ModelAnimationType.ForceLightningAttack, "FL_ATTACK"}, + { ModelAnimationType.ForceLightningDie, "FL_DIE"}, + { ModelAnimationType.ForceRun, "FORCE_RUN"}, + { ModelAnimationType.TransportLanding, "LAND"}, + { ModelAnimationType.TransportLeaving, "TAKEOFF"}, + { ModelAnimationType.FlameAttack, "FLAME_ATTACK"}, + { ModelAnimationType.Demolition, "DEMOLITION"}, + { ModelAnimationType.BombToss, "BOMBTOSS"}, + { ModelAnimationType.Jump, "JUMP"}, + { ModelAnimationType.FlyIdle, "FLYIDLE"}, + { ModelAnimationType.FlyLand, "FLYLAND"}, + { ModelAnimationType.LandIdle, "FLYLANDIDLE"}, + { ModelAnimationType.Land, "FLYLANDDROP"}, + { ModelAnimationType.HcWin, "HC_WIN"}, + { ModelAnimationType.HcLose, "HC_LOSE"}, + { ModelAnimationType.HcDraw, "HC_DRAW"}, + { ModelAnimationType.ShieldOn, "SHIELD_ON"}, + { ModelAnimationType.ShieldOff, "SHIELD_OFF"}, + { ModelAnimationType.CableAttackDie, "CA_DIE"}, + { ModelAnimationType.DeployedCableAttackDie, "DEPLOYED_CA_DIE"}, + { ModelAnimationType.DeployedDie, "DEPLOYED_DIE"}, + { ModelAnimationType.RunAroundOnFire, "FIRE_MOVE"}, + { ModelAnimationType.FireDie, "FIRE_DIE"}, + { ModelAnimationType.PoundAttack, "POUND_ATTACK"}, + { ModelAnimationType.EatAttack, "EAT_ATTACK"}, + { ModelAnimationType.EatDie, "EATEN_DIE"}, + { ModelAnimationType.MoveWalk, "WALKMOVE"}, + { ModelAnimationType.MoveCrouch, "CROUCHMOVE"}, + { ModelAnimationType.StructureOpen, "OPEN"}, + { ModelAnimationType.StructureHold, "HOLD"}, + { ModelAnimationType.StructureClose, "CLOSE"}, + { ModelAnimationType.IdleCrouch, "CROUCHIDLE"}, + { ModelAnimationType.TurnLeftCrouch, "CROUCHTURNL"}, + { ModelAnimationType.TurnRightCrouch, "CROUCHTURNR"}, + { ModelAnimationType.Build, "BUILD"}, + { ModelAnimationType.TransitionOwnership, "TRANS"}, + { ModelAnimationType.SelfDestruct, "SELF_DESTRUCT"}, + { ModelAnimationType.Attention, "ATTENTION"}, + { ModelAnimationType.Celebrate, "CELEBRATE"}, + { ModelAnimationType.FlinchLeft, "FLINCHL"}, + { ModelAnimationType.FlinchRight, "FLINCHR"}, + { ModelAnimationType.FlinchFront, "FLINCHF"}, + { ModelAnimationType.FlinchBack, "FLINCHB"}, + { ModelAnimationType.AttackFlinchLeft, "ATTACKFLINCHL"}, + { ModelAnimationType.AttackFlinchRight, "ATTACKFLINCHR"}, + { ModelAnimationType.AttackFlinchFront, "ATTACKFLINCHF"}, + { ModelAnimationType.AttackFlinchBack, "ATTACKFLINCHB"}, + { ModelAnimationType.Talk, "TALK"}, + { ModelAnimationType.TalkGesture, "TALKGESTURE"}, + { ModelAnimationType.TalkQuestion, "TALKQUESTION"}, + { ModelAnimationType.Hacking, "HACKING"}, + { ModelAnimationType.Repairing, "REPAIRING"}, + { ModelAnimationType.Choke, "CHOKE"}, + { ModelAnimationType.ChokeDie, "CHOKEDEATH"}, + { ModelAnimationType.DropTroopers, "TROOPDROP"}, + { ModelAnimationType.RopeSlide, "ROPESLIDE"}, + { ModelAnimationType.RopeLand, "ROPELAND"}, + { ModelAnimationType.RopeDrop, "ROPE_DROP"}, + { ModelAnimationType.RopeLift, "ROPE_LIFT"}, + { ModelAnimationType.Alarm, "ALARM"}, + { ModelAnimationType.Warning, "WARNING"}, + { ModelAnimationType.Crushed, "CRUSHED"}, + { ModelAnimationType.PowerDown, "POWERDOWN"}, + { ModelAnimationType.PowerUp, "POWERUP"} }; + + // ReSharper disable StringLiteralTypo + private static readonly Dictionary FocSupportedAnimations = + + EawSupportedAnimations.Concat(new Dictionary + { + { ModelAnimationType.SpinMove, "SPINMOVE" }, + { ModelAnimationType.ForceRevealBegin, "FORCE_REVEAL_BEGIN" }, + { ModelAnimationType.ForceRevealLoop, "FORCE_REVEAL_LOOP" }, + { ModelAnimationType.ForceRevealEnd, "FORCE_REVEAL_END" }, + { ModelAnimationType.SaberThrow, "SWORD_THROW" }, + { ModelAnimationType.SaberControl, "SWORD_CONTROL" }, + { ModelAnimationType.SaberCatch, "SWORD_CATCH" }, + { ModelAnimationType.SaberSpin, "SWORDSPIN" }, + { ModelAnimationType.ContaminateAttack, "CONTAMINATE_ATTACK" }, + { ModelAnimationType.ContaminateLoop, "CONTAMINATE_LOOP" }, + { ModelAnimationType.ContaminateRelease, "CONTAMINATE_RELEASE" }, + { ModelAnimationType.DeployedWalk, "WALK" }, + { ModelAnimationType.PadBuild, "PAD_BUILD" }, + { ModelAnimationType.PadSell, "PAD_SELL" }, + { ModelAnimationType.Heal, "HEAL" }, + }) + .ToDictionary(x => x.Key, x => x.Value); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs index 00ca4f2..b42eec6 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs @@ -24,7 +24,14 @@ public FontManager(GameRepository repository, GameEngineErrorReporterWrapper err _fontManager = new NetFontManager(); } - public IReadOnlyCollection FontNames => [.._fontNames]; + public IReadOnlyCollection FontNames + { + get + { + ThrowIfNotInitialized(); + return [.._fontNames]; + } + } public FontData? CreateFont(string fontName, int size, bool bold, bool italic, bool staticSize, float stretchFactor) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/WindowsFontManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/WindowsFontManager.cs index fe8f546..ef2344f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/WindowsFontManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/WindowsFontManager.cs @@ -28,7 +28,8 @@ public IEnumerable GetFontFamilies() return fonts; } - static IEnumerable<(Gdi32.ENUMLOGFONTEXDV lpelfe, Gdi32.ENUMTEXTMETRIC _, Gdi32.FontType __)> GetFonts(Gdi32.SafeHDC hdc) + private static IEnumerable<(Gdi32.ENUMLOGFONTEXDV lpelfe, Gdi32.ENUMTEXTMETRIC _, Gdi32.FontType __)> GetFonts( + Gdi32.SafeHDC hdc) { return Gdi32.EnumFontFamiliesEx(hdc, lfCharSet: CharacterSet.DEFAULT_CHARSET); } From d9eecf49f5aca686920625bf0a717e41f98d68ad Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 21 Feb 2026 14:35:49 +0100 Subject: [PATCH 14/41] refactor commandbar parser --- .../CommandBar/CommandBarGameManager.cs | 4 +- .../NamedObjects/CommandBarComponentParser.cs | 739 ++++++++++-------- .../Primitives/PetroglyphXmlBooleanParser.cs | 2 +- .../PetroglyphXmlLooseStringListParser.cs | 2 +- .../Primitives/PetroglyphXmlVector2FParser.cs | 2 +- 5 files changed, 418 insertions(+), 331 deletions(-) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 8b5d175..b19112a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -84,8 +84,8 @@ protected override async Task InitializeCoreAsync(CancellationToken token) var parsedCommandBarComponents = new FrugalValueListDictionary(); await Task.Run(() => contentParser.ParseEntriesFromFileListXml( - "DATA\\XML\\CommandBarComponentFiles.XML", - ".\\DATA\\XML", + ".\\Data\\XML\\CommandBarComponentFiles.xml", + ".\\DATA\\XML\\", parsedCommandBarComponents, VerifyFilePathLength), token); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index be3dcc0..69a3120 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -1,7 +1,6 @@ using System; using System.Collections.ObjectModel; using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.CommandBar.Xml; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; @@ -18,330 +17,6 @@ protected override CommandBarComponentData CreateXmlObject(string name, Crc32 na return new CommandBarComponentData(name, nameCrc, location); } - protected override bool ParseTag(XElement tag, CommandBarComponentData componentData, in IReadOnlyFrugalValueListDictionary parseState) - { - switch (tag.Name.LocalName) - { - case CommandBarComponentTags.SelectedTextureName: - componentData.SelectedTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.BlankTextureName: - componentData.BlankTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.IconAlternateTextureName: - componentData.IconAlternateTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.MouseOverTextureName: - componentData.MouseOverTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.BarTextureName: - componentData.BarTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.BarOverlayName: - componentData.BarOverlayNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.AlternateFontName: - componentData.AlternateFontNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.TooltipText: - componentData.TooltipTexts = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.LowerEffectTextureName: - componentData.LowerEffectTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.UpperEffectTextureName: - componentData.UpperEffectTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.OverlayTextureName: - componentData.OverlayTextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - case CommandBarComponentTags.Overlay2TextureName: - componentData.Overlay2TextureNames = new ReadOnlyCollection(PetroglyphXmlLooseStringListParser.Instance.Parse(tag)); - return true; - - case CommandBarComponentTags.IconTextureName: - componentData.IconTextureName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DisabledTextureName: - componentData.DisabledTextureName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.FlashTextureName: - componentData.FlashTextureName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BuildTextureName: - componentData.BuildTextureName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ModelName: - componentData.ModelName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BoneName: - componentData.BoneName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.CursorTextureName: - componentData.CursorTextureName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.FontName: - componentData.FontName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ClickSfx: - componentData.ClickSfx = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.MouseOverSfx: - componentData.MouseOverSfx = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.RightClickSfx: - componentData.RightClickSfx = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Type: - componentData.Type = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Group: - componentData.Group = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.AssociatedText: - componentData.AssociatedText = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - - case CommandBarComponentTags.DragAndDrop: - componentData.DragAndDrop = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DragSelect: - componentData.DragSelect = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Receptor: - componentData.Receptor = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Toggle: - componentData.Toggle = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Tab: - componentData.Tab = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Hidden: - componentData.Hidden = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ClearColor: - componentData.ClearColor = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Disabled: - componentData.Disabled = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.SwapTexture: - componentData.SwapTexture = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DrawAdditive: - componentData.DrawAdditive = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Editable: - componentData.Editable = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TextOutline: - componentData.TextOutline = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Stackable: - componentData.Stackable = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ModelOffsetX: - componentData.ModelOffsetX = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ModelOffsetY: - componentData.ModelOffsetY = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ScaleModelX: - componentData.ScaleModelX = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ScaleModelY: - componentData.ScaleModelY = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Collideable: - componentData.Collideable = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TextEmboss: - componentData.TextEmboss = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ShouldGhost: - componentData.ShouldGhost = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.GhostBaseOnly: - componentData.GhostBaseOnly = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.CrossFade: - componentData.CrossFade = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.LeftJustified: - componentData.LeftJustified = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.RightJustified: - componentData.RightJustified = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.NoShell: - componentData.NoShell = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.SnapDrag: - componentData.SnapDrag = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.SnapLocation: - componentData.SnapLocation = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.OffsetRender: - componentData.OffsetRender = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BlinkFade: - componentData.BlinkFade = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.NoHiddenCollision: - componentData.NoHiddenCollision = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ManualOffset: - componentData.ManualOffset = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.SelectedAlpha: - componentData.SelectedAlpha = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.PixelAlign: - componentData.PixelAlign = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.CanDragStack: - componentData.CanDragStack = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.CanAnimate: - componentData.CanAnimate = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.LoopAnim: - componentData.LoopAnim = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.SmoothBar: - componentData.SmoothBar = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.OutlinedBar: - componentData.OutlinedBar = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DragBack: - componentData.DragBack = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.LowerEffectAdditive: - componentData.LowerEffectAdditive = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.UpperEffectAdditive: - componentData.UpperEffectAdditive = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ClickShift: - componentData.ClickShift = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TutorialScene: - componentData.TutorialScene = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DialogScene: - componentData.DialogScene = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ShouldRenderAtDragPos: - componentData.ShouldRenderAtDragPos = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DisableDarken: - componentData.DisableDarken = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.AnimateBack: - componentData.AnimateBack = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.AnimateUpperEffect: - componentData.AnimateUpperEffect = PetroglyphXmlBooleanParser.Instance.Parse(tag); - return true; - - case CommandBarComponentTags.Size: - componentData.Size = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TextOffset: - componentData.TextOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TextOffset2: - componentData.TextOffset2 = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Offset: - componentData.Offset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DefaultOffset: - componentData.DefaultOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DefaultOffsetWidescreen: - componentData.DefaultOffsetWidescreen = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.IconOffset: - componentData.IconOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.MouseOverOffset: - componentData.MouseOverOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.DisabledOffset: - componentData.DisabledOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BuildDialOffset: - componentData.BuildDialOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BuildDial2Offset: - componentData.BuildDial2Offset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.LowerEffectOffset: - componentData.LowerEffectOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.UpperEffectOffset: - componentData.UpperEffectOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.OverlayOffset: - componentData.OverlayOffset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.Overlay2Offset: - componentData.Overlay2Offset = PetroglyphXmlVector2FParser.Instance.Parse(tag); - return true; - - case CommandBarComponentTags.MaxTextLength: - componentData.MaxTextLength = PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.FontPointSize: - componentData.FontPointSize = (int)PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - - case CommandBarComponentTags.Scale: - componentData.Scale = PetroglyphXmlFloatParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BlinkRate: - componentData.BlinkRate = PetroglyphXmlFloatParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.MaxTextWidth: - componentData.MaxTextWidth = PetroglyphXmlFloatParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.BlinkDuration: - componentData.BlinkDuration = PetroglyphXmlFloatParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.ScaleDuration: - componentData.ScaleDuration = PetroglyphXmlFloatParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.AnimFps: - componentData.AnimFps = PetroglyphXmlFloatParser.Instance.Parse(tag); - return true; - - case CommandBarComponentTags.BaseLayer: - componentData.BaseLayer = (int)PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.MaxBarLevel: - componentData.MaxBarLevel = (int)PetroglyphXmlUnsignedIntegerParser.Instance.Parse(tag); - return true; - - case CommandBarComponentTags.Color: - componentData.Color = PetroglyphXmlRgbaColorParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TextColor: - componentData.TextColor = PetroglyphXmlRgbaColorParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.TextColor2: - componentData.TextColor2 = PetroglyphXmlRgbaColorParser.Instance.Parse(tag); - return true; - case CommandBarComponentTags.MaxBarColor: - componentData.MaxBarColor = PetroglyphXmlRgbaColorParser.Instance.Parse(tag); - return true; - - default: return true; - } - } protected override void ValidateAndFixupValues(CommandBarComponentData xmlData, XElement element) { @@ -357,11 +32,423 @@ protected override void ValidateAndFixupValues(CommandBarComponentData xmlData, xmlData.FixupValues(); } - private sealed class CommandBarComponentDataXmlTagMapper(IServiceProvider serviceProvider) + private sealed class CommandBarComponentDataXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) { protected override void BuildMappings() { + AddMapping( + CommandBarComponentTags.SelectedTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.SelectedTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.BlankTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.BlankTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.IconTextureName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.IconTextureName = val); + AddMapping( + CommandBarComponentTags.IconAlternateTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.IconAlternateTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.MouseOverTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.MouseOverTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.DisabledTextureName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.DisabledTextureName = val); + AddMapping( + CommandBarComponentTags.FlashTextureName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.FlashTextureName = val); + AddMapping( + CommandBarComponentTags.BarTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.BarTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.BarOverlayName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.BarOverlayNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.BuildTextureName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.BuildTextureName = val); + AddMapping( + CommandBarComponentTags.ModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.ModelName = val); + AddMapping( + CommandBarComponentTags.BoneName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.BoneName = val); + AddMapping( + CommandBarComponentTags.CursorTextureName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.CursorTextureName = val); + AddMapping( + CommandBarComponentTags.FontName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.FontName = val); + AddMapping( + CommandBarComponentTags.AlternateFontName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.AlternateFontNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.TooltipText, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.TooltipTexts = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.ClickSfx, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.ClickSfx = val); + AddMapping( + CommandBarComponentTags.MouseOverSfx, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.MouseOverSfx = val); + AddMapping( + CommandBarComponentTags.LowerEffectTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.LowerEffectTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.UpperEffectTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.UpperEffectTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.OverlayTextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.OverlayTextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.Overlay2TextureName, + PetroglyphXmlLooseStringListParser.Instance.Parse, + (obj, val) => obj.Overlay2TextureNames = new ReadOnlyCollection(val)); + AddMapping( + CommandBarComponentTags.RightClickSfx, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.RightClickSfx = val); + AddMapping( + CommandBarComponentTags.Type, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.Type = val); + AddMapping( + CommandBarComponentTags.Group, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.Group = val); + AddMapping( + CommandBarComponentTags.DragAndDrop, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.DragAndDrop = val); + AddMapping( + CommandBarComponentTags.DragSelect, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.DragSelect = val); + AddMapping( + CommandBarComponentTags.Receptor, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Receptor = val); + AddMapping( + CommandBarComponentTags.Toggle, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Toggle = val); + AddMapping( + CommandBarComponentTags.Tab, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Tab = val); + AddMapping( + CommandBarComponentTags.AssociatedText, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.AssociatedText = val); + AddMapping( + CommandBarComponentTags.Hidden, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Hidden = val); + AddMapping( + CommandBarComponentTags.Scale, + PetroglyphXmlFloatParser.Instance.Parse, + (obj, val) => obj.Scale = val); + AddMapping( + CommandBarComponentTags.Color, + PetroglyphXmlRgbaColorParser.Instance.Parse, + (obj, val) => obj.Color = val); + AddMapping( + CommandBarComponentTags.TextColor, + PetroglyphXmlRgbaColorParser.Instance.Parse, + (obj, val) => obj.TextColor = val); + AddMapping( + CommandBarComponentTags.TextColor2, + PetroglyphXmlRgbaColorParser.Instance.Parse, + (obj, val) => obj.TextColor2 = val); + AddMapping( + CommandBarComponentTags.Size, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.Size = val); + AddMapping( + CommandBarComponentTags.ClearColor, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ClearColor = val); + AddMapping( + CommandBarComponentTags.Disabled, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Disabled = val); + AddMapping( + CommandBarComponentTags.SwapTexture, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.SwapTexture = val); + AddMapping( + CommandBarComponentTags.BaseLayer, + x => (int)PetroglyphXmlUnsignedIntegerParser.Instance.Parse(x), + (obj, val) => obj.BaseLayer = val); + AddMapping( + CommandBarComponentTags.DrawAdditive, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.DrawAdditive = val); + AddMapping( + CommandBarComponentTags.TextOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.TextOffset = val); + AddMapping( + CommandBarComponentTags.TextOffset2, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.TextOffset2 = val); + AddMapping( + CommandBarComponentTags.Offset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.Offset = val); + AddMapping( + CommandBarComponentTags.DefaultOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.DefaultOffset = val); + AddMapping( + CommandBarComponentTags.DefaultOffsetWidescreen, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.DefaultOffsetWidescreen = val); + AddMapping( + CommandBarComponentTags.IconOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.IconOffset = val); + AddMapping( + CommandBarComponentTags.MouseOverOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.MouseOverOffset = val); + AddMapping( + CommandBarComponentTags.DisabledOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.DisabledOffset = val); + AddMapping( + CommandBarComponentTags.BuildDialOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.BuildDialOffset = val); + AddMapping( + CommandBarComponentTags.BuildDial2Offset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.BuildDial2Offset = val); + AddMapping( + CommandBarComponentTags.LowerEffectOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.LowerEffectOffset = val); + AddMapping( + CommandBarComponentTags.UpperEffectOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.UpperEffectOffset = val); + AddMapping( + CommandBarComponentTags.OverlayOffset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.OverlayOffset = val); + AddMapping( + CommandBarComponentTags.Overlay2Offset, + PetroglyphXmlVector2FParser.Instance.Parse, + (obj, val) => obj.Overlay2Offset = val); + AddMapping( + CommandBarComponentTags.Editable, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Editable = val); + AddMapping( + CommandBarComponentTags.MaxTextLength, + PetroglyphXmlUnsignedIntegerParser.Instance.Parse, + (obj, val) => obj.MaxTextLength = val); + AddMapping( + CommandBarComponentTags.BlinkRate, + PetroglyphXmlFloatParser.Instance.Parse, + (obj, val) => obj.BlinkRate = val); + AddMapping( + CommandBarComponentTags.FontPointSize, + x => (int)PetroglyphXmlUnsignedIntegerParser.Instance.Parse(x), + (obj, val) => obj.FontPointSize = val); + AddMapping( + CommandBarComponentTags.TextOutline, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.TextOutline = val); + AddMapping( + CommandBarComponentTags.MaxTextWidth, + PetroglyphXmlFloatParser.Instance.Parse, + (obj, val) => obj.MaxTextWidth = val); + AddMapping( + CommandBarComponentTags.Stackable, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Stackable = val); + AddMapping( + CommandBarComponentTags.ModelOffsetX, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ModelOffsetX = val); + AddMapping( + CommandBarComponentTags.ModelOffsetY, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ModelOffsetY = val); + AddMapping( + CommandBarComponentTags.ScaleModelX, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ScaleModelX = val); + AddMapping( + CommandBarComponentTags.ScaleModelY, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ScaleModelY = val); + AddMapping( + CommandBarComponentTags.Collideable, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.Collideable = val); + AddMapping( + CommandBarComponentTags.TextEmboss, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.TextEmboss = val); + AddMapping( + CommandBarComponentTags.ShouldGhost, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ShouldGhost = val); + AddMapping( + CommandBarComponentTags.GhostBaseOnly, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.GhostBaseOnly = val); + AddMapping( + CommandBarComponentTags.MaxBarLevel, + x => PetroglyphXmlIntegerParser.Instance.Parse(x), + (obj, val) => obj.MaxBarLevel = val); + AddMapping( + CommandBarComponentTags.MaxBarColor, + PetroglyphXmlRgbaColorParser.Instance.Parse, + (obj, val) => obj.MaxBarColor = val); + AddMapping( + CommandBarComponentTags.CrossFade, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.CrossFade = val); + AddMapping( + CommandBarComponentTags.LeftJustified, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.LeftJustified = val); + AddMapping( + CommandBarComponentTags.RightJustified, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.RightJustified = val); + AddMapping( + CommandBarComponentTags.NoShell, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.NoShell = val); + AddMapping( + CommandBarComponentTags.SnapDrag, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.SnapDrag = val); + AddMapping( + CommandBarComponentTags.SnapLocation, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.SnapLocation = val); + AddMapping( + CommandBarComponentTags.BlinkDuration, + PetroglyphXmlFloatParser.Instance.Parse, + (obj, val) => obj.BlinkDuration = val); + AddMapping( + CommandBarComponentTags.ScaleDuration, + PetroglyphXmlFloatParser.Instance.Parse, + (obj, val) => obj.ScaleDuration = val); + AddMapping( + CommandBarComponentTags.OffsetRender, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.OffsetRender = val); + AddMapping( + CommandBarComponentTags.BlinkFade, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.BlinkFade = val); + AddMapping( + CommandBarComponentTags.NoHiddenCollision, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.NoHiddenCollision = val); + AddMapping( + CommandBarComponentTags.ManualOffset, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ManualOffset = val); + AddMapping( + CommandBarComponentTags.SelectedAlpha, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.SelectedAlpha = val); + AddMapping( + CommandBarComponentTags.PixelAlign, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.PixelAlign = val); + AddMapping( + CommandBarComponentTags.CanDragStack, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.CanDragStack = val); + AddMapping( + CommandBarComponentTags.CanAnimate, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.CanAnimate = val); + AddMapping( + CommandBarComponentTags.AnimFps, + PetroglyphXmlFloatParser.Instance.Parse, + (obj, val) => obj.AnimFps = val); + AddMapping( + CommandBarComponentTags.LoopAnim, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.LoopAnim = val); + AddMapping( + CommandBarComponentTags.SmoothBar, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.SmoothBar = val); + AddMapping( + CommandBarComponentTags.OutlinedBar, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.OutlinedBar = val); + AddMapping( + CommandBarComponentTags.DragBack, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.DragBack = val); + AddMapping( + CommandBarComponentTags.LowerEffectAdditive, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.LowerEffectAdditive = val); + AddMapping( + CommandBarComponentTags.UpperEffectAdditive, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.UpperEffectAdditive = val); + AddMapping( + CommandBarComponentTags.ClickShift, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ClickShift = val); + AddMapping( + CommandBarComponentTags.TutorialScene, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.TutorialScene = val); + AddMapping( + CommandBarComponentTags.DialogScene, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.DialogScene = val); + AddMapping( + CommandBarComponentTags.ShouldRenderAtDragPos, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.ShouldRenderAtDragPos = val); + AddMapping( + CommandBarComponentTags.DisableDarken, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.DisableDarken = val); + AddMapping( + CommandBarComponentTags.AnimateBack, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.AnimateBack = val); + AddMapping( + CommandBarComponentTags.AnimateUpperEffect, + PetroglyphXmlBooleanParser.Instance.Parse, + (obj, val) => obj.AnimateUpperEffect = val); } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs index b52554d..c609d0f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlBooleanParser.cs @@ -9,7 +9,7 @@ public sealed class PetroglyphXmlBooleanParser : PetroglyphPrimitiveXmlParser false; - internal override int EngineDataTypeId => 0x0; + internal override int EngineDataTypeId => 0x0 & 0x50; private PetroglyphXmlBooleanParser() { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs index 47a0603..3859a3a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlLooseStringListParser.cs @@ -20,7 +20,7 @@ public sealed class PetroglyphXmlLooseStringListParser : PetroglyphPrimitiveXmlP public static readonly PetroglyphXmlLooseStringListParser Instance = new(); private protected override IList DefaultValue => []; - internal override int EngineDataTypeId => 0x18; + internal override int EngineDataTypeId => 0x18 & 0x1B; private PetroglyphXmlLooseStringListParser() { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs index c35e5b8..488ee0a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlVector2FParser.cs @@ -14,7 +14,7 @@ public sealed class PetroglyphXmlVector2FParser : PetroglyphPrimitiveXmlParser default; - internal override int EngineDataTypeId => throw new NotImplementedException(); + internal override int EngineDataTypeId => 0x0F; private PetroglyphXmlVector2FParser() { From 3f5ee17a946ed6d89e8f2ead3383d1ddbc8436a1 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Feb 2026 19:07:14 +0100 Subject: [PATCH 15/41] Shell scale and offset calculation --- .../CommandBar/CommandBarGameManager.cs | 213 +--------------- .../CommandBarGameManager_Initialization.cs | 237 ++++++++++++++++++ .../Components/CommandBarShellComponent.cs | 26 ++ .../Rendering/Matrix3x4.cs | 198 +++++++++++++++ .../Utilities/PGMath.cs | 12 + .../Utilities/PGMath.cs | 4 +- 6 files changed, 482 insertions(+), 208 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Matrix3x4.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/PGMath.cs diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index b19112a..4478fea 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -1,27 +1,20 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using PG.Commons.Hashing; using PG.StarWarsGame.Engine.CommandBar.Components; -using PG.StarWarsGame.Engine.CommandBar.Xml; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.GameConstants; using PG.StarWarsGame.Engine.IO.Repositories; using PG.StarWarsGame.Engine.Rendering; using PG.StarWarsGame.Engine.Rendering.Font; -using PG.StarWarsGame.Files.Binary; using PG.StarWarsGame.Files.MTD.Files; using PG.StarWarsGame.Files.MTD.Services; using System; using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using AnakinRaW.CommonUtilities.Collections; -using PG.StarWarsGame.Engine.Xml; +using System.Numerics; namespace PG.StarWarsGame.Engine.CommandBar; -internal class CommandBarGameManager( +internal partial class CommandBarGameManager( GameRepository repository, PGRender pgRender, IGameConstants gameConstants, @@ -33,7 +26,6 @@ internal class CommandBarGameManager( private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService(); private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); private readonly Dictionary _groups = new(); - private readonly PGRender _pgRender = pgRender; private bool _megaTextureExists; private FontData? _defaultFont; @@ -42,7 +34,7 @@ internal class CommandBarGameManager( public IReadOnlyDictionary Groups => _groups; - public FontData? DefaultFont + public FontData? DefaultFont { get { @@ -70,200 +62,7 @@ private set } } - protected override async Task InitializeCoreAsync(CancellationToken token) - { - Logger?.LogInformation("Creating command bar components..."); - - var contentParser = new PetroglyphStarWarsGameXmlParser(GameRepository, new PetroglyphStarWarsGameXmlParseSettings - { - GameManager = ToString(), - InvalidObjectXmlFailsInitialization = true, - InvalidFilesListXmlFailsInitialization = true - }, ServiceProvider, ErrorReporter); - - var parsedCommandBarComponents = new FrugalValueListDictionary(); - - await Task.Run(() => contentParser.ParseEntriesFromFileListXml( - ".\\Data\\XML\\CommandBarComponentFiles.xml", - ".\\DATA\\XML\\", - parsedCommandBarComponents, - VerifyFilePathLength), - token); - - // Create Scene - // Create Camera - // Resize(true) - - foreach (var parsedCommandBarComponent in parsedCommandBarComponents.Values) - { - var component = CommandBarBaseComponent.Create(parsedCommandBarComponent, ErrorReporter); - if (component is not null) - { - var crc = _hashingService.GetCrc32(component.Name, PGConstants.DefaultPGEncoding); - NamedEntries.Add(crc, component); - } - } - - SetComponentGroup(Components); - SetMegaTexture(); - SetDefaultFont(); - - LinkComponentsToShell(); - LinkComponentsWithActions(); - } - - private void LinkComponentsWithActions() - { - var nameLookup = SupportedCommandBarComponentData.GetComponentIdsForEngine(GameRepository.EngineType); - - foreach (var idPair in nameLookup) - { - var crc = _hashingService.GetCrc32(idPair.Value, PGConstants.DefaultPGEncoding); - if (NamedEntries.TryGetFirstValue(crc, out var component)) - component.Id = idPair.Key; - } - } - - private void LinkComponentsToShell() - { - if (!Groups.TryGetValue(CommandBarConstants.ShellGroupName, out var shellGroup)) - return; - - var modelCache = new Dictionary(); - foreach (var component in Components) - { - if (component.Type == CommandBarComponentType.Shell) - continue; - - foreach (var shellComponent in shellGroup.Components) - { - if (LinkToShell(component, shellComponent as CommandBarShellComponent, modelCache)) - break; - } - } - - foreach (var model in modelCache.Values) - model?.Dispose(); - } - - private bool LinkToShell( - CommandBarBaseComponent component, - CommandBarShellComponent? shell, - IDictionary modelCache) - { - if (shell is null) - { - ErrorReporter.Assert( - EngineAssert.FromNullOrEmpty( - [component.Name], $"Cannot link component '{component}' because shell component is null.")); - return false; - } - - var componentName = component.Name; - if (string.IsNullOrEmpty(componentName)) - return false; - - var modelPath = shell.ModelPath; - if (string.IsNullOrEmpty(modelPath)) - return false; - - if (!modelCache.TryGetValue(shell.Name, out var model)) - { - model = _pgRender.LoadModelAndAnimations(modelPath.AsSpan(), null, true); - modelCache.Add(shell.Name, model); - } - - if (model is null) - { - ErrorReporter.Assert( - EngineAssert.FromNullOrEmpty( - [$"component='{component.Name}'", $"shell='{shell.Name}'"], - $"Cannot link component '{componentName}' to shell '{shell.Name}' because model '{modelPath}' could not be loaded.")); - return false; - } - - if (!model.IsModel) - { - ErrorReporter.Assert( - EngineAssert.FromNullOrEmpty( - [$"component='{component.Name}'", $"shell='{shell.Name}'"], - $"Cannot link component '{componentName}' to shell '{shell.Name}' because the loaded file '{modelPath}' is not a model.")); - return false; - } - - var boneIndex = model.IndexOfBone(componentName); - - if (boneIndex == -1) - return false; - component.Bone = boneIndex; - component.ParentShell = shell; - return true; - } - - private void SetDefaultFont() - { - // The code is only triggered iff at least one Text CommandbarBar component existed - if (Components.FirstOrDefault(x => x is CommandBarTextComponent or CommandBarTextButtonComponent) is null) - return; - - if (_defaultFont is null) - { - // TODO: From GameConstants - var fontName = PGConstants.DefaultUnicodeFontName; - var size = 11; - var font = fontManager.CreateFont(fontName, size, true, false, false, 1.0f); - if (font is null) - ErrorReporter.Assert(EngineAssert.FromNullOrEmpty([ToString()], $"Unable to create Default from name {fontName}")); - DefaultFont = font; - } - } - - private void SetMegaTexture() - { - // The code is only triggered iff at least one Shell CommandbarBar component existed - if (Components.FirstOrDefault(x => x is CommandBarShellComponent) is null) - return; - // Note: The tag is not used by the engine - var mtdPath = FileSystem.Path.Combine("DATA\\ART\\TEXTURES", $"{CommandBarConstants.MegaTextureBaseName}.mtd"); - using var megaTexture = GameRepository.TryOpenFile(mtdPath); - - try - { - MegaTextureFile = megaTexture is null ? null : _mtdFileService.Load(megaTexture); - } - catch (BinaryCorruptedException e) - { - var message = $"Failed to load MTD file '{mtdPath}': {e.Message}"; - Logger?.LogError(e, message); - ErrorReporter.Assert(EngineAssert.Create(EngineAssertKind.CorruptBinary, mtdPath, [], message)); - } - _megaTextureExists = GameRepository.TextureRepository.FileExists($"{CommandBarConstants.MegaTextureBaseName}.tga"); - } - - private void SetComponentGroup(IEnumerable components) - { - var groupData = components - .Where(x => !string.IsNullOrEmpty(x.XmlData.Group)) - .GroupBy(x => x.XmlData.Group!, StringComparer.Ordinal); + public Vector3 CommandBarScale { get; } - foreach (var grouping in groupData) - { - var group = new CommandBarComponentGroup(grouping.Key, grouping); - _groups.Add(grouping.Key, group); - foreach (var component in grouping) - component.Group = group; - } - } - - private void VerifyFilePathLength(string filePath) - { - if (filePath.Length > PGConstants.MaxCommandBarDatabaseFileName) - { - ErrorReporter.Report(new InitializationError - { - GameManager = ToString(), - Message = $"CommandBar file '{filePath}' is longer than {PGConstants.MaxCommandBarDatabaseFileName} characters." - }); - } - } -} + public Vector3 CommandBarOffset { get; internal set; } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs new file mode 100644 index 0000000..8bfa0d2 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs @@ -0,0 +1,237 @@ +using AnakinRaW.CommonUtilities.Collections; +using Microsoft.Extensions.Logging; +using PG.Commons.Hashing; +using PG.StarWarsGame.Engine.CommandBar.Components; +using PG.StarWarsGame.Engine.CommandBar.Xml; +using PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Engine.Rendering; +using PG.StarWarsGame.Engine.Xml; +using PG.StarWarsGame.Files.Binary; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Threading; +using System.Threading.Tasks; + +namespace PG.StarWarsGame.Engine.CommandBar; + +internal partial class CommandBarGameManager +{ + protected override async Task InitializeCoreAsync(CancellationToken token) + { + Logger?.LogInformation("Creating command bar components..."); + + var contentParser = new PetroglyphStarWarsGameXmlParser(GameRepository, new PetroglyphStarWarsGameXmlParseSettings + { + GameManager = ToString(), + InvalidObjectXmlFailsInitialization = true, + InvalidFilesListXmlFailsInitialization = true + }, ServiceProvider, ErrorReporter); + + var parsedCommandBarComponents = new FrugalValueListDictionary(); + + await Task.Run(() => contentParser.ParseEntriesFromFileListXml( + ".\\Data\\XML\\CommandBarComponentFiles.xml", + ".\\DATA\\XML\\", + parsedCommandBarComponents, + VerifyFilePathLength), + token); + + CommandBarOffset = new Vector3(-0.5f, -0.5f, 0.0f); + + // Create Scene + // Create Camera + // Resize(force: true) + + foreach (var parsedCommandBarComponent in parsedCommandBarComponents.Values) + { + var component = CommandBarBaseComponent.Create(parsedCommandBarComponent, ErrorReporter); + if (component is not null) + { + var crc = _hashingService.GetCrc32(component.Name, PGConstants.DefaultPGEncoding); + NamedEntries.Add(crc, component); + } + + if (component is CommandBarShellComponent shellComponent) + SetModelTransform(shellComponent); + } + + SetComponentGroup(Components); + SetMegaTexture(); + SetDefaultFont(); + + LinkComponentsToShell(); + LinkComponentsWithActions(); + + + // CommandBarClass::Set_Encyclopedia_Delay_Time(this); + // CommandBarClass::Find_Neighbors(this); + + // CommandBarClass::Load_Hero_Particles(this); + // CommandBarClass::Load_Corruption_Particle(this); + } + + private void SetModelTransform(CommandBarShellComponent shellComponent) + { + if (string.IsNullOrEmpty(shellComponent.ModelPath) || + !GameRepository.ModelRepository.FileExists(shellComponent.ModelPath)) + return; + shellComponent.SetOffsetAndScale(CommandBarOffset, CommandBarScale); + } + + private void LinkComponentsWithActions() + { + // NB: Currently we do not have "action" but we keep the original method name + var nameLookup = SupportedCommandBarComponentData.GetComponentIdsForEngine(GameRepository.EngineType); + foreach (var idPair in nameLookup) + { + var crc = _hashingService.GetCrc32(idPair.Value, PGConstants.DefaultPGEncoding); + if (NamedEntries.TryGetFirstValue(crc, out var component)) + component.Id = idPair.Key; + } + } + + private void LinkComponentsToShell() + { + if (!Groups.TryGetValue(CommandBarConstants.ShellGroupName, out var shellGroup)) + return; + + var modelCache = new Dictionary(); + foreach (var component in Components) + { + if (component.Type == CommandBarComponentType.Shell) + continue; + + foreach (var shellComponent in shellGroup.Components) + { + if (LinkToShell(component, shellComponent as CommandBarShellComponent, modelCache)) + break; + } + } + + foreach (var model in modelCache.Values) + model?.Dispose(); + } + + private bool LinkToShell( + CommandBarBaseComponent component, + CommandBarShellComponent? shell, + IDictionary modelCache) + { + if (shell is null) + { + ErrorReporter.Assert( + EngineAssert.FromNullOrEmpty( + [component.Name], $"Cannot link component '{component}' because shell component is null.")); + return false; + } + + var componentName = component.Name; + if (string.IsNullOrEmpty(componentName)) + return false; + + var modelPath = shell.ModelPath; + if (string.IsNullOrEmpty(modelPath)) + return false; + + if (!modelCache.TryGetValue(shell.Name, out var model)) + { + model = pgRender.LoadModelAndAnimations(modelPath.AsSpan(), null, true); + modelCache.Add(shell.Name, model); + } + + if (model is null) + { + ErrorReporter.Assert( + EngineAssert.FromNullOrEmpty( + [$"component='{component.Name}'", $"shell='{shell.Name}'"], + $"Cannot link component '{componentName}' to shell '{shell.Name}' because model '{modelPath}' could not be loaded.")); + return false; + } + + if (!model.IsModel) + { + ErrorReporter.Assert( + EngineAssert.FromNullOrEmpty( + [$"component='{component.Name}'", $"shell='{shell.Name}'"], + $"Cannot link component '{componentName}' to shell '{shell.Name}' because the loaded file '{modelPath}' is not a model.")); + return false; + } + + var boneIndex = model.IndexOfBone(componentName); + + if (boneIndex == -1) + return false; + component.Bone = boneIndex; + component.ParentShell = shell; + return true; + } + + private void SetDefaultFont() + { + // The code is only triggered iff at least one Text CommandbarBar component existed + if (Components.FirstOrDefault(x => x is CommandBarTextComponent or CommandBarTextButtonComponent) is null) + return; + + if (_defaultFont is null) + { + // TODO: From GameConstants + var fontName = PGConstants.DefaultUnicodeFontName; + var size = 11; + var font = fontManager.CreateFont(fontName, size, true, false, false, 1.0f); + if (font is null) + ErrorReporter.Assert(EngineAssert.FromNullOrEmpty([ToString()], $"Unable to create Default from name {fontName}")); + DefaultFont = font; + } + } + + private void SetMegaTexture() + { + // The code is only triggered iff at least one Shell CommandbarBar component existed + if (Components.FirstOrDefault(x => x is CommandBarShellComponent) is null) + return; + // Note: The tag is not used by the engine + var mtdPath = FileSystem.Path.Combine("DATA\\ART\\TEXTURES", $"{CommandBarConstants.MegaTextureBaseName}.mtd"); + using var megaTexture = GameRepository.TryOpenFile(mtdPath); + + try + { + MegaTextureFile = megaTexture is null ? null : _mtdFileService.Load(megaTexture); + } + catch (BinaryCorruptedException e) + { + var message = $"Failed to load MTD file '{mtdPath}': {e.Message}"; + Logger?.LogError(e, message); + ErrorReporter.Assert(EngineAssert.Create(EngineAssertKind.CorruptBinary, mtdPath, [], message)); + } + _megaTextureExists = GameRepository.TextureRepository.FileExists($"{CommandBarConstants.MegaTextureBaseName}.tga"); + } + + private void SetComponentGroup(IEnumerable components) + { + var groupData = components + .Where(x => !string.IsNullOrEmpty(x.XmlData.Group)) + .GroupBy(x => x.XmlData.Group!, StringComparer.Ordinal); + + foreach (var grouping in groupData) + { + var group = new CommandBarComponentGroup(grouping.Key, grouping); + _groups.Add(grouping.Key, group); + foreach (var component in grouping) + component.Group = group; + } + } + + private void VerifyFilePathLength(string filePath) + { + if (filePath.Length > PGConstants.MaxCommandBarDatabaseFileName) + { + ErrorReporter.Report(new InitializationError + { + GameManager = ToString(), + Message = $"CommandBar file '{filePath}' is longer than {PGConstants.MaxCommandBarDatabaseFileName} characters." + }); + } + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Components/CommandBarShellComponent.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Components/CommandBarShellComponent.cs index 799040e..f649d80 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Components/CommandBarShellComponent.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Components/CommandBarShellComponent.cs @@ -1,4 +1,7 @@ using PG.StarWarsGame.Engine.CommandBar.Xml; +using System.Numerics; +using PG.StarWarsGame.Engine.Rendering; +using PG.StarWarsGame.Engine.Utilities; namespace PG.StarWarsGame.Engine.CommandBar.Components; @@ -10,10 +13,33 @@ public class CommandBarShellComponent : CommandBarBaseComponent public string? ModelPath { get; } + public Matrix3x4 ModelTransform { get; internal set; } = Matrix3x4.Identity; + public CommandBarShellComponent(CommandBarComponentData xmlData) : base(xmlData) { ModelName = xmlData.ModelName; if (!string.IsNullOrEmpty(ModelName)) ModelPath = $"DATA\\ART\\MODELS\\{ModelName}"; } + + internal void SetOffsetAndScale(Vector3 offset, Vector3 scale) + { + var newOffset = new Vector3(0.0f, 0.0f, 0.0f); + var newScale = new Vector3(1.0f, 1.0f, 1.0f); + if (XmlData.ModelOffsetX) + newOffset.X = offset.X; + if (XmlData.ModelOffsetY) + newOffset.Y = offset.Y; + if (XmlData.ScaleModelX) + newScale.X = scale.X; + if (XmlData.ScaleModelY) + newScale.Y = scale.Y; + + newOffset.X = PGMath.Floor(newOffset.X) + 0.5f; + newOffset.Y = PGMath.Floor(newOffset.Y) + 0.5f; + + ModelTransform = Matrix3x4.Identity + * Matrix3x4.Scale(newScale) + * Matrix3x4.CreateTranslation(newOffset); + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Matrix3x4.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Matrix3x4.cs new file mode 100644 index 0000000..136f647 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Matrix3x4.cs @@ -0,0 +1,198 @@ +using System; +using System.Globalization; +using System.Numerics; + +namespace PG.StarWarsGame.Engine.Rendering; + +public struct Matrix3x4 : IEquatable +{ + public float M11; + public float M12; + public float M13; + public float M14; + public float M21; + public float M22; + public float M23; + public float M24; + public float M31; + public float M32; + public float M33; + public float M34; + + public static Matrix3x4 Identity { get; } = new( + 1f, 0.0f, 0.0f, 0.0f, + 0.0f, 1f, 0.0f, 0.0f, + 0.0f, 0.0f, 1f, 0.0f); + + /// Constructs a Matrix3x4 from the given components. + public Matrix3x4( + float m11, + float m12, + float m13, + float m14, + float m21, + float m22, + float m23, + float m24, + float m31, + float m32, + float m33, + float m34) + { + M11 = m11; + M12 = m12; + M13 = m13; + M14 = m14; + M21 = m21; + M22 = m22; + M23 = m23; + M24 = m24; + M31 = m31; + M32 = m32; + M33 = m33; + M34 = m34; + } + + public static Matrix3x4 Scale(Vector3 scale) + { + return Scale(scale.X, scale.Y, scale.Z); + } + + public static Matrix3x4 Scale(float xScale, float yScale, float zScale) + { + return new Matrix3x4 + { + M11 = xScale, M12 = 0, M13 = 0, M14 = 0, + M21 = 0, M22 = yScale, M23 = 0, M24 = 0, + M31 = 0, M32 = 0, M33 = zScale, M34 = 0 + }; + } + + public static Matrix3x4 CreateTranslation(Vector3 position) + { + return CreateTranslation(position.X, position.Y, position.Z); + } + + public static Matrix3x4 CreateTranslation(float xPosition, float yPosition, float zPosition) + { + return new Matrix3x4 + { + M11 = 1, M12 = 0, M13 = 0, M14 = xPosition, + M21 = 0, M22 = 1, M23 = 0, M24 = yPosition, + M31 = 0, M32 = 0, M33 = 1, M34 = zPosition + }; + } + + public static Matrix3x4 operator *(Matrix3x4 value1, Matrix3x4 value2) + { + Matrix3x4 matrix3x4; + matrix3x4.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21 + value1.M13 * value2.M31; + matrix3x4.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22 + value1.M13 * value2.M32; + matrix3x4.M13 = value1.M11 * value2.M13 + value1.M12 * value2.M23 + value1.M13 * value2.M33; + matrix3x4.M14 = value1.M11 * value2.M14 + value1.M12 * value2.M24 + value1.M13 * value2.M34 + value1.M14; + matrix3x4.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21 + value1.M23 * value2.M31; + matrix3x4.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22 + value1.M23 * value2.M32; + matrix3x4.M23 = value1.M21 * value2.M13 + value1.M22 * value2.M23 + value1.M23 * value2.M33; + matrix3x4.M24 = value1.M21 * value2.M14 + value1.M22 * value2.M24 + value1.M23 * value2.M34 + value1.M24; + matrix3x4.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value1.M33 * value2.M31; + matrix3x4.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value1.M33 * value2.M32; + matrix3x4.M33 = value1.M31 * value2.M13 + value1.M32 * value2.M23 + value1.M33 * value2.M33; + matrix3x4.M34 = value1.M31 * value2.M14 + value1.M32 * value2.M24 + value1.M33 * value2.M34 + value1.M34; + return matrix3x4; + } + + public static Matrix3x4 operator *(Matrix3x4 value1, float value2) + { + Matrix3x4 matrix3x4; + matrix3x4.M11 = value1.M11 * value2; + matrix3x4.M12 = value1.M12 * value2; + matrix3x4.M13 = value1.M13 * value2; + matrix3x4.M14 = value1.M14 * value2; + matrix3x4.M21 = value1.M21 * value2; + matrix3x4.M22 = value1.M22 * value2; + matrix3x4.M23 = value1.M23 * value2; + matrix3x4.M24 = value1.M24 * value2; + matrix3x4.M31 = value1.M31 * value2; + matrix3x4.M32 = value1.M32 * value2; + matrix3x4.M33 = value1.M33 * value2; + matrix3x4.M34 = value1.M34 * value2; + return matrix3x4; + } + + /// + /// Returns a boolean indicating whether the given two matrices are equal. + /// + /// The first matrix to compare. + /// The second matrix to compare. + /// True if the given matrices are equal; False otherwise. + public static bool operator ==(Matrix3x4 value1, Matrix3x4 value2) + { + return value1.M11 == (double)value2.M11 && value1.M22 == (double)value2.M22 && value1.M33 == (double)value2.M33 && + value1.M12 == (double)value2.M12 && value1.M13 == (double)value2.M13 && value1.M14 == (double)value2.M14 && + value1.M21 == (double)value2.M21 && value1.M23 == (double)value2.M23 && value1.M24 == (double)value2.M24 && + value1.M31 == (double)value2.M31 && value1.M32 == (double)value2.M32 && value1.M34 == (double)value2.M34; + } + + /// + /// Returns a boolean indicating whether the given two matrices are not equal. + /// + /// The first matrix to compare. + /// The second matrix to compare. + /// True if the given matrices are not equal; False if they are equal. + public static bool operator !=(Matrix3x4 value1, Matrix3x4 value2) + { + return value1.M11 != (double)value2.M11 || value1.M12 != (double)value2.M12 || value1.M13 != (double)value2.M13 || value1.M14 != (double)value2.M14 || + value1.M21 != (double)value2.M21 || value1.M22 != (double)value2.M22 || value1.M23 != (double)value2.M23 || value1.M24 != (double)value2.M24 || + value1.M31 != (double)value2.M31 || value1.M32 != (double)value2.M32 || value1.M33 != (double)value2.M33 || value1.M34 != (double)value2.M34; + } + + /// + /// Returns a boolean indicating whether this matrix instance is equal to the other given matrix. + /// + /// The matrix to compare this instance to. + /// True if the matrices are equal; False otherwise. + public bool Equals(Matrix3x4 other) + { + return M11 == (double)other.M11 && M22 == (double)other.M22 && M33 == (double)other.M33 && + M12 == (double)other.M12 && M13 == (double)other.M13 && M14 == (double)other.M14 && + M21 == (double)other.M21 && M23 == (double)other.M23 && M24 == (double)other.M24 && + M31 == (double)other.M31 && M32 == (double)other.M32 && M34 == (double)other.M34; + } + + /// + /// Returns a boolean indicating whether the given Object is equal to this matrix instance. + /// + /// The Object to compare against. + /// True if the Object is equal to this matrix; False otherwise. + public override bool Equals(object? obj) => obj is Matrix3x4 other && Equals(other); + + /// Returns a String representing this matrix instance. + /// The string representation. + public override string ToString() + { + var currentCulture = CultureInfo.CurrentCulture; + return string.Format(currentCulture, + "{{ {{M11:{0} M12:{1} M13:{2} M14:{3}}} {{M21:{4} M22:{5} M23:{6} M24:{7}}} {{M31:{8} M32:{9} M33:{10} M34:{11}}}", + M11.ToString(currentCulture), + M12.ToString(currentCulture), + M13.ToString(currentCulture), + M14.ToString(currentCulture), + M21.ToString(currentCulture), + M22.ToString(currentCulture), + M23.ToString(currentCulture), + M24.ToString(currentCulture), + M31.ToString(currentCulture), + M32.ToString(currentCulture), + M33.ToString(currentCulture), + M34.ToString(currentCulture)); + } + + /// Returns the hash code for this instance. + /// The hash code. + public override int GetHashCode() + { + return M11.GetHashCode() + M12.GetHashCode() + M13.GetHashCode() + M14.GetHashCode() + + M21.GetHashCode() + M22.GetHashCode() + M23.GetHashCode() + M24.GetHashCode() + + M31.GetHashCode() + M32.GetHashCode() + M33.GetHashCode() + M34.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/PGMath.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/PGMath.cs new file mode 100644 index 0000000..bacabc3 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/PGMath.cs @@ -0,0 +1,12 @@ +using System; + +namespace PG.StarWarsGame.Engine.Utilities; + +internal static class PGMath +{ +#if NETSTANDARD2_1_OR_GREATER || NET + public static float Floor(float value) => MathF.Floor(value); +#else + public static float Floor(float value) => (float)Math.Floor(value); +#endif +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs index 96e7c7e..4290b15 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Utilities/PGMath.cs @@ -1,6 +1,8 @@ using System; -using System.Numerics; using System.Runtime.CompilerServices; +#if NET7_0_OR_GREATER +using System.Numerics; +#endif namespace PG.StarWarsGame.Files.XML.Utilities; From 694b98fdc0af355854701ce4ab1fb0ac13813551 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Mon, 23 Feb 2026 13:17:48 +0100 Subject: [PATCH 16/41] update deps and modules --- modules/ModdingToolBase | 2 +- src/ModVerify/ModVerify.csproj | 2 +- test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ModdingToolBase b/modules/ModdingToolBase index e12f6ce..8319d9f 160000 --- a/modules/ModdingToolBase +++ b/modules/ModdingToolBase @@ -1 +1 @@ -Subproject commit e12f6ceedb83fe9e3372dd89c68d508f8479cf92 +Subproject commit 8319d9f54ca9593f1bf2e4e54225b50fc28380d8 diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj index 948719f..16c356e 100644 --- a/src/ModVerify/ModVerify.csproj +++ b/src/ModVerify/ModVerify.csproj @@ -28,7 +28,7 @@ - + diff --git a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj index 58914c1..6eedefe 100644 --- a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj +++ b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj @@ -25,7 +25,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 9179fc02e5c249ddc7fd3b33f4969ad6c05fbd06 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 24 Feb 2026 12:00:45 +0100 Subject: [PATCH 17/41] move some comments --- .../CommandBar/CommandBarGameManager_Initialization.cs | 6 +++++- .../CommandBar/SupportedCommandBarComponentData.cs | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs index 8bfa0d2..da82ef6 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs @@ -82,13 +82,17 @@ private void SetModelTransform(CommandBarShellComponent shellComponent) private void LinkComponentsWithActions() { - // NB: Currently we do not have "action" but we keep the original method name var nameLookup = SupportedCommandBarComponentData.GetComponentIdsForEngine(GameRepository.EngineType); foreach (var idPair in nameLookup) { + // The engine does not uppercase the name here var crc = _hashingService.GetCrc32(idPair.Value, PGConstants.DefaultPGEncoding); if (NamedEntries.TryGetFirstValue(crc, out var component)) + { + // NB: Currently we do not have "action" + // but we keep the original method name 'LinkComponentsWithActions' component.Id = idPair.Key; + } } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/SupportedCommandBarComponentData.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/SupportedCommandBarComponentData.cs index 7b6eeb6..388599c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/SupportedCommandBarComponentData.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/SupportedCommandBarComponentData.cs @@ -5,6 +5,8 @@ namespace PG.StarWarsGame.Engine.CommandBar; public static class SupportedCommandBarComponentData { + // Unfortunately we cannot use EnumConversionDictionary, because EaW and use different enum values + // for the same components, so we need to maintain separate dictionaries for each engine. public static IReadOnlyDictionary GetComponentIdsForEngine(GameEngineType engineType) { return engineType switch From a8fe6485f456b79674430fdbbfe307ecc3654d88 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Wed, 25 Feb 2026 23:34:43 +0100 Subject: [PATCH 18/41] start implementing correct gameobject parser --- .../Engine/GameAssertErrorReporter.cs | 8 +- .../ErrorReporting/EngineAssertKind.cs | 1 + .../GameObjects/GameObject.cs | 30 ++++- .../GameObjects/GameObjectTypeGameManager.cs | 107 ++++++++++++++---- .../GameObjects/IGameObjectTypeGameManager.cs | 10 +- .../NamedObjects/CommandBarComponentParser.cs | 14 ++- .../NamedObjects/GameObjectFileParser.cs | 57 ++++++++++ .../Parsers/NamedObjects/GameObjectParser.cs | 73 +++++++++++- .../Parsers/NamedObjects/SfxEventParser.cs | 7 +- .../Xml/PetroglyphStarWarsGameXmlParser.cs | 2 +- .../Parsers/Base/XmlObjectParserBase.cs | 4 +- .../Parsers/IXmlContainerFileParser.cs | 13 +++ .../Parsers/NamedXmlObjectParser.cs | 11 +- .../Parsers/XmlContainerFileParser.cs | 20 ++-- .../Parsers/XmlObjectParser.cs | 2 +- 15 files changed, 312 insertions(+), 47 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs diff --git a/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs b/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs index f75334c..f98d2cd 100644 --- a/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs +++ b/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs @@ -17,7 +17,12 @@ protected override ErrorData CreateError(EngineAssert assert) var context = new List(); context.AddRange(assert.Context); context.Add($"location='{GetLocation(assert)}'"); - return new ErrorData(GetIdFromError(assert.Kind), assert.Message, context, assert.Value, VerificationSeverity.Warning); + return new ErrorData( + GetIdFromError(assert.Kind), + assert.Message, + context, + assert.Value, + VerificationSeverity.Warning); } private static string GetLocation(EngineAssert assert) @@ -41,6 +46,7 @@ private static string GetIdFromError(EngineAssertKind assertKind) EngineAssertKind.ValueOutOfRange => VerifierErrorCodes.AssertValueOutOfRange, EngineAssertKind.InvalidValue => VerifierErrorCodes.AssertValueInvalid, EngineAssertKind.FileNotFound => VerifierErrorCodes.FileNotFound, + EngineAssertKind.DuplicateEntry => VerifierErrorCodes.DuplicateFound, _ => throw new ArgumentOutOfRangeException(nameof(assertKind), assertKind, null) }; } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssertKind.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssertKind.cs index e3a2d69..f2d1ccd 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssertKind.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssertKind.cs @@ -7,4 +7,5 @@ public enum EngineAssertKind InvalidValue, CorruptBinary, FileNotFound, + DuplicateEntry } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index 1d05bdd..80be9f4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -9,16 +9,34 @@ namespace PG.StarWarsGame.Engine.GameObjects; public sealed class GameObject : NamedXmlObject { - internal GameObject(string type, string name, Crc32 nameCrc, GameObjectType estimatedType, XmlLocationInfo location) + internal GameObject( + string type, + string name, + Crc32 nameCrc, + int index, + GameObjectType estimatedType, + XmlLocationInfo location) : base(name, nameCrc, location) { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), "Index must be greater than 0."); + Index = index; + Id = (int)nameCrc; Type = type ?? throw new ArgumentNullException(nameof(type)); EstimatedType = estimatedType; LandTerrainModelMapping = new ReadOnlyDictionary(InternalLandTerrainModelMapping); } + internal int Id { get; } + + public int Index { get; } + public string Type { get; } + public string VariantOfExistingTypeName { get; internal set; } + + public bool IsLoadingComplete { get; internal set; } + public GameObjectType EstimatedType { get; } public string? GalacticModel { get; internal set; } @@ -81,4 +99,14 @@ private static void AddNotEmpty(ISet set, string? value, Predicate(repository, errorReporter, serviceProvider), IGameObjectTypeGameManager +internal class GameObjectTypeGameManager : GameManagerBase, IGameObjectTypeGameManager { + private readonly List _gameObjects; + + public GameObjectTypeGameManager( + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) + : base(repository, errorReporter, serviceProvider) + { + _gameObjects = new List(); + GameObjects = new ReadOnlyCollection(_gameObjects); + } + + + public IReadOnlyList GameObjects + { + get + { + ThrowIfNotInitialized(); + return field; + } + } + protected override async Task InitializeCoreAsync(CancellationToken token) { Logger?.LogInformation("Parsing GameObjects..."); await Task.Run(ParseGameObjectDatabases, token); } - private void ParseGameObjectDatabases() { - var parser = new PetroglyphStarWarsGameXmlParser(GameRepository, + var gameParser = new PetroglyphStarWarsGameXmlParser(GameRepository, new PetroglyphStarWarsGameXmlParseSettings { GameManager = ToString(), @@ -29,28 +52,45 @@ private void ParseGameObjectDatabases() InvalidObjectXmlFailsInitialization = false, }, ServiceProvider, ErrorReporter); - var xmlFileList = parser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files - .Select(x => - { - var filePath = FileSystem.Path.Combine(@".\DATA\XML\", x); - VerifyFilePathLength(filePath); - return filePath; - }).ToList(); - + var xmlFileList = gameParser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files + .Select(x => FileSystem.Path.Combine(@".\DATA\XML\", x)) + .Where(VerifyFilePathLength) + .ToList(); - //var gameObjectFileParser = new GameObjectFileParser(serviceProvider, errorReporter); + var gameObjectFileParser = new GameObjectFileParser(ServiceProvider, ErrorReporter); var allLoaded = false; + + // This also acts a guard against infinite loops in case of unexpected circular dependencies or + // when a unit declares itself as its own for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++) { + Logger?.LogDebug("***** Parsing game object types - pass {PassNumber} *****", passNumber); + + if (passNumber != 0) + gameObjectFileParser.OverlayLoad = true; + foreach (var gameObjectXmlFile in xmlFileList) { if (passNumber == 0) { - //ParseSingleGameObjectFile(gameObjectXmlFile, parser, gameObjectFileParser); + try + { + gameObjectFileParser.GameObjectParsed += OnGameObjectParsed; + ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); + } + finally + { + gameObjectFileParser.GameObjectParsed -= OnGameObjectParsed; + } } else { + foreach (var gameObject in _gameObjects) + { + if (!gameObject.IsLoadingComplete && gameObject.Location.XmlFile == gameObjectXmlFile) + ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); + } } } @@ -65,12 +105,38 @@ private void ParseGameObjectDatabases() } } - //private void ParseSingleGameObjectFile(string file, EngineXmlParser engineParser, GameObjectFileParser gameObjectFileParser) - //{ - // engineParser.ParseEntriesFromContainerFile(gameObjectFileParser, file, NamedEntries); - //} + private void OnGameObjectParsed(object sender, GameObjectParsedEventArgs e) + { + if (!e.Unique) + { + var entries = NamedEntries.GetValues(e.ParsedElement.Crc32) + .Select(x => x.Name); + ErrorReporter.Assert(EngineAssert.Create( + EngineAssertKind.DuplicateEntry, + e.ParsedElement.Crc32, entries, + $"Error: Game object type {e.ParsedElement.Name} is defined multiple times.")); + } - private void VerifyFilePathLength(string filePath) + if (NamedEntries.ValueCount >= 0x10000) + { + ErrorReporter.Assert( + EngineAssert.Create( + EngineAssertKind.ValueOutOfRange, + NamedEntries.ValueCount, + [ToString()], + "Too many game object types defined.")); + } + } + + private void ParseSingleGameObjectFile( + string file, + PetroglyphStarWarsGameXmlParser gameParser, + GameObjectFileParser gameObjectFileParser) + { + gameParser.ParseObjectsFromContainerFile(file, gameObjectFileParser, NamedEntries); + } + + private bool VerifyFilePathLength(string filePath) { if (filePath.Length > PGConstants.MaxGameObjectDatabaseFileName) { @@ -81,6 +147,9 @@ private void VerifyFilePathLength(string filePath) GameManager = ToString(), Message = $"Game object file '{filePath}' is longer than {PGConstants.MaxGameObjectDatabaseFileName} characters." }); + return false; } + + return true; } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs index f31273f..300f5e4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs @@ -1,3 +1,9 @@ -namespace PG.StarWarsGame.Engine.GameObjects; +using System.Collections.Generic; -public interface IGameObjectTypeGameManager : IGameManager; \ No newline at end of file +namespace PG.StarWarsGame.Engine.GameObjects; + +public interface IGameObjectTypeGameManager : IGameManager +{ + // List represent XML load order + IReadOnlyList GameObjects { get; } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index 69a3120..d099a5f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -1,10 +1,11 @@ -using System; -using System.Collections.ObjectModel; -using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.CommandBar.Xml; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Collections.ObjectModel; +using System.Xml.Linq; using Crc32 = PG.Commons.Hashing.Crc32; namespace PG.StarWarsGame.Engine.Xml.Parsers; @@ -12,7 +13,12 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class CommandBarComponentParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : NamedXmlObjectParser(serviceProvider, new CommandBarComponentDataXmlTagMapper(serviceProvider), errorReporter) { - protected override CommandBarComponentData CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) + protected override CommandBarComponentData CreateXmlObject( + string name, + Crc32 nameCrc, + XElement element, + IReadOnlyFrugalValueListDictionary parsedEntries, + XmlLocationInfo location) { return new CommandBarComponentData(name, nameCrc, location); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs new file mode 100644 index 0000000..c45638a --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs @@ -0,0 +1,57 @@ +using AnakinRaW.CommonUtilities.Collections; +using PG.Commons.Hashing; +using PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Engine.GameObjects; +using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.IO; + +namespace PG.StarWarsGame.Engine.Xml.Parsers; + +internal sealed class GameObjectParsedEventArgs : EventArgs +{ + public bool Unique { get; } + + public GameObject ParsedElement { get; } + + internal GameObjectParsedEventArgs(GameObject parsedElement, bool unique) + { + Unique = unique; + ParsedElement = parsedElement ?? throw new ArgumentNullException(nameof(parsedElement)); + } +} + + +internal class GameObjectFileParser(IServiceProvider serviceProvider, IGameEngineErrorReporter? errorReporter) + : PetroglyphXmlFileParserBase(serviceProvider, errorReporter), IXmlContainerFileParser +{ + public event EventHandler? GameObjectParsed; + + private readonly GameObjectParser _gameObjectParser = new(serviceProvider, errorReporter); + + public NamedXmlObjectParser ElementParser => _gameObjectParser; + + public bool OverlayLoad + { + get; + set + { + field = value; + _gameObjectParser.OverlayLoad = value; + } + } + + public void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries) + { + var root = GetRootElement(xmlStream, out _); + foreach (var xElement in root.Elements()) + { + var parsedElement = _gameObjectParser.Parse(xElement, parsedEntries, out var entryCrc); + if (!OverlayLoad) + { + parsedEntries.Add(entryCrc, parsedElement); + GameObjectParsed?.Invoke(this, new GameObjectParsedEventArgs(parsedElement, true)); + } + } + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index e28ff37..c7555a8 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Xml.Linq; using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine.GameObjects; @@ -25,14 +26,78 @@ public static class GameObjectXmlTags public const string DamagedSmokeAssetName = "Damaged_Smoke_Asset_Name"; } + + internal class GameObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : NamedXmlObjectParser(serviceProvider, new GameObjectXmlTagMapper(serviceProvider), errorReporter) { - protected override GameObject CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) + internal bool OverlayLoad { get; set; } + + protected override GameObject CreateXmlObject( + string name, + Crc32 nameCrc, + XElement element, + IReadOnlyFrugalValueListDictionary parsedEntries, + XmlLocationInfo location) + { + if (!OverlayLoad) + { + var type = GetTagName(element); + var objectType = EstimateType(type); + return new GameObject(type, name, nameCrc, parsedEntries.ValueCount, objectType, location); + } + else + { + parsedEntries.TryGetFirstValue(nameCrc, out var type); + Debug.Assert(type is not null); + + OverlayType(type!, element, false); + + + return type!; + } + } + + protected override void ValidateAndFixupValues(GameObject gameObject, XElement element) { - var type = GetTagName(element); - var objectType = EstimateType(type); - return new GameObject(type, name, nameCrc, objectType, location); + if (!OverlayLoad) + { + gameObject.PostLoadFixup(); + if (string.IsNullOrEmpty(gameObject.VariantOfExistingTypeName)) + gameObject.IsLoadingComplete = true; + else + OverlayType(gameObject, element); + } + } + + private void OverlayType(GameObject gameObject, XElement element) + { + var baseType = gameObject.VariantOfExistingType; + if (baseType is null) + { + var baseTypeName = gameObject.VariantOfExistingTypeName; + if (string.IsNullOrEmpty(baseTypeName)) + return; + + baseType = FindBaseType(baseTypeName); + if (baseType is null) + return; + } + OverlayType(baseType, gameObject, element); + } + + private void OverlayType(GameObject baseType, GameObject derivedType, XElement element) + { + if (!baseType.IsLoadingComplete) + return; + + derivedType.ApplyBaseType(baseType); + + + ParseObject(derivedType, element, ReadOnlyFrugalValueListDictionary.Empty); + + derivedType.PostLoadFixup(); + derivedType.IsLoadingComplete = true; } protected override bool ParseTag(XElement tag, GameObject xmlObject, in IReadOnlyFrugalValueListDictionary parseState) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs index 484b075..c2d4b65 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs @@ -14,7 +14,12 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class SfxEventParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : NamedXmlObjectParser(serviceProvider, new SfxEventXmlTagMapper(serviceProvider), errorReporter) { - protected override SfxEvent CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location) + protected override SfxEvent CreateXmlObject( + string name, + Crc32 nameCrc, + XElement element, + IReadOnlyFrugalValueListDictionary parsedEntries, + XmlLocationInfo location) { return new SfxEvent(name, nameCrc, location); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs index 7beb801..95328ba 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs @@ -75,7 +75,7 @@ public void ParseEntriesFromFileListXml( public bool ParseObjectsFromContainerFile( string xmlFile, - XmlContainerFileParser parser, + IXmlContainerFileParser parser, IFrugalValueListDictionary entries) where T : NamedXmlObject { return ParseCore(xmlFile, stream => diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs index dd9ac3d..ee7b5ff 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs @@ -16,7 +16,7 @@ protected virtual void ValidateAndFixupValues(TObject namedXmlObject, XElement e { } - protected void Parse(TObject xmlObject, XElement element, in TParseState state) + protected void ParseObject(TObject xmlObject, XElement element, in TParseState state) { foreach (var tag in element.Elements()) { @@ -36,7 +36,7 @@ protected void Parse(TObject xmlObject, XElement element, in TParseState state) } else { - Parse(xmlObject, tag, in state); + ParseObject(xmlObject, tag, in state); } } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs new file mode 100644 index 0000000..8afbdbd --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs @@ -0,0 +1,13 @@ +using System.IO; +using AnakinRaW.CommonUtilities.Collections; +using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML.Data; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public interface IXmlContainerFileParser : IPetroglyphXmlParserInfo where T : NamedXmlObject +{ + NamedXmlObjectParser ElementParser { get; } + + void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries); +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs index 140dcd0..1ae65e2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs @@ -22,13 +22,18 @@ public abstract class NamedXmlObjectParser( public T Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) { var name = GetXmlObjectName(element, out nameCrc); - var namedXmlObject = CreateXmlObject(name, nameCrc, element, XmlLocationInfo.FromElement(element)); - Parse(namedXmlObject, element, parsedEntries); + var namedXmlObject = CreateXmlObject(name, nameCrc, element, parsedEntries, XmlLocationInfo.FromElement(element)); + ParseObject(namedXmlObject, element, parsedEntries); ValidateAndFixupValues(namedXmlObject, element); return namedXmlObject; } - protected abstract T CreateXmlObject(string name, Crc32 nameCrc, XElement element, XmlLocationInfo location); + protected abstract T CreateXmlObject( + string name, + Crc32 nameCrc, + XElement element, + IReadOnlyFrugalValueListDictionary parsedEntries, + XmlLocationInfo location); private string GetXmlObjectName(XElement element, out Crc32 crc32) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs index 12f0f5d..8ef0e93 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs @@ -1,9 +1,10 @@ using AnakinRaW.CommonUtilities.Collections; using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; using System; using System.IO; -using PG.StarWarsGame.Files.XML.Data; +using System.Xml.Linq; namespace PG.StarWarsGame.Files.XML.Parsers; @@ -11,7 +12,8 @@ public sealed class XmlContainerFileParser( IServiceProvider serviceProvider, NamedXmlObjectParser elementParser, IXmlParserErrorReporter? listener = null) - : PetroglyphXmlFileParserBase(serviceProvider, listener) where T : NamedXmlObject + : PetroglyphXmlFileParserBase(serviceProvider, listener), IXmlContainerFileParser + where T : NamedXmlObject { public NamedXmlObjectParser ElementParser { get; } = elementParser ?? throw new ArgumentNullException(nameof(elementParser)); @@ -19,11 +21,13 @@ public sealed class XmlContainerFileParser( public void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries) { var root = GetRootElement(xmlStream, out _); - - foreach (var xElement in root.Elements()) - { - var parsedElement = ElementParser.Parse(xElement, parsedEntries, out var entryCrc); - parsedEntries.Add(entryCrc, parsedElement); - } + foreach (var xElement in root.Elements()) + ParseElement(xElement, parsedEntries); + } + + private void ParseElement(XElement element, IFrugalValueListDictionary parsedEntries) + { + var parsedElement = ElementParser.Parse(element, parsedEntries, out var entryCrc); + parsedEntries.Add(entryCrc, parsedElement); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs index 039867c..5511035 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs @@ -11,7 +11,7 @@ public abstract class XmlObjectParser(IXmlTagMapper tagMapper, public TObject Parse(XElement element) { var xmlObject = CreateXmlObject(XmlLocationInfo.FromElement(element)); - Parse(xmlObject, element, EmptyParseState.Instance); + ParseObject(xmlObject, element, EmptyParseState.Instance); ValidateAndFixupValues(xmlObject, element); ; return xmlObject; } From 99d81bebae4309cb30883896e6fa306171bf23aa Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 28 Feb 2026 12:34:51 +0100 Subject: [PATCH 19/41] fix bugs in parser and start engine compliant gameobject parsing --- .../Audio/Sfx/SfxEvent.cs | 34 ++- .../Audio/Sfx/SfxEventGameManager.cs | 8 +- .../CommandBar/CommandBarGameManager.cs | 3 +- .../CommandBar/Xml/CommandBarComponentData.cs | 73 +++-- .../GameConstants/GameConstants.cs | 8 +- .../PG.StarWarsGame.Engine/GameManagerBase.cs | 19 +- .../GameObjects/GameObject.cs | 34 ++- .../GameObjects/GameObjectType.cs | 46 --- .../GameObjects/GameObjectTypeGameManager.cs | 3 +- .../GameObjects/MapEnvironmentType.cs | 33 +++ .../GuiDialog/GuiDialogGameManager.cs | 8 +- .../PetroglyphStarWarsGameEngineService.cs | 12 +- .../Rendering/Font/FontManager.cs | 8 +- .../NamedObjects/CommandBarComponentParser.cs | 44 ++- .../NamedObjects/GameObjectFileParser.cs | 2 +- .../Parsers/NamedObjects/GameObjectParser.cs | 262 +++++++++--------- .../Parsers/NamedObjects/SfxEventParser.cs | 27 +- .../Parsers/Base/IXmlTagMapper.cs | 2 +- .../Base/PetroglyphXmlFileParserBase.cs | 14 +- .../Parsers/Base/PetroglyphXmlParserBase.cs | 17 +- .../Parsers/Base/XmlObjectParserBase.cs | 23 +- .../Parsers/INamedXmlObjectParser.cs | 11 + .../Parsers/IXmlContainerFileParser.cs | 2 +- .../Parsers/NamedXmlObjectParser.cs | 38 ++- .../Parsers/XmlContainerFileParser.cs | 4 +- .../Parsers/XmlObjectParser.cs | 21 +- .../Parsers/XmlTagMapper.cs | 26 +- 27 files changed, 458 insertions(+), 324 deletions(-) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectType.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/INamedXmlObjectParser.cs diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs index d384007..181d5c0 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using PG.Commons.Hashing; using PG.StarWarsGame.Files.XML; @@ -6,6 +8,7 @@ namespace PG.StarWarsGame.Engine.Audio.Sfx; +[DebuggerDisplay("{Name}")] public sealed class SfxEvent : NamedXmlObject { private byte _minVolume = DefaultMinVolume; @@ -45,6 +48,11 @@ public sealed class SfxEvent : NamedXmlObject public const byte DefaultMaxPan2d = 50; public const float DefaultVolumeSaturationDistance = 300.0f; + internal readonly List PreSamplesInternal = new(); + internal readonly List SamplesInternal = new(); + internal readonly List PostSamplesInternal = new(); + internal readonly List LocalizedTextIDsInternal = new(); + public bool IsPreset { get; internal set; } public bool Is3D { get; internal set; } = DefaultIs3d; @@ -69,14 +77,14 @@ public sealed class SfxEvent : NamedXmlObject public IEnumerable AllSamples => PreSamples.Concat(Samples).Concat(PostSamples); - public IReadOnlyList PreSamples { get; internal set; } = []; - - public IReadOnlyList Samples { get; internal set; } = []; + public IReadOnlyList PreSamples { get; } - public IReadOnlyList PostSamples { get; internal set; } = []; + public IReadOnlyList Samples { get; } - public IReadOnlyList LocalizedTextIDs { get; internal set; } = []; + public IReadOnlyList PostSamples { get; } + public IReadOnlyList LocalizedTextIDs { get; } + public byte Priority { get; internal set; } = DefaultPriority; public byte Probability { get; internal set; } = DefaultProbability; @@ -161,6 +169,7 @@ public uint MaxPostdelay internal SfxEvent(string name, Crc32 nameCrc, XmlLocationInfo location) : base(name, nameCrc, location) { + PreSamples = new ReadOnlyCollection(PreSamplesInternal); } internal void FixupValues() @@ -197,10 +206,10 @@ public void ApplyPreset(SfxEvent preset) IsAmbientVo = preset.IsAmbientVo; IsLocalized = preset.IsLocalized; PlaySequentially = preset.PlaySequentially; - PreSamples = preset.PreSamples; - Samples = preset.Samples; - PostSamples = preset.PostSamples; - LocalizedTextIDs = preset.LocalizedTextIDs; + SetList(PreSamplesInternal, preset.PreSamplesInternal); + SetList(SamplesInternal, preset.SamplesInternal); + SetList(PostSamplesInternal, preset.PostSamplesInternal); + SetList(LocalizedTextIDsInternal, preset.LocalizedTextIDsInternal); Priority = preset.Priority; Probability = preset.Probability; PlayCount = preset.PlayCount; @@ -219,6 +228,13 @@ public void ApplyPreset(SfxEvent preset) MaxPitch = preset.MaxPitch; MinPan2D = preset.MinPan2D; MaxPan2D = preset.MaxPan2D; + return; + + static void SetList(List target, List source) + { + target.Clear(); + target.AddRange(source); + } } private static void AdjustMinMaxValues(ref byte minValue, ref byte maxValue) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs index a9034ef..1b15c1e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs @@ -11,8 +11,12 @@ namespace PG.StarWarsGame.Engine.Audio.Sfx; -internal class SfxEventGameManager(GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(repository, errorReporter, serviceProvider), ISfxEventGameManager +internal class SfxEventGameManager( + GameEngineType engineType, + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) + : GameManagerBase(engineType, repository, errorReporter, serviceProvider), ISfxEventGameManager { public IEnumerable InstalledLanguages { get; private set; } = []; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 4478fea..28ed70e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -15,13 +15,14 @@ namespace PG.StarWarsGame.Engine.CommandBar; internal partial class CommandBarGameManager( + GameEngineType engineType, GameRepository repository, PGRender pgRender, IGameConstants gameConstants, IFontManager fontManager, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(repository, errorReporter, serviceProvider), ICommandBarGameManager + : GameManagerBase(engineType, repository, errorReporter, serviceProvider), ICommandBarGameManager { private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService(); private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs index 82168a3..659130a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/Xml/CommandBarComponentData.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Numerics; using PG.Commons.Hashing; @@ -9,7 +8,7 @@ namespace PG.StarWarsGame.Engine.CommandBar.Xml; -public sealed class CommandBarComponentData(string name, Crc32 crc, XmlLocationInfo location) : NamedXmlObject(name, crc, location) +public sealed class CommandBarComponentData : NamedXmlObject { public const float DefaultScale = 1.0f; public const float DefaultBlinkRate = 0.2f; @@ -17,18 +16,31 @@ public sealed class CommandBarComponentData(string name, Crc32 crc, XmlLocationI public static readonly Vector2 DefaultOffsetWidescreenValue = new(9.9999998e17f, 9.9999998e17f); public static readonly Vector4Int WhiteColor = new(255, 255, 255, 255); - public IReadOnlyList SelectedTextureNames { get; internal set; } = []; - public IReadOnlyList BlankTextureNames { get; internal set; } = []; - public IReadOnlyList IconAlternateTextureNames { get; internal set; } = []; - public IReadOnlyList MouseOverTextureNames { get; internal set; } = []; - public IReadOnlyList BarTextureNames { get; internal set; } = []; - public IReadOnlyList BarOverlayNames { get; internal set; } = []; - public IReadOnlyList AlternateFontNames { get; internal set; } = []; - public IReadOnlyList TooltipTexts { get; internal set; } = []; - public IReadOnlyList LowerEffectTextureNames { get; internal set; } = []; - public IReadOnlyList UpperEffectTextureNames { get; internal set; } = []; - public IReadOnlyList OverlayTextureNames { get; internal set; } = []; - public IReadOnlyList Overlay2TextureNames { get; internal set; } = []; + internal readonly List SelectedTextureNamesInternal = []; + internal readonly List BlankTextureNamesInternal = []; + internal readonly List IconAlternateTextureNamesInternal = []; + internal readonly List MouseOverTextureNamesInternal = []; + internal readonly List BarTextureNamesInternal = []; + internal readonly List BarOverlayNamesInternal = []; + internal readonly List AlternateFontNamesInternal = []; + internal readonly List TooltipTextsInternal = []; + internal readonly List LowerEffectTextureNamesInternal = []; + internal readonly List UpperEffectTextureNamesInternal = []; + internal readonly List OverlayTextureNamesInternal = []; + internal readonly List Overlay2TextureNamesInternal = []; + + public IReadOnlyList SelectedTextureNames { get; } + public IReadOnlyList BlankTextureNames { get; } + public IReadOnlyList IconAlternateTextureNames { get; } + public IReadOnlyList MouseOverTextureNames { get; } + public IReadOnlyList BarTextureNames { get; } + public IReadOnlyList BarOverlayNames { get; } + public IReadOnlyList AlternateFontNames { get; } + public IReadOnlyList TooltipTexts { get; } + public IReadOnlyList LowerEffectTextureNames { get; } + public IReadOnlyList UpperEffectTextureNames { get; } + public IReadOnlyList OverlayTextureNames { get; } + public IReadOnlyList Overlay2TextureNames { get; } public string? IconTextureName { get; internal set; } public string? DisabledTextureName { get; internal set; } @@ -128,21 +140,26 @@ public sealed class CommandBarComponentData(string name, Crc32 crc, XmlLocationI public Vector4Int? TextColor2 { get; internal set; } public Vector4Int? MaxBarColor { get; internal set; } = WhiteColor; - internal void FixupValues() + public CommandBarComponentData(string name, Crc32 crc, XmlLocationInfo location) : base(name, crc, location) { - if (AlternateFontNames.Count == 0) - return; - var newFontNames = new string[AlternateFontNames.Count]; - for (var i = 0; i < AlternateFontNames.Count; i++) - { - var current = AlternateFontNames[i]; + SelectedTextureNames = new ReadOnlyCollection(SelectedTextureNamesInternal); + BlankTextureNames = new ReadOnlyCollection(BlankTextureNamesInternal); + IconAlternateTextureNames = new ReadOnlyCollection(IconAlternateTextureNamesInternal); + MouseOverTextureNames = new ReadOnlyCollection(MouseOverTextureNamesInternal); + BarTextureNames = new ReadOnlyCollection(BarTextureNamesInternal); + BarOverlayNames = new ReadOnlyCollection(BarOverlayNamesInternal); + AlternateFontNames = new ReadOnlyCollection(AlternateFontNamesInternal); + TooltipTexts = new ReadOnlyCollection(TooltipTextsInternal); + LowerEffectTextureNames = new ReadOnlyCollection(LowerEffectTextureNamesInternal); + UpperEffectTextureNames = new ReadOnlyCollection(UpperEffectTextureNamesInternal); + OverlayTextureNames = new ReadOnlyCollection(OverlayTextureNamesInternal); + Overlay2TextureNames = new ReadOnlyCollection(Overlay2TextureNamesInternal); + } - if (current.AsSpan().IndexOf('_') != -1) - newFontNames[i] = current.Replace('_', ' '); - else - newFontNames[i] = current; - } - AlternateFontNames = new ReadOnlyCollection(newFontNames); + internal void FixupValues() + { + for (var i = 0; i < AlternateFontNamesInternal.Count; i++) + AlternateFontNamesInternal[i] = AlternateFontNamesInternal[i].Replace('_', ' '); } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs index 1c36061..ca56b84 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs @@ -6,8 +6,12 @@ namespace PG.StarWarsGame.Engine.GameConstants; -internal class GameConstants(GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(repository, errorReporter, serviceProvider), IGameConstants +internal class GameConstants( + GameEngineType engineType, + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) + : GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGameConstants { protected override Task InitializeCoreAsync(CancellationToken token) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs index 607121d..ab74b37 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs @@ -12,8 +12,12 @@ namespace PG.StarWarsGame.Engine; -internal abstract class GameManagerBase(GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(repository, errorReporter, serviceProvider), IGameManager +internal abstract class GameManagerBase( + GameEngineType engineType, + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) + : GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGameManager { protected readonly FrugalValueListDictionary NamedEntries = new(); @@ -40,11 +44,18 @@ internal abstract class GameManagerBase protected readonly GameEngineErrorReporterWrapper ErrorReporter; public bool IsInitialized => _initialized; - - protected GameManagerBase(GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) + + public GameEngineType EngineType { get; } + + protected GameManagerBase( + GameEngineType engineType, + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) { GameRepository = repository ?? throw new ArgumentNullException(nameof(repository)); ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + EngineType = engineType; Logger = serviceProvider.GetService()?.CreateLogger(GetType()); FileSystem = serviceProvider.GetRequiredService(); ErrorReporter = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter)); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index 80be9f4..e039a26 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -1,20 +1,21 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using PG.Commons.Hashing; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; namespace PG.StarWarsGame.Engine.GameObjects; +[DebuggerDisplay("{Name} ({ClassificationName})")] public sealed class GameObject : NamedXmlObject { internal GameObject( - string type, - string name, - Crc32 nameCrc, + string name, + string classification, + Crc32 nameCrc, int index, - GameObjectType estimatedType, XmlLocationInfo location) : base(name, nameCrc, location) { @@ -22,8 +23,7 @@ internal GameObject( throw new ArgumentOutOfRangeException(nameof(index), "Index must be greater than 0."); Index = index; Id = (int)nameCrc; - Type = type ?? throw new ArgumentNullException(nameof(type)); - EstimatedType = estimatedType; + ClassificationName = classification ?? throw new ArgumentNullException(nameof(classification)); LandTerrainModelMapping = new ReadOnlyDictionary(InternalLandTerrainModelMapping); } @@ -31,14 +31,14 @@ internal GameObject( public int Index { get; } - public string Type { get; } + public string ClassificationName { get; } - public string VariantOfExistingTypeName { get; internal set; } + public string? VariantOfExistingTypeName { get; internal set; } - public bool IsLoadingComplete { get; internal set; } - - public GameObjectType EstimatedType { get; } + public GameObject? VariantOfExistingType { get; internal set; } + public bool IsLoadingComplete { get; internal set; } + public string? GalacticModel { get; internal set; } public string? DestroyedGalacticModel { get; internal set; } @@ -57,7 +57,7 @@ internal GameObject( public string? LandAnimOverrideModel { get; internal set; } - public string? XxxSpaceModeModel { get; internal set; } + public string SpaceAnimOverrideModel { get; internal set; } public string? DamagedSmokeAssetModel { get; internal set; } @@ -81,8 +81,11 @@ public IEnumerable Models AddNotEmpty(models, GalacticFleetOverrideModel); AddNotEmpty(models, GuiModel); AddNotEmpty(models, ModelName); + + // TODO: Is this really correct? AddNotEmpty(models, LandAnimOverrideModel, s => s.EndsWith(".alo", StringComparison.OrdinalIgnoreCase)); - AddNotEmpty(models, XxxSpaceModeModel); + AddNotEmpty(models, SpaceAnimOverrideModel, s => s.EndsWith(".alo", StringComparison.OrdinalIgnoreCase)); + AddNotEmpty(models, DamagedSmokeAssetModel); foreach (var model in InternalLandTerrainModelMapping.Values) models.Add(model); @@ -109,4 +112,9 @@ public void PostLoadFixup() // The engine loads references for scripts, images, hardpoints, etc., // but we don't do that here. } + + internal void ApplyBaseType(GameObject baseType) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectType.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectType.cs deleted file mode 100644 index 0b84517..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectType.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace PG.StarWarsGame.Engine.GameObjects; - -public enum GameObjectType -{ - Unknown = 0, - CinematicObject = 1, - Container = 2, - GenericHeroUnit = 3, - GroundBase = 4, - GroundBuildable = 5, - GroundCompany = 6, - GroundInfantry = 7, - GroundStructure = 8, - GroundVehicle = 9, - HeroCompany = 10, - HeroUnit = 11, - IndigenousUnit = 12, - LandBombingUnit = 13, - LandPrimarySkydome = 14, - LandSecondarySkydome = 15, - Marker = 16, - MiscObject = 17, - MobileDefenseUnit = 18, - MultiplayerStructureMarker = 19, - Particle = 20, - Planet = 21, - Projectile = 22, - Prop = 23, - ScriptMarker = 24, - SecondaryStructure = 25, - SlaveCompany = 26, - SlaveUnit = 27, - SpaceBuildable = 28, - SpacePrimarySkydome = 29, - SpaceProp = 30, - SpaceSecondarySkydome = 31, - SpaceUnit = 32, - SpecialEffect = 33, - SpecialStructure = 34, - Squadron = 35, - StarBase = 36, - TechBuilding = 37, - TransportUnit = 38, - UniqueUint = 39, - UpgradeUnit = 40 -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 6fd4828..02e866a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -17,10 +17,11 @@ internal class GameObjectTypeGameManager : GameManagerBase, IGameObj private readonly List _gameObjects; public GameObjectTypeGameManager( + GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : base(repository, errorReporter, serviceProvider) + : base(engineType, repository, errorReporter, serviceProvider) { _gameObjects = new List(); GameObjects = new ReadOnlyCollection(_gameObjects); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs new file mode 100644 index 0000000..6109b74 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using PG.StarWarsGame.Engine.Xml; + +namespace PG.StarWarsGame.Engine.GameObjects; + +// TODO: Not sure, this is the correct namespace + +public enum MapEnvironmentType +{ + Temperate = 0x0, + Arctic = 0x1, + Desert = 0x2, + Forest = 0x3, + Swamp = 0x4, + Volcanic = 0x5, + Urban = 0x6, + Space = 0x7, +} + +// TODO: To separate GameManager that holds these Conversion instances +public static class MapEnvironmentTypeConversion +{ + public static readonly EnumConversionDictionary Dictionary = new([ + new KeyValuePair("Temperate", MapEnvironmentType.Temperate), + new KeyValuePair("Arctic", MapEnvironmentType.Arctic), + new KeyValuePair("Desert", MapEnvironmentType.Desert), + new KeyValuePair("Forest", MapEnvironmentType.Forest), + new KeyValuePair("Swamp", MapEnvironmentType.Swamp), + new KeyValuePair("Volcanic", MapEnvironmentType.Volcanic), + new KeyValuePair("Urban", MapEnvironmentType.Urban), + new KeyValuePair("Space", MapEnvironmentType.Space) + ]); +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs index 5b96451..887e0c2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs @@ -14,8 +14,12 @@ namespace PG.StarWarsGame.Engine.GuiDialog; -internal partial class GuiDialogGameManager(GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(repository, errorReporter, serviceProvider), IGuiDialogManager +internal partial class GuiDialogGameManager( + GameEngineType engineType, + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) + : GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGuiDialogManager { private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs index 42a2416..1ef6f29 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs @@ -74,7 +74,7 @@ private async Task InitializeEngineAsync( var pgRender = new PGRender(repository, errorReporter, serviceProvider); - var gameConstants = new GameConstants.GameConstants(repository, errorReporter, serviceProvider); + var gameConstants = new GameConstants.GameConstants(engineType, repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing GameConstants"); await gameConstants.InitializeAsync(token); @@ -82,23 +82,23 @@ private async Task InitializeEngineAsync( // MousePointer - var fontManger = new FontManager(repository, errorReporter, serviceProvider); + var fontManger = new FontManager(engineType, repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing FontManager"); await fontManger.InitializeAsync(token); - var guiDialogs = new GuiDialogGameManager(repository, errorReporter, serviceProvider); + var guiDialogs = new GuiDialogGameManager(engineType, repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing GUIDialogManager"); await guiDialogs.InitializeAsync(token); - var sfxGameManager = new SfxEventGameManager(repository, errorReporter, serviceProvider); + var sfxGameManager = new SfxEventGameManager(engineType, repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing SFXManager"); await sfxGameManager.InitializeAsync(token); - var commandBarManager = new CommandBarGameManager(repository, pgRender, gameConstants, fontManger, errorReporter, serviceProvider); + var commandBarManager = new CommandBarGameManager(engineType, repository, pgRender, gameConstants, fontManger, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing CommandBar"); await commandBarManager.InitializeAsync(token); - var gameObjetTypeManager = new GameObjectTypeGameManager(repository, errorReporter, serviceProvider); + var gameObjetTypeManager = new GameObjectTypeGameManager(engineType, repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing GameObjectTypeManager"); await gameObjetTypeManager.InitializeAsync(token); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs index b42eec6..1d8a5c4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs @@ -15,8 +15,12 @@ internal class FontManager : GameManagerBase, IFontManager private ISet _fontNames = null!; - public FontManager(GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : base(repository, errorReporter, serviceProvider) + public FontManager( + GameEngineType engineType, + GameRepository repository, + GameEngineErrorReporterWrapper errorReporter, + IServiceProvider serviceProvider) + : base(engineType, repository, errorReporter, serviceProvider) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) _fontManager = new WindowsFontManager(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index d099a5f..954f79e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -4,7 +4,6 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; using System; -using System.Collections.ObjectModel; using System.Xml.Linq; using Crc32 = PG.Commons.Hashing.Crc32; @@ -13,6 +12,9 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class CommandBarComponentParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : NamedXmlObjectParser(serviceProvider, new CommandBarComponentDataXmlTagMapper(serviceProvider), errorReporter) { + protected override bool UpperCaseNameForCrc => true; + protected override bool UpperCaseNameForObject => false; + protected override CommandBarComponentData CreateXmlObject( string name, Crc32 nameCrc, @@ -24,7 +26,7 @@ protected override CommandBarComponentData CreateXmlObject( } - protected override void ValidateAndFixupValues(CommandBarComponentData xmlData, XElement element) + protected override void ValidateAndFixupValues(CommandBarComponentData xmlData, XElement element, in IReadOnlyFrugalValueListDictionary parsedEntries) { if (xmlData.Name.Length > PGConstants.MaxCommandBarComponentName) { @@ -37,7 +39,7 @@ protected override void ValidateAndFixupValues(CommandBarComponentData xmlData, xmlData.FixupValues(); } - + private sealed class CommandBarComponentDataXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) { @@ -46,11 +48,13 @@ protected override void BuildMappings() AddMapping( CommandBarComponentTags.SelectedTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.SelectedTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.SelectedTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.BlankTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.BlankTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.BlankTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.IconTextureName, PetroglyphXmlStringParser.Instance.Parse, @@ -58,11 +62,13 @@ protected override void BuildMappings() AddMapping( CommandBarComponentTags.IconAlternateTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.IconAlternateTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.IconAlternateTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.MouseOverTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.MouseOverTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.MouseOverTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.DisabledTextureName, PetroglyphXmlStringParser.Instance.Parse, @@ -74,11 +80,13 @@ protected override void BuildMappings() AddMapping( CommandBarComponentTags.BarTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.BarTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.BarTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.BarOverlayName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.BarOverlayNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.BarOverlayNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.BuildTextureName, PetroglyphXmlStringParser.Instance.Parse, @@ -102,11 +110,13 @@ protected override void BuildMappings() AddMapping( CommandBarComponentTags.AlternateFontName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.AlternateFontNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.AlternateFontNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.TooltipText, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.TooltipTexts = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.TooltipTextsInternal, val, replace)); AddMapping( CommandBarComponentTags.ClickSfx, PetroglyphXmlStringParser.Instance.Parse, @@ -118,19 +128,23 @@ protected override void BuildMappings() AddMapping( CommandBarComponentTags.LowerEffectTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.LowerEffectTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.LowerEffectTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.UpperEffectTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.UpperEffectTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.UpperEffectTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.OverlayTextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.OverlayTextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.OverlayTextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.Overlay2TextureName, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.Overlay2TextureNames = new ReadOnlyCollection(val)); + (obj, val, replace) => + SetOrReplaceList(obj.Overlay2TextureNamesInternal, val, replace)); AddMapping( CommandBarComponentTags.RightClickSfx, PetroglyphXmlStringParser.Instance.Parse, diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs index c45638a..3ed7556 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs @@ -29,7 +29,7 @@ internal class GameObjectFileParser(IServiceProvider serviceProvider, IGameEngin private readonly GameObjectParser _gameObjectParser = new(serviceProvider, errorReporter); - public NamedXmlObjectParser ElementParser => _gameObjectParser; + public INamedXmlObjectParser ElementParser => _gameObjectParser; public bool OverlayLoad { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index c7555a8..1ecb773 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -1,38 +1,25 @@ -using System; -using System.Diagnostics; -using System.Xml.Linq; -using AnakinRaW.CommonUtilities.Collections; +using AnakinRaW.CommonUtilities.Collections; +using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine.GameObjects; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.ErrorHandling; using PG.StarWarsGame.Files.XML.Parsers; +using System; +using System.Diagnostics; +using System.Xml.Linq; using Crc32 = PG.Commons.Hashing.Crc32; namespace PG.StarWarsGame.Engine.Xml.Parsers; -public static class GameObjectXmlTags -{ - public const string LandTerrainModelMapping = "Land_Terrain_Model_Mapping"; - public const string GalacticModelName = "Galactic_Model_Name"; - public const string DestroyedGalacticModelName = "Destroyed_Galactic_Model_Name"; - public const string LandModelName = "Land_Model_Name"; - public const string SpaceModelName = "Space_Model_Name"; - public const string ModelName = "Model_Name"; - public const string TacticalModelName = "Tactical_Model_Name"; - public const string GalacticFleetOverrideModelName = "Galactic_Fleet_Override_Model_Name"; - public const string GuiModelName = "GUI_Model_Name"; - public const string LandModelAnimOverrideName = "Land_Model_Anim_Override_Name"; - public const string XxxSpaceModelName = "xxxSpace_Model_Name"; - public const string DamagedSmokeAssetName = "Damaged_Smoke_Asset_Name"; -} - - - -internal class GameObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) +internal partial class GameObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : NamedXmlObjectParser(serviceProvider, new GameObjectXmlTagMapper(serviceProvider), errorReporter) { internal bool OverlayLoad { get; set; } + protected override bool UpperCaseNameForCrc => true; + + protected override bool UpperCaseNameForObject => true; + protected override GameObject CreateXmlObject( string name, Crc32 nameCrc, @@ -40,37 +27,64 @@ protected override GameObject CreateXmlObject( IReadOnlyFrugalValueListDictionary parsedEntries, XmlLocationInfo location) { - if (!OverlayLoad) - { - var type = GetTagName(element); - var objectType = EstimateType(type); - return new GameObject(type, name, nameCrc, parsedEntries.ValueCount, objectType, location); - } - else + if (OverlayLoad) { parsedEntries.TryGetFirstValue(nameCrc, out var type); Debug.Assert(type is not null); + OverlayType(type, element, parsedEntries); + return type; + } - OverlayType(type!, element, false); - + // The engine actually manages a CRC table of the classification names, + // but since we uppercase the name and this feature is nowhere used, + // except for "MultiplayerStructureMarker", + // we can just use the name as the classification. + var classificationName = GetTagName(element).ToUpperInvariant(); + var gameObjectType = new GameObject(name, classificationName, nameCrc, parsedEntries.ValueCount, location); + if (Logger != null) + LogCreatingNewGameObjectType(Logger, gameObjectType.Name); + return gameObjectType; + } - return type!; + protected override void ParseObject( + GameObject xmlObject, + XElement element, + bool replace, + in IReadOnlyFrugalValueListDictionary parsedEntries) + { + if (element.HasElements && element.Attribute("SubObjectList")?.Value == "Yes") + { + // TODO + return; + } + + if (OverlayLoad) + { + Debug.Assert(replace); + OverlayType(xmlObject, element, parsedEntries); + } + else + { + base.ParseObject(xmlObject, element, replace, in parsedEntries); } } - protected override void ValidateAndFixupValues(GameObject gameObject, XElement element) + protected override void ValidateAndFixupValues(GameObject gameObject, XElement element, in IReadOnlyFrugalValueListDictionary parsedEntries) { if (!OverlayLoad) { + //BehaviorClass.AddImpliedBehaviors(this, BehaviorNames); + //InitBehaviorMap(); + gameObject.PostLoadFixup(); if (string.IsNullOrEmpty(gameObject.VariantOfExistingTypeName)) gameObject.IsLoadingComplete = true; else - OverlayType(gameObject, element); + OverlayType(gameObject, element, parsedEntries); } } - private void OverlayType(GameObject gameObject, XElement element) + private void OverlayType(GameObject gameObject, XElement element, IReadOnlyFrugalValueListDictionary parsedEntries) { var baseType = gameObject.VariantOfExistingType; if (baseType is null) @@ -79,7 +93,9 @@ private void OverlayType(GameObject gameObject, XElement element) if (string.IsNullOrEmpty(baseTypeName)) return; - baseType = FindBaseType(baseTypeName); + var nameCrc = CreateNameCrc(baseTypeName); + + parsedEntries.TryGetFirstValue(nameCrc, out baseType); if (baseType is null) return; } @@ -93,118 +109,92 @@ private void OverlayType(GameObject baseType, GameObject derivedType, XElement e derivedType.ApplyBaseType(baseType); - - ParseObject(derivedType, element, ReadOnlyFrugalValueListDictionary.Empty); + ParseTags(derivedType, element, true, ReadOnlyFrugalValueListDictionary.Empty); derivedType.PostLoadFixup(); derivedType.IsLoadingComplete = true; } - protected override bool ParseTag(XElement tag, GameObject xmlObject, in IReadOnlyFrugalValueListDictionary parseState) + protected override bool ParseTag( + XElement tag, + GameObject xmlObject, + bool replace, + in IReadOnlyFrugalValueListDictionary parseState) { - switch (tag.Name.LocalName) - { - case GameObjectXmlTags.LandTerrainModelMapping: - var mappingValue = CommaSeparatedStringKeyValueListParser.Instance.Parse(tag); - var dict = xmlObject.InternalLandTerrainModelMapping; - foreach (var keyValuePair in mappingValue) - { - if (!dict.ContainsKey(keyValuePair.key)) - dict.Add(keyValuePair.key, keyValuePair.value); - } - return true; - case GameObjectXmlTags.GalacticModelName: - xmlObject.GalacticModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.DestroyedGalacticModelName: - xmlObject.DestroyedGalacticModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.LandModelName: - xmlObject.LandModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.SpaceModelName: - xmlObject.SpaceModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.ModelName: - xmlObject.ModelName = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.TacticalModelName: - xmlObject.TacticalModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.GalacticFleetOverrideModelName: - xmlObject.GalacticFleetOverrideModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.GuiModelName: - xmlObject.GuiModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.LandModelAnimOverrideName: - xmlObject.LandAnimOverrideModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.XxxSpaceModelName: - xmlObject.XxxSpaceModeModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - case GameObjectXmlTags.DamagedSmokeAssetName: - xmlObject.DamagedSmokeAssetModel = PetroglyphXmlStringParser.Instance.Parse(tag); - return true; - default: return true; // TODO: Once parsing is complete, switch to false. - } - } - - private static GameObjectType EstimateType(string tagName) - { - if (tagName.StartsWith("Props_")) - return GameObjectType.Prop; - if (tagName.StartsWith("CIN_", StringComparison.OrdinalIgnoreCase)) - return GameObjectType.CinematicObject; + // The engine ignores the return value, but we do not, so we can report unknown tags. + base.ParseTag(tag, xmlObject, replace, in parseState); - return tagName switch - { - "Container" => GameObjectType.Container, - "GenericHeroUnit" => GameObjectType.GenericHeroUnit, - "GroundBase" => GameObjectType.GroundBase, - "GroundBuildable" => GameObjectType.GroundBuildable, - "GroundCompany" => GameObjectType.GroundCompany, - "GroundInfantry" => GameObjectType.GroundInfantry, - "GroundStructure" => GameObjectType.GroundStructure, - "GroundVehicle" => GameObjectType.GroundVehicle, - "HeroCompany" => GameObjectType.HeroCompany, - "HeroUnit" => GameObjectType.HeroUnit, - "Indigenous_Unit" => GameObjectType.IndigenousUnit, - "LandBombingUnit" => GameObjectType.LandBombingUnit, - "LandPrimarySkydome" => GameObjectType.LandPrimarySkydome, - "LandSecondarySkydome" => GameObjectType.LandSecondarySkydome, - "Marker" => GameObjectType.Marker, - "MiscObject" => GameObjectType.MiscObject, - "Mobile_Defense_Unit" => GameObjectType.MobileDefenseUnit, - "MultiplayerStructureMarker" => GameObjectType.MultiplayerStructureMarker, - "Particle" => GameObjectType.Particle, - "Planet" => GameObjectType.Planet, - "Projectile" => GameObjectType.Projectile, - "ScriptMarker" => GameObjectType.ScriptMarker, - "SecondaryStructure" => GameObjectType.SecondaryStructure, - "SlaveCompany" => GameObjectType.SlaveCompany, - "Slave_Unit" => GameObjectType.SlaveUnit, - "SpaceBuildable" => GameObjectType.SpaceBuildable, - "SpacePrimarySkydome" => GameObjectType.SpacePrimarySkydome, - "SpaceProp" => GameObjectType.SpaceProp, - "SpaceSecondarySkydome" => GameObjectType.SpaceSecondarySkydome, - "SpaceUnit" => GameObjectType.SpaceUnit, - "SpecialEffect" => GameObjectType.SpecialEffect, - "SpecialStructure" => GameObjectType.SpecialStructure, - "Squadron" => GameObjectType.Squadron, - "StarBase" => GameObjectType.StarBase, - "TechBuilding" => GameObjectType.TechBuilding, - "TransportUnit" => GameObjectType.TransportUnit, - "UniqueUnit" => GameObjectType.UniqueUint, - "UpgradeObject" => GameObjectType.UpgradeUnit, - _ => GameObjectType.Unknown - }; + // TODO: Once parsing is complete, return original parse result. + return true; } private sealed class GameObjectXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) { protected override void BuildMappings() { + AddMapping( + GameObjectXmlTags.GalacticModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.GalacticModel = val); + AddMapping( + GameObjectXmlTags.GalacticFleetOverrideModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.GalacticFleetOverrideModel = val); + AddMapping( + GameObjectXmlTags.DestroyedGalacticModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.DestroyedGalacticModel = val); + AddMapping( + GameObjectXmlTags.LandModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.LandModel = val); + + // TODO + //AddMapping( + // GameObjectXmlTags.LandTerrainModelMapping, + // PetroglyphXmlStringParser.Instance.Parse, + // (obj, val) => obj.InternalLandTerrainModelMapping = val); + + AddMapping( + GameObjectXmlTags.SpaceModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.SpaceModel = val); + AddMapping( + GameObjectXmlTags.LandModelAnimOverrideName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.LandAnimOverrideModel = val); + AddMapping( + GameObjectXmlTags.SpaceModelAnimOverrideName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.SpaceAnimOverrideModel = val); + + + AddMapping( + GameObjectXmlTags.GuiModelName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.GuiModel = val); + + AddMapping( + GameObjectXmlTags.DamagedSmokeAssetName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.DamagedSmokeAssetModel = val); } } + + [LoggerMessage(LogLevel.Debug, "--- Creating new GameObjectTypeClass for key '{objectName}'")] + static partial void LogCreatingNewGameObjectType(ILogger logger, string objectName); + + internal static class GameObjectXmlTags + { + public const string LandTerrainModelMapping = "Land_Terrain_Model_Mapping"; + public const string GalacticModelName = "Galactic_Model_Name"; + public const string DestroyedGalacticModelName = "Destroyed_Galactic_Model_Name"; + public const string LandModelName = "Land_Model_Name"; + public const string SpaceModelName = "Space_Model_Name"; + public const string GalacticFleetOverrideModelName = "Galactic_Fleet_Override_Model_Name"; + public const string GuiModelName = "GUI_Model_Name"; + public const string LandModelAnimOverrideName = "Land_Model_Anim_Override_Name"; + public const string SpaceModelAnimOverrideName = "Space_Model_Anim_Override_Name"; + public const string DamagedSmokeAssetName = "Damaged_Smoke_Asset_Name"; + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs index c2d4b65..d51533b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.ObjectModel; using System.Diagnostics; using System.Xml.Linq; using AnakinRaW.CommonUtilities.Collections; @@ -14,6 +13,13 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; internal class SfxEventParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) : NamedXmlObjectParser(serviceProvider, new SfxEventXmlTagMapper(serviceProvider), errorReporter) { + // This is a slight derivation from the engine: + // The engine does not upper case the name neither for the name itself and the CRC. + // However, the SFXEventManager maps all SFXEvent by their upper-cased name CRC values. + // We create and store upper-cased name CRC to the SFXEvent too. + protected override bool UpperCaseNameForCrc => true; + protected override bool UpperCaseNameForObject => false; + protected override SfxEvent CreateXmlObject( string name, Crc32 nameCrc, @@ -24,7 +30,7 @@ protected override SfxEvent CreateXmlObject( return new SfxEvent(name, nameCrc, location); } - protected override void ValidateAndFixupValues(SfxEvent sfxEvent, XElement element) + protected override void ValidateAndFixupValues(SfxEvent sfxEvent, XElement element, in IReadOnlyFrugalValueListDictionary parsedEntries) { if (sfxEvent.Name.Length > PGConstants.MaxSFXEventName) { @@ -92,11 +98,16 @@ protected override void ValidateAndFixupValues(SfxEvent sfxEvent, XElement eleme sfxEvent.FixupValues(); } - protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, + protected override bool ParseTag( + XElement tag, + SfxEvent sfxEvent, + bool replace, in IReadOnlyFrugalValueListDictionary parsedEntries) { if (tag.Name.LocalName == SfxEventXmlTags.UsePreset) { + // TODO: Needs is Valid Check? + var presetName = PetroglyphXmlStringParser.Instance.Parse(tag); Debug.Assert(!string.IsNullOrEmpty(presetName)); @@ -119,7 +130,7 @@ protected override bool ParseTag(XElement tag, SfxEvent sfxEvent, return true; } - return base.ParseTag(tag, sfxEvent, parsedEntries); + return base.ParseTag(tag, sfxEvent, replace, parsedEntries); } @@ -139,19 +150,19 @@ protected override void BuildMappings() AddMapping( SfxEventXmlTags.Samples, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.Samples = new ReadOnlyCollection(val)); + (obj, val, replace) => SetOrReplaceList(obj.SamplesInternal, val, replace)); AddMapping( SfxEventXmlTags.PreSamples, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.PreSamples = new ReadOnlyCollection(val)); + (obj, val, replace) => SetOrReplaceList(obj.PreSamplesInternal, val, replace)); AddMapping( SfxEventXmlTags.PostSamples, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.PostSamples = new ReadOnlyCollection(val)); + (obj, val, replace) => SetOrReplaceList(obj.PostSamplesInternal, val, replace)); AddMapping( SfxEventXmlTags.TextID, PetroglyphXmlLooseStringListParser.Instance.Parse, - (obj, val) => obj.LocalizedTextIDs = new ReadOnlyCollection(val)); + (obj, val, replace) => SetOrReplaceList(obj.LocalizedTextIDsInternal, val, replace)); AddMapping( SfxEventXmlTags.PlaySequentially, PetroglyphXmlBooleanParser.Instance.Parse, diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs index 5db7353..13cbedb 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs @@ -5,5 +5,5 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public interface IXmlTagMapper where T : XmlObject { - bool TryParseEntry(XElement element, T target); + bool TryParseEntry(XElement element, T target, bool replace); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs index 178fece..2ac7f6c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlFileParserBase.cs @@ -29,7 +29,7 @@ protected XElement GetRootElement(Stream xmlStream, out string fileName) if (string.IsNullOrEmpty(fileName)) throw new InvalidOperationException("Unable to parse XML from unnamed stream. Either parse from a file or MEG stream."); - SkipLeadingWhiteSpace(fileName, xmlStream); + SkipCharactersUntilXmlHeader(fileName, xmlStream); var asciiStreamReader = new StreamReader(xmlStream, XmlFileConstants.XmlEncoding, false, 1024, leaveOpen: true); using var xmlReader = XmlReader.Create(asciiStreamReader, new XmlReaderSettings @@ -77,18 +77,16 @@ private string GetStrippedFileName(string filePath) } - private void SkipLeadingWhiteSpace(string fileName, Stream stream) + private void SkipCharactersUntilXmlHeader(string fileName, Stream stream) { using var r = new StreamReader(stream, XmlFileConstants.XmlEncoding, false, 10, true); var count = 0; - while (true) - { - var c = (char)r.Read(); - if (!char.IsWhiteSpace(c)) - break; + // It might be possible, that a XML file starts with leading spaces or even a encoding BOM. + // The engine skips everything until the first '<' character, so we have to do the same to avoid parsing errors. + + while ((char)r.Read() != '<') count++; - } if (count != 0) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs index af9fdb1..ef2380e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/PetroglyphXmlParserBase.cs @@ -1,4 +1,6 @@ -using System.Linq; +using System; +using System.Linq; +using System.Runtime.Serialization; using PG.StarWarsGame.Files.XML.ErrorHandling; using System.Xml.Linq; @@ -68,12 +70,17 @@ protected string GetNameAttributeValue(XElement element) return nameAttribute is null ? string.Empty : nameAttribute.Value; } - protected bool GetNameAttributeValue(XElement element, out string value) + protected bool GetNameAttributeValue(XElement element, out string value, bool uppercase) { return GetAttributeValue(element, "Name", out value!, string.Empty); } - protected bool GetAttributeValue(XElement element, string attribute, out string? value, string? defaultValue = null) + protected bool GetAttributeValue( + XElement element, + string attribute, + out string? value, + string defaultValue = "", + bool uppercase = false) { // In this engine, this is actually case-sensitive var nameAttribute = element.Attributes() @@ -82,6 +89,8 @@ protected bool GetAttributeValue(XElement element, string attribute, out string? if (nameAttribute is null) { value = defaultValue; + if (uppercase) + value = value.ToUpperInvariant(); ErrorReporter?.Report(new XmlError(this, element) { ErrorKind = XmlParseErrorKind.MissingAttribute, @@ -91,6 +100,8 @@ protected bool GetAttributeValue(XElement element, string attribute, out string? } value = nameAttribute.Value; + if (uppercase) + value = value.ToUpperInvariant(); return true; } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs index ee7b5ff..d36c151 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs @@ -12,11 +12,21 @@ public abstract class XmlObjectParserBase(IXmlTagMapper true; - protected virtual void ValidateAndFixupValues(TObject namedXmlObject, XElement element) + protected virtual void ValidateAndFixupValues(TObject namedXmlObject, XElement element, in TParseState state) { } - protected void ParseObject(TObject xmlObject, XElement element, in TParseState state) + protected virtual void ParseObject(TObject xmlObject, XElement element, bool replace, in TParseState state) + { + ParseTags(xmlObject, element, replace, in state); + } + + protected virtual bool ParseTag(XElement tag, TObject xmlObject, bool replace, in TParseState parseState) + { + return IsTagValid(tag) && XmlTagMapper.TryParseEntry(tag, xmlObject, replace); + } + + protected void ParseTags(TObject xmlObject, XElement element, bool replace, in TParseState state) { foreach (var tag in element.Elements()) { @@ -25,7 +35,7 @@ protected void ParseObject(TObject xmlObject, XElement element, in TParseState s if (string.IsNullOrEmpty(tag.PGValue) && IgnoreEmptyValue) continue; - if (!ParseTag(tag, xmlObject, state)) + if (!ParseTag(tag, xmlObject, replace, state)) { ErrorReporter?.Report(new XmlError(this, tag) { @@ -36,13 +46,8 @@ protected void ParseObject(TObject xmlObject, XElement element, in TParseState s } else { - ParseObject(xmlObject, tag, in state); + ParseObject(xmlObject, tag, replace, in state); } } } - - protected virtual bool ParseTag(XElement tag, TObject xmlObject, in TParseState parseState) - { - return IsTagValid(tag) && XmlTagMapper.TryParseEntry(tag, xmlObject); - } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/INamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/INamedXmlObjectParser.cs new file mode 100644 index 0000000..ec7f855 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/INamedXmlObjectParser.cs @@ -0,0 +1,11 @@ +using System.Xml.Linq; +using AnakinRaW.CommonUtilities.Collections; +using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML.Data; + +namespace PG.StarWarsGame.Files.XML.Parsers; + +public interface INamedXmlObjectParser : IPetroglyphXmlParserInfo where T : NamedXmlObject +{ + T Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc); +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs index 8afbdbd..f9e8349 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/IXmlContainerFileParser.cs @@ -7,7 +7,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public interface IXmlContainerFileParser : IPetroglyphXmlParserInfo where T : NamedXmlObject { - NamedXmlObjectParser ElementParser { get; } + INamedXmlObjectParser ElementParser { get; } void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs index 1ae65e2..15d2d01 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs @@ -2,29 +2,38 @@ using System.Xml.Linq; using AnakinRaW.CommonUtilities.Collections; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using PG.Commons.Hashing; using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; namespace PG.StarWarsGame.Files.XML.Parsers; -public abstract class NamedXmlObjectParser( - IServiceProvider serviceProvider, - IXmlTagMapper tagMapper, - IXmlParserErrorReporter? errorReporter) - : XmlObjectParserBase>(tagMapper, errorReporter) +public abstract class NamedXmlObjectParser : + XmlObjectParserBase>, INamedXmlObjectParser where T : NamedXmlObject { - protected virtual bool UpperCaseNameForCrc => true; + protected abstract bool UpperCaseNameForCrc { get; } + protected abstract bool UpperCaseNameForObject { get; } - protected readonly ICrc32HashingService HashingService = serviceProvider.GetRequiredService(); + protected readonly ICrc32HashingService HashingService; + + protected readonly ILogger? Logger; + + protected NamedXmlObjectParser(IServiceProvider serviceProvider, + IXmlTagMapper tagMapper, + IXmlParserErrorReporter? errorReporter) : base(tagMapper, errorReporter) + { + HashingService = serviceProvider.GetRequiredService(); + Logger = serviceProvider.GetService()?.CreateLogger(GetType()); + } public T Parse(XElement element, IReadOnlyFrugalValueListDictionary parsedEntries, out Crc32 nameCrc) { var name = GetXmlObjectName(element, out nameCrc); var namedXmlObject = CreateXmlObject(name, nameCrc, element, parsedEntries, XmlLocationInfo.FromElement(element)); - ParseObject(namedXmlObject, element, parsedEntries); - ValidateAndFixupValues(namedXmlObject, element); + ParseObject(namedXmlObject, element, false, parsedEntries); + ValidateAndFixupValues(namedXmlObject, element, parsedEntries); return namedXmlObject; } @@ -35,12 +44,17 @@ protected abstract T CreateXmlObject( IReadOnlyFrugalValueListDictionary parsedEntries, XmlLocationInfo location); - private string GetXmlObjectName(XElement element, out Crc32 crc32) + protected virtual Crc32 CreateNameCrc(string name) { - GetNameAttributeValue(element, out var name); - crc32 = UpperCaseNameForCrc + return UpperCaseNameForCrc ? HashingService.GetCrc32Upper(name.AsSpan(), XmlFileConstants.XmlEncoding) : HashingService.GetCrc32(name.AsSpan(), XmlFileConstants.XmlEncoding); + } + + protected string GetXmlObjectName(XElement element, out Crc32 crc32) + { + GetNameAttributeValue(element, out var name, UpperCaseNameForObject); + crc32 = CreateNameCrc(name); if (crc32 == default) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs index 8ef0e93..c75df69 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlContainerFileParser.cs @@ -10,12 +10,12 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public sealed class XmlContainerFileParser( IServiceProvider serviceProvider, - NamedXmlObjectParser elementParser, + INamedXmlObjectParser elementParser, IXmlParserErrorReporter? listener = null) : PetroglyphXmlFileParserBase(serviceProvider, listener), IXmlContainerFileParser where T : NamedXmlObject { - public NamedXmlObjectParser ElementParser { get; } = + public INamedXmlObjectParser ElementParser { get; } = elementParser ?? throw new ArgumentNullException(nameof(elementParser)); public void ParseFile(Stream xmlStream, IFrugalValueListDictionary parsedEntries) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs index 5511035..4358b56 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs @@ -11,20 +11,29 @@ public abstract class XmlObjectParser(IXmlTagMapper tagMapper, public TObject Parse(XElement element) { var xmlObject = CreateXmlObject(XmlLocationInfo.FromElement(element)); - ParseObject(xmlObject, element, EmptyParseState.Instance); - ValidateAndFixupValues(xmlObject, element); ; + ParseObject(xmlObject, element, false, EmptyParseState.Instance); + ValidateAndFixupValues(xmlObject, element, EmptyParseState.Instance); return xmlObject; } protected abstract TObject CreateXmlObject(XmlLocationInfo location); - protected sealed override bool ParseTag(XElement tag, TObject xmlObject, in EmptyParseState parseState) + protected sealed override bool ParseTag(XElement tag, TObject xmlObject, bool replace, in EmptyParseState parseState) { - return ParseTag(tag, xmlObject); + return ParseTag(tag, xmlObject, replace); + } + + protected sealed override void ValidateAndFixupValues(TObject xmlObject, XElement element, in EmptyParseState parseState) + { + ValidateAndFixupValues(xmlObject, element); + } + + protected virtual bool ParseTag(XElement tag, TObject xmlObject, bool replace) + { + return XmlTagMapper.TryParseEntry(tag, xmlObject, replace); } - protected virtual bool ParseTag(XElement tag, TObject xmlObject) + protected virtual void ValidateAndFixupValues(TObject xmlObject, XElement element) { - return XmlTagMapper.TryParseEntry(tag, xmlObject); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs index 366ccaf..4b42ce6 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs @@ -10,7 +10,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers; public abstract class XmlTagMapper : IXmlTagMapper where TObject : XmlObject { - private delegate void ParserValueAction(TObject target, XElement element); + private delegate void ParserValueAction(TObject target, XElement element, bool replace); private readonly Dictionary _tagMappings = new(); private readonly ICrc32HashingService _crcService; @@ -27,7 +27,21 @@ protected XmlTagMapper(IServiceProvider serviceProvider) protected abstract void BuildMappings(); - protected void AddMapping(string tagName, Func parser, Action setter) + protected static void SetOrReplaceList(IList destinationList, IEnumerable values, bool replace) + { + if (replace) + destinationList.Clear(); + foreach (var value in values) + destinationList.Add(value); + } + + protected void AddMapping(string tagName, Func parser, + Action setter) + { + AddMapping(tagName, parser, (target, value, _) => setter(target, value)); + } + + protected void AddMapping(string tagName, Func parser, Action setter) { ThrowHelper.ThrowIfNullOrEmpty(tagName); if (tagName.Length >= XmlFileConstants.MaxTagNameLength) @@ -41,14 +55,14 @@ protected void AddMapping(string tagName, Func parser, var crc = GetCrc32(tagName); - _tagMappings[crc] = (target, element) => + _tagMappings[crc] = (target, element, replace) => { var value = parser(element); - setter(target, value); + setter(target, value, replace); }; } - public bool TryParseEntry(XElement element, TObject target) + public bool TryParseEntry(XElement element, TObject target, bool replace) { var tagName = element.Name.LocalName; if (tagName.Length >= XmlFileConstants.MaxTagNameLength) @@ -59,7 +73,7 @@ public bool TryParseEntry(XElement element, TObject target) if (!_tagMappings.TryGetValue(crc, out var mapping)) return false; - mapping(target, element); + mapping(target, element, replace); return true; } From 0ec1eacb504181ca1842dc0c2c56b2129380724d Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 28 Feb 2026 15:20:00 +0100 Subject: [PATCH 20/41] parsing is engine type aware --- .../Verifiers/ReferencedModelsVerifier.cs | 7 +- .../Audio/Sfx/SfxEventGameManager.cs | 3 +- .../CommandBar/CommandBarGameManager.cs | 3 +- .../GameConstants/GameConstants.cs | 3 +- .../PG.StarWarsGame.Engine/GameManagerBase.cs | 6 +- .../GameObjects/GameObject.cs | 72 ++------- ...ameObjectTypeGameManager.Initialization.cs | 131 +++++++++++++++ .../GameObjects/GameObjectTypeGameManager.cs | 152 ++++-------------- .../GameObjects/IGameObjectTypeGameManager.cs | 14 ++ .../GameObjects/MapEnvironmentType.cs | 2 +- .../GuiDialog/GuiDialogGameManager.cs | 3 +- .../PetroglyphEngineServiceContribution.cs | 4 +- .../PetroglyphStarWarsGameEngineService.cs | 12 +- .../Rendering/Font/FontManager.cs | 3 +- .../Xml/IPetroglyphXmlFileParserFactory.cs | 10 ++ .../Xml}/NamedXmlObjectParser.cs | 12 +- .../{Parsers => }/ParserNotFoundException.cs | 2 +- .../GameObjectFileParser.cs | 21 +-- .../Xml/Parsers/GameObjectParsedEventArgs.cs | 17 ++ .../IPetroglyphXmlFileParserFactory.cs | 10 -- .../NamedObjects/CommandBarComponentParser.cs | 7 +- .../Parsers/NamedObjects/GameObjectParser.cs | 34 ++-- .../Parsers/NamedObjects/SfxEventParser.cs | 4 +- .../Xml/PetroglyphStarWarsGameXmlParser.cs | 3 +- .../Xml}/XmlObjectParser.cs | 21 ++- .../Xml}/XmlObjectParserBase.cs | 14 +- ...erFactory.cs => XmlObjectParserFactory.cs} | 14 +- .../Xml}/XmlTagMapper.cs | 59 +++++-- .../Parsers/Base/IXmlTagMapper.cs | 9 -- .../Parsers/EmptyParseState.cs | 6 - .../CommaSeparatedStringKeyValueListParser.cs | 34 +++- 31 files changed, 396 insertions(+), 296 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs rename src/PetroglyphTools/{PG.StarWarsGame.Files.XML/Parsers => PG.StarWarsGame.Engine/Xml}/NamedXmlObjectParser.cs (87%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{Parsers => }/ParserNotFoundException.cs (89%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/{NamedObjects => }/GameObjectFileParser.cs (69%) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectParsedEventArgs.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs rename src/PetroglyphTools/{PG.StarWarsGame.Files.XML/Parsers => PG.StarWarsGame.Engine/Xml}/XmlObjectParser.cs (67%) rename src/PetroglyphTools/{PG.StarWarsGame.Files.XML/Parsers/Base => PG.StarWarsGame.Engine/Xml}/XmlObjectParserBase.cs (79%) rename src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/{Parsers/PetroglyphXmlParserFactory.cs => XmlObjectParserFactory.cs} (53%) rename src/PetroglyphTools/{PG.StarWarsGame.Files.XML/Parsers => PG.StarWarsGame.Engine/Xml}/XmlTagMapper.cs (53%) delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs diff --git a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs index 4a5feb6..6ce5eed 100644 --- a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs +++ b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs @@ -20,7 +20,10 @@ public override void Verify(CancellationToken token) var gameObjectEntries = GameEngine.GameObjectTypeManager.Entries.ToList(); var hardcodedModels = FocHardcodedConstants.HardcodedModels.ToList(); - var totalModelsCount = gameObjectEntries.Sum(x => x.Models.Count()) + hardcodedModels.Count; + var totalModelsCount = + gameObjectEntries + .Sum(x => GameEngine.GameObjectTypeManager.GetModels(x).Count()) + + hardcodedModels.Count; if (totalModelsCount == 0) return; @@ -36,7 +39,7 @@ public override void Verify(CancellationToken token) foreach (var gameObject in gameObjectEntries) { context[0] = $"GameObject: {gameObject.Name}"; - foreach (var model in gameObject.Models) + foreach (var model in GameEngine.GameObjectTypeManager.GetModels(gameObject)) { OnProgress((double)++counter / totalModelsCount, $"Model - '{model}'"); inner.Verify(model, context, token); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs index 1b15c1e..99f1c31 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEventGameManager.cs @@ -12,11 +12,10 @@ namespace PG.StarWarsGame.Engine.Audio.Sfx; internal class SfxEventGameManager( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(engineType, repository, errorReporter, serviceProvider), ISfxEventGameManager + : GameManagerBase(repository, errorReporter, serviceProvider), ISfxEventGameManager { public IEnumerable InstalledLanguages { get; private set; } = []; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 28ed70e..4478fea 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -15,14 +15,13 @@ namespace PG.StarWarsGame.Engine.CommandBar; internal partial class CommandBarGameManager( - GameEngineType engineType, GameRepository repository, PGRender pgRender, IGameConstants gameConstants, IFontManager fontManager, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(engineType, repository, errorReporter, serviceProvider), ICommandBarGameManager + : GameManagerBase(repository, errorReporter, serviceProvider), ICommandBarGameManager { private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService(); private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs index ca56b84..3874e07 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameConstants/GameConstants.cs @@ -7,11 +7,10 @@ namespace PG.StarWarsGame.Engine.GameConstants; internal class GameConstants( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGameConstants + : GameManagerBase(repository, errorReporter, serviceProvider), IGameConstants { protected override Task InitializeCoreAsync(CancellationToken token) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs index ab74b37..c3dd55d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameManagerBase.cs @@ -13,11 +13,10 @@ namespace PG.StarWarsGame.Engine; internal abstract class GameManagerBase( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGameManager + : GameManagerBase(repository, errorReporter, serviceProvider), IGameManager { protected readonly FrugalValueListDictionary NamedEntries = new(); @@ -48,14 +47,13 @@ internal abstract class GameManagerBase public GameEngineType EngineType { get; } protected GameManagerBase( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) { GameRepository = repository ?? throw new ArgumentNullException(nameof(repository)); ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - EngineType = engineType; + EngineType = repository.EngineType; Logger = serviceProvider.GetService()?.CreateLogger(GetType()); FileSystem = serviceProvider.GetRequiredService(); ErrorReporter = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter)); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index e039a26..394db3f 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -11,21 +11,7 @@ namespace PG.StarWarsGame.Engine.GameObjects; [DebuggerDisplay("{Name} ({ClassificationName})")] public sealed class GameObject : NamedXmlObject { - internal GameObject( - string name, - string classification, - Crc32 nameCrc, - int index, - XmlLocationInfo location) - : base(name, nameCrc, location) - { - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index), "Index must be greater than 0."); - Index = index; - Id = (int)nameCrc; - ClassificationName = classification ?? throw new ArgumentNullException(nameof(classification)); - LandTerrainModelMapping = new ReadOnlyDictionary(InternalLandTerrainModelMapping); - } + internal readonly List<(string terrain, string model)> InternalLandTerrainModelMapping = []; internal int Id { get; } @@ -61,48 +47,24 @@ internal GameObject( public string? DamagedSmokeAssetModel { get; internal set; } - public IReadOnlyDictionary LandTerrainModelMapping { get; } - - internal Dictionary InternalLandTerrainModelMapping { get; } = new(StringComparer.OrdinalIgnoreCase); - - /// - /// Gets all model files (including particles) the game object references. - /// - public IEnumerable Models - { - get - { - var models = new HashSet(StringComparer.OrdinalIgnoreCase); - AddNotEmpty(models, GalacticModel); - AddNotEmpty(models, DestroyedGalacticModel); - AddNotEmpty(models, LandModel); - AddNotEmpty(models, SpaceModel); - AddNotEmpty(models, TacticalModel); - AddNotEmpty(models, GalacticFleetOverrideModel); - AddNotEmpty(models, GuiModel); - AddNotEmpty(models, ModelName); - - // TODO: Is this really correct? - AddNotEmpty(models, LandAnimOverrideModel, s => s.EndsWith(".alo", StringComparison.OrdinalIgnoreCase)); - AddNotEmpty(models, SpaceAnimOverrideModel, s => s.EndsWith(".alo", StringComparison.OrdinalIgnoreCase)); - - AddNotEmpty(models, DamagedSmokeAssetModel); - foreach (var model in InternalLandTerrainModelMapping.Values) - models.Add(model); - - return models; - } - - } - - private static void AddNotEmpty(ISet set, string? value, Predicate? predicate = null) + public IReadOnlyList<(string terrain, string model)> LandTerrainModelMappingValues { get; } + + internal GameObject( + string name, + string classification, + Crc32 nameCrc, + int index, + XmlLocationInfo location) + : base(name, nameCrc, location) { - if (value is null) - return; - if (predicate is null || predicate(value)) - set.Add(value); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), "Index must be greater than 0."); + Index = index; + Id = (int)nameCrc; + ClassificationName = classification ?? throw new ArgumentNullException(nameof(classification)); + LandTerrainModelMappingValues = new ReadOnlyCollection<(string, string)>(InternalLandTerrainModelMapping); } - + public void PostLoadFixup() { // TODO: diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs new file mode 100644 index 0000000..af8fcdb --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs @@ -0,0 +1,131 @@ +using Microsoft.Extensions.Logging; +using PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Engine.Xml; +using PG.StarWarsGame.Engine.Xml.Parsers; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace PG.StarWarsGame.Engine.GameObjects; + +internal partial class GameObjectTypeGameManager +{ + protected override async Task InitializeCoreAsync(CancellationToken token) + { + Logger?.LogInformation("Parsing GameObjects..."); + await Task.Run(ParseGameObjectDatabases, token); + } + + private void ParseGameObjectDatabases() + { + var gameParser = new PetroglyphStarWarsGameXmlParser(GameRepository, + new PetroglyphStarWarsGameXmlParseSettings + { + GameManager = ToString(), + InvalidFilesListXmlFailsInitialization = true, + InvalidObjectXmlFailsInitialization = false, + }, ServiceProvider, ErrorReporter); + + var xmlFileList = gameParser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files + .Select(x => FileSystem.Path.Combine(@".\DATA\XML\", x)) + .Where(VerifyFilePathLength) + .ToList(); + + var gameObjectFileParser = new GameObjectFileParser(EngineType, ServiceProvider, ErrorReporter); + + var allLoaded = false; + + // This also acts a guard against infinite loops in case of unexpected circular dependencies or + // when a unit declares itself as its own + for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++) + { + Logger?.LogDebug("***** Parsing game object types - pass {PassNumber} *****", passNumber); + + if (passNumber != 0) + gameObjectFileParser.OverlayLoad = true; + + foreach (var gameObjectXmlFile in xmlFileList) + { + if (passNumber == 0) + { + try + { + gameObjectFileParser.GameObjectParsed += OnGameObjectParsed!; + ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); + } + finally + { + gameObjectFileParser.GameObjectParsed -= OnGameObjectParsed!; + } + } + else + { + foreach (var gameObject in _gameObjects) + { + if (!gameObject.IsLoadingComplete && gameObject.Location.XmlFile == gameObjectXmlFile) + ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); + } + } + } + + + + //GameObjectTypeClass::Static_Post_Load_Fixup(); + //SFXEventReferenceClass::Static_Post_Load_Fixup(); + //SpeechEventReferenceClass::Static_Post_Load_Fixup(); + //MusicEventReferenceClass::Static_Post_Load_Fixup(); + //FactionReferenceClass::Static_Post_Load_Fixup(); + //... + } + } + + private void OnGameObjectParsed(object sender, GameObjectParsedEventArgs e) + { + if (!e.Unique) + { + var entries = NamedEntries.GetValues(e.GameObject.Crc32) + .Select(x => x.Name); + ErrorReporter.Assert(EngineAssert.Create( + EngineAssertKind.DuplicateEntry, + e.GameObject.Crc32, entries, + $"Error: Game object type {e.GameObject.Name} is defined multiple times.")); + } + + if (NamedEntries.ValueCount >= 0x10000) + { + ErrorReporter.Assert( + EngineAssert.Create( + EngineAssertKind.ValueOutOfRange, + NamedEntries.ValueCount, + [ToString()], + "Too many game object types defined.")); + } + + _gameObjects.Add(e.GameObject); + } + + private void ParseSingleGameObjectFile( + string file, + PetroglyphStarWarsGameXmlParser gameParser, + GameObjectFileParser gameObjectFileParser) + { + gameParser.ParseObjectsFromContainerFile(file, gameObjectFileParser, NamedEntries); + } + + private bool VerifyFilePathLength(string filePath) + { + if (filePath.Length > PGConstants.MaxGameObjectDatabaseFileName) + { + // Technically this is an assert in the engine, but in Release Mode, the game CTDs. + // Thus, we rank this as an initialization error. + ErrorReporter.Report(new InitializationError + { + GameManager = ToString(), + Message = $"Game object file '{filePath}' is longer than {PGConstants.MaxGameObjectDatabaseFileName} characters." + }); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 02e866a..e92f3f5 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -1,29 +1,22 @@ -using Microsoft.Extensions.Logging; -using PG.StarWarsGame.Engine.ErrorReporting; +using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO.Repositories; -using PG.StarWarsGame.Engine.Xml; -using PG.StarWarsGame.Engine.Xml.Parsers; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; namespace PG.StarWarsGame.Engine.GameObjects; -internal class GameObjectTypeGameManager : GameManagerBase, IGameObjectTypeGameManager +internal partial class GameObjectTypeGameManager : GameManagerBase, IGameObjectTypeGameManager { private readonly List _gameObjects; public GameObjectTypeGameManager( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : base(engineType, repository, errorReporter, serviceProvider) + : base(repository, errorReporter, serviceProvider) { - _gameObjects = new List(); + _gameObjects = []; GameObjects = new ReadOnlyCollection(_gameObjects); } @@ -37,120 +30,45 @@ public IReadOnlyList GameObjects } } - protected override async Task InitializeCoreAsync(CancellationToken token) + public IEnumerable GetModels(GameObject gameObject) { - Logger?.LogInformation("Parsing GameObjects..."); - await Task.Run(ParseGameObjectDatabases, token); - } - - private void ParseGameObjectDatabases() - { - var gameParser = new PetroglyphStarWarsGameXmlParser(GameRepository, - new PetroglyphStarWarsGameXmlParseSettings - { - GameManager = ToString(), - InvalidFilesListXmlFailsInitialization = true, - InvalidObjectXmlFailsInitialization = false, - }, ServiceProvider, ErrorReporter); - - var xmlFileList = gameParser.ParseFileList(@"DATA\XML\GAMEOBJECTFILES.XML").Files - .Select(x => FileSystem.Path.Combine(@".\DATA\XML\", x)) - .Where(VerifyFilePathLength) - .ToList(); - - var gameObjectFileParser = new GameObjectFileParser(ServiceProvider, ErrorReporter); + var models = new HashSet(StringComparer.OrdinalIgnoreCase); + AddNotEmpty(gameObject.GalacticModel); + AddNotEmpty(gameObject.DestroyedGalacticModel); + AddNotEmpty(gameObject.LandModel); + AddNotEmpty(gameObject.SpaceModel); + AddNotEmpty(gameObject.TacticalModel); + AddNotEmpty(gameObject.GalacticFleetOverrideModel); + AddNotEmpty(gameObject.GuiModel); + AddNotEmpty(gameObject.ModelName); + AddNotEmpty(gameObject.LandAnimOverrideModel); + AddNotEmpty(gameObject.SpaceAnimOverrideModel); + AddNotEmpty(gameObject.DamagedSmokeAssetModel); + AddTerrainMappingModels(); + return models; + + + void AddNotEmpty(string? value, Predicate? predicate = null) + { + if (string.IsNullOrEmpty(value)) + return; + if (predicate is null || predicate(value)) + models.Add(value); + } - var allLoaded = false; - // This also acts a guard against infinite loops in case of unexpected circular dependencies or - // when a unit declares itself as its own - for (var passNumber = 0; !allLoaded && passNumber < 10; passNumber++) + void AddTerrainMappingModels() { - Logger?.LogDebug("***** Parsing game object types - pass {PassNumber} *****", passNumber); - - if (passNumber != 0) - gameObjectFileParser.OverlayLoad = true; - - foreach (var gameObjectXmlFile in xmlFileList) + var visitedEnvTypes = new HashSet(); + foreach (var mapping in gameObject.LandTerrainModelMappingValues) { - if (passNumber == 0) - { - try - { - gameObjectFileParser.GameObjectParsed += OnGameObjectParsed; - ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); - } - finally - { - gameObjectFileParser.GameObjectParsed -= OnGameObjectParsed; - } - } - else + if (MapEnvironmentTypeConversion.ConversionDictionary.TryStringToEnum(mapping.terrain, out var envType)) { - foreach (var gameObject in _gameObjects) - { - if (!gameObject.IsLoadingComplete && gameObject.Location.XmlFile == gameObjectXmlFile) - ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); - } + // The engine only uses the first model for each environment type. + if (visitedEnvTypes.Add(envType)) + AddNotEmpty(mapping.model); } } - - - - //GameObjectTypeClass::Static_Post_Load_Fixup(); - //SFXEventReferenceClass::Static_Post_Load_Fixup(); - //SpeechEventReferenceClass::Static_Post_Load_Fixup(); - //MusicEventReferenceClass::Static_Post_Load_Fixup(); - //FactionReferenceClass::Static_Post_Load_Fixup(); - //... - } - } - - private void OnGameObjectParsed(object sender, GameObjectParsedEventArgs e) - { - if (!e.Unique) - { - var entries = NamedEntries.GetValues(e.ParsedElement.Crc32) - .Select(x => x.Name); - ErrorReporter.Assert(EngineAssert.Create( - EngineAssertKind.DuplicateEntry, - e.ParsedElement.Crc32, entries, - $"Error: Game object type {e.ParsedElement.Name} is defined multiple times.")); - } - - if (NamedEntries.ValueCount >= 0x10000) - { - ErrorReporter.Assert( - EngineAssert.Create( - EngineAssertKind.ValueOutOfRange, - NamedEntries.ValueCount, - [ToString()], - "Too many game object types defined.")); - } - } - - private void ParseSingleGameObjectFile( - string file, - PetroglyphStarWarsGameXmlParser gameParser, - GameObjectFileParser gameObjectFileParser) - { - gameParser.ParseObjectsFromContainerFile(file, gameObjectFileParser, NamedEntries); - } - - private bool VerifyFilePathLength(string filePath) - { - if (filePath.Length > PGConstants.MaxGameObjectDatabaseFileName) - { - // Technically this is an assert in the engine, but in Release Mode, the game CTDs. - // Thus, we rank this as an initialization error. - ErrorReporter.Report(new InitializationError - { - GameManager = ToString(), - Message = $"Game object file '{filePath}' is longer than {PGConstants.MaxGameObjectDatabaseFileName} characters." - }); - return false; } - - return true; } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs index 300f5e4..21e3ea0 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs @@ -6,4 +6,18 @@ public interface IGameObjectTypeGameManager : IGameManager { // List represent XML load order IReadOnlyList GameObjects { get; } + + /// + /// Retrieves the collection of model and particle names directly associated with the specified . + /// + /// + /// Death Clones, Projectiles, Hardpoints, etc. are not included in the returned collection. + /// + /// + /// The for which to retrieve the associated model names. + /// + /// + /// An containing the names of the models associated with the specified . + /// + IEnumerable GetModels(GameObject gameObject); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs index 6109b74..2faf565 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/MapEnvironmentType.cs @@ -20,7 +20,7 @@ public enum MapEnvironmentType // TODO: To separate GameManager that holds these Conversion instances public static class MapEnvironmentTypeConversion { - public static readonly EnumConversionDictionary Dictionary = new([ + public static readonly EnumConversionDictionary ConversionDictionary = new([ new KeyValuePair("Temperate", MapEnvironmentType.Temperate), new KeyValuePair("Arctic", MapEnvironmentType.Arctic), new KeyValuePair("Desert", MapEnvironmentType.Desert), diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs index 887e0c2..d6b4ca9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/GuiDialogGameManager.cs @@ -15,11 +15,10 @@ namespace PG.StarWarsGame.Engine.GuiDialog; internal partial class GuiDialogGameManager( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : GameManagerBase(engineType, repository, errorReporter, serviceProvider), IGuiDialogManager + : GameManagerBase(repository, errorReporter, serviceProvider), IGuiDialogManager { private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); private readonly ICrc32HashingService _hashingService = serviceProvider.GetRequiredService(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs index c8b8380..73bd755 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphEngineServiceContribution.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine.IO; using PG.StarWarsGame.Engine.Localization; -using PG.StarWarsGame.Engine.Xml.Parsers; +using PG.StarWarsGame.Engine.Xml; namespace PG.StarWarsGame.Engine; @@ -12,7 +12,7 @@ public static void ContributeServices(IServiceCollection serviceCollection) // Singletons serviceCollection.AddSingleton(sp => new GameRepositoryFactory(sp)); serviceCollection.AddSingleton(sp => new GameLanguageManagerProvider(sp)); - serviceCollection.AddSingleton(sp => new PetroglyphXmlFileParserFactory(sp)); + serviceCollection.AddSingleton(sp => new XmlObjectParserFactory(sp)); serviceCollection.AddSingleton(sp => new PetroglyphStarWarsGameEngineService(sp)); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs index 1ef6f29..42a2416 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PetroglyphStarWarsGameEngineService.cs @@ -74,7 +74,7 @@ private async Task InitializeEngineAsync( var pgRender = new PGRender(repository, errorReporter, serviceProvider); - var gameConstants = new GameConstants.GameConstants(engineType, repository, errorReporter, serviceProvider); + var gameConstants = new GameConstants.GameConstants(repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing GameConstants"); await gameConstants.InitializeAsync(token); @@ -82,23 +82,23 @@ private async Task InitializeEngineAsync( // MousePointer - var fontManger = new FontManager(engineType, repository, errorReporter, serviceProvider); + var fontManger = new FontManager(repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing FontManager"); await fontManger.InitializeAsync(token); - var guiDialogs = new GuiDialogGameManager(engineType, repository, errorReporter, serviceProvider); + var guiDialogs = new GuiDialogGameManager(repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing GUIDialogManager"); await guiDialogs.InitializeAsync(token); - var sfxGameManager = new SfxEventGameManager(engineType, repository, errorReporter, serviceProvider); + var sfxGameManager = new SfxEventGameManager(repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing SFXManager"); await sfxGameManager.InitializeAsync(token); - var commandBarManager = new CommandBarGameManager(engineType, repository, pgRender, gameConstants, fontManger, errorReporter, serviceProvider); + var commandBarManager = new CommandBarGameManager(repository, pgRender, gameConstants, fontManger, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing CommandBar"); await commandBarManager.InitializeAsync(token); - var gameObjetTypeManager = new GameObjectTypeGameManager(engineType, repository, errorReporter, serviceProvider); + var gameObjetTypeManager = new GameObjectTypeGameManager(repository, errorReporter, serviceProvider); initReporter?.ReportProgress("Initializing GameObjectTypeManager"); await gameObjetTypeManager.InitializeAsync(token); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs index 1d8a5c4..75654f2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Rendering/Font/FontManager.cs @@ -16,11 +16,10 @@ internal class FontManager : GameManagerBase, IFontManager private ISet _fontNames = null!; public FontManager( - GameEngineType engineType, GameRepository repository, GameEngineErrorReporterWrapper errorReporter, IServiceProvider serviceProvider) - : base(engineType, repository, errorReporter, serviceProvider) + : base(repository, errorReporter, serviceProvider) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) _fontManager = new WindowsFontManager(); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs new file mode 100644 index 0000000..787535a --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/IPetroglyphXmlFileParserFactory.cs @@ -0,0 +1,10 @@ +using PG.StarWarsGame.Files.XML.Data; +using PG.StarWarsGame.Files.XML.ErrorHandling; + +namespace PG.StarWarsGame.Engine.Xml; + +public interface IPetroglyphXmlFileParserFactory +{ + NamedXmlObjectParser CreateNamedXmlObjectParser(GameEngineType engine, IXmlParserErrorReporter? errorReporter) + where T : NamedXmlObject; +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObjectParser.cs similarity index 87% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObjectParser.cs index 15d2d01..d397eb2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/NamedXmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/NamedXmlObjectParser.cs @@ -4,10 +4,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Parsers; -namespace PG.StarWarsGame.Files.XML.Parsers; +namespace PG.StarWarsGame.Engine.Xml; public abstract class NamedXmlObjectParser : XmlObjectParserBase>, INamedXmlObjectParser @@ -20,9 +22,11 @@ public abstract class NamedXmlObjectParser : protected readonly ILogger? Logger; - protected NamedXmlObjectParser(IServiceProvider serviceProvider, - IXmlTagMapper tagMapper, - IXmlParserErrorReporter? errorReporter) : base(tagMapper, errorReporter) + protected NamedXmlObjectParser( + GameEngineType engine, + XmlTagMapper tagMapper, + IXmlParserErrorReporter? errorReporter, + IServiceProvider serviceProvider) : base(engine, tagMapper, errorReporter) { HashingService = serviceProvider.GetRequiredService(); Logger = serviceProvider.GetService()?.CreateLogger(GetType()); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/ParserNotFoundException.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs similarity index 89% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/ParserNotFoundException.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs index 79b5d0c..fd4fba3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/ParserNotFoundException.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/ParserNotFoundException.cs @@ -1,6 +1,6 @@ using System; -namespace PG.StarWarsGame.Engine.Xml.Parsers; +namespace PG.StarWarsGame.Engine.Xml; internal sealed class ParserNotFoundException : Exception { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectFileParser.cs similarity index 69% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectFileParser.cs index 3ed7556..66efb71 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectFileParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectFileParser.cs @@ -8,26 +8,15 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; -internal sealed class GameObjectParsedEventArgs : EventArgs -{ - public bool Unique { get; } - - public GameObject ParsedElement { get; } - - internal GameObjectParsedEventArgs(GameObject parsedElement, bool unique) - { - Unique = unique; - ParsedElement = parsedElement ?? throw new ArgumentNullException(nameof(parsedElement)); - } -} - - -internal class GameObjectFileParser(IServiceProvider serviceProvider, IGameEngineErrorReporter? errorReporter) +internal class GameObjectFileParser( + GameEngineType engine, + IServiceProvider serviceProvider, + IGameEngineErrorReporter? errorReporter) : PetroglyphXmlFileParserBase(serviceProvider, errorReporter), IXmlContainerFileParser { public event EventHandler? GameObjectParsed; - private readonly GameObjectParser _gameObjectParser = new(serviceProvider, errorReporter); + private readonly GameObjectParser _gameObjectParser = new(engine, serviceProvider, errorReporter); public INamedXmlObjectParser ElementParser => _gameObjectParser; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectParsedEventArgs.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectParsedEventArgs.cs new file mode 100644 index 0000000..692c423 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/GameObjectParsedEventArgs.cs @@ -0,0 +1,17 @@ +using System; +using PG.StarWarsGame.Engine.GameObjects; + +namespace PG.StarWarsGame.Engine.Xml.Parsers; + +internal sealed class GameObjectParsedEventArgs : EventArgs +{ + public bool Unique { get; } + + public GameObject GameObject { get; } + + internal GameObjectParsedEventArgs(GameObject gameObject, bool unique) + { + Unique = unique; + GameObject = gameObject ?? throw new ArgumentNullException(nameof(gameObject)); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs deleted file mode 100644 index c940274..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/IPetroglyphXmlFileParserFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using PG.StarWarsGame.Files.XML.Data; -using PG.StarWarsGame.Files.XML.ErrorHandling; -using PG.StarWarsGame.Files.XML.Parsers; - -namespace PG.StarWarsGame.Engine.Xml.Parsers; - -internal interface IPetroglyphXmlFileParserFactory -{ - NamedXmlObjectParser CreateNamedXmlObjectParser(IXmlParserErrorReporter? errorReporter) where T : NamedXmlObject; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs index 954f79e..ced9c3c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/CommandBarComponentParser.cs @@ -9,8 +9,11 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; -internal class CommandBarComponentParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : NamedXmlObjectParser(serviceProvider, new CommandBarComponentDataXmlTagMapper(serviceProvider), errorReporter) +internal class CommandBarComponentParser( + GameEngineType engine, + IServiceProvider serviceProvider, + IXmlParserErrorReporter? errorReporter = null) + : NamedXmlObjectParser(engine, new CommandBarComponentDataXmlTagMapper(serviceProvider), errorReporter, serviceProvider) { protected override bool UpperCaseNameForCrc => true; protected override bool UpperCaseNameForObject => false; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index 1ecb773..af2aa71 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -11,9 +11,12 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; -internal partial class GameObjectParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : NamedXmlObjectParser(serviceProvider, new GameObjectXmlTagMapper(serviceProvider), errorReporter) -{ +internal partial class GameObjectParser( + GameEngineType engine, + IServiceProvider serviceProvider, + IXmlParserErrorReporter? errorReporter = null) + : NamedXmlObjectParser(engine, new GameObjectXmlTagMapper(serviceProvider), errorReporter, serviceProvider) +{ internal bool OverlayLoad { get; set; } protected override bool UpperCaseNameForCrc => true; @@ -148,13 +151,11 @@ protected override void BuildMappings() GameObjectXmlTags.LandModelName, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.LandModel = val); - - // TODO - //AddMapping( - // GameObjectXmlTags.LandTerrainModelMapping, - // PetroglyphXmlStringParser.Instance.Parse, - // (obj, val) => obj.InternalLandTerrainModelMapping = val); - + AddMapping( + GameObjectXmlTags.LandTerrainModelMapping, + CommaSeparatedStringKeyValueListParser.Instance.Parse, + (obj, val, replace) => + SetOrReplaceList(obj.InternalLandTerrainModelMapping, val, replace)); AddMapping( GameObjectXmlTags.SpaceModelName, PetroglyphXmlStringParser.Instance.Parse, @@ -168,16 +169,21 @@ protected override void BuildMappings() PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.SpaceAnimOverrideModel = val); + // TODO AddMapping( - GameObjectXmlTags.GuiModelName, + GameObjectXmlTags.DamagedSmokeAssetName, PetroglyphXmlStringParser.Instance.Parse, - (obj, val) => obj.GuiModel = val); + (obj, val) => obj.DamagedSmokeAssetModel = val); + + // TODO AddMapping( - GameObjectXmlTags.DamagedSmokeAssetName, + GameObjectXmlTags.GuiModelName, PetroglyphXmlStringParser.Instance.Parse, - (obj, val) => obj.DamagedSmokeAssetModel = val); + (obj, val) => obj.GuiModel = val); + + // TODO } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs index d51533b..b20f217 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/SfxEventParser.cs @@ -10,8 +10,8 @@ namespace PG.StarWarsGame.Engine.Xml.Parsers; -internal class SfxEventParser(IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) - : NamedXmlObjectParser(serviceProvider, new SfxEventXmlTagMapper(serviceProvider), errorReporter) +internal class SfxEventParser(GameEngineType engine, IServiceProvider serviceProvider, IXmlParserErrorReporter? errorReporter = null) + : NamedXmlObjectParser(engine, new SfxEventXmlTagMapper(serviceProvider), errorReporter, serviceProvider) { // This is a slight derivation from the engine: // The engine does not upper case the name neither for the name itself and the CRC. diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs index 95328ba..f849d05 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/PetroglyphStarWarsGameXmlParser.cs @@ -9,7 +9,6 @@ using PG.Commons.Services; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO; -using PG.StarWarsGame.Engine.Xml.Parsers; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; @@ -63,7 +62,7 @@ public void ParseEntriesFromFileListXml( var xmlFiles = container.Files.Select(x => FileSystem.Path.Combine(lookupPath, x)).ToList(); var parser = new XmlContainerFileParser(Services, - _fileParserFactory.CreateNamedXmlObjectParser(_reporter), _reporter); + _fileParserFactory.CreateNamedXmlObjectParser(_gameRepository.EngineType, _reporter), _reporter); foreach (var file in xmlFiles) { diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs similarity index 67% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs index 4358b56..923e6b1 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParser.cs @@ -1,11 +1,15 @@ -using PG.StarWarsGame.Files.XML.Data; +using System.Xml.Linq; +using PG.StarWarsGame.Files.XML; +using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; -using System.Xml.Linq; -namespace PG.StarWarsGame.Files.XML.Parsers; +namespace PG.StarWarsGame.Engine.Xml; -public abstract class XmlObjectParser(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter = null) - : XmlObjectParserBase(tagMapper, errorReporter) +public abstract class XmlObjectParser( + GameEngineType engine, + XmlTagMapper tagMapper, + IXmlParserErrorReporter? errorReporter = null) + : XmlObjectParserBase.EmptyParseState>(engine, tagMapper, errorReporter) where TObject : XmlObject { public TObject Parse(XElement element) @@ -30,10 +34,15 @@ protected sealed override void ValidateAndFixupValues(TObject xmlObject, XElemen protected virtual bool ParseTag(XElement tag, TObject xmlObject, bool replace) { - return XmlTagMapper.TryParseEntry(tag, xmlObject, replace); + return XmlTagMapper.TryParseEntry(tag, xmlObject, replace, Engine); } protected virtual void ValidateAndFixupValues(TObject xmlObject, XElement element) { } + + public readonly struct EmptyParseState + { + public static readonly EmptyParseState Instance = new(); + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParserBase.cs similarity index 79% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParserBase.cs index d36c151..9a23ddd 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/XmlObjectParserBase.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParserBase.cs @@ -1,14 +1,20 @@ using System; using System.Xml.Linq; +using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; using PG.StarWarsGame.Files.XML.ErrorHandling; +using PG.StarWarsGame.Files.XML.Parsers; -namespace PG.StarWarsGame.Files.XML.Parsers; +namespace PG.StarWarsGame.Engine.Xml; -public abstract class XmlObjectParserBase(IXmlTagMapper tagMapper, IXmlParserErrorReporter? errorReporter) +public abstract class XmlObjectParserBase( + GameEngineType engine, + XmlTagMapper tagMapper, + IXmlParserErrorReporter? errorReporter) : PetroglyphXmlParserBase(errorReporter) where TObject : XmlObject { - protected readonly IXmlTagMapper XmlTagMapper = tagMapper ?? throw new ArgumentNullException(nameof(tagMapper)); + protected readonly XmlTagMapper XmlTagMapper = tagMapper ?? throw new ArgumentNullException(nameof(tagMapper)); + protected readonly GameEngineType Engine = engine; protected virtual bool IgnoreEmptyValue => true; @@ -23,7 +29,7 @@ protected virtual void ParseObject(TObject xmlObject, XElement element, bool rep protected virtual bool ParseTag(XElement tag, TObject xmlObject, bool replace, in TParseState parseState) { - return IsTagValid(tag) && XmlTagMapper.TryParseEntry(tag, xmlObject, replace); + return IsTagValid(tag) && XmlTagMapper.TryParseEntry(tag, xmlObject, replace, Engine); } protected void ParseTags(TObject xmlObject, XElement element, bool replace, in TParseState state) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParserFactory.cs similarity index 53% rename from src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParserFactory.cs index 736b729..eeee6e2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/PetroglyphXmlParserFactory.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlObjectParserFactory.cs @@ -4,20 +4,20 @@ using PG.StarWarsGame.Files.XML.ErrorHandling; using System; using PG.StarWarsGame.Files.XML.Data; -using PG.StarWarsGame.Files.XML.Parsers; +using PG.StarWarsGame.Engine.Xml.Parsers; -namespace PG.StarWarsGame.Engine.Xml.Parsers; +namespace PG.StarWarsGame.Engine.Xml; -internal sealed class PetroglyphXmlFileParserFactory(IServiceProvider serviceProvider) : IPetroglyphXmlFileParserFactory +internal sealed class XmlObjectParserFactory(IServiceProvider serviceProvider) : IPetroglyphXmlFileParserFactory { - public NamedXmlObjectParser CreateNamedXmlObjectParser(IXmlParserErrorReporter? errorReporter) where T : NamedXmlObject + public NamedXmlObjectParser CreateNamedXmlObjectParser(GameEngineType engine, IXmlParserErrorReporter? errorReporter) where T : NamedXmlObject { if (typeof(T) == typeof(SfxEvent)) - return ChangeType(new SfxEventParser(serviceProvider, errorReporter)); + return ChangeType(new SfxEventParser(engine, serviceProvider, errorReporter)); if (typeof(T) == typeof(CommandBarComponentData)) - return ChangeType(new CommandBarComponentParser(serviceProvider, errorReporter)); + return ChangeType(new CommandBarComponentParser(engine, serviceProvider, errorReporter)); if (typeof(T) == typeof(GameObject)) - return ChangeType(new GameObjectParser(serviceProvider, errorReporter)); + return ChangeType(new GameObjectParser(engine, serviceProvider, errorReporter)); throw new ParserNotFoundException(typeof(T)); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlTagMapper.cs similarity index 53% rename from src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs rename to src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlTagMapper.cs index 4b42ce6..32fc2fb 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/XmlTagMapper.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/XmlTagMapper.cs @@ -1,18 +1,34 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Xml.Linq; using AnakinRaW.CommonUtilities; using Microsoft.Extensions.DependencyInjection; using PG.Commons.Hashing; +using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; -namespace PG.StarWarsGame.Files.XML.Parsers; +namespace PG.StarWarsGame.Engine.Xml; -public abstract class XmlTagMapper : IXmlTagMapper where TObject : XmlObject +public abstract class XmlTagMapper where TObject : XmlObject { private delegate void ParserValueAction(TObject target, XElement element, bool replace); - private readonly Dictionary _tagMappings = new(); + private readonly struct MappingEntry(SupportedEngines supportedEngines, ParserValueAction action) + { + public readonly SupportedEngines SupportedEngines = supportedEngines; + public readonly ParserValueAction Action = action; + } + + [Flags] + public enum SupportedEngines + { + Eaw = 1, + Foc = 2, + All = Eaw | Foc + } + + private readonly Dictionary _tagMappings = new(); private readonly ICrc32HashingService _crcService; protected XmlTagMapper(IServiceProvider serviceProvider) @@ -35,13 +51,20 @@ protected static void SetOrReplaceList(IList destinationList, IEnumerable< destinationList.Add(value); } - protected void AddMapping(string tagName, Func parser, - Action setter) + protected void AddMapping( + string tagName, + Func parser, + Action setter, + SupportedEngines supportedEngines = SupportedEngines.All) { - AddMapping(tagName, parser, (target, value, _) => setter(target, value)); + AddMapping(tagName, parser, (target, value, _) => setter(target, value), supportedEngines); } - protected void AddMapping(string tagName, Func parser, Action setter) + protected void AddMapping( + string tagName, + Func parser, + Action setter, + SupportedEngines supportedEngines = SupportedEngines.All) { ThrowHelper.ThrowIfNullOrEmpty(tagName); if (tagName.Length >= XmlFileConstants.MaxTagNameLength) @@ -55,14 +78,14 @@ protected void AddMapping(string tagName, Func parser, var crc = GetCrc32(tagName); - _tagMappings[crc] = (target, element, replace) => + _tagMappings[crc] = new MappingEntry(supportedEngines, (target, element, replace) => { var value = parser(element); setter(target, value, replace); - }; + }); } - public bool TryParseEntry(XElement element, TObject target, bool replace) + public bool TryParseEntry(XElement element, TObject target, bool replace, GameEngineType engine) { var tagName = element.Name.LocalName; if (tagName.Length >= XmlFileConstants.MaxTagNameLength) @@ -73,10 +96,24 @@ public bool TryParseEntry(XElement element, TObject target, bool replace) if (!_tagMappings.TryGetValue(crc, out var mapping)) return false; - mapping(target, element, replace); + if (!IsEngineSupported(mapping.SupportedEngines, engine)) + return false; + + mapping.Action(target, element, replace); return true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsEngineSupported(SupportedEngines supportedEngines, GameEngineType requestedEngine) + { + // Convert enum value to its corresponding flag by shifting bit 1 left + // Eaw (0) -> 1 << 0 = 1, Foc (1) -> 1 << 1 = 2 + var engineFlag = (SupportedEngines)(1 << (int)requestedEngine); + // Use bitwise AND to check if the flag is set in supportedEngines + // Returns true if the bit is present, false otherwise + return (supportedEngines & engineFlag) != 0; + } + private Crc32 GetCrc32(string tagName) { return _crcService.GetCrc32Upper(tagName, XmlFileConstants.XmlEncoding); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs deleted file mode 100644 index 13cbedb..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Base/IXmlTagMapper.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Xml.Linq; -using PG.StarWarsGame.Files.XML.Data; - -namespace PG.StarWarsGame.Files.XML.Parsers; - -public interface IXmlTagMapper where T : XmlObject -{ - bool TryParseEntry(XElement element, T target, bool replace); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs deleted file mode 100644 index c8eac60..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/EmptyParseState.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PG.StarWarsGame.Files.XML.Parsers; - -public readonly struct EmptyParseState -{ - public static readonly EmptyParseState Instance = new(); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs index ff175ed..8316fd5 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/CommaSeparatedStringKeyValueListParser.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Xml.Linq; +using PG.StarWarsGame.Files.XML.ErrorHandling; namespace PG.StarWarsGame.Files.XML.Parsers; // Used e.g, by // Format: Key, Value, Key, Value // There might be arbitrary spaces, tabs and newlines -// TODO: This class is not yet implemented, compliant to the engine + public sealed class CommaSeparatedStringKeyValueListParser : PetroglyphPrimitiveXmlParser> { public static readonly CommaSeparatedStringKeyValueListParser Instance = new(); @@ -17,15 +18,31 @@ private CommaSeparatedStringKeyValueListParser() } private protected override IList<(string key, string value)> DefaultValue => []; - internal override int EngineDataTypeId => throw new NotImplementedException(); + + internal override int EngineDataTypeId => 0x34; protected internal override IList<(string key, string value)> ParseCore(ReadOnlySpan trimmedValue, XElement element) { - var values = element.PGValue.Split(','); + var valueText = element.PGValue; + + if (string.IsNullOrEmpty(valueText)) + return DefaultValue; + + if (valueText.Length >= 0x10000) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.TooLongData, + Message = "Input string exceeds maximum size." + }); + return DefaultValue; + } + + var values = valueText.Split(','); // Cases: Empty tag or invalid value (e.g, terrain only, wrong separator, etc.) - if (values.Length <= 1) - return new List<(string key, string value)>(0); + if (values.Length < 2) + return DefaultValue; var keyValueList = new List<(string key, string value)>(values.Length + 1 / 2); @@ -33,7 +50,14 @@ private CommaSeparatedStringKeyValueListParser() { // Case: Incomplete key-value pair if (values.Length - 1 < i + 1) + { + ErrorReporter?.Report(new XmlError(this, element) + { + ErrorKind = XmlParseErrorKind.MalformedValue, + Message = "Unexpected end of string. Missing string for conversion/string pair!" + }); break; + } var key = values[i].Trim(); var value = values[i + 1].Trim(); From f3cdad83219987062e796bf9eb9d364e5f68e68e Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 28 Feb 2026 17:02:44 +0100 Subject: [PATCH 21/41] load base types --- .../Verifiers/ReferencedModelsVerifier.cs | 2 ++ .../Audio/Sfx/SfxEvent.cs | 3 +++ .../GameObjects/GameObject.cs | 18 +++++++++++++++--- ...GameObjectTypeGameManager.Initialization.cs | 8 +++++++- .../GameObjects/GameObjectTypeGameManager.cs | 1 - .../Utilities/ExtensionMethods.cs | 15 +++++++++++++++ .../Parsers/NamedObjects/GameObjectParser.cs | 13 +++++++------ .../Primitives/PetroglyphXmlStringParser.cs | 2 +- 8 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/ExtensionMethods.cs diff --git a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs index 6ce5eed..de56c33 100644 --- a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs +++ b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs @@ -7,6 +7,8 @@ namespace AET.ModVerify.Verifiers; +// TODO: Add GameObjectTypeVerifier and check that LandModelTerrainOverride is correct (all keys correct, no dups) + public sealed class ReferencedModelsVerifier( IStarWarsGameEngine engine, GameVerifySettings settings, diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs index 181d5c0..43f437d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Audio/Sfx/SfxEvent.cs @@ -170,6 +170,9 @@ internal SfxEvent(string name, Crc32 nameCrc, XmlLocationInfo location) : base(name, nameCrc, location) { PreSamples = new ReadOnlyCollection(PreSamplesInternal); + Samples = new ReadOnlyCollection(SamplesInternal); + PostSamples = new ReadOnlyCollection(PostSamplesInternal); + LocalizedTextIDs = new ReadOnlyCollection(LocalizedTextIDsInternal); } internal void FixupValues() diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index 394db3f..72f7118 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; using PG.Commons.Hashing; +using PG.StarWarsGame.Engine.Utilities; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; @@ -33,8 +34,6 @@ public sealed class GameObject : NamedXmlObject public string? SpaceModel { get; internal set; } - public string? TacticalModel { get; internal set; } - public string? GalacticFleetOverrideModel { get; internal set; } public string? GuiModel { get; internal set; } @@ -77,6 +76,19 @@ public void PostLoadFixup() internal void ApplyBaseType(GameObject baseType) { - throw new NotImplementedException(); + // The following properties must not be inherited from the base type: + // ID, CRC, Name, Location, IsLoadingComplete, ClassificationName and VariantOfExistingType[Name], LuaScript + + GalacticModel = baseType.GalacticModel; + DestroyedGalacticModel = baseType.DestroyedGalacticModel; + LandModel = baseType.LandModel; + SpaceModel = baseType.SpaceModel; + GalacticFleetOverrideModel = baseType.GalacticFleetOverrideModel; + GuiModel = baseType.GuiModel; + ModelName = baseType.ModelName; + LandAnimOverrideModel = baseType.LandAnimOverrideModel; + SpaceAnimOverrideModel = baseType.SpaceAnimOverrideModel; + DamagedSmokeAssetModel = baseType.DamagedSmokeAssetModel; + InternalLandTerrainModelMapping.ClearAddRange(baseType.InternalLandTerrainModelMapping); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs index af8fcdb..4535ef4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using AnakinRaW.CommonUtilities.FileSystem; namespace PG.StarWarsGame.Engine.GameObjects; @@ -62,7 +63,7 @@ private void ParseGameObjectDatabases() { foreach (var gameObject in _gameObjects) { - if (!gameObject.IsLoadingComplete && gameObject.Location.XmlFile == gameObjectXmlFile) + if (!gameObject.IsLoadingComplete && IsSameFile(gameObject.Location.XmlFile, gameObjectXmlFile)) ParseSingleGameObjectFile(gameObjectXmlFile, gameParser, gameObjectFileParser); } } @@ -79,6 +80,11 @@ private void ParseGameObjectDatabases() } } + private bool IsSameFile(string filePathA, string filePathB) + { + return FileSystem.Path.AreEqual(filePathA, filePathB); + } + private void OnGameObjectParsed(object sender, GameObjectParsedEventArgs e) { if (!e.Unique) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index e92f3f5..37c5074 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -37,7 +37,6 @@ public IEnumerable GetModels(GameObject gameObject) AddNotEmpty(gameObject.DestroyedGalacticModel); AddNotEmpty(gameObject.LandModel); AddNotEmpty(gameObject.SpaceModel); - AddNotEmpty(gameObject.TacticalModel); AddNotEmpty(gameObject.GalacticFleetOverrideModel); AddNotEmpty(gameObject.GuiModel); AddNotEmpty(gameObject.ModelName); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/ExtensionMethods.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/ExtensionMethods.cs new file mode 100644 index 0000000..e67024f --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Utilities/ExtensionMethods.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace PG.StarWarsGame.Engine.Utilities; + +internal static class ExtensionMethods +{ + extension(List list) + { + public void ClearAddRange(IEnumerable items) + { + list.Clear(); + list.AddRange(items); + } + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index af2aa71..015750e 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -63,7 +63,6 @@ protected override void ParseObject( if (OverlayLoad) { - Debug.Assert(replace); OverlayType(xmlObject, element, parsedEntries); } else @@ -168,22 +167,22 @@ protected override void BuildMappings() GameObjectXmlTags.SpaceModelAnimOverrideName, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.SpaceAnimOverrideModel = val); - - // TODO - + AddMapping( GameObjectXmlTags.DamagedSmokeAssetName, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.DamagedSmokeAssetModel = val); - // TODO AddMapping( GameObjectXmlTags.GuiModelName, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.GuiModel = val); - // TODO + AddMapping( + GameObjectXmlTags.VariantOfExistingType, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.VariantOfExistingTypeName = val); } } @@ -202,5 +201,7 @@ internal static class GameObjectXmlTags public const string LandModelAnimOverrideName = "Land_Model_Anim_Override_Name"; public const string SpaceModelAnimOverrideName = "Space_Model_Anim_Override_Name"; public const string DamagedSmokeAssetName = "Damaged_Smoke_Asset_Name"; + + public const string VariantOfExistingType = "Variant_Of_Existing_Type"; } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs index 13cce7e..010a0f8 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/Primitives/PetroglyphXmlStringParser.cs @@ -9,7 +9,7 @@ public sealed class PetroglyphXmlStringParser : PetroglyphPrimitiveXmlParser string.Empty; - internal override int EngineDataTypeId => 0x17; + internal override int EngineDataTypeId => 0x17 & 0x1D & 0x1F; private PetroglyphXmlStringParser() { From 6caf136a30ddb905cc50eb74a7964d5c97c00474 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 14 Mar 2026 13:08:22 +0100 Subject: [PATCH 22/41] GameObjectType PostLoadFixup --- .../ErrorReporting/EngineAssert.cs | 4 +-- .../GameObjects/GameObject.cs | 16 ++++----- ...ameObjectTypeGameManager.Initialization.cs | 33 +++++++++++++++++-- .../GameObjects/GameObjectTypeGameManager.cs | 6 +++- .../Parsers/NamedObjects/GameObjectParser.cs | 16 +++++++-- 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssert.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssert.cs index 5cc4c49..38a07a9 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssert.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/ErrorReporting/EngineAssert.cs @@ -9,7 +9,7 @@ namespace PG.StarWarsGame.Engine.ErrorReporting; public sealed class EngineAssert { - private static readonly string ThisNameSpace = typeof(EngineAssert).Namespace!; + private static readonly string ThisNamespace = typeof(EngineAssert).Namespace!; private const string NullLiteral = "NULL"; public string Value { get; } @@ -66,7 +66,7 @@ internal static EngineAssert Create(EngineAssertKind kind, object? value, IEnume { var frame = trace.GetFrame(i); var method = frame.GetMethod(); - if (method.DeclaringType is null || method.DeclaringType.Namespace?.Equals(ThisNameSpace) == false) + if (method.DeclaringType is null || method.DeclaringType.Namespace?.Equals(ThisNamespace) == false) return frame; } return null; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index 72f7118..510f65b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -63,16 +63,6 @@ internal GameObject( ClassificationName = classification ?? throw new ArgumentNullException(nameof(classification)); LandTerrainModelMappingValues = new ReadOnlyCollection<(string, string)>(InternalLandTerrainModelMapping); } - - public void PostLoadFixup() - { - // TODO: - // MaxSpeed *= 1.0; - // MaxThrust *= 1.0; - - // The engine loads references for scripts, images, hardpoints, etc., - // but we don't do that here. - } internal void ApplyBaseType(GameObject baseType) { @@ -91,4 +81,10 @@ internal void ApplyBaseType(GameObject baseType) DamagedSmokeAssetModel = baseType.DamagedSmokeAssetModel; InternalLandTerrainModelMapping.ClearAddRange(baseType.InternalLandTerrainModelMapping); } + + internal void PostLoadFixup() + { + // This method is different than the fixup that is performed after parsing the object. + // IDK why there are two separate fixups. This fixup performs more value coercions + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs index 4535ef4..7993b38 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using System; +using Microsoft.Extensions.Logging; using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.Xml; using PG.StarWarsGame.Engine.Xml.Parsers; @@ -70,13 +71,39 @@ private void ParseGameObjectDatabases() } - - //GameObjectTypeClass::Static_Post_Load_Fixup(); + PostLoadFixup(); //SFXEventReferenceClass::Static_Post_Load_Fixup(); //SpeechEventReferenceClass::Static_Post_Load_Fixup(); //MusicEventReferenceClass::Static_Post_Load_Fixup(); //FactionReferenceClass::Static_Post_Load_Fixup(); //... + + allLoaded = true; + + foreach (var gameObject in _gameObjects) + { + gameObject.PostLoadFixup(); + if (!gameObject.IsLoadingComplete) + allLoaded = false; + } + } + } + + private void PostLoadFixup() + { + // In the engine, this is the so-called static post load fixup. + foreach (var gameObject in _gameObjects) + { + var baseTypeName = gameObject.VariantOfExistingTypeName; + if (string.IsNullOrEmpty(baseTypeName) || baseTypeName.Equals("None", StringComparison.OrdinalIgnoreCase)) + continue; + + // At this point the engine would assert, if the base type was not found. + // We do not, because the game reports this error for every iteration of the loading loop, + // which would bloat error logs. + var baseNameHash = _hashingService.GetCrc32Upper(baseTypeName, PGConstants.DefaultPGEncoding); + NamedEntries.TryGetFirstValue(baseNameHash, out var baseType); + gameObject.VariantOfExistingType = baseType; } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index 37c5074..cbcea6a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -1,14 +1,17 @@ -using PG.StarWarsGame.Engine.ErrorReporting; +using PG.Commons.Hashing; +using PG.StarWarsGame.Engine.ErrorReporting; using PG.StarWarsGame.Engine.IO.Repositories; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using Microsoft.Extensions.DependencyInjection; namespace PG.StarWarsGame.Engine.GameObjects; internal partial class GameObjectTypeGameManager : GameManagerBase, IGameObjectTypeGameManager { private readonly List _gameObjects; + private readonly ICrc32HashingService _hashingService; public GameObjectTypeGameManager( GameRepository repository, @@ -16,6 +19,7 @@ public GameObjectTypeGameManager( IServiceProvider serviceProvider) : base(repository, errorReporter, serviceProvider) { + _hashingService = serviceProvider.GetRequiredService(); _gameObjects = []; GameObjects = new ReadOnlyCollection(_gameObjects); } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index 015750e..c9ce844 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -75,10 +75,11 @@ protected override void ValidateAndFixupValues(GameObject gameObject, XElement e { if (!OverlayLoad) { + // TODO //BehaviorClass.AddImpliedBehaviors(this, BehaviorNames); //InitBehaviorMap(); - gameObject.PostLoadFixup(); + PostLoadFixup(gameObject); if (string.IsNullOrEmpty(gameObject.VariantOfExistingTypeName)) gameObject.IsLoadingComplete = true; else @@ -113,7 +114,7 @@ private void OverlayType(GameObject baseType, GameObject derivedType, XElement e ParseTags(derivedType, element, true, ReadOnlyFrugalValueListDictionary.Empty); - derivedType.PostLoadFixup(); + PostLoadFixup(derivedType); derivedType.IsLoadingComplete = true; } @@ -130,6 +131,17 @@ protected override bool ParseTag( return true; } + private void PostLoadFixup(GameObject gameObject) + { + // TODO: + // MaxSpeed *= 1.0; + // MaxThrust *= 1.0; + // Asserts and some coercions + + // The engine loads references for scripts, images, hardpoints, etc., + // but we don't do that here. + } + private sealed class GameObjectXmlTagMapper(IServiceProvider serviceProvider) : XmlTagMapper(serviceProvider) { protected override void BuildMappings() From 8d9460ede4ed2d7c8b6c035fd28d2fd504652f2c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 14 Mar 2026 13:14:32 +0100 Subject: [PATCH 23/41] order json by erorr ID --- src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs index 1feb655..d9cdebe 100644 --- a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs +++ b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs @@ -30,6 +30,7 @@ private JsonVerificationReport CreateJsonReport(VerificationResult result) if (Settings.AggregateResults) { errors = result.Errors + .OrderBy(x => x.Id) .GroupBy(x => new GroupKey(x.Asset, x.Id, x.VerifierChain)) .Select, JsonVerificationErrorBase>(g => { @@ -43,7 +44,9 @@ private JsonVerificationReport CreateJsonReport(VerificationResult result) } else { - errors = result.Errors.Select(x => new JsonVerificationError(x)); + errors = result.Errors + .OrderBy(x => x.Id) + .Select(x => new JsonVerificationError(x)); } return new JsonVerificationReport From a3364ef90c4958835d634508451b321680765c9f Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 14 Mar 2026 14:51:58 +0100 Subject: [PATCH 24/41] update deps --- Directory.Build.props | 2 +- modules/ModdingToolBase | 2 +- src/ModVerify.CliApp/ModVerify.CliApp.csproj | 18 +++++++++--------- src/ModVerify/ModVerify.csproj | 4 ++-- ...GameObjectTypeGameManager.Initialization.cs | 2 ++ .../PG.StarWarsGame.Engine.csproj | 6 +++--- .../PG.StarWarsGame.Files.ChunkFiles.csproj | 2 +- .../PG.StarWarsGame.Files.XML.csproj | 2 +- .../ModVerify.CliApp.Test.csproj | 4 ++-- 9 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 723456e..3e2f119 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,7 +33,7 @@ - + all 3.9.50 diff --git a/modules/ModdingToolBase b/modules/ModdingToolBase index 8319d9f..da06a41 160000 --- a/modules/ModdingToolBase +++ b/modules/ModdingToolBase @@ -1 +1 @@ -Subproject commit 8319d9f54ca9593f1bf2e4e54225b50fc28380d8 +Subproject commit da06a410b8fa954fdc36676953f7e918c86992c9 diff --git a/src/ModVerify.CliApp/ModVerify.CliApp.csproj b/src/ModVerify.CliApp/ModVerify.CliApp.csproj index 7dcf361..f6abc83 100644 --- a/src/ModVerify.CliApp/ModVerify.CliApp.csproj +++ b/src/ModVerify.CliApp/ModVerify.CliApp.csproj @@ -32,16 +32,16 @@ - - + + - - - - - + + + + + @@ -62,7 +62,7 @@ - + compile runtime; build; native; contentfiles; analyzers; buildtransitive @@ -70,7 +70,7 @@ compile runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj index 16c356e..f9b2056 100644 --- a/src/ModVerify/ModVerify.csproj +++ b/src/ModVerify/ModVerify.csproj @@ -27,8 +27,8 @@ - - + + diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs index 7993b38..9b1437a 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.Initialization.cs @@ -87,6 +87,8 @@ private void ParseGameObjectDatabases() allLoaded = false; } } + + // TODO: The Engine is now asserting some SFX files of all types } private void PostLoadFixup() diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj index 47b3a7f..260c9e4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj @@ -23,10 +23,10 @@ - - + + - + diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj index 9fe818c..000b3a6 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.ChunkFiles/PG.StarWarsGame.Files.ChunkFiles.csproj @@ -17,6 +17,6 @@ preview - + \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj index 961034b..4a8bced 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Files.XML/PG.StarWarsGame.Files.XML.csproj @@ -18,7 +18,7 @@ preview - + diff --git a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj index 6eedefe..9d4526e 100644 --- a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj +++ b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj @@ -17,8 +17,8 @@ - - + + From 59675e771368eec0e83f9baa7f5760a4d65aefdd Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 15 Mar 2026 13:46:43 +0100 Subject: [PATCH 25/41] refactorings of verifiers --- src/ModVerify/DefaultGameVerifiersProvider.cs | 5 +- src/ModVerify/GameVerifyPipeline.cs | 1 + src/ModVerify/ModVerify.csproj.DotSettings | 1 + .../Engine/GameAssertErrorReporter.cs | 2 +- .../VerifierChainEqualityComparer.cs | 1 + .../CommandBar/CommandBarVerifier.Base.cs | 136 ------------------ .../CommandBarVerifier.Components.cs | 86 +++++++++++ .../CommandBar/CommandBarVerifier.Groups.cs | 56 ++++++++ .../{ => Commons}/AudioFilesVerifier.cs | 9 +- .../Verifiers/Commons/DuplicateVerifier.cs | 35 +++++ .../IDuplicateVerificationContext.cs | 11 ++ .../MtdDuplicateVerificationContext.cs | 32 +++++ ...edXmlObjectDuplicateVerificationContext.cs | 37 +++++ .../Verifiers/Commons/ModelVerifier.cs | 3 +- .../Verifiers/DuplicateNameFinder.cs | 104 -------------- .../GameObjects/GameObjectTypeVerifier.cs | 27 ++++ .../DuplicateVerificationContextExtensions.cs | 22 +++ .../NameBasedEqualityComparer.cs | 2 +- src/ModVerify/Verifiers/VerifierErrorCodes.cs | 2 +- 19 files changed, 322 insertions(+), 250 deletions(-) create mode 100644 src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs create mode 100644 src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs rename src/ModVerify/Verifiers/{ => Commons}/AudioFilesVerifier.cs (98%) create mode 100644 src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs create mode 100644 src/ModVerify/Verifiers/Commons/Duplicates/IDuplicateVerificationContext.cs create mode 100644 src/ModVerify/Verifiers/Commons/Duplicates/MtdDuplicateVerificationContext.cs create mode 100644 src/ModVerify/Verifiers/Commons/Duplicates/NamedXmlObjectDuplicateVerificationContext.cs delete mode 100644 src/ModVerify/Verifiers/DuplicateNameFinder.cs create mode 100644 src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs create mode 100644 src/ModVerify/Verifiers/Utilities/DuplicateVerificationContextExtensions.cs rename src/ModVerify/Verifiers/{ => Utilities}/NameBasedEqualityComparer.cs (94%) diff --git a/src/ModVerify/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs index b84ff87..e62b46b 100644 --- a/src/ModVerify/DefaultGameVerifiersProvider.cs +++ b/src/ModVerify/DefaultGameVerifiersProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using AET.ModVerify.Settings; using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.Commons; using AET.ModVerify.Verifiers.GuiDialogs; using PG.StarWarsGame.Engine; @@ -14,9 +15,9 @@ public IEnumerable GetVerifiers( GameVerifySettings settings, IServiceProvider serviceProvider) { - yield break; + //yield break; yield return new ReferencedModelsVerifier(database, settings, serviceProvider); - yield return new DuplicateNameFinder(database, settings, serviceProvider); + //yield return new DuplicateNameFinder(database, settings, serviceProvider); yield return new AudioFilesVerifier(database, settings, serviceProvider); yield return new GuiDialogsVerifier(database, settings, serviceProvider); yield return new CommandBarVerifier(database, settings, serviceProvider); diff --git a/src/ModVerify/GameVerifyPipeline.cs b/src/ModVerify/GameVerifyPipeline.cs index 4ed351e..37031c9 100644 --- a/src/ModVerify/GameVerifyPipeline.cs +++ b/src/ModVerify/GameVerifyPipeline.cs @@ -11,6 +11,7 @@ using AET.ModVerify.Settings; using AET.ModVerify.Utilities; using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.Utilities; using AnakinRaW.CommonUtilities.SimplePipeline; using AnakinRaW.CommonUtilities.SimplePipeline.Runners; using Microsoft.Extensions.DependencyInjection; diff --git a/src/ModVerify/ModVerify.csproj.DotSettings b/src/ModVerify/ModVerify.csproj.DotSettings index 3859842..ca2367c 100644 --- a/src/ModVerify/ModVerify.csproj.DotSettings +++ b/src/ModVerify/ModVerify.csproj.DotSettings @@ -5,5 +5,6 @@ True False True + True True True \ No newline at end of file diff --git a/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs b/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs index f98d2cd..0c8c633 100644 --- a/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs +++ b/src/ModVerify/Reporting/Engine/GameAssertErrorReporter.cs @@ -46,7 +46,7 @@ private static string GetIdFromError(EngineAssertKind assertKind) EngineAssertKind.ValueOutOfRange => VerifierErrorCodes.AssertValueOutOfRange, EngineAssertKind.InvalidValue => VerifierErrorCodes.AssertValueInvalid, EngineAssertKind.FileNotFound => VerifierErrorCodes.FileNotFound, - EngineAssertKind.DuplicateEntry => VerifierErrorCodes.DuplicateFound, + EngineAssertKind.DuplicateEntry => VerifierErrorCodes.Duplicate, _ => throw new ArgumentOutOfRangeException(nameof(assertKind), assertKind, null) }; } diff --git a/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs b/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs index abb01ef..27897cb 100644 --- a/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs +++ b/src/ModVerify/Reporting/VerifierChainEqualityComparer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.Utilities; namespace AET.ModVerify.Reporting; diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs index 3373f8e..e8c4ec2 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs @@ -1,12 +1,7 @@ using System; -using System.Linq; using System.Threading; -using AET.ModVerify.Reporting; using AET.ModVerify.Settings; -using AnakinRaW.CommonUtilities.Collections; using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Engine.CommandBar; -using PG.StarWarsGame.Engine.CommandBar.Components; namespace AET.ModVerify.Verifiers; @@ -27,135 +22,4 @@ public override void Verify(CancellationToken token) VerifyCommandBarShellsGroups(); VerifyCommandBarComponents(); } - - private void VerifySingleComponent(CommandBarBaseComponent component) - { - VerifyCommandBarModel(component); - VerifyComponentBone(component); - } -} - -partial class CommandBarVerifier -{ - private void VerifyCommandBarModel(CommandBarBaseComponent component) - { - if (component is not CommandBarShellComponent shellComponent) - return; - - if (shellComponent.ModelPath is null) - { - AddError(VerificationError.Create(VerifierChain, - CommandBarShellNoModel, $"The CommandBarShellComponent '{component.Name}' has no model specified.", - VerificationSeverity.Error, shellComponent.Name)); - return; - } - - var model = GameEngine.PGRender.LoadModelAndAnimations(shellComponent.ModelPath.AsSpan(), null); - if (model is null) - { - AddError(VerificationError.Create(VerifierChain, - CommandBarShellNoModel, $"Could not find model '{shellComponent.ModelPath}' for CommandBarShellComponent '{component.Name}'.", - VerificationSeverity.Error, [shellComponent.Name], shellComponent.ModelPath)); - return; - } - } - - private void VerifyComponentBone(CommandBarBaseComponent component) - { - if (component is CommandBarShellComponent) - return; - - if (component.Bone == -1) - { - AddError(VerificationError.Create(VerifierChain, - CommandBarShellNoModel, $"The CommandBar component '{component.Name}' is not connected to a shell component.", - VerificationSeverity.Warning, component.Name)); - } - } -} - -partial class CommandBarVerifier -{ - private void VerifyCommandBarComponents() - { - var occupiedComponentIds = SupportedCommandBarComponentData.GetComponentIdsForEngine(Repository.EngineType).Keys - .ToDictionary(value => value, _ => false); - - foreach (var component in GameEngine.CommandBar.Components) - { - if (!occupiedComponentIds.TryGetValue(component.Id, out var alreadyOccupied)) - { - AddError(VerificationError.Create( - VerifierChain, - CommandBarUnsupportedComponent, - $"The CommandBar component '{component.Name}' is not supported by the game.", - VerificationSeverity.Information, - component.Name)); - } - else - { - occupiedComponentIds[component.Id] = true; - } - - if (alreadyOccupied) - { - AddError(VerificationError.Create(VerifierChain, - CommandBarDuplicateComponent, - $"The CommandBar component '{component.Name}' with ID '{component.Id}' already exists.", - VerificationSeverity.Warning, - component.Name)); - } - - VerifySingleComponent(component); - } - } -} - -partial class CommandBarVerifier -{ - private void VerifyCommandBarShellsGroups() - { - var shellGroups = new FrugalList(); - foreach (var groupPair in GameEngine.CommandBar.Groups) - { - if (groupPair.Key == CommandBarConstants.ShellGroupName) - { - shellGroups.Add(groupPair.Key); - VerifyShellGroup(groupPair.Value); - } - else if (groupPair.Key.Equals(CommandBarConstants.ShellGroupName, StringComparison.OrdinalIgnoreCase)) - { - shellGroups.Add(groupPair.Key); - } - } - - if (shellGroups.Count == 0) - AddError(VerificationError.Create(VerifierChain, - CommandBarNoShellsGroup, - $"No CommandBarGroup '{CommandBarConstants.ShellGroupName}' found.", - VerificationSeverity.Error, - "GameCommandBar")); - - if (shellGroups.Count > 1) - AddError(VerificationError.Create(VerifierChain, - CommandBarManyShellsGroup, - $"Found more than one Shells CommandBarGroup. Mind that group names are case-sensitive. Correct name is '{CommandBarConstants.ShellGroupName}'", - VerificationSeverity.Warning, - shellGroups, "GameCommandBar")); - } - - private void VerifyShellGroup(CommandBarComponentGroup shellGroup) - { - foreach (var component in shellGroup.Components) - { - var shellComponent = component as CommandBarShellComponent; - if (shellComponent?.Type is not CommandBarComponentType.Shell) - { - AddError(VerificationError.Create(VerifierChain, - CommandBarNoShellsComponentInShellGroup, - $"The CommandBar component '{component.Name}' is not a shell component, but part of the '{CommandBarConstants.ShellGroupName}' group.", - VerificationSeverity.Warning, component.Name)); - } - } - } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs new file mode 100644 index 0000000..a7bd044 --- /dev/null +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs @@ -0,0 +1,86 @@ +using AET.ModVerify.Reporting; +using PG.StarWarsGame.Engine.CommandBar; +using PG.StarWarsGame.Engine.CommandBar.Components; +using System; +using System.Linq; + +namespace AET.ModVerify.Verifiers; + +partial class CommandBarVerifier +{ + private void VerifyCommandBarComponents() + { + var occupiedComponentIds = SupportedCommandBarComponentData.GetComponentIdsForEngine(Repository.EngineType).Keys + .ToDictionary(value => value, _ => false); + + foreach (var component in GameEngine.CommandBar.Components) + { + if (!occupiedComponentIds.TryGetValue(component.Id, out var alreadyOccupied)) + { + AddError(VerificationError.Create( + VerifierChain, + CommandBarUnsupportedComponent, + $"The CommandBar component '{component.Name}' is not supported by the game.", + VerificationSeverity.Information, + component.Name)); + } + else + { + occupiedComponentIds[component.Id] = true; + } + + if (alreadyOccupied) + { + AddError(VerificationError.Create(VerifierChain, + CommandBarDuplicateComponent, + $"The CommandBar component '{component.Name}' with ID '{component.Id}' already exists.", + VerificationSeverity.Warning, + component.Name)); + } + + VerifySingleComponent(component); + } + } + + private void VerifySingleComponent(CommandBarBaseComponent component) + { + VerifyCommandBarModel(component); + VerifyComponentBone(component); + } + + private void VerifyCommandBarModel(CommandBarBaseComponent component) + { + if (component is not CommandBarShellComponent shellComponent) + return; + + if (shellComponent.ModelPath is null) + { + AddError(VerificationError.Create(VerifierChain, + CommandBarShellNoModel, $"The CommandBarShellComponent '{component.Name}' has no model specified.", + VerificationSeverity.Error, shellComponent.Name)); + return; + } + + var model = GameEngine.PGRender.LoadModelAndAnimations(shellComponent.ModelPath.AsSpan(), null); + if (model is null) + { + AddError(VerificationError.Create(VerifierChain, + CommandBarShellNoModel, $"Could not find model '{shellComponent.ModelPath}' for CommandBarShellComponent '{component.Name}'.", + VerificationSeverity.Error, [shellComponent.Name], shellComponent.ModelPath)); + return; + } + } + + private void VerifyComponentBone(CommandBarBaseComponent component) + { + if (component is CommandBarShellComponent) + return; + + if (component.Bone == -1) + { + AddError(VerificationError.Create(VerifierChain, + CommandBarShellNoModel, $"The CommandBar component '{component.Name}' is not connected to a shell component.", + VerificationSeverity.Warning, component.Name)); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs new file mode 100644 index 0000000..5ca7e58 --- /dev/null +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs @@ -0,0 +1,56 @@ +using System; +using AET.ModVerify.Reporting; +using AnakinRaW.CommonUtilities.Collections; +using PG.StarWarsGame.Engine.CommandBar; +using PG.StarWarsGame.Engine.CommandBar.Components; + +namespace AET.ModVerify.Verifiers; + +partial class CommandBarVerifier +{ + private void VerifyCommandBarShellsGroups() + { + var shellGroups = new FrugalList(); + foreach (var groupPair in GameEngine.CommandBar.Groups) + { + if (groupPair.Key == CommandBarConstants.ShellGroupName) + { + shellGroups.Add(groupPair.Key); + VerifyShellGroup(groupPair.Value); + } + else if (groupPair.Key.Equals(CommandBarConstants.ShellGroupName, StringComparison.OrdinalIgnoreCase)) + { + shellGroups.Add(groupPair.Key); + } + } + + if (shellGroups.Count == 0) + AddError(VerificationError.Create(VerifierChain, + CommandBarNoShellsGroup, + $"No CommandBarGroup '{CommandBarConstants.ShellGroupName}' found.", + VerificationSeverity.Error, + "GameCommandBar")); + + if (shellGroups.Count > 1) + AddError(VerificationError.Create(VerifierChain, + CommandBarManyShellsGroup, + $"Found more than one Shells CommandBarGroup. Mind that group names are case-sensitive. Correct name is '{CommandBarConstants.ShellGroupName}'", + VerificationSeverity.Warning, + shellGroups, "GameCommandBar")); + } + + private void VerifyShellGroup(CommandBarComponentGroup shellGroup) + { + foreach (var component in shellGroup.Components) + { + var shellComponent = component as CommandBarShellComponent; + if (shellComponent?.Type is not CommandBarComponentType.Shell) + { + AddError(VerificationError.Create(VerifierChain, + CommandBarNoShellsComponentInShellGroup, + $"The CommandBar component '{component.Name}' is not a shell component, but part of the '{CommandBarConstants.ShellGroupName}' group.", + VerificationSeverity.Warning, component.Name)); + } + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/AudioFilesVerifier.cs b/src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs similarity index 98% rename from src/ModVerify/Verifiers/AudioFilesVerifier.cs rename to src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs index ddd9252..fd2759b 100644 --- a/src/ModVerify/Verifiers/AudioFilesVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs @@ -8,17 +8,18 @@ using System.Threading; using AET.ModVerify.Reporting; using AET.ModVerify.Settings; +using AnakinRaW.CommonUtilities.FileSystem; using AnakinRaW.CommonUtilities.FileSystem.Normalization; using Microsoft.Extensions.DependencyInjection; using PG.Commons.Hashing; using PG.StarWarsGame.Engine; using PG.StarWarsGame.Engine.Audio.Sfx; using PG.StarWarsGame.Engine.Localization; -#if NETSTANDARD2_0 -using AnakinRaW.CommonUtilities.FileSystem; -#endif -namespace AET.ModVerify.Verifiers; +namespace AET.ModVerify.Verifiers.Commons; + +// TODO: Refactor to make this a generic audio file verifier that can be used for +// SFXEvents, MusicEvents and SpeechEvents public class AudioFilesVerifier : GameVerifier { diff --git a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs new file mode 100644 index 0000000..6d6cd3b --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs @@ -0,0 +1,35 @@ +using AET.ModVerify.Reporting; +using AET.ModVerify.Settings; +using PG.StarWarsGame.Engine; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace AET.ModVerify.Verifiers.Commons; + +public sealed class DuplicateVerifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : GameVerifier(parent, gameEngine, settings, serviceProvider) +{ + public override string FriendlyName => "Duplicates"; + + public override void Verify(IDuplicateVerificationContext toVerify, IReadOnlyCollection contextInfo, CancellationToken token) + { + foreach (var crc32 in toVerify.GetCrcs()) + { + if (toVerify.HasDuplicates(crc32, out var entryNames, out var context, out var errorMessage)) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.Duplicate, + errorMessage, + VerificationSeverity.Error, + context, + entryNames)); + } + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/Duplicates/IDuplicateVerificationContext.cs b/src/ModVerify/Verifiers/Commons/Duplicates/IDuplicateVerificationContext.cs new file mode 100644 index 0000000..4301e54 --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/Duplicates/IDuplicateVerificationContext.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using PG.Commons.Hashing; + +namespace AET.ModVerify.Verifiers.Commons; + +public interface IDuplicateVerificationContext +{ + string SourceName { get; } + IEnumerable GetCrcs(); + bool HasDuplicates(Crc32 crc, out string entryNames, out IEnumerable duplicateContext, out string errorMessage); +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/Duplicates/MtdDuplicateVerificationContext.cs b/src/ModVerify/Verifiers/Commons/Duplicates/MtdDuplicateVerificationContext.cs new file mode 100644 index 0000000..624a0a6 --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/Duplicates/MtdDuplicateVerificationContext.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using PG.Commons.Hashing; +using PG.StarWarsGame.Files.MTD.Files; + +namespace AET.ModVerify.Verifiers.Commons; + +internal sealed class MtdDuplicateVerificationContext(IMtdFile mtdFile) : IDuplicateVerificationContext +{ + public string SourceName => mtdFile.FileName; + + public IEnumerable GetCrcs() => mtdFile.Content.Select(x => x.Crc32); + + public bool HasDuplicates(Crc32 crc, out string entryNames, out IEnumerable duplicateContext, out string errorMessage) + { + var entries = mtdFile.Content.EntriesWithCrc(crc); + if (entries.Count > 1) + { + var firstEntry = entries.First(); + entryNames = firstEntry.FileName; + duplicateContext = entries.Select(x => $"'{x.FileName}' (CRC: {x.Crc32})"); + errorMessage = $"MTD File '{SourceName}' has duplicate definitions for CRC ({firstEntry}): " + + $"{string.Join(",", entries.Select(x => x.FileName))}"; + return true; + } + + entryNames = string.Empty; + duplicateContext = []; + errorMessage = string.Empty; + return false; + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/Duplicates/NamedXmlObjectDuplicateVerificationContext.cs b/src/ModVerify/Verifiers/Commons/Duplicates/NamedXmlObjectDuplicateVerificationContext.cs new file mode 100644 index 0000000..d50057d --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/Duplicates/NamedXmlObjectDuplicateVerificationContext.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PG.Commons.Hashing; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Files.XML.Data; + +namespace AET.ModVerify.Verifiers.Commons; + +internal sealed class NamedXmlObjectDuplicateVerificationContext(string databaseName, IGameManager gameManager) + : IDuplicateVerificationContext + where T : NamedXmlObject +{ + public string SourceName => databaseName; + + public IEnumerable GetCrcs() => gameManager.EntryKeys; + + public bool HasDuplicates(Crc32 crc, out string entryNames, out IEnumerable duplicateContext, out string errorMessage) + { + var entries = gameManager.GetEntries(crc); + if (entries.Count > 1) + { + var firstEntry = entries.First(); + entryNames = firstEntry.Name; + duplicateContext = entries.Select(x => $"'{x.Name}' - {x.Location}"); + var message = $"{SourceName} '{firstEntry.Name}' ({firstEntry.Crc32}) has duplicate definitions: "; + message = entries.Aggregate(message, (current, entry) => current + $"['{entry.Name}' in {entry.Location.XmlFile}:{entry.Location.Line}] "); + errorMessage = message.TrimEnd(); + return true; + } + + entryNames = string.Empty; + duplicateContext = Array.Empty(); + errorMessage = string.Empty; + return false; + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs index 25704d1..8ec92e6 100644 --- a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs @@ -25,7 +25,8 @@ public sealed class SingleModelVerifier : GameVerifier private readonly TextureVeifier _textureVerifier; private readonly IAlreadyVerifiedCache? _cache; - public SingleModelVerifier(IGameVerifierInfo? parent, + public SingleModelVerifier( + IGameVerifierInfo? parent, IStarWarsGameEngine engine, GameVerifySettings settings, IServiceProvider serviceProvider) : base(parent, engine, settings, serviceProvider) diff --git a/src/ModVerify/Verifiers/DuplicateNameFinder.cs b/src/ModVerify/Verifiers/DuplicateNameFinder.cs deleted file mode 100644 index c6b3089..0000000 --- a/src/ModVerify/Verifiers/DuplicateNameFinder.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using AET.ModVerify.Reporting; -using AET.ModVerify.Settings; -using AnakinRaW.CommonUtilities.Collections; -using PG.Commons.Hashing; -using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Files.MTD.Data; -using PG.StarWarsGame.Files.MTD.Files; -using PG.StarWarsGame.Files.XML.Data; - -namespace AET.ModVerify.Verifiers; - -public sealed class DuplicateNameFinder( - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifier(null, gameEngine, settings, serviceProvider) -{ - public override string FriendlyName => "Duplicates"; - - public override void Verify(CancellationToken token) - { - CheckXmlObjectsForDuplicates("GameObject", GameEngine.GameObjectTypeManager); - CheckXmlObjectsForDuplicates("SFXEvent", GameEngine.SfxGameManager); - - if (GameEngine.GuiDialogManager.MtdFile is not null) - CheckMtdForDuplicates(GameEngine.GuiDialogManager.MtdFile); - - if (GameEngine.CommandBar.MegaTextureFile is not null) - { - if (!GameEngine.CommandBar.MegaTextureFile.FilePath.Equals(GameEngine.GuiDialogManager.MtdFile?.FileName)) - CheckMtdForDuplicates(GameEngine.CommandBar.MegaTextureFile); - } - } - - private void CheckForDuplicateCrcEntries( - string sourceName, - TSource source, - Func> crcSelector, - Func> entrySelector, - Func entryToStringSelector, - Func, IEnumerable> contextSelector, - Func, string, string> errorMessageCreator) - { - foreach (var crc32 in crcSelector(source)) - { - var entries = entrySelector(source, crc32); - if (entries.Count > 1) - { - var entryNames = entryToStringSelector(entries.First()); - var context = contextSelector(entries); - AddError(VerificationError.Create( - VerifierChain, - VerifierErrorCodes.DuplicateFound, - errorMessageCreator(entries, sourceName), - VerificationSeverity.Error, - context, - entryNames)); - } - } - } - - private void CheckMtdForDuplicates(IMtdFile mtdFile) - { - CheckForDuplicateCrcEntries( - mtdFile.FileName, - mtdFile, - mtd => mtd.Content.Select(x => x.Crc32), - (mtd, crc32) => mtd.Content.EntriesWithCrc(crc32), - entry => entry.FileName, - entries => entries.Select(x => $"'{x.FileName}' (CRC: {x.Crc32})"), - CreateDuplicateMtdErrorMessage); - } - - private void CheckXmlObjectsForDuplicates(string databaseName, IGameManager gameManager) where T : NamedXmlObject - { - CheckForDuplicateCrcEntries( - databaseName, - gameManager, - manager => manager.EntryKeys, - (manager, crc32) => manager.GetEntries(crc32), - entry => entry.Name, - entries => entries.Select(x => $"'{x.Name}' - {x.Location}"), - CreateDuplicateXmlErrorMessage); - } - - private static string CreateDuplicateMtdErrorMessage(ImmutableFrugalList entries, string fileName) - { - var firstEntry = entries.First(); - return $"MTD File '{fileName}' has duplicate definitions for CRC ({firstEntry}): {string.Join(",", entries.Select(x => x.FileName))}"; - } - - private static string CreateDuplicateXmlErrorMessage(ImmutableFrugalList entries, string databaseName) where T : NamedXmlObject - { - var firstEntry = entries.First(); - var message = $"{databaseName} '{firstEntry.Name}' ({firstEntry.Crc32}) has duplicate definitions: "; - foreach (var entry in entries) - message += $"['{entry.Name}' in {entry.Location.XmlFile}:{entry.Location.Line}] "; - return message.TrimEnd(); - } -} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs new file mode 100644 index 0000000..c9ce8f2 --- /dev/null +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading; +using AET.ModVerify.Settings; +using AET.ModVerify.Verifiers.Commons; +using AET.ModVerify.Verifiers.Utilities; +using PG.StarWarsGame.Engine; + +namespace AET.ModVerify.Verifiers.GameObjects; + +public sealed class GameObjectTypeVerifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : GameVerifier(parent, gameEngine, settings, serviceProvider) +{ + public override string FriendlyName => "GameObjectType Verifier"; + + public override void Verify(CancellationToken token) + { + var context = IDuplicateVerificationContext.CreateForNamedXmlObjects(GameEngine.GameObjectTypeManager, "GameObjectType"); + var verifier = new DuplicateVerifier(this, GameEngine, Settings, Services); + verifier.Verify(context, [], token); + foreach (var error in verifier.VerifyErrors) + AddError(error); + } +} diff --git a/src/ModVerify/Verifiers/Utilities/DuplicateVerificationContextExtensions.cs b/src/ModVerify/Verifiers/Utilities/DuplicateVerificationContextExtensions.cs new file mode 100644 index 0000000..cd81de6 --- /dev/null +++ b/src/ModVerify/Verifiers/Utilities/DuplicateVerificationContextExtensions.cs @@ -0,0 +1,22 @@ +using AET.ModVerify.Verifiers.Commons; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Files.MTD.Files; +using PG.StarWarsGame.Files.XML.Data; + +namespace AET.ModVerify.Verifiers.Utilities; + +public static class DuplicateVerificationContextExtensions +{ + extension(IDuplicateVerificationContext) + { + public static IDuplicateVerificationContext CreateForMtd(IMtdFile mtdFile) + { + return new MtdDuplicateVerificationContext(mtdFile); + } + + public static IDuplicateVerificationContext CreateForNamedXmlObjects(IGameManager gameManager, string databaseName) where T : NamedXmlObject + { + return new NamedXmlObjectDuplicateVerificationContext(databaseName, gameManager); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/NameBasedEqualityComparer.cs b/src/ModVerify/Verifiers/Utilities/NameBasedEqualityComparer.cs similarity index 94% rename from src/ModVerify/Verifiers/NameBasedEqualityComparer.cs rename to src/ModVerify/Verifiers/Utilities/NameBasedEqualityComparer.cs index 01f396f..1a44506 100644 --- a/src/ModVerify/Verifiers/NameBasedEqualityComparer.cs +++ b/src/ModVerify/Verifiers/Utilities/NameBasedEqualityComparer.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace AET.ModVerify.Verifiers; +namespace AET.ModVerify.Verifiers.Utilities; internal sealed class NameBasedEqualityComparer : IEqualityComparer, IEqualityComparer { diff --git a/src/ModVerify/Verifiers/VerifierErrorCodes.cs b/src/ModVerify/Verifiers/VerifierErrorCodes.cs index a526715..96aea86 100644 --- a/src/ModVerify/Verifiers/VerifierErrorCodes.cs +++ b/src/ModVerify/Verifiers/VerifierErrorCodes.cs @@ -17,7 +17,7 @@ public static class VerifierErrorCodes public const string FilePathTooLong = "FILE01"; public const string InvalidFilePath = "FILE02"; - public const string DuplicateFound = "DUP00"; + public const string Duplicate = "DUP00"; public const string SampleNotPCM = "WAV00"; public const string SampleNotMono = "WAV01"; From f4e373e70e80f80e5abc73ae66290cb3bbf05b38 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 15 Mar 2026 18:04:34 +0100 Subject: [PATCH 26/41] refactoring sfx verifier --- src/ModVerify/DefaultGameVerifiersProvider.cs | 5 +- src/ModVerify/ModVerify.csproj.DotSettings | 1 + .../Verifiers/Commons/Audio/AudioFileInfo.cs | 15 ++ .../Verifiers/Commons/Audio/AudioFileType.cs | 7 + .../Verifiers/Commons/AudioFileVerifier.cs | 114 ++++++++ .../Verifiers/Commons/AudioFilesVerifier.cs | 250 ------------------ .../Verifiers/Commons/ModelVerifier.cs | 29 +- .../Verifiers/Commons/TextureVeifier.cs | 7 - .../SfxEvents/SfxEventVerifier.Duplicates.cs | 17 ++ .../SfxEvents/SfxEventVerifier.Samples.cs | 122 +++++++++ .../SfxEvents/SfxEventVerifier.XRef.cs | 22 ++ .../Verifiers/SfxEvents/SfxEventVerifier.cs | 71 +++++ src/ModVerify/Verifiers/VerifierErrorCodes.cs | 3 + 13 files changed, 390 insertions(+), 273 deletions(-) create mode 100644 src/ModVerify/Verifiers/Commons/Audio/AudioFileInfo.cs create mode 100644 src/ModVerify/Verifiers/Commons/Audio/AudioFileType.cs create mode 100644 src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs delete mode 100644 src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs create mode 100644 src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs create mode 100644 src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs create mode 100644 src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs create mode 100644 src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs diff --git a/src/ModVerify/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs index e62b46b..69fac2a 100644 --- a/src/ModVerify/DefaultGameVerifiersProvider.cs +++ b/src/ModVerify/DefaultGameVerifiersProvider.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using AET.ModVerify.Settings; using AET.ModVerify.Verifiers; -using AET.ModVerify.Verifiers.Commons; using AET.ModVerify.Verifiers.GuiDialogs; +using AET.ModVerify.Verifiers.SfxEvents; using PG.StarWarsGame.Engine; namespace AET.ModVerify; @@ -17,8 +17,7 @@ public IEnumerable GetVerifiers( { //yield break; yield return new ReferencedModelsVerifier(database, settings, serviceProvider); - //yield return new DuplicateNameFinder(database, settings, serviceProvider); - yield return new AudioFilesVerifier(database, settings, serviceProvider); + yield return new SfxEventVerifier(database, settings, serviceProvider); yield return new GuiDialogsVerifier(database, settings, serviceProvider); yield return new CommandBarVerifier(database, settings, serviceProvider); } diff --git a/src/ModVerify/ModVerify.csproj.DotSettings b/src/ModVerify/ModVerify.csproj.DotSettings index ca2367c..ec3a74c 100644 --- a/src/ModVerify/ModVerify.csproj.DotSettings +++ b/src/ModVerify/ModVerify.csproj.DotSettings @@ -5,6 +5,7 @@ True False True + True True True True \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/Audio/AudioFileInfo.cs b/src/ModVerify/Verifiers/Commons/Audio/AudioFileInfo.cs new file mode 100644 index 0000000..ee428cb --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/Audio/AudioFileInfo.cs @@ -0,0 +1,15 @@ +namespace AET.ModVerify.Verifiers.Commons; + +public class AudioFileInfo +{ + public string SampleName { get; } + public AudioFileType ExpectedType { get; } + public bool IsAmbient { get; } + + public AudioFileInfo(string sampleName, AudioFileType expectedType, bool isAmbient) + { + SampleName = sampleName; + ExpectedType = expectedType; + IsAmbient = isAmbient; + } +} diff --git a/src/ModVerify/Verifiers/Commons/Audio/AudioFileType.cs b/src/ModVerify/Verifiers/Commons/Audio/AudioFileType.cs new file mode 100644 index 0000000..05ea0bc --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/Audio/AudioFileType.cs @@ -0,0 +1,7 @@ +namespace AET.ModVerify.Verifiers.Commons; + +public enum AudioFileType +{ + Wav, + Mp3 +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs new file mode 100644 index 0000000..9f0dd85 --- /dev/null +++ b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.IO; +using AET.ModVerify.Reporting; +using AET.ModVerify.Settings; +using PG.StarWarsGame.Engine; +using System.Threading; +using Microsoft.Extensions.DependencyInjection; + +namespace AET.ModVerify.Verifiers.Commons; + +public class AudioFileVerifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : GameVerifier(parent, gameEngine, settings, serviceProvider) +{ + private readonly IAlreadyVerifiedCache? _alreadyVerifiedCache = serviceProvider.GetService(); + + public override string FriendlyName => "Audio File format"; + + public override void Verify(AudioFileInfo sampleInfo, IReadOnlyCollection contextInfo, CancellationToken token) + { + var sampleString = sampleInfo.SampleName; + + using var sampleStream = Repository.TryOpenFile(sampleString.AsSpan()); + if (sampleStream is null) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.FileNotFound, + $"Audio file '{sampleString}' could not be found.", + VerificationSeverity.Error, + [..contextInfo], + sampleString)); + return; + } + + if (!_alreadyVerifiedCache?.TryAddEntry(sampleInfo.SampleName) is false) + return; + + if (sampleInfo.ExpectedType == AudioFileType.Mp3) + { + // TODO: MP3 support to be implemented + return; + } + + using var binaryReader = new BinaryReader(sampleStream); + + // Skip Header + "fmt " + binaryReader.BaseStream.Seek(16, SeekOrigin.Begin); + + var fmtSize = binaryReader.ReadInt32(); + var format = (WaveFormats)binaryReader.ReadInt16(); + var channels = binaryReader.ReadInt16(); + + var sampleRate = binaryReader.ReadInt32(); + var bytesPerSecond = binaryReader.ReadInt32(); + + var frameSize = binaryReader.ReadInt16(); + var bitPerSecondPerChannel = binaryReader.ReadInt16(); + + if (format != WaveFormats.PCM) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.SampleNotPCM, + $"Audio file '{sampleString}' has an invalid format '{format}'. Supported is {WaveFormats.PCM}", + VerificationSeverity.Error, + [..contextInfo], + sampleString)); + } + + if (channels > 1 && !sampleInfo.IsAmbient) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.SampleNotMono, + $"Audio file '{sampleString}' is not mono audio.", + VerificationSeverity.Information, + sampleString)); + } + + if (sampleRate > 48_000) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.InvalidSampleRate, + $"Audio file '{sampleString}' has a too high sample rate of {sampleRate}. Maximum is 48.000Hz.", + VerificationSeverity.Error, + [..contextInfo], + sampleString)); + } + + if (bitPerSecondPerChannel > 16) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.InvalidBitsPerSeconds, + $"Audio file '{sampleString}' has an invalid bit size of {bitPerSecondPerChannel}. Supported are 16bit.", + VerificationSeverity.Error, + [..contextInfo], + sampleString)); + } + } + + private enum WaveFormats + { + PCM = 1, + MSADPCM = 2, + IEEE_Float = 3, + } +} diff --git a/src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs b/src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs deleted file mode 100644 index fd2759b..0000000 --- a/src/ModVerify/Verifiers/Commons/AudioFilesVerifier.cs +++ /dev/null @@ -1,250 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Generic; -using System.IO; -using System.IO.Abstractions; -using System.Linq; -using System.Text; -using System.Threading; -using AET.ModVerify.Reporting; -using AET.ModVerify.Settings; -using AnakinRaW.CommonUtilities.FileSystem; -using AnakinRaW.CommonUtilities.FileSystem.Normalization; -using Microsoft.Extensions.DependencyInjection; -using PG.Commons.Hashing; -using PG.StarWarsGame.Engine; -using PG.StarWarsGame.Engine.Audio.Sfx; -using PG.StarWarsGame.Engine.Localization; - -namespace AET.ModVerify.Verifiers.Commons; - -// TODO: Refactor to make this a generic audio file verifier that can be used for -// SFXEvents, MusicEvents and SpeechEvents - -public class AudioFilesVerifier : GameVerifier -{ - private static readonly PathNormalizeOptions SampleNormalizerOptions = new() - { - UnifyCase = UnifyCasingKind.UpperCaseForce, - UnifySeparatorKind = DirectorySeparatorKind.Windows, - UnifyDirectorySeparators = true - }; - - private readonly ICrc32HashingService _hashingService; - private readonly IFileSystem _fileSystem; - private readonly IGameLanguageManager _languageManager; - - public AudioFilesVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) - : base(null, gameEngine, settings, serviceProvider) - { - _hashingService = serviceProvider.GetRequiredService(); - _fileSystem = serviceProvider.GetRequiredService(); - _languageManager = serviceProvider.GetRequiredService() - .GetLanguageManager(Repository.EngineType); - } - - public override string FriendlyName => "Audio Files"; - - public override void Verify(CancellationToken token) - { - var visitedSamples = new HashSet(); - var languagesToVerify = GetLanguagesToVerify().ToList(); - - - var numSamples = GameEngine.SfxGameManager.Entries.Sum(x => x.AllSamples.Count()); - double counter = 0; - - foreach (var sfxEvent in GameEngine.SfxGameManager.Entries) - { - foreach (var codedSample in sfxEvent.AllSamples) - { - OnProgress(++counter / numSamples, $"Audio File - '{codedSample}'"); - VerifySample(codedSample.AsSpan(), sfxEvent, languagesToVerify, visitedSamples); - } - } - } - - private void VerifySample(ReadOnlySpan sample, SfxEvent sfxEvent, IEnumerable languagesToVerify, HashSet visitedSamples) - { - char[]? pooledBuffer = null; - - var buffer = sample.Length < PGConstants.MaxMegEntryPathLength - ? stackalloc char[PGConstants.MaxMegEntryPathLength] - : pooledBuffer = ArrayPool.Shared.Rent(sample.Length); - - try - { - var length = PathNormalizer.Normalize(sample, buffer, SampleNormalizerOptions); - var sampleNameBuffer = buffer.Slice(0, length); - - var crc = _hashingService.GetCrc32(sampleNameBuffer, Encoding.ASCII); - if (!visitedSamples.Add(crc)) - return; - - if (sfxEvent.IsLocalized) - { - foreach (var language in languagesToVerify) - { - VerifySampleLocalized(sfxEvent, sampleNameBuffer, language, out var localized); - if (!localized) - return; - } - } - else - { - VerifySample(sampleNameBuffer, sfxEvent); - } - } - finally - { - if (pooledBuffer is not null) - ArrayPool.Shared.Return(pooledBuffer); - } - - } - - private void VerifySampleLocalized(SfxEvent sfxEvent, ReadOnlySpan sample, LanguageType language, out bool localized) - { - char[]? pooledBuffer = null; - - var buffer = sample.Length < PGConstants.MaxMegEntryPathLength - ? stackalloc char[PGConstants.MaxMegEntryPathLength] - : pooledBuffer = ArrayPool.Shared.Rent(sample.Length); - try - { - var l = _languageManager.LocalizeFileName(sample, language, buffer, out localized); - var localizedName = buffer.Slice(0, l); - VerifySample(localizedName, sfxEvent); - } - finally - { - if (pooledBuffer is not null) - ArrayPool.Shared.Return(pooledBuffer); - } - } - - private void VerifySample(ReadOnlySpan sample, SfxEvent sfxEvent) - { - using var sampleStream = Repository.TryOpenFile(sample); - if (sampleStream is null) - { - var sampleString = sample.ToString(); - AddError(VerificationError.Create( - VerifierChain, - VerifierErrorCodes.FileNotFound, - $"Audio file '{sampleString}' could not be found.", - VerificationSeverity.Error, - [sfxEvent.Name], - sampleString)); - return; - } - using var binaryReader = new BinaryReader(sampleStream); - - // Skip Header + "fmt " - binaryReader.BaseStream.Seek(16, SeekOrigin.Begin); - - var fmtSize = binaryReader.ReadInt32(); - var format = (WaveFormats)binaryReader.ReadInt16(); - var channels = binaryReader.ReadInt16(); - - var sampleRate = binaryReader.ReadInt32(); - var bytesPerSecond = binaryReader.ReadInt32(); - - var frameSize = binaryReader.ReadInt16(); - var bitPerSecondPerChannel = binaryReader.ReadInt16(); - - if (format != WaveFormats.PCM) - { - var sampleString = sample.ToString(); - AddError(VerificationError.Create( - VerifierChain, - VerifierErrorCodes.SampleNotPCM, - $"Audio file '{sampleString}' has an invalid format '{format}'. Supported is {WaveFormats.PCM}", - VerificationSeverity.Error, - [sfxEvent.Name], - sampleString)); - } - - if (channels > 1 && !IsAmbient2D(sfxEvent)) - { - var sampleString = sample.ToString(); - AddError(VerificationError.Create( - VerifierChain, - VerifierErrorCodes.SampleNotMono, - $"Audio file '{sampleString}' is not mono audio.", - VerificationSeverity.Information, - sampleString)); - } - - if (sampleRate > 48_000) - { - var sampleString = sample.ToString(); - AddError(VerificationError.Create( - VerifierChain, - VerifierErrorCodes. InvalidSampleRate, - $"Audio file '{sampleString}' has a too high sample rate of {sampleRate}. Maximum is 48.000Hz.", - VerificationSeverity.Error, - [sfxEvent.Name], - sampleString)); - } - - if (bitPerSecondPerChannel > 16) - { - var sampleString = sample.ToString(); - AddError(VerificationError.Create( - VerifierChain, - VerifierErrorCodes.InvalidBitsPerSeconds, - $"Audio file '{sampleString}' has an invalid bit size of {bitPerSecondPerChannel}. Supported are 16bit.", - VerificationSeverity.Error, - [sfxEvent.Name], - sampleString)); - } - } - - // Some heuristics whether a SFXEvent is most likely to be an ambient sound. - private bool IsAmbient2D(SfxEvent sfxEvent) - { - if (!sfxEvent.Is2D) - return false; - - if (sfxEvent.IsPreset) - return false; - - // If the event is located in SFXEventsAmbient.xml we simply assume it's an ambient sound. - var fileName = _fileSystem.Path.GetFileName(sfxEvent.Location.XmlFile.AsSpan()); - if (fileName.Equals("SFXEventsAmbient.xml".AsSpan(), StringComparison.OrdinalIgnoreCase)) - return true; - - if (string.IsNullOrEmpty(sfxEvent.UsePresetName)) - return false; - - if (sfxEvent.UsePresetName!.StartsWith("Preset_AMB_2D")) - return true; - - return true; - } - - private IEnumerable GetLanguagesToVerify() - { - switch (Settings.LocalizationOption) - { - case VerifyLocalizationOption.English: - return new List { LanguageType.English }; - case VerifyLocalizationOption.CurrentSystem: - return new List { _languageManager.GetLanguagesFromUser() }; - case VerifyLocalizationOption.AllInstalled: - return GameEngine.InstalledLanguages; - case VerifyLocalizationOption.All: - return _languageManager.SupportedLanguages; - default: - throw new NotSupportedException($"{Settings.LocalizationOption} is not supported"); - } - } - - private enum WaveFormats - { - PCM = 1, - MSADPCM = 2, - IEEE_Float = 3, - } -} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs index 8ec92e6..3acf1ff 100644 --- a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs @@ -61,9 +61,23 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte var modelName = FileSystem.Path.GetFileName(modelPath.AsSpan()); - if (_cache?.TryAddEntry(modelName) == false) + // We always want to report that a file was not found, so that error reports show all XRefs to the not found model. + if (!GameEngine.GameRepository.ModelRepository.FileExists(modelPath)) + { + var modelNameString = modelName.ToString(); + var error = VerificationError.Create( + VerifierChain, + VerifierErrorCodes.FileNotFound, + $"Unable to find .ALO file '{modelNameString}'", + VerificationSeverity.Error, + contextInfo, + modelNameString); + AddError(error); + } + + if (_cache?.TryAddEntry(modelName) is false) return; - + IAloFile? aloFile = null; try { @@ -81,18 +95,7 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte } if (aloFile is null) - { - var modelNameString = modelName.ToString(); - var error = VerificationError.Create( - VerifierChain, - VerifierErrorCodes.FileNotFound, - $"Unable to find .ALO file '{modelNameString}'", - VerificationSeverity.Error, - contextInfo, - modelNameString); - AddError(error); return; - } VerifyModelOrParticle(aloFile, contextInfo, token); } diff --git a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs b/src/ModVerify/Verifiers/Commons/TextureVeifier.cs index 1bd3a08..c81bd0e 100644 --- a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs +++ b/src/ModVerify/Verifiers/Commons/TextureVeifier.cs @@ -4,7 +4,6 @@ using System.Threading; using AET.ModVerify.Reporting; using AET.ModVerify.Settings; -using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine; namespace AET.ModVerify.Verifiers.Commons; @@ -16,8 +15,6 @@ public sealed class TextureVeifier( IServiceProvider serviceProvider) : GameVerifier(parent, gameEngine, settings, serviceProvider) { - private readonly IAlreadyVerifiedCache? _cache = serviceProvider.GetService(); - public override void Verify(string texturePath, IReadOnlyCollection contextInfo, CancellationToken token) { Verify(texturePath.AsSpan(), contextInfo, token); @@ -27,10 +24,6 @@ public void Verify(ReadOnlySpan textureName, IReadOnlyCollection c { token.ThrowIfCancellationRequested(); - - if (_cache?.TryAddEntry(textureName) == false) - return; - if (Repository.TextureRepository.FileExists(textureName, false, out var tooLongPath)) return; diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs new file mode 100644 index 0000000..d946402 --- /dev/null +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs @@ -0,0 +1,17 @@ +using System.Threading; +using AET.ModVerify.Verifiers.Commons; +using AET.ModVerify.Verifiers.Utilities; + +namespace AET.ModVerify.Verifiers.SfxEvents; + +public partial class SfxEventVerifier +{ + private void VerifyDuplicates(CancellationToken token) + { + var context = IDuplicateVerificationContext.CreateForNamedXmlObjects(GameEngine.SfxGameManager, "SFXEvent"); + var verifier = new DuplicateVerifier(this, GameEngine, Settings, Services); + verifier.Verify(context, [], token); + foreach (var error in verifier.VerifyErrors) + AddError(error); + } +} diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs new file mode 100644 index 0000000..789b09c --- /dev/null +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs @@ -0,0 +1,122 @@ +using System; +using System.Buffers; +using System.Threading; +using AET.ModVerify.Reporting; +using AET.ModVerify.Verifiers.Commons; +using AnakinRaW.CommonUtilities.FileSystem.Normalization; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.Audio.Sfx; +using PG.StarWarsGame.Engine.Localization; + +namespace AET.ModVerify.Verifiers.SfxEvents; + +public partial class SfxEventVerifier +{ + private void VerifySamples(SfxEvent sfxEvent, CancellationToken token) + { + EventHandler errorHandler = (_, e) => AddError(e.Error); + _audioFileVerifier.Error += errorHandler; + + try + { + var isAmbient = IsAmbient2D(sfxEvent); + + foreach (var codedSample in sfxEvent.AllSamples) + { + VerifySample(codedSample.AsSpan(), sfxEvent, isAmbient, token); + } + } + finally + { + _audioFileVerifier.Error -= errorHandler; + } + } + + private void VerifySample( + ReadOnlySpan sample, + SfxEvent sfxEvent, + bool isAmbient, + CancellationToken token) + { + char[]? pooledBuffer = null; + + var buffer = sample.Length < PGConstants.MaxMegEntryPathLength + ? stackalloc char[PGConstants.MaxMegEntryPathLength] + : pooledBuffer = ArrayPool.Shared.Rent(sample.Length); + + try + { + var length = PathNormalizer.Normalize(sample, buffer, SampleNormalizerOptions); + var sampleNameBuffer = buffer.Slice(0, length); + + if (sfxEvent.IsLocalized) + { + foreach (var language in _languagesToVerify) + { + VerifySampleLocalized(sfxEvent, sampleNameBuffer, isAmbient, language, out var localized, token); + if (!localized) + { + // There is no reason to continue if we failed to localize the sample name, because the verification will fail anyway + // and we want to avoid multiple errors for the same sample. + return; + } + } + } + else + { + var audioInfo = new AudioFileInfo(sampleNameBuffer.ToString(), AudioFileType.Wav, isAmbient); + _audioFileVerifier.Verify(audioInfo, [sfxEvent.Name], token); + } + } + finally + { + if (pooledBuffer is not null) + ArrayPool.Shared.Return(pooledBuffer); + } + } + + private void VerifySampleLocalized(SfxEvent sfxEvent, ReadOnlySpan sample, bool isAmbient, LanguageType language, out bool localized, CancellationToken token) + { + char[]? pooledBuffer = null; + + var buffer = sample.Length < PGConstants.MaxMegEntryPathLength + ? stackalloc char[PGConstants.MaxMegEntryPathLength] + : pooledBuffer = ArrayPool.Shared.Rent(sample.Length); + try + { + var l = _languageManager.LocalizeFileName(sample, language, buffer, out localized); + var localizedName = buffer.Slice(0, l); + + var audioInfo = new AudioFileInfo(localizedName.ToString(), AudioFileType.Wav, isAmbient); + _audioFileVerifier.Verify(audioInfo, [sfxEvent.Name], token); + } + finally + { + if (pooledBuffer is not null) + ArrayPool.Shared.Return(pooledBuffer); + } + } + + // Some heuristics whether a SFXEvent is most likely to be an ambient sound. + private bool IsAmbient2D(SfxEvent sfxEvent) + { + if (!sfxEvent.Is2D) + return false; + + if (sfxEvent.IsPreset) + return false; + + // If the event is located in SFXEventsAmbient.xml we simply assume it's an ambient sound. + var fileName = _fileSystem.Path.GetFileName(sfxEvent.Location.XmlFile).AsSpan(); + if (fileName.Equals("SFXEventsAmbient.xml".AsSpan(), StringComparison.OrdinalIgnoreCase)) + return true; + + if (string.IsNullOrEmpty(sfxEvent.UsePresetName)) + return false; + + if (sfxEvent.UsePresetName!.StartsWith("Preset_AMB_2D", StringComparison.OrdinalIgnoreCase)) + return true; + + return false; + } +} diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs new file mode 100644 index 0000000..5c04cae --- /dev/null +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs @@ -0,0 +1,22 @@ +using System.Threading; +using AET.ModVerify.Reporting; +using PG.StarWarsGame.Engine.Audio.Sfx; + +namespace AET.ModVerify.Verifiers.SfxEvents; + +public partial class SfxEventVerifier +{ + private void VerifyPresetRef(SfxEvent sfxEvent, CancellationToken token) + { + if (!string.IsNullOrEmpty(sfxEvent.UsePresetName) && sfxEvent.Preset is null) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.MissingXRef, + $"SFX Event '{sfxEvent.Name}' has Use_Preset set to '{sfxEvent.UsePresetName}' but the preset could not be found.", + VerificationSeverity.Error, + [sfxEvent.Name], + sfxEvent.UsePresetName)); + } + } +} diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs new file mode 100644 index 0000000..bc09317 --- /dev/null +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs @@ -0,0 +1,71 @@ +using AET.ModVerify.Settings; +using AET.ModVerify.Verifiers.Commons; +using AnakinRaW.CommonUtilities.FileSystem.Normalization; +using Microsoft.Extensions.DependencyInjection; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.Localization; +using System; +using System.Collections.Generic; +using System.IO.Abstractions; +using System.Threading; + +namespace AET.ModVerify.Verifiers.SfxEvents; + +public sealed partial class SfxEventVerifier : GameVerifier +{ + private static readonly PathNormalizeOptions SampleNormalizerOptions = new() + { + UnifyCase = UnifyCasingKind.UpperCaseForce, + UnifySeparatorKind = DirectorySeparatorKind.Windows, + UnifyDirectorySeparators = true + }; + + private readonly IGameLanguageManager _languageManager; + private readonly IFileSystem _fileSystem; + private readonly AudioFileVerifier _audioFileVerifier; + private readonly IReadOnlyCollection _languagesToVerify; + + public override string FriendlyName => "SFX Events"; + + public SfxEventVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) + : base(null, gameEngine, settings, serviceProvider) + { + _languageManager = serviceProvider.GetRequiredService() + .GetLanguageManager(Repository.EngineType); + _fileSystem = serviceProvider.GetRequiredService(); + _audioFileVerifier = new AudioFileVerifier(this, gameEngine, settings, serviceProvider); + _languagesToVerify = GetLanguagesToVerify(); + } + + public override void Verify(CancellationToken token) + { + VerifyDuplicates(token); + + var numEvents = GameEngine.SfxGameManager.Entries.Count; + double counter = 0; + foreach (var sfxEvent in GameEngine.SfxGameManager.Entries) + { + OnProgress(++counter / numEvents, $"SFX Event - '{sfxEvent.Name}'"); + + VerifyPresetRef(sfxEvent, token); + VerifySamples(sfxEvent, token); + } + } + + private IReadOnlyCollection GetLanguagesToVerify() + { + switch (Settings.LocalizationOption) + { + case VerifyLocalizationOption.English: + return [LanguageType.English]; + case VerifyLocalizationOption.CurrentSystem: + return [_languageManager.GetLanguagesFromUser()]; + case VerifyLocalizationOption.AllInstalled: + return [..GameEngine.InstalledLanguages]; + case VerifyLocalizationOption.All: + return [.._languageManager.SupportedLanguages]; + default: + throw new NotSupportedException($"{Settings.LocalizationOption} is not supported"); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/VerifierErrorCodes.cs b/src/ModVerify/Verifiers/VerifierErrorCodes.cs index 96aea86..b6f365c 100644 --- a/src/ModVerify/Verifiers/VerifierErrorCodes.cs +++ b/src/ModVerify/Verifiers/VerifierErrorCodes.cs @@ -18,6 +18,9 @@ public static class VerifierErrorCodes public const string InvalidFilePath = "FILE02"; public const string Duplicate = "DUP00"; + public const string MissingXRef = "XREF00"; + + public const string MissingPreset = "SFX00"; public const string SampleNotPCM = "WAV00"; public const string SampleNotMono = "WAV01"; From b1c7990da7623b670e5cc0b31f0e50c72770f47e Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Mar 2026 11:52:19 +0100 Subject: [PATCH 27/41] implement xref and models check for gameobjects --- src/ModVerify/DefaultGameVerifiersProvider.cs | 12 ++-- src/ModVerify/GameVerifyPipeline.cs | 1 + src/ModVerify/IGameVerifiersProvider.cs | 2 +- src/ModVerify/ModVerify.csproj.DotSettings | 5 +- .../{ => Engine}/GameEngineErrorCollector.cs | 2 +- .../CommandBarVerifier.Components.cs | 13 ++-- .../CommandBar/CommandBarVerifier.Groups.cs | 2 +- .../CommandBar/CommandBarVerifier.cs} | 10 +-- .../GameObjectTypeVerifier.Models.cs | 13 ++++ .../GameObjectTypeVerifier.XRef.cs | 21 ++++++ .../GameObjects/GameObjectTypeVerifier.cs | 42 +++++++---- src/ModVerify/Verifiers/GameVerifierBase.cs | 4 ++ .../Verifiers/NamedGameEntityVerifier.cs | 70 +++++++++++++++++++ .../Verifiers/ReferencedModelsVerifier.cs | 68 ------------------ .../SfxEvents/SfxEventVerifier.Duplicates.cs | 17 ----- .../SfxEvents/SfxEventVerifier.Samples.cs | 38 ++++------ .../SfxEvents/SfxEventVerifier.XRef.cs | 9 ++- .../Verifiers/SfxEvents/SfxEventVerifier.cs | 26 +++---- 18 files changed, 195 insertions(+), 160 deletions(-) rename src/ModVerify/Verifiers/{ => Engine}/GameEngineErrorCollector.cs (96%) rename src/ModVerify/Verifiers/{ => GameObjects}/CommandBar/CommandBarVerifier.Components.cs (93%) rename src/ModVerify/Verifiers/{ => GameObjects}/CommandBar/CommandBarVerifier.Groups.cs (97%) rename src/ModVerify/Verifiers/{CommandBar/CommandBarVerifier.Base.cs => GameObjects/CommandBar/CommandBarVerifier.cs} (74%) create mode 100644 src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Models.cs create mode 100644 src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs create mode 100644 src/ModVerify/Verifiers/NamedGameEntityVerifier.cs delete mode 100644 src/ModVerify/Verifiers/ReferencedModelsVerifier.cs delete mode 100644 src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs diff --git a/src/ModVerify/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs index 69fac2a..965af6b 100644 --- a/src/ModVerify/DefaultGameVerifiersProvider.cs +++ b/src/ModVerify/DefaultGameVerifiersProvider.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using AET.ModVerify.Settings; using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.CommandBar; +using AET.ModVerify.Verifiers.GameObjects; using AET.ModVerify.Verifiers.GuiDialogs; using AET.ModVerify.Verifiers.SfxEvents; using PG.StarWarsGame.Engine; @@ -11,14 +13,14 @@ namespace AET.ModVerify; public sealed class DefaultGameVerifiersProvider : IGameVerifiersProvider { public IEnumerable GetVerifiers( - IStarWarsGameEngine database, + IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) { //yield break; - yield return new ReferencedModelsVerifier(database, settings, serviceProvider); - yield return new SfxEventVerifier(database, settings, serviceProvider); - yield return new GuiDialogsVerifier(database, settings, serviceProvider); - yield return new CommandBarVerifier(database, settings, serviceProvider); + yield return new SfxEventVerifier(gameEngine, settings, serviceProvider); + yield return new GuiDialogsVerifier(gameEngine, settings, serviceProvider); + yield return new GameObjectTypeVerifier(gameEngine, settings, serviceProvider); + yield return new CommandBarVerifier(gameEngine, settings, serviceProvider); } } \ No newline at end of file diff --git a/src/ModVerify/GameVerifyPipeline.cs b/src/ModVerify/GameVerifyPipeline.cs index 37031c9..4a7e0fb 100644 --- a/src/ModVerify/GameVerifyPipeline.cs +++ b/src/ModVerify/GameVerifyPipeline.cs @@ -11,6 +11,7 @@ using AET.ModVerify.Settings; using AET.ModVerify.Utilities; using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.Engine; using AET.ModVerify.Verifiers.Utilities; using AnakinRaW.CommonUtilities.SimplePipeline; using AnakinRaW.CommonUtilities.SimplePipeline.Runners; diff --git a/src/ModVerify/IGameVerifiersProvider.cs b/src/ModVerify/IGameVerifiersProvider.cs index 8cde9dc..c34c98d 100644 --- a/src/ModVerify/IGameVerifiersProvider.cs +++ b/src/ModVerify/IGameVerifiersProvider.cs @@ -9,7 +9,7 @@ namespace AET.ModVerify; public interface IGameVerifiersProvider { IEnumerable GetVerifiers( - IStarWarsGameEngine database, + IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider); } \ No newline at end of file diff --git a/src/ModVerify/ModVerify.csproj.DotSettings b/src/ModVerify/ModVerify.csproj.DotSettings index ec3a74c..dcc29bb 100644 --- a/src/ModVerify/ModVerify.csproj.DotSettings +++ b/src/ModVerify/ModVerify.csproj.DotSettings @@ -4,8 +4,9 @@ True True False - True + False True True True - True \ No newline at end of file + True + False \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameEngineErrorCollector.cs b/src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs similarity index 96% rename from src/ModVerify/Verifiers/GameEngineErrorCollector.cs rename to src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs index 975e360..0dee603 100644 --- a/src/ModVerify/Verifiers/GameEngineErrorCollector.cs +++ b/src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs @@ -6,7 +6,7 @@ using AET.ModVerify.Settings; using PG.StarWarsGame.Engine; -namespace AET.ModVerify.Verifiers; +namespace AET.ModVerify.Verifiers.Engine; public sealed class GameEngineErrorCollector( IGameEngineErrorCollection errorCollection, diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs b/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Components.cs similarity index 93% rename from src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs rename to src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Components.cs index a7bd044..9b49239 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs +++ b/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Components.cs @@ -1,16 +1,17 @@ -using AET.ModVerify.Reporting; +using System; +using System.Linq; +using AET.ModVerify.Reporting; using PG.StarWarsGame.Engine.CommandBar; using PG.StarWarsGame.Engine.CommandBar.Components; -using System; -using System.Linq; -namespace AET.ModVerify.Verifiers; +namespace AET.ModVerify.Verifiers.CommandBar; partial class CommandBarVerifier { private void VerifyCommandBarComponents() { - var occupiedComponentIds = SupportedCommandBarComponentData.GetComponentIdsForEngine(Repository.EngineType).Keys + var occupiedComponentIds = SupportedCommandBarComponentData + .GetComponentIdsForEngine(Repository.EngineType).Keys .ToDictionary(value => value, _ => false); foreach (var component in GameEngine.CommandBar.Components) @@ -32,7 +33,7 @@ private void VerifyCommandBarComponents() if (alreadyOccupied) { AddError(VerificationError.Create(VerifierChain, - CommandBarDuplicateComponent, + VerifierErrorCodes.Duplicate, $"The CommandBar component '{component.Name}' with ID '{component.Id}' already exists.", VerificationSeverity.Warning, component.Name)); diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs b/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Groups.cs similarity index 97% rename from src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs rename to src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Groups.cs index 5ca7e58..85f3d73 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs +++ b/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Groups.cs @@ -4,7 +4,7 @@ using PG.StarWarsGame.Engine.CommandBar; using PG.StarWarsGame.Engine.CommandBar.Components; -namespace AET.ModVerify.Verifiers; +namespace AET.ModVerify.Verifiers.CommandBar; partial class CommandBarVerifier { diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs b/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.cs similarity index 74% rename from src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs rename to src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.cs index e8c4ec2..3a6301a 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Base.cs +++ b/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.cs @@ -3,7 +3,7 @@ using AET.ModVerify.Settings; using PG.StarWarsGame.Engine; -namespace AET.ModVerify.Verifiers; +namespace AET.ModVerify.Verifiers.CommandBar; public partial class CommandBarVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) : GameVerifier(null, gameEngine, settings, serviceProvider) @@ -11,15 +11,17 @@ public partial class CommandBarVerifier(IStarWarsGameEngine gameEngine, GameVeri public const string CommandBarNoShellsGroup = "CMDBAR00"; public const string CommandBarManyShellsGroup = "CMDBAR01"; public const string CommandBarNoShellsComponentInShellGroup = "CMDBAR02"; - public const string CommandBarDuplicateComponent = "CMDBAR03"; - public const string CommandBarUnsupportedComponent = "CMDBAR04"; - public const string CommandBarShellNoModel = "CMDBAR05"; + public const string CommandBarUnsupportedComponent = "CMDBAR03"; + public const string CommandBarShellNoModel = "CMDBAR04"; public override string FriendlyName => "CommandBar"; public override void Verify(CancellationToken token) { + OnProgress(0.0, "Verifying CommandBar Shell"); VerifyCommandBarShellsGroups(); + OnProgress(0.5d, "Verifying CommandBar components"); VerifyCommandBarComponents(); + OnProgress(1.0d, null); } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Models.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Models.cs new file mode 100644 index 0000000..39699a7 --- /dev/null +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Models.cs @@ -0,0 +1,13 @@ +using PG.StarWarsGame.Engine.GameObjects; +using System.Threading; + +namespace AET.ModVerify.Verifiers.GameObjects; + +public sealed partial class GameObjectTypeVerifier +{ + private void VerifyModels(GameObject gameObject, string[] context, CancellationToken token) + { + foreach (var model in GameEngine.GameObjectTypeManager.GetModels(gameObject)) + _singleModelVerifier.Verify(model, context, token); + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs new file mode 100644 index 0000000..3d6b266 --- /dev/null +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs @@ -0,0 +1,21 @@ +using AET.ModVerify.Reporting; +using PG.StarWarsGame.Engine.GameObjects; + +namespace AET.ModVerify.Verifiers.GameObjects; + +public sealed partial class GameObjectTypeVerifier +{ + private void VerifyXRefs(GameObject gameObject, string[] context) + { + if (!string.IsNullOrEmpty(gameObject.VariantOfExistingTypeName) && gameObject.VariantOfExistingType is null) + { + AddError(VerificationError.Create( + VerifierChain, + VerifierErrorCodes.MissingXRef, + $"Missing base type '{gameObject.VariantOfExistingTypeName}' for GameObject '{gameObject.Name}'", + VerificationSeverity.Critical, + context, + gameObject.VariantOfExistingTypeName)); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs index c9ce8f2..1d74754 100644 --- a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs @@ -2,26 +2,40 @@ using System.Threading; using AET.ModVerify.Settings; using AET.ModVerify.Verifiers.Commons; -using AET.ModVerify.Verifiers.Utilities; using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.GameObjects; namespace AET.ModVerify.Verifiers.GameObjects; -public sealed class GameObjectTypeVerifier( - IGameVerifierInfo? parent, - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifier(parent, gameEngine, settings, serviceProvider) +// TODO: Add GameObjectTypeVerifier and check that LandModelTerrainOverride is correct (all keys correct, no dups) +public sealed partial class GameObjectTypeVerifier : NamedGameEntityVerifier { + private readonly SingleModelVerifier _singleModelVerifier; + public override string FriendlyName => "GameObjectType Verifier"; - public override void Verify(CancellationToken token) + public override IGameManager GameManager => GameEngine.GameObjectTypeManager; + + public override string EntityTypeName => "GameObjectType"; + + public GameObjectTypeVerifier( + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : base(gameEngine, settings, serviceProvider) + { + _singleModelVerifier = new SingleModelVerifier(this, gameEngine, settings, serviceProvider); + } + + protected override void VerifyEntity(GameObject entity, string[] context, double progress, CancellationToken token) + { + VerifyXRefs(entity, context); + VerifyModels(entity, context, token); + } + + protected override void PostEntityVerify(CancellationToken token) { - var context = IDuplicateVerificationContext.CreateForNamedXmlObjects(GameEngine.GameObjectTypeManager, "GameObjectType"); - var verifier = new DuplicateVerifier(this, GameEngine, Settings, Services); - verifier.Verify(context, [], token); - foreach (var error in verifier.VerifyErrors) - AddError(error); + foreach (var modelError in _singleModelVerifier.VerifyErrors) + AddError(modelError); } -} +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameVerifierBase.cs b/src/ModVerify/Verifiers/GameVerifierBase.cs index 22b2789..c74a6a9 100644 --- a/src/ModVerify/Verifiers/GameVerifierBase.cs +++ b/src/ModVerify/Verifiers/GameVerifierBase.cs @@ -8,6 +8,8 @@ using System.Collections.Generic; using System.IO.Abstractions; using AET.ModVerify.Progress; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using PG.StarWarsGame.Engine; namespace AET.ModVerify.Verifiers; @@ -22,6 +24,7 @@ public abstract class GameVerifierBase : IGameVerifierInfo protected readonly IFileSystem FileSystem; protected readonly IServiceProvider Services; protected readonly GameVerifySettings Settings; + protected readonly ILogger Logger; public IReadOnlyCollection VerifyErrors => [.. _verifyErrors.Keys]; @@ -45,6 +48,7 @@ protected GameVerifierBase( { if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider)); + Logger = serviceProvider.GetService()?.CreateLogger(GetType()) ?? NullLogger.Instance; FileSystem = serviceProvider.GetRequiredService(); Services = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); Parent = parent; diff --git a/src/ModVerify/Verifiers/NamedGameEntityVerifier.cs b/src/ModVerify/Verifiers/NamedGameEntityVerifier.cs new file mode 100644 index 0000000..18ec9c3 --- /dev/null +++ b/src/ModVerify/Verifiers/NamedGameEntityVerifier.cs @@ -0,0 +1,70 @@ +using System; +using System.Threading; +using AET.ModVerify.Settings; +using AET.ModVerify.Verifiers.Commons; +using AET.ModVerify.Verifiers.Utilities; +using Microsoft.Extensions.Logging; +using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Files.XML.Data; + +namespace AET.ModVerify.Verifiers; + +public abstract partial class NamedGameEntityVerifier( + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : GameVerifier(null, gameEngine, settings, serviceProvider) + where T : NamedXmlObject +{ + public abstract IGameManager GameManager { get; } + + public abstract string EntityTypeName { get; } + + public sealed override void Verify(CancellationToken token) + { + OnProgress(0.0, $"Verifying GameManager for '{EntityTypeName}'"); + PreEntityVerify(token); + OnProgress(0.5, null); + + var numEntities = GameEngine.GameObjectTypeManager.Entries.Count; + double counter = 0; + var context = new string[1]; + foreach (var gameEntity in GameManager.Entries) + { + LogVerifyingEntityTypeName(Logger, EntityTypeName, gameEntity.Name); + var progress = 0.5 + ++counter / numEntities * 0.5; + OnProgress(progress, $"{EntityTypeName} - '{gameEntity.Name}'"); + context[0] = gameEntity.Name; + VerifyEntity(gameEntity, context, progress, token); + } + + PostEntityVerify(token); + } + + protected virtual void PostEntityVerify(CancellationToken token) + { + } + + protected abstract void VerifyEntity(T entity, string[] context, double progress, CancellationToken token); + + protected virtual void PreEntityVerify(CancellationToken token) + { + VerifyDuplicates(token); + } + + private void VerifyDuplicates(CancellationToken token) + { + LogCheckingEntityTypeForDuplicateEntries(Logger, EntityTypeName); + var context = IDuplicateVerificationContext.CreateForNamedXmlObjects(GameManager, EntityTypeName); + var verifier = new DuplicateVerifier(this, GameEngine, Settings, Services); + verifier.Verify(context, [], token); + foreach (var error in verifier.VerifyErrors) + AddError(error); + } + + [LoggerMessage(LogLevel.Trace, "Verifying {entityType} - '{name}'")] + static partial void LogVerifyingEntityTypeName(ILogger? logger, string entityType, string name); + + [LoggerMessage(LogLevel.Debug, "Checking {entityType} for duplicate entries")] + static partial void LogCheckingEntityTypeForDuplicateEntries(ILogger logger, string entityType); +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs b/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs deleted file mode 100644 index de56c33..0000000 --- a/src/ModVerify/Verifiers/ReferencedModelsVerifier.cs +++ /dev/null @@ -1,68 +0,0 @@ -using AET.ModVerify.Settings; -using AET.ModVerify.Verifiers.Commons; -using PG.StarWarsGame.Engine; -using System; -using System.Linq; -using System.Threading; - -namespace AET.ModVerify.Verifiers; - -// TODO: Add GameObjectTypeVerifier and check that LandModelTerrainOverride is correct (all keys correct, no dups) - -public sealed class ReferencedModelsVerifier( - IStarWarsGameEngine engine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifier(null, engine, settings, serviceProvider) -{ - public override string FriendlyName => "Referenced Models"; - - public override void Verify(CancellationToken token) - { - var gameObjectEntries = GameEngine.GameObjectTypeManager.Entries.ToList(); - var hardcodedModels = FocHardcodedConstants.HardcodedModels.ToList(); - - var totalModelsCount = - gameObjectEntries - .Sum(x => GameEngine.GameObjectTypeManager.GetModels(x).Count()) - + hardcodedModels.Count; - - if (totalModelsCount == 0) - return; - - var counter = 0; - - var inner = new SingleModelVerifier(this, GameEngine, Settings, Services); - try - { - inner.Error += OnModelError; - - var context = new string[1]; - foreach (var gameObject in gameObjectEntries) - { - context[0] = $"GameObject: {gameObject.Name}"; - foreach (var model in GameEngine.GameObjectTypeManager.GetModels(gameObject)) - { - OnProgress((double)++counter / totalModelsCount, $"Model - '{model}'"); - inner.Verify(model, context, token); - } - } - - context[0] = "Hardcoded Model"; - foreach (var hardcodedModel in hardcodedModels) - { - OnProgress((double)++counter / totalModelsCount, $"Model - '{hardcodedModel}'"); - inner.Verify(hardcodedModel, context, token); - } - } - finally - { - inner.Error -= OnModelError; - } - } - - private void OnModelError(object sender, VerificationErrorEventArgs e) - { - AddError(e.Error); - } -} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs deleted file mode 100644 index d946402..0000000 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Duplicates.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Threading; -using AET.ModVerify.Verifiers.Commons; -using AET.ModVerify.Verifiers.Utilities; - -namespace AET.ModVerify.Verifiers.SfxEvents; - -public partial class SfxEventVerifier -{ - private void VerifyDuplicates(CancellationToken token) - { - var context = IDuplicateVerificationContext.CreateForNamedXmlObjects(GameEngine.SfxGameManager, "SFXEvent"); - var verifier = new DuplicateVerifier(this, GameEngine, Settings, Services); - verifier.Verify(context, [], token); - foreach (var error in verifier.VerifyErrors) - AddError(error); - } -} diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs index 789b09c..68aee32 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.Samples.cs @@ -1,7 +1,6 @@ using System; using System.Buffers; using System.Threading; -using AET.ModVerify.Reporting; using AET.ModVerify.Verifiers.Commons; using AnakinRaW.CommonUtilities.FileSystem.Normalization; using PG.StarWarsGame.Engine; @@ -12,29 +11,17 @@ namespace AET.ModVerify.Verifiers.SfxEvents; public partial class SfxEventVerifier { - private void VerifySamples(SfxEvent sfxEvent, CancellationToken token) + private void VerifySamples(SfxEvent sfxEvent, string[] context, CancellationToken token) { - EventHandler errorHandler = (_, e) => AddError(e.Error); - _audioFileVerifier.Error += errorHandler; - - try - { - var isAmbient = IsAmbient2D(sfxEvent); - - foreach (var codedSample in sfxEvent.AllSamples) - { - VerifySample(codedSample.AsSpan(), sfxEvent, isAmbient, token); - } - } - finally - { - _audioFileVerifier.Error -= errorHandler; - } + var isAmbient = IsAmbient2D(sfxEvent); + foreach (var codedSample in sfxEvent.AllSamples) + VerifySample(codedSample.AsSpan(), sfxEvent, context, isAmbient, token); } private void VerifySample( ReadOnlySpan sample, - SfxEvent sfxEvent, + SfxEvent sfxEvent, + string[] context, bool isAmbient, CancellationToken token) { @@ -53,7 +40,7 @@ private void VerifySample( { foreach (var language in _languagesToVerify) { - VerifySampleLocalized(sfxEvent, sampleNameBuffer, isAmbient, language, out var localized, token); + VerifySampleLocalized(context, sampleNameBuffer, isAmbient, language, out var localized, token); if (!localized) { // There is no reason to continue if we failed to localize the sample name, because the verification will fail anyway @@ -65,7 +52,7 @@ private void VerifySample( else { var audioInfo = new AudioFileInfo(sampleNameBuffer.ToString(), AudioFileType.Wav, isAmbient); - _audioFileVerifier.Verify(audioInfo, [sfxEvent.Name], token); + _audioFileVerifier.Verify(audioInfo, context, token); } } finally @@ -75,7 +62,12 @@ private void VerifySample( } } - private void VerifySampleLocalized(SfxEvent sfxEvent, ReadOnlySpan sample, bool isAmbient, LanguageType language, out bool localized, CancellationToken token) + private void VerifySampleLocalized(string[] context, + ReadOnlySpan sample, + bool isAmbient, + LanguageType language, + out bool localized, + CancellationToken token) { char[]? pooledBuffer = null; @@ -88,7 +80,7 @@ private void VerifySampleLocalized(SfxEvent sfxEvent, ReadOnlySpan sample, var localizedName = buffer.Slice(0, l); var audioInfo = new AudioFileInfo(localizedName.ToString(), AudioFileType.Wav, isAmbient); - _audioFileVerifier.Verify(audioInfo, [sfxEvent.Name], token); + _audioFileVerifier.Verify(audioInfo, context, token); } finally { diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs index 5c04cae..5a90f2b 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs @@ -1,21 +1,20 @@ -using System.Threading; -using AET.ModVerify.Reporting; +using AET.ModVerify.Reporting; using PG.StarWarsGame.Engine.Audio.Sfx; namespace AET.ModVerify.Verifiers.SfxEvents; public partial class SfxEventVerifier { - private void VerifyPresetRef(SfxEvent sfxEvent, CancellationToken token) + private void VerifyPresetRef(SfxEvent sfxEvent, string[] context) { if (!string.IsNullOrEmpty(sfxEvent.UsePresetName) && sfxEvent.Preset is null) { AddError(VerificationError.Create( VerifierChain, VerifierErrorCodes.MissingXRef, - $"SFX Event '{sfxEvent.Name}' has Use_Preset set to '{sfxEvent.UsePresetName}' but the preset could not be found.", + $"Missing preset '{sfxEvent.UsePresetName}' for SFXEvent '{sfxEvent.Name}'.", VerificationSeverity.Error, - [sfxEvent.Name], + context, sfxEvent.UsePresetName)); } } diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs index bc09317..ad9b3ea 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs @@ -8,10 +8,11 @@ using System.Collections.Generic; using System.IO.Abstractions; using System.Threading; +using PG.StarWarsGame.Engine.Audio.Sfx; namespace AET.ModVerify.Verifiers.SfxEvents; -public sealed partial class SfxEventVerifier : GameVerifier +public sealed partial class SfxEventVerifier : NamedGameEntityVerifier { private static readonly PathNormalizeOptions SampleNormalizerOptions = new() { @@ -25,10 +26,12 @@ public sealed partial class SfxEventVerifier : GameVerifier private readonly AudioFileVerifier _audioFileVerifier; private readonly IReadOnlyCollection _languagesToVerify; + public override IGameManager GameManager => GameEngine.SfxGameManager; public override string FriendlyName => "SFX Events"; + public override string EntityTypeName => "SFXEvent"; public SfxEventVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) - : base(null, gameEngine, settings, serviceProvider) + : base( gameEngine, settings, serviceProvider) { _languageManager = serviceProvider.GetRequiredService() .GetLanguageManager(Repository.EngineType); @@ -37,19 +40,16 @@ public SfxEventVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings setti _languagesToVerify = GetLanguagesToVerify(); } - public override void Verify(CancellationToken token) + protected override void VerifyEntity(SfxEvent entity, string[] context, double progress, CancellationToken token) { - VerifyDuplicates(token); - - var numEvents = GameEngine.SfxGameManager.Entries.Count; - double counter = 0; - foreach (var sfxEvent in GameEngine.SfxGameManager.Entries) - { - OnProgress(++counter / numEvents, $"SFX Event - '{sfxEvent.Name}'"); + VerifyPresetRef(entity, context); + VerifySamples(entity, context, token); + } - VerifyPresetRef(sfxEvent, token); - VerifySamples(sfxEvent, token); - } + protected override void PostEntityVerify(CancellationToken token) + { + foreach (var sampleError in _audioFileVerifier.VerifyErrors) + AddError(sampleError); } private IReadOnlyCollection GetLanguagesToVerify() From bac693b5b6e7407d427ca4fba830e5a414243a54 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Mar 2026 12:41:37 +0100 Subject: [PATCH 28/41] refactor ctors --- .../CommandBarVerifier.Components.cs | 0 .../CommandBar/CommandBarVerifier.Groups.cs | 0 .../CommandBar/CommandBarVerifier.cs | 2 +- .../Verifiers/Commons/AudioFileVerifier.cs | 22 +++++--- .../Verifiers/Commons/DuplicateVerifier.cs | 20 ++++--- .../Verifiers/Commons/ModelVerifier.cs | 8 ++- .../Verifiers/Commons/TextureVeifier.cs | 20 ++++--- .../Engine/GameEngineErrorCollector.cs | 2 +- .../GameObjects/GameObjectTypeVerifier.cs | 2 +- src/ModVerify/Verifiers/GameVerifier.cs | 52 ++++++++++++++----- src/ModVerify/Verifiers/GameVerifierBase.cs | 22 ++++++++ .../GuiDialogs/GuiDialogsVerifier.cs | 8 +-- .../Verifiers/SfxEvents/SfxEventVerifier.cs | 9 ++-- 13 files changed, 126 insertions(+), 41 deletions(-) rename src/ModVerify/Verifiers/{GameObjects => }/CommandBar/CommandBarVerifier.Components.cs (100%) rename src/ModVerify/Verifiers/{GameObjects => }/CommandBar/CommandBarVerifier.Groups.cs (100%) rename src/ModVerify/Verifiers/{GameObjects => }/CommandBar/CommandBarVerifier.cs (93%) diff --git a/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Components.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs similarity index 100% rename from src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Components.cs rename to src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs diff --git a/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Groups.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs similarity index 100% rename from src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.Groups.cs rename to src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs diff --git a/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs similarity index 93% rename from src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.cs rename to src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs index 3a6301a..6180d1b 100644 --- a/src/ModVerify/Verifiers/GameObjects/CommandBar/CommandBarVerifier.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs @@ -6,7 +6,7 @@ namespace AET.ModVerify.Verifiers.CommandBar; public partial class CommandBarVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) - : GameVerifier(null, gameEngine, settings, serviceProvider) + : GameVerifier(gameEngine, settings, serviceProvider) { public const string CommandBarNoShellsGroup = "CMDBAR00"; public const string CommandBarManyShellsGroup = "CMDBAR01"; diff --git a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs index 9f0dd85..1de7e95 100644 --- a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs @@ -9,14 +9,22 @@ namespace AET.ModVerify.Verifiers.Commons; -public class AudioFileVerifier( - IGameVerifierInfo? parent, - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifier(parent, gameEngine, settings, serviceProvider) +public class AudioFileVerifier : GameVerifier { - private readonly IAlreadyVerifiedCache? _alreadyVerifiedCache = serviceProvider.GetService(); + private readonly IAlreadyVerifiedCache? _alreadyVerifiedCache; + + public AudioFileVerifier(GameVerifierBase parent) : base(parent) + { + _alreadyVerifiedCache = Services.GetService(); + } + + public AudioFileVerifier(IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) : base(parent, gameEngine, settings, serviceProvider) + { + _alreadyVerifiedCache = serviceProvider.GetService(); + } public override string FriendlyName => "Audio File format"; diff --git a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs index 6d6cd3b..5f4ede8 100644 --- a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs @@ -7,13 +7,21 @@ namespace AET.ModVerify.Verifiers.Commons; -public sealed class DuplicateVerifier( - IGameVerifierInfo? parent, - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifier(parent, gameEngine, settings, serviceProvider) +public sealed class DuplicateVerifier : GameVerifier { + public DuplicateVerifier(GameVerifierBase parent) : base(parent) + { + } + + public DuplicateVerifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : base(parent, gameEngine, settings, serviceProvider) + { + } + public override string FriendlyName => "Duplicates"; public override void Verify(IDuplicateVerificationContext toVerify, IReadOnlyCollection contextInfo, CancellationToken token) diff --git a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs index 3acf1ff..ad9cadb 100644 --- a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs @@ -25,13 +25,19 @@ public sealed class SingleModelVerifier : GameVerifier private readonly TextureVeifier _textureVerifier; private readonly IAlreadyVerifiedCache? _cache; + public SingleModelVerifier(GameVerifierBase parent) : base(parent) + { + _textureVerifier = new TextureVeifier(this); + _cache = Services.GetService(); + } + public SingleModelVerifier( IGameVerifierInfo? parent, IStarWarsGameEngine engine, GameVerifySettings settings, IServiceProvider serviceProvider) : base(parent, engine, settings, serviceProvider) { - _textureVerifier = new TextureVeifier(this, engine, settings, serviceProvider); + _textureVerifier = new TextureVeifier(this); _cache = serviceProvider.GetService(); } diff --git a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs b/src/ModVerify/Verifiers/Commons/TextureVeifier.cs index c81bd0e..9aa6cbb 100644 --- a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs +++ b/src/ModVerify/Verifiers/Commons/TextureVeifier.cs @@ -8,13 +8,21 @@ namespace AET.ModVerify.Verifiers.Commons; -public sealed class TextureVeifier( - IGameVerifierInfo? parent, - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifier(parent, gameEngine, settings, serviceProvider) +public sealed class TextureVeifier : GameVerifier { + public TextureVeifier(GameVerifierBase parent) : base(parent) + { + } + + public TextureVeifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) : + base(parent, gameEngine, settings, serviceProvider) + { + } + public override void Verify(string texturePath, IReadOnlyCollection contextInfo, CancellationToken token) { Verify(texturePath.AsSpan(), contextInfo, token); diff --git a/src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs b/src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs index 0dee603..70c1cb3 100644 --- a/src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs +++ b/src/ModVerify/Verifiers/Engine/GameEngineErrorCollector.cs @@ -13,7 +13,7 @@ public sealed class GameEngineErrorCollector( IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) - : GameVerifier(null, gameEngine, settings, serviceProvider) + : GameVerifier(gameEngine, settings, serviceProvider) { public override string FriendlyName => "Game Engine Initialization"; diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs index 1d74754..179ebfc 100644 --- a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs @@ -24,7 +24,7 @@ public GameObjectTypeVerifier( IServiceProvider serviceProvider) : base(gameEngine, settings, serviceProvider) { - _singleModelVerifier = new SingleModelVerifier(this, gameEngine, settings, serviceProvider); + _singleModelVerifier = new SingleModelVerifier(this); } protected override void VerifyEntity(GameObject entity, string[] context, double progress, CancellationToken token) diff --git a/src/ModVerify/Verifiers/GameVerifier.cs b/src/ModVerify/Verifiers/GameVerifier.cs index aebfe94..83871d9 100644 --- a/src/ModVerify/Verifiers/GameVerifier.cs +++ b/src/ModVerify/Verifiers/GameVerifier.cs @@ -6,22 +6,50 @@ namespace AET.ModVerify.Verifiers; -public abstract class GameVerifier( - IGameVerifierInfo? parent, - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifierBase(parent, gameEngine, settings, serviceProvider) where T : notnull +public abstract class GameVerifier : GameVerifierBase where T : notnull { + protected GameVerifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) : base(parent, gameEngine, settings, serviceProvider) + { + } + protected GameVerifier(GameVerifierBase parent) : base(parent) + { + } + + protected GameVerifier( + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) : base(gameEngine, settings, serviceProvider) + { + } + public abstract void Verify(T toVerify, IReadOnlyCollection contextInfo, CancellationToken token); } -public abstract class GameVerifier( - IGameVerifierInfo? parent, - IStarWarsGameEngine gameEngine, - GameVerifySettings settings, - IServiceProvider serviceProvider) - : GameVerifierBase(parent, gameEngine, settings, serviceProvider) +public abstract class GameVerifier : GameVerifierBase { + protected GameVerifier( + IGameVerifierInfo? parent, + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : base(parent, gameEngine, settings, serviceProvider) + { + } + protected GameVerifier(GameVerifierBase parent) : base(parent) + { + } + + protected GameVerifier( + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : base(gameEngine, settings, serviceProvider) + { + } + public abstract void Verify(CancellationToken token); } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameVerifierBase.cs b/src/ModVerify/Verifiers/GameVerifierBase.cs index c74a6a9..cb8e044 100644 --- a/src/ModVerify/Verifiers/GameVerifierBase.cs +++ b/src/ModVerify/Verifiers/GameVerifierBase.cs @@ -40,6 +40,28 @@ public abstract class GameVerifierBase : IGameVerifierInfo protected IReadOnlyList VerifierChain { get; } + + protected GameVerifierBase(GameVerifierBase parent) + { + if (parent == null) + throw new ArgumentNullException(nameof(parent)); + Services = parent.Services; + Logger = Services.GetService()?.CreateLogger(GetType()) ?? NullLogger.Instance; + FileSystem = Services.GetRequiredService(); + Parent = parent; + Settings = parent.Settings; + GameEngine = parent.GameEngine; + VerifierChain = CreateVerifierChain(); + } + + protected GameVerifierBase( + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : this (null, gameEngine, settings, serviceProvider) + { + } + protected GameVerifierBase( IGameVerifierInfo? parent, IStarWarsGameEngine gameEngine, diff --git a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs index 320815e..cdc2c7e 100644 --- a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs +++ b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs @@ -22,12 +22,14 @@ sealed class GuiDialogsVerifier : GameVerifier private readonly IAlreadyVerifiedCache? _cache; private readonly TextureVeifier _textureVerifier; - public GuiDialogsVerifier(IStarWarsGameEngine gameEngine, + public GuiDialogsVerifier( + IStarWarsGameEngine gameEngine, GameVerifySettings settings, - IServiceProvider serviceProvider) : base(null, gameEngine, settings, serviceProvider) + IServiceProvider serviceProvider) + : base(gameEngine, settings, serviceProvider) { _cache = serviceProvider.GetService(); - _textureVerifier = new TextureVeifier(this, gameEngine, settings, serviceProvider); + _textureVerifier = new TextureVeifier(this); } public override void Verify(CancellationToken token) diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs index ad9b3ea..d19c248 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs @@ -30,13 +30,16 @@ public sealed partial class SfxEventVerifier : NamedGameEntityVerifier public override string FriendlyName => "SFX Events"; public override string EntityTypeName => "SFXEvent"; - public SfxEventVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) - : base( gameEngine, settings, serviceProvider) + public SfxEventVerifier( + IStarWarsGameEngine gameEngine, + GameVerifySettings settings, + IServiceProvider serviceProvider) + : base(gameEngine, settings, serviceProvider) { _languageManager = serviceProvider.GetRequiredService() .GetLanguageManager(Repository.EngineType); _fileSystem = serviceProvider.GetRequiredService(); - _audioFileVerifier = new AudioFileVerifier(this, gameEngine, settings, serviceProvider); + _audioFileVerifier = new AudioFileVerifier(this); _languagesToVerify = GetLanguagesToVerify(); } From e33b5d455f0f40e2100f78f2142c81cb7587b026 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Mar 2026 13:17:51 +0100 Subject: [PATCH 29/41] refactor verifierchain --- .../Properties/launchSettings.json | 2 +- .../Engine/EngineErrorReporterBase.cs | 18 ++++++++---- .../Reporting/RestoredVerifierInfo.cs | 5 ++++ src/ModVerify/Reporting/VerificationError.cs | 14 +++++---- .../CommandBarVerifier.Components.cs | 10 +++---- .../CommandBar/CommandBarVerifier.Groups.cs | 6 ++-- .../Verifiers/Commons/AudioFileVerifier.cs | 10 +++---- .../Verifiers/Commons/DuplicateVerifier.cs | 2 +- .../Verifiers/Commons/ModelVerifier.cs | 18 ++++++------ .../Verifiers/Commons/TextureVeifier.cs | 4 +-- .../GameObjectTypeVerifier.XRef.cs | 2 +- src/ModVerify/Verifiers/GameVerifierBase.cs | 29 ++++--------------- .../GuiDialogs/GuiDialogsVerifier.cs | 8 ++--- src/ModVerify/Verifiers/IGameVerifierInfo.cs | 6 +++- .../SfxEvents/SfxEventVerifier.XRef.cs | 2 +- .../Utilities/GameVerifierInfoExtensions.cs | 18 ++++++++++++ 16 files changed, 86 insertions(+), 68 deletions(-) create mode 100644 src/ModVerify/Verifiers/Utilities/GameVerifierInfoExtensions.cs diff --git a/src/ModVerify.CliApp/Properties/launchSettings.json b/src/ModVerify.CliApp/Properties/launchSettings.json index 128bcdd..06a3b72 100644 --- a/src/ModVerify.CliApp/Properties/launchSettings.json +++ b/src/ModVerify.CliApp/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Verify": { "commandName": "Project", - "commandLineArgs": "" + "commandLineArgs": "verify --offline" }, "Verify (Interactive)": { "commandName": "Project", diff --git a/src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs b/src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs index 7200f23..f8c7cd2 100644 --- a/src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs +++ b/src/ModVerify/Reporting/Engine/EngineErrorReporterBase.cs @@ -6,25 +6,33 @@ namespace AET.ModVerify.Reporting.Engine; -internal abstract class EngineErrorReporterBase(IGameRepository gameRepository, IServiceProvider serviceProvider) - : IGameVerifierInfo +internal abstract class EngineErrorReporterBase : IGameVerifierInfo { - protected readonly IGameRepository GameRepository = gameRepository ?? throw new ArgumentNullException(nameof(gameRepository)); - protected readonly IServiceProvider ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + protected readonly IGameRepository GameRepository; + protected readonly IServiceProvider ServiceProvider; public IGameVerifierInfo? Parent => null; + public IReadOnlyList VerifierChain { get; } + public string Name => GetType().FullName; public abstract string FriendlyName { get; } + protected EngineErrorReporterBase(IGameRepository gameRepository, IServiceProvider serviceProvider) + { + GameRepository = gameRepository ?? throw new ArgumentNullException(nameof(gameRepository)); + ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + VerifierChain = [this]; + } + public IEnumerable GetErrors(IEnumerable errors) { foreach (var error in errors) { var errorData = CreateError(error); yield return new VerificationError( - errorData.Identifier, errorData.Message, [this], errorData.Context, errorData.Asset, errorData.Severity); + errorData.Identifier, errorData.Message, this, errorData.Context, errorData.Asset, errorData.Severity); } } diff --git a/src/ModVerify/Reporting/RestoredVerifierInfo.cs b/src/ModVerify/Reporting/RestoredVerifierInfo.cs index 0c29488..0f0a87b 100644 --- a/src/ModVerify/Reporting/RestoredVerifierInfo.cs +++ b/src/ModVerify/Reporting/RestoredVerifierInfo.cs @@ -1,10 +1,15 @@ using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.Utilities; +using System.Collections.Generic; namespace AET.ModVerify.Reporting; internal sealed class RestoredVerifierInfo : IGameVerifierInfo { public IGameVerifierInfo? Parent { get; init; } + + public IReadOnlyList VerifierChain => field ??= this.GetVerifierChain(); + public required string Name { get; init; } public string FriendlyName => Name; } \ No newline at end of file diff --git a/src/ModVerify/Reporting/VerificationError.cs b/src/ModVerify/Reporting/VerificationError.cs index d55f71b..334b7c6 100644 --- a/src/ModVerify/Reporting/VerificationError.cs +++ b/src/ModVerify/Reporting/VerificationError.cs @@ -28,11 +28,13 @@ public sealed class VerificationError : IEquatable public VerificationError( string id, string message, - IReadOnlyList verifiers, + IGameVerifierInfo verifier, IEnumerable contextEntries, string asset, VerificationSeverity severity) { + if (verifier == null) + throw new ArgumentNullException(nameof(verifier)); if (contextEntries == null) throw new ArgumentNullException(nameof(contextEntries)); if (asset is null) @@ -41,7 +43,7 @@ public VerificationError( Id = id; Message = message ?? throw new ArgumentNullException(nameof(message)); - VerifierChain = [.. verifiers]; + VerifierChain = verifier.VerifierChain; Severity = severity; ContextEntries = _contextEntries = [.. contextEntries]; Asset = asset; @@ -58,18 +60,18 @@ internal VerificationError(JsonVerificationError error) } public static VerificationError Create( - IReadOnlyList verifiers, + IGameVerifierInfo verifier, string id, string message, VerificationSeverity severity, IEnumerable context, string asset) { - return new VerificationError(id, message, verifiers, context, asset, severity); + return new VerificationError(id, message, verifier, context, asset, severity); } public static VerificationError Create( - IReadOnlyList verifiers, + IGameVerifierInfo verifier, string id, string message, VerificationSeverity severity, @@ -78,7 +80,7 @@ public static VerificationError Create( return new VerificationError( id, message, - verifiers, + verifier, [], asset, severity); diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs index 9b49239..4552cf6 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs @@ -19,7 +19,7 @@ private void VerifyCommandBarComponents() if (!occupiedComponentIds.TryGetValue(component.Id, out var alreadyOccupied)) { AddError(VerificationError.Create( - VerifierChain, + this, CommandBarUnsupportedComponent, $"The CommandBar component '{component.Name}' is not supported by the game.", VerificationSeverity.Information, @@ -32,7 +32,7 @@ private void VerifyCommandBarComponents() if (alreadyOccupied) { - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, VerifierErrorCodes.Duplicate, $"The CommandBar component '{component.Name}' with ID '{component.Id}' already exists.", VerificationSeverity.Warning, @@ -56,7 +56,7 @@ private void VerifyCommandBarModel(CommandBarBaseComponent component) if (shellComponent.ModelPath is null) { - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, CommandBarShellNoModel, $"The CommandBarShellComponent '{component.Name}' has no model specified.", VerificationSeverity.Error, shellComponent.Name)); return; @@ -65,7 +65,7 @@ private void VerifyCommandBarModel(CommandBarBaseComponent component) var model = GameEngine.PGRender.LoadModelAndAnimations(shellComponent.ModelPath.AsSpan(), null); if (model is null) { - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, CommandBarShellNoModel, $"Could not find model '{shellComponent.ModelPath}' for CommandBarShellComponent '{component.Name}'.", VerificationSeverity.Error, [shellComponent.Name], shellComponent.ModelPath)); return; @@ -79,7 +79,7 @@ private void VerifyComponentBone(CommandBarBaseComponent component) if (component.Bone == -1) { - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, CommandBarShellNoModel, $"The CommandBar component '{component.Name}' is not connected to a shell component.", VerificationSeverity.Warning, component.Name)); } diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs index 85f3d73..e3ed107 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Groups.cs @@ -25,14 +25,14 @@ private void VerifyCommandBarShellsGroups() } if (shellGroups.Count == 0) - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, CommandBarNoShellsGroup, $"No CommandBarGroup '{CommandBarConstants.ShellGroupName}' found.", VerificationSeverity.Error, "GameCommandBar")); if (shellGroups.Count > 1) - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, CommandBarManyShellsGroup, $"Found more than one Shells CommandBarGroup. Mind that group names are case-sensitive. Correct name is '{CommandBarConstants.ShellGroupName}'", VerificationSeverity.Warning, @@ -46,7 +46,7 @@ private void VerifyShellGroup(CommandBarComponentGroup shellGroup) var shellComponent = component as CommandBarShellComponent; if (shellComponent?.Type is not CommandBarComponentType.Shell) { - AddError(VerificationError.Create(VerifierChain, + AddError(VerificationError.Create(this, CommandBarNoShellsComponentInShellGroup, $"The CommandBar component '{component.Name}' is not a shell component, but part of the '{CommandBarConstants.ShellGroupName}' group.", VerificationSeverity.Warning, component.Name)); diff --git a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs index 1de7e95..077324a 100644 --- a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs @@ -36,7 +36,7 @@ public override void Verify(AudioFileInfo sampleInfo, IReadOnlyCollection 1 && !sampleInfo.IsAmbient) { AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.SampleNotMono, $"Audio file '{sampleString}' is not mono audio.", VerificationSeverity.Information, @@ -93,7 +93,7 @@ public override void Verify(AudioFileInfo sampleInfo, IReadOnlyCollection 48_000) { AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidSampleRate, $"Audio file '{sampleString}' has a too high sample rate of {sampleRate}. Maximum is 48.000Hz.", VerificationSeverity.Error, @@ -104,7 +104,7 @@ public override void Verify(AudioFileInfo sampleInfo, IReadOnlyCollection 16) { AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidBitsPerSeconds, $"Audio file '{sampleString}' has an invalid bit size of {bitPerSecondPerChannel}. Supported are 16bit.", VerificationSeverity.Error, diff --git a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs index 5f4ede8..f5179a6 100644 --- a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs @@ -31,7 +31,7 @@ public override void Verify(IDuplicateVerificationContext toVerify, IReadOnlyCol if (toVerify.HasDuplicates(crc32, out var entryNames, out var context, out var errorMessage)) { AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.Duplicate, errorMessage, VerificationSeverity.Error, diff --git a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs index ad9cadb..7ca3eac 100644 --- a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/ModelVerifier.cs @@ -72,7 +72,7 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte { var modelNameString = modelName.ToString(); var error = VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.FileNotFound, $"Unable to find .ALO file '{modelNameString}'", VerificationSeverity.Error, @@ -95,7 +95,7 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte { var aloFilePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), modelPath.AsSpan()).ToString(); var message = $"'{aloFilePath}' is corrupted: {e.Message}"; - AddError(VerificationError.Create(VerifierChain, VerifierErrorCodes.FileCorrupt, message, + AddError(VerificationError.Create(this, VerifierErrorCodes.FileCorrupt, message, VerificationSeverity.Critical, contextInfo, aloFilePath)); return; } @@ -139,7 +139,7 @@ private void VerifyParticle(IAloParticleFile file, IReadOnlyCollection c { var particlePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), file.FilePath.AsSpan()).ToString(); AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidFilePath, $"Invalid texture file name '{texture}' in particle '{particlePath}'", VerificationSeverity.Error, @@ -154,7 +154,7 @@ private void VerifyParticle(IAloParticleFile file, IReadOnlyCollection c { var particlePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), file.FilePath.AsSpan()).ToString(); AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidParticleName, $"The particle name '{file.Content.Name}' does not match file name '{particlePath}'", VerificationSeverity.Error, @@ -173,7 +173,7 @@ private void VerifyModel(IAloModelFile file, IReadOnlyCollection context { var modelFilePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), file.FilePath.AsSpan()).ToString(); AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidFilePath, $"Invalid texture file name '{texture}' in model '{modelFilePath}'", VerificationSeverity.Error, @@ -191,7 +191,7 @@ private void VerifyModel(IAloModelFile file, IReadOnlyCollection context var modelFilePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), file.FilePath.AsSpan()).ToString(); AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidFilePath, $"Invalid shader file name '{shader}' in model '{modelFilePath}'", VerificationSeverity.Error, @@ -210,7 +210,7 @@ private void VerifyModel(IAloModelFile file, IReadOnlyCollection context var modelFilePath = FileSystem.Path .GetGameStrippedPath(Repository.Path.AsSpan(), file.FilePath.AsSpan()).ToString(); AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.InvalidFilePath, $"Invalid proxy file name '{proxy}' for model '{modelFilePath}'", VerificationSeverity.Error, @@ -238,7 +238,7 @@ private void VerifyProxyExists(IPetroglyphFileHolder model, string proxy, IReadO { var message = $"Proxy particle '{proxyName}' not found for model '{modelFilePath}'"; var error = VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.FileNotFound, message, VerificationSeverity.Error, @@ -261,7 +261,7 @@ private void VerifyShaderExists(IPetroglyphFileHolder model, string shader, IRea var modelFilePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), model.FilePath.AsSpan()).ToString(); var message = $"Shader effect '{shader}' not found for model '{modelFilePath}'."; var error = VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.FileNotFound, message, VerificationSeverity.Error, diff --git a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs b/src/ModVerify/Verifiers/Commons/TextureVeifier.cs index 9aa6cbb..5fc9a55 100644 --- a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs +++ b/src/ModVerify/Verifiers/Commons/TextureVeifier.cs @@ -39,7 +39,7 @@ public void Verify(ReadOnlySpan textureName, IReadOnlyCollection c if (tooLongPath) { - AddError(VerificationError.Create(VerifierChain, VerifierErrorCodes.FilePathTooLong, + AddError(VerificationError.Create(this, VerifierErrorCodes.FilePathTooLong, $"Could not find texture '{pathString}' because the engine resolved a path that is too long.", VerificationSeverity.Error, contextInfo, pathString)); return; @@ -56,7 +56,7 @@ public void Verify(ReadOnlySpan textureName, IReadOnlyCollection c messageBuilder.Append('.'); - AddError(VerificationError.Create(VerifierChain, VerifierErrorCodes.FileNotFound, + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, messageBuilder.ToString(), VerificationSeverity.Error, contextInfo, pathString)); } diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs index 3d6b266..0bd952d 100644 --- a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs @@ -10,7 +10,7 @@ private void VerifyXRefs(GameObject gameObject, string[] context) if (!string.IsNullOrEmpty(gameObject.VariantOfExistingTypeName) && gameObject.VariantOfExistingType is null) { AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.MissingXRef, $"Missing base type '{gameObject.VariantOfExistingTypeName}' for GameObject '{gameObject.Name}'", VerificationSeverity.Critical, diff --git a/src/ModVerify/Verifiers/GameVerifierBase.cs b/src/ModVerify/Verifiers/GameVerifierBase.cs index cb8e044..2da47bc 100644 --- a/src/ModVerify/Verifiers/GameVerifierBase.cs +++ b/src/ModVerify/Verifiers/GameVerifierBase.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using PG.StarWarsGame.Engine; +using AET.ModVerify.Verifiers.Utilities; namespace AET.ModVerify.Verifiers; @@ -38,20 +39,14 @@ public abstract class GameVerifierBase : IGameVerifierInfo protected IGameRepository Repository => GameEngine.GameRepository; - protected IReadOnlyList VerifierChain { get; } + public IReadOnlyList VerifierChain { get; } - protected GameVerifierBase(GameVerifierBase parent) + protected GameVerifierBase(GameVerifierBase parent) + : this(parent, parent.GameEngine, parent.Settings, parent.Services) { if (parent == null) throw new ArgumentNullException(nameof(parent)); - Services = parent.Services; - Logger = Services.GetService()?.CreateLogger(GetType()) ?? NullLogger.Instance; - FileSystem = Services.GetRequiredService(); - Parent = parent; - Settings = parent.Settings; - GameEngine = parent.GameEngine; - VerifierChain = CreateVerifierChain(); } protected GameVerifierBase( @@ -76,7 +71,7 @@ protected GameVerifierBase( Parent = parent; Settings = settings ?? throw new ArgumentNullException(nameof(settings)); GameEngine = gameEngine ?? throw new ArgumentNullException(nameof(gameEngine)); - VerifierChain = CreateVerifierChain(); + VerifierChain = this.GetVerifierChain(); } protected void AddError(VerificationError error) @@ -106,18 +101,4 @@ protected void OnProgress(double progress, string? message) { Progress?.Invoke(this, new(progress, message)); } - - private IReadOnlyList CreateVerifierChain() - { - var verifierChain = new List { this }; - - var parent = Parent; - while (parent != null) - { - verifierChain.Insert(0, parent); - parent = parent.Parent; - } - - return verifierChain; - } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs index cdc2c7e..f89cfea 100644 --- a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs +++ b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs @@ -67,8 +67,8 @@ private void VerifyMegaTexturesExist(CancellationToken token) if (GameEngine.GuiDialogManager.MtdFile is null) { var mtdFileName = megaTextureName ?? "<>"; - VerificationError.Create(VerifierChain, VerifierErrorCodes.FileNotFound, $"MtdFile '{mtdFileName}.mtd' could not be found", - VerificationSeverity.Critical, mtdFileName); + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, $"MtdFile '{mtdFileName}.mtd' could not be found", + VerificationSeverity.Critical, mtdFileName)); } if (megaTextureName is not null) @@ -122,7 +122,7 @@ componentType is not GuiComponentType.Scanlines && if (origin == GuiTextureOrigin.MegaTexture && texture.Texture.Length > MtdFileConstants.MaxFileNameSize) { - AddError(VerificationError.Create(VerifierChain, VerifierErrorCodes.FilePathTooLong, + AddError(VerificationError.Create(this, VerifierErrorCodes.FilePathTooLong, $"The filename is too long. Max length is {MtdFileConstants.MaxFileNameSize} characters.", VerificationSeverity.Error, texture.Texture)); } @@ -133,7 +133,7 @@ componentType is not GuiComponentType.Scanlines && if (texture.Texture.Length > PGConstants.MaxMegEntryPathLength) message += " The file name is too long."; - AddError(VerificationError.Create(VerifierChain, VerifierErrorCodes.FileNotFound, + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, message, VerificationSeverity.Error, [component, origin.ToString()], texture.Texture)); } diff --git a/src/ModVerify/Verifiers/IGameVerifierInfo.cs b/src/ModVerify/Verifiers/IGameVerifierInfo.cs index cba43d1..731d605 100644 --- a/src/ModVerify/Verifiers/IGameVerifierInfo.cs +++ b/src/ModVerify/Verifiers/IGameVerifierInfo.cs @@ -1,9 +1,13 @@ -namespace AET.ModVerify.Verifiers; +using System.Collections.Generic; + +namespace AET.ModVerify.Verifiers; public interface IGameVerifierInfo { IGameVerifierInfo? Parent { get; } + IReadOnlyList VerifierChain { get; } + string Name { get; } string FriendlyName { get; } diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs index 5a90f2b..187921d 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs @@ -10,7 +10,7 @@ private void VerifyPresetRef(SfxEvent sfxEvent, string[] context) if (!string.IsNullOrEmpty(sfxEvent.UsePresetName) && sfxEvent.Preset is null) { AddError(VerificationError.Create( - VerifierChain, + this, VerifierErrorCodes.MissingXRef, $"Missing preset '{sfxEvent.UsePresetName}' for SFXEvent '{sfxEvent.Name}'.", VerificationSeverity.Error, diff --git a/src/ModVerify/Verifiers/Utilities/GameVerifierInfoExtensions.cs b/src/ModVerify/Verifiers/Utilities/GameVerifierInfoExtensions.cs new file mode 100644 index 0000000..05787a8 --- /dev/null +++ b/src/ModVerify/Verifiers/Utilities/GameVerifierInfoExtensions.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace AET.ModVerify.Verifiers.Utilities; + +internal static class GameVerifierInfoExtensions +{ + public static IReadOnlyList GetVerifierChain(this IGameVerifierInfo verifier) + { + if (verifier.Parent is null) + return [verifier]; + + var parentChain = verifier.Parent.VerifierChain; + var result = new List(parentChain.Count + 1); + result.AddRange(parentChain); + result.Add(verifier); + return result; + } +} From c6290ced0d536c74517289aedf9b523f5dce6daa Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Mar 2026 16:20:33 +0100 Subject: [PATCH 30/41] hardcoded assets verifier --- src/ModVerify/DefaultGameVerifiersProvider.cs | 8 +- src/ModVerify/ModVerify.csproj.DotSettings | 2 +- .../Engine/HardcodedAssetsVerifier.cs | 36 +++ .../FocHardcodedConstants.cs | 21 -- .../HardcodedEngineAssets.cs | 302 ++++++++++++++++++ 5 files changed, 344 insertions(+), 25 deletions(-) create mode 100644 src/ModVerify/Verifiers/Engine/HardcodedAssetsVerifier.cs delete mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/FocHardcodedConstants.cs create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/HardcodedEngineAssets.cs diff --git a/src/ModVerify/DefaultGameVerifiersProvider.cs b/src/ModVerify/DefaultGameVerifiersProvider.cs index 965af6b..d7ce226 100644 --- a/src/ModVerify/DefaultGameVerifiersProvider.cs +++ b/src/ModVerify/DefaultGameVerifiersProvider.cs @@ -1,12 +1,13 @@ -using System; -using System.Collections.Generic; -using AET.ModVerify.Settings; +using AET.ModVerify.Settings; using AET.ModVerify.Verifiers; using AET.ModVerify.Verifiers.CommandBar; +using AET.ModVerify.Verifiers.Engine; using AET.ModVerify.Verifiers.GameObjects; using AET.ModVerify.Verifiers.GuiDialogs; using AET.ModVerify.Verifiers.SfxEvents; using PG.StarWarsGame.Engine; +using System; +using System.Collections.Generic; namespace AET.ModVerify; @@ -19,6 +20,7 @@ public IEnumerable GetVerifiers( { //yield break; yield return new SfxEventVerifier(gameEngine, settings, serviceProvider); + yield return new HardcodedAssetsVerifier(gameEngine, settings, serviceProvider); yield return new GuiDialogsVerifier(gameEngine, settings, serviceProvider); yield return new GameObjectTypeVerifier(gameEngine, settings, serviceProvider); yield return new CommandBarVerifier(gameEngine, settings, serviceProvider); diff --git a/src/ModVerify/ModVerify.csproj.DotSettings b/src/ModVerify/ModVerify.csproj.DotSettings index dcc29bb..d3b37e3 100644 --- a/src/ModVerify/ModVerify.csproj.DotSettings +++ b/src/ModVerify/ModVerify.csproj.DotSettings @@ -8,5 +8,5 @@ True True True - True + False False \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Engine/HardcodedAssetsVerifier.cs b/src/ModVerify/Verifiers/Engine/HardcodedAssetsVerifier.cs new file mode 100644 index 0000000..69a6800 --- /dev/null +++ b/src/ModVerify/Verifiers/Engine/HardcodedAssetsVerifier.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; +using AET.ModVerify.Settings; +using AET.ModVerify.Verifiers.Commons; +using PG.StarWarsGame.Engine; + +namespace AET.ModVerify.Verifiers.Engine; + +public sealed class HardcodedAssetsVerifier : GameVerifier +{ + private readonly SingleModelVerifier _modelVerifier; + + public HardcodedAssetsVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) + : base(gameEngine, settings, serviceProvider) + { + _modelVerifier = new SingleModelVerifier(this); + } + + public override void Verify(CancellationToken token) + { + OnProgress(0.0d, "Verifying Hardcoded Models"); + VerifyModels(token); + OnProgress(1.0, null); + } + + private void VerifyModels(CancellationToken token) + { + var models = HardcodedEngineAssets.GetHardcodedModels(GameEngine.EngineType); + + foreach (var model in models) + _modelVerifier.Verify(model, [], token); + + foreach (var error in _modelVerifier.VerifyErrors) + AddError(error); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/FocHardcodedConstants.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/FocHardcodedConstants.cs deleted file mode 100644 index d7eb4af..0000000 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/FocHardcodedConstants.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -namespace PG.StarWarsGame.Engine; - -public static class FocHardcodedConstants -{ - /// - /// These models / particles are hardcoded into StarWarsG.exe. - /// - public static IList HardcodedModels { get; } = new List - { - "i_tutorial_arrow.alo", - "p_hero_empire_fx.alo", - "i_tactical_corrupt.alo", - "p_icon_corrupt.alo", - "w_planet_select_neutral.alo", - "i_game_arrow.alo", - "i_galactic_radar.alo", - "W_TextScroll.alo" - }; -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/HardcodedEngineAssets.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/HardcodedEngineAssets.cs new file mode 100644 index 0000000..92a7cdf --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/HardcodedEngineAssets.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; + +namespace PG.StarWarsGame.Engine; + +public static class HardcodedEngineAssets +{ + /// + /// These models / particles are hardcoded into StarWarsG.exe. + /// + public static IList HardcodedFocModels { get; } = new List + { + "i_tutorial_arrow.alo", + "p_hero_empire_fx.alo", + "i_tactical_corrupt.alo", + "p_icon_corrupt.alo", + "w_planet_select_neutral.alo", + "i_game_arrow.alo", + "i_galactic_radar.alo", + "W_TextScroll.alo" + }; + + + /// + /// These models / particles are hardcoded into StarWarsG.exe. + /// + public static IList HardcodedEawModels { get; } = new List + { + "i_tutorial_arrow.alo", + "p_hero_empire_fx.alo", + "w_planet_select_neutral.alo", + "i_game_arrow.alo", + "i_galactic_radar.alo", + "W_TextScroll.alo" + }; + + public static IList HardcodedFocTextures { get; } = new List + { + "splash.tga", + "SPLASH_E3.tga", + "i_button_temporary.tga", + "i_attention00.tga", + "i_tree_arrow_right.tga", + "load_overlay.tga", + "i_pa_weather_sun.tga", + "i_pa_weather_fire.tga", + "i_pa_weather_snow.tga", + "i_pa_weather_rain.tga", + "i_pa_weather_wind.tga", + "Menuback_Overlay.TGA", + "i_button_space_station.tga", + "i_button_ground_base.tga", + "i_button_space_unitcount.tga", + "i_button_ground_unitcount.tga", + "i_dialogue_blank.tga", + "checked_box.tga", + "Galactic_Back.tga", + "Generic_Space.tga", + "Generic_Land.tga", + "red_dot.tga", + "yellow_dot.tga", + "green_dot.tga", + "i_tree_arrow_2right.tga", + "i_tree_arrow_3right.tga", + "i_tree_arrow_down.tga", + "Generic_Flat_B.tga", + "w_generic_white.tga", + "w_shadow_blob.tga", + "w_light_blob.tga", + "p_particle_master.tga", + "missing_texture_xxx.tga", + "D_master_decal.tga", + "p_particle_depth_master.tga", + "MT_CommandBar.tga", + "MT_CommandBarCompressed.dds", + "DEFAULTPOINTER_00.TGA", + "tractor_beam00.tga", + "i_button_unknown.tga", + "i_icon_stealth.tga", + "e_line2.tga", + "e_line.tga", + "i_bar_icons_space.tga", + "i_bar_icons_land.tga", + "e_topbar2.tga", + "e_topbar.tga", + "e_against_frame.tga", + "missing.tga", + "i_encyclopedia_border.tga", + "i_radar_default_blip.tga", + "select_overlay.tga", + "i_icon_raid.tga", + "maptemp.tga", + "shield_range.tga", + "W_galaxy_line.tga", + "W_galaxy_line_alpha.tga", + "W_galaxy_dot.tga", + "i_sa_defend_mode.tga", + "i_sa_deploy.tga", + "i_sa_interdict.tga", + "i_sa_barrage_area.tga", + "i_sa_capture_vehicles.tga", + "i_sa_spread_out.tga", + "i_sa_power_to_engines.tga", + "i_sa_rocket_attack.tga", + "i_sa_power_to_weapons.tga", + "i_sa_tractor_beam.tga", + "i_sa_fire_energy_weapon.tga", + "i_sa_missile_jammer.tga", + "i_sa_evasive_maneuvers.tga", + "i_sa_all_ships_concentrate_fire.tga", + "i_sa_sprint.tga", + "i_sa_stim_pack.tga", + "i_sa_s_foil_mode.tga", + "i_sa_maximum_firepower.tga", + "i_sa_swap_weapons.tga", + "i_sa_full_salvo.tga", + "i_sa_force_cloak.tga", + "i_sa_sensor_jamming.tga", + "i_sa_force_crush.tga", + "i_sa_force_push.tga", + "i_sa_force_lighting.tga", + "i_sa_flame_thrower.tga", + "i_sa_jetpack_jump.tga", + "i_sa_force_protect.tga", + "i_sa_hack_turret.tga", + "i_sa_repair_vehicle.tga", + "i_sa_sticky_bomb.tga", + "i_sa_electronic_scramble.tga", + "i_sa_area_heal.tga", + "i_sa_join_me.tga", + "i_sa_tow_cable_attack.tga", + "i_sa_sensor_ping.tga", + "i_sa_cover_me.tga", + "i_sa_Harmonic_bomb.tga", + "i_sa_drop_bomb.tga", + "i_sa_weaken_enemy.tga", + "i_sa_drain_life.tga", + "i_sa_blast.tga", + "i_sa_shield_flare.tga", + "i_sa_deploy_squad.tga", + "i_sa_stun.tga", + "i_sa_contaminate.tga", + "i_sa_berserker.tga", + "i_sa_force_sight.tga", + "i_sa_saber_throw.tga", + "i_sa_laser_defense.tga", + "i_sa_force_confuse.tga", + "i_sa_leech_shields.tga", + "i_sa_tactical_bribe.tga", + "i_sa_cluster_bomb.tga", + "i_sa_place_remote_bomb.tga", + "i_sa_detonate_remote_bomb.tga", + "i_sa_infection.tga", + "i_sa_proximity_mines.tga", + "i_sa_buzz_droids.tga", + "i_sa_summon.tga", + "i_sa_corrupt_systems.tga", + "i_sa_hunt.tga", + "i_sa_lure.tga", + "i_sa_self_destruct.tga", + "i_sa_deploy_stormtroopers.tga", + "i_sa_ion_cannon_shot.tga", + "i_sa_lucky_shot.tga", + "lightning_default.tga", + "Mon_Mothma.tga", + "Tarkin.tga", + "W_Cable.tga", + "i_information00.tga", + "W_Laser_Pill.tga", + "lensflare.tga", + "W_Space_FOW_Grid.tga", + "W_Space_Reinforce_FOW_Grid.tga", + }; + + public static IList HardcodedEawTextures { get; } = new List + { + "splash.tga", + "i_button_temporary.tga", + "i_attention00.tga", + "i_tree_arrow_right.tga", + "load_overlay.tga", + "i_pa_weather_sun.tga", + "i_pa_weather_fire.tga", + "i_pa_weather_snow.tga", + "i_pa_weather_rain.tga", + "i_pa_weather_wind.tga", + "Menuback_Overlay.TGA", + "i_button_space_station.tga", + "i_button_ground_base.tga", + "i_button_space_unitcount.tga", + "i_button_ground_unitcount.tga", + "i_dialogue_blank.tga", + "checked_box.tga", + "Galactic_Back.tga", + "Generic_Space.tga", + "Generic_Land.tga", + "red_dot.tga", + "yellow_dot.tga", + "green_dot.tga", + "i_tree_arrow_2right.tga", + "i_tree_arrow_3right.tga", + "i_tree_arrow_down.tga", + "Generic_Flat_B.tga", + "w_generic_white.tga", + "w_shadow_blob.tga", + "w_light_blob.tga", + "p_particle_master.tga", + "missing_texture_xxx.tga", + "D_master_decal.tga", + "p_particle_depth_master.tga", + "MT_CommandBar.tga", + "MT_CommandBarCompressed.dds", + "DEFAULTPOINTER_00.TGA", + "tractor_beam00.tga", + "i_button_unknown.tga", + "i_icon_stealth.tga", + "e_line2.tga", + "e_line.tga", + "i_bar_icons_space.tga", + "i_bar_icons_land.tga", + "e_topbar2.tga", + "e_topbar.tga", + "e_against_frame.tga", + "missing.tga", + "i_encyclopedia_border.tga", + "i_radar_default_blip.tga", + "select_overlay.tga", + "i_icon_raid.tga", + "W_galaxy_line.tga", + "W_galaxy_line_alpha.tga", + "W_galaxy_dot.tga", + "i_sa_defend_mode.tga", + "i_sa_deploy.tga", + "i_sa_interdict.tga", + "i_sa_barrage_area.tga", + "i_sa_capture_vehicles.tga", + "i_sa_spread_out.tga", + "i_sa_power_to_engines.tga", + "i_sa_rocket_attack.tga", + "i_sa_power_to_weapons.tga", + "i_sa_tractor_beam.tga", + "i_sa_fire_energy_weapon.tga", + "i_sa_missile_jammer.tga", + "i_sa_evasive_maneuvers.tga", + "i_sa_all_ships_concentrate_fire.tga", + "i_sa_sprint.tga", + "i_sa_s_foil_mode.tga", + "i_sa_maximum_firepower.tga", + "i_sa_force_crush.tga", + "i_sa_force_push.tga", + "i_sa_force_lighting.tga", + "i_sa_flame_thrower.tga", + "i_sa_jetpack_jump.tga", + "i_sa_force_protect.tga", + "i_sa_hack_turret.tga", + "i_sa_repair_vehicle.tga", + "i_sa_sticky_bomb.tga", + "i_sa_electronic_scramble.tga", + "i_sa_area_heal.tga", + "i_sa_join_me.tga", + "i_sa_tow_cable_attack.tga", + "i_sa_sensor_ping.tga", + "i_sa_cover_me.tga", + "i_sa_Harmonic_bomb.tga", + "i_sa_drop_bomb.tga", + "i_sa_weaken_enemy.tga", + "i_sa_hunt.tga", + "i_sa_lure.tga", + "i_sa_self_destruct.tga", + "i_sa_deploy_stormtroopers.tga", + "i_sa_ion_cannon_shot.tga", + "i_sa_lucky_shot.tga", + "lightning_default.tga", + "Mon_Mothma.tga", + "Tarkin.tga", + "W_Cable.tga", + "i_information00.tga", + "W_Laser_Pill.tga", + "W_Space_FOW_Grid.tga", + "W_Space_Reinforce_FOW_Grid.tga", + }; + + public static IList GetHardcodedModels(GameEngineType engine) + { + return engine switch + { + GameEngineType.Eaw => HardcodedEawModels, + GameEngineType.Foc => HardcodedFocModels, + _ => throw new ArgumentOutOfRangeException(nameof(engine), engine, null) + }; + } + + public static IList GetHardcodedTextures(GameEngineType engine) + { + return engine switch + { + GameEngineType.Eaw => HardcodedEawTextures, + GameEngineType.Foc => HardcodedFocTextures, + _ => throw new ArgumentOutOfRangeException(nameof(engine), engine, null) + }; + } +} \ No newline at end of file From 1b613db259e585fcce7711807fcc7ce61c6db928 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Tue, 17 Mar 2026 16:56:52 +0100 Subject: [PATCH 31/41] update deps --- src/ModVerify/ModVerify.csproj | 2 +- test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj index f9b2056..8fce201 100644 --- a/src/ModVerify/ModVerify.csproj +++ b/src/ModVerify/ModVerify.csproj @@ -28,7 +28,7 @@ - + diff --git a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj index 9d4526e..5a852b4 100644 --- a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj +++ b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj @@ -25,7 +25,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 84cd691bd6ba66f78c88bb985ecdb6b1b5666ae4 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sat, 21 Mar 2026 12:37:49 +0100 Subject: [PATCH 32/41] refactorings and new some new verifications --- .../CommandBarVerifier.Components.cs | 60 ++++-------------- .../CommandBarVerifier.MegaTexture.cs | 41 +++++++++++++ .../CommandBarVerifier.SingleComponent.cs | 61 +++++++++++++++++++ .../CommandBar/CommandBarVerifier.cs | 39 +++++++++--- .../Verifiers/Commons/DuplicateVerifier.cs | 4 +- ...odelVerifier.cs => SingleModelVerifier.cs} | 29 +++------ .../{TextureVeifier.cs => TextureVerifier.cs} | 6 +- .../GuiDialogs/GuiDialogsVerifier.cs | 19 +++--- .../CommandBar/CommandBarGameManager.cs | 38 +++++++++++- .../CommandBarGameManager_Initialization.cs | 6 +- .../CommandBar/ICommandBarGameManager.cs | 7 ++- .../PG.StarWarsGame.Engine/IO/IRepository.cs | 2 + .../IO/MultiPassRepository.cs | 25 ++++++-- .../IO/Repositories/GameRepository.Files.cs | 27 ++++++-- 14 files changed, 256 insertions(+), 108 deletions(-) create mode 100644 src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.MegaTexture.cs create mode 100644 src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs rename src/ModVerify/Verifiers/Commons/{ModelVerifier.cs => SingleModelVerifier.cs} (93%) rename src/ModVerify/Verifiers/Commons/{TextureVeifier.cs => TextureVerifier.cs} (92%) diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs index 4552cf6..3b43093 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.Components.cs @@ -1,21 +1,27 @@ -using System; -using System.Linq; -using AET.ModVerify.Reporting; +using AET.ModVerify.Reporting; using PG.StarWarsGame.Engine.CommandBar; -using PG.StarWarsGame.Engine.CommandBar.Components; +using System.Linq; +using System.Threading; namespace AET.ModVerify.Verifiers.CommandBar; partial class CommandBarVerifier { - private void VerifyCommandBarComponents() + private void VerifyCommandBarComponents(CancellationToken token, double startProgress) { var occupiedComponentIds = SupportedCommandBarComponentData .GetComponentIdsForEngine(Repository.EngineType).Keys .ToDictionary(value => value, _ => false); + var counter = 0; + var numEntities = GameEngine.CommandBar.Components.Count; + var num = 1 - startProgress; + foreach (var component in GameEngine.CommandBar.Components) { + var progress = num + (++counter / (double)numEntities) * startProgress; + OnProgress(progress, $"CommandBarComponent - '{component.Name}'"); + if (!occupiedComponentIds.TryGetValue(component.Id, out var alreadyOccupied)) { AddError(VerificationError.Create( @@ -39,49 +45,7 @@ private void VerifyCommandBarComponents() component.Name)); } - VerifySingleComponent(component); - } - } - - private void VerifySingleComponent(CommandBarBaseComponent component) - { - VerifyCommandBarModel(component); - VerifyComponentBone(component); - } - - private void VerifyCommandBarModel(CommandBarBaseComponent component) - { - if (component is not CommandBarShellComponent shellComponent) - return; - - if (shellComponent.ModelPath is null) - { - AddError(VerificationError.Create(this, - CommandBarShellNoModel, $"The CommandBarShellComponent '{component.Name}' has no model specified.", - VerificationSeverity.Error, shellComponent.Name)); - return; - } - - var model = GameEngine.PGRender.LoadModelAndAnimations(shellComponent.ModelPath.AsSpan(), null); - if (model is null) - { - AddError(VerificationError.Create(this, - CommandBarShellNoModel, $"Could not find model '{shellComponent.ModelPath}' for CommandBarShellComponent '{component.Name}'.", - VerificationSeverity.Error, [shellComponent.Name], shellComponent.ModelPath)); - return; - } - } - - private void VerifyComponentBone(CommandBarBaseComponent component) - { - if (component is CommandBarShellComponent) - return; - - if (component.Bone == -1) - { - AddError(VerificationError.Create(this, - CommandBarShellNoModel, $"The CommandBar component '{component.Name}' is not connected to a shell component.", - VerificationSeverity.Warning, component.Name)); + VerifySingleComponent(component, token); } } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.MegaTexture.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.MegaTexture.cs new file mode 100644 index 0000000..8d86bad --- /dev/null +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.MegaTexture.cs @@ -0,0 +1,41 @@ +using System.Threading; +using AET.ModVerify.Reporting; +using AET.ModVerify.Verifiers.Commons; +using AET.ModVerify.Verifiers.Utilities; +using PG.StarWarsGame.Engine.CommandBar; + +namespace AET.ModVerify.Verifiers.CommandBar; + +partial class CommandBarVerifier +{ + private void VerifyMegaTexture(CancellationToken token) + { + if (CommandBar.MtdFile is null) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, + $"Cannot find CommandBar MegaTextureDirectory '{CommandBarConstants.MegaTextureBaseName}.mtd'", + VerificationSeverity.Critical, $"{CommandBarConstants.MegaTextureBaseName}.mtd")); + } + else + { + var dupVerifier = new DuplicateVerifier(this); + dupVerifier.Verify(IDuplicateVerificationContext.CreateForMtd(CommandBar.MtdFile), [], token); + + foreach (var duplicateError in dupVerifier.VerifyErrors) + AddError(duplicateError); + } + + if (CommandBar.MegaTextureFileName is null) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, + $"Cannot find CommandBar MegaTexture '{CommandBarConstants.MegaTextureBaseName}.tga'", + VerificationSeverity.Critical, $"{CommandBarConstants.MegaTextureBaseName}.tga")); + } + else if (!GameEngine.GameRepository.TextureRepository.FileExists(CommandBar.MegaTextureFileName)) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, + $"Cannot find CommandBar MegaTexture '{CommandBarConstants.MegaTextureBaseName}.tga'", + VerificationSeverity.Critical, $"{CommandBarConstants.MegaTextureBaseName}.tga")); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs new file mode 100644 index 0000000..e71d39c --- /dev/null +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs @@ -0,0 +1,61 @@ +using AET.ModVerify.Reporting; +using PG.StarWarsGame.Engine.CommandBar.Components; +using System; +using System.Threading; + +namespace AET.ModVerify.Verifiers.CommandBar; + +partial class CommandBarVerifier +{ + private void VerifySingleComponent(CommandBarBaseComponent component, CancellationToken token) + { + VerifyCommandBarModel(component, token); + VerifyComponentBone(component); + + // TODO: Textures + } + + private void VerifyCommandBarModel(CommandBarBaseComponent component, CancellationToken token) + { + if (component is not CommandBarShellComponent shellComponent) + return; + + if (shellComponent.ModelPath is null) + { + AddError(VerificationError.Create(this, + CommandBarShellNoModel, $"The CommandBarShellComponent '{component.Name}' has no model specified.", + VerificationSeverity.Error, [shellComponent.Name], shellComponent.Name)); + return; + } + + using var model = GameEngine.PGRender.LoadModelAndAnimations(shellComponent.ModelPath.AsSpan(), null); + if (model is null) + { + AddError(VerificationError.Create(this, + CommandBarShellNoModel, $"Could not find model '{shellComponent.ModelPath}' for CommandBarShellComponent '{component.Name}'.", + VerificationSeverity.Error, [shellComponent.Name], shellComponent.ModelPath)); + return; + } + + _modelVerifier.VerifyModelOrParticle(model.File, [shellComponent.Name], token); + + if (model.Animations.Cout == 0) + return; + + // TODO: Verify Animations + + } + + private void VerifyComponentBone(CommandBarBaseComponent component) + { + if (component is CommandBarShellComponent) + return; + + if (component.Bone == -1) + { + AddError(VerificationError.Create(this, + CommandBarShellNoModel, $"The CommandBar component '{component.Name}' is not connected to a shell component.", + VerificationSeverity.Warning, component.Name)); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs index 6180d1b..4894673 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.cs @@ -1,27 +1,52 @@ using System; +using System.Linq; using System.Threading; using AET.ModVerify.Settings; +using AET.ModVerify.Verifiers.Commons; using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.CommandBar; namespace AET.ModVerify.Verifiers.CommandBar; -public partial class CommandBarVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) - : GameVerifier(gameEngine, settings, serviceProvider) -{ +public partial class CommandBarVerifier : GameVerifier +{ public const string CommandBarNoShellsGroup = "CMDBAR00"; public const string CommandBarManyShellsGroup = "CMDBAR01"; public const string CommandBarNoShellsComponentInShellGroup = "CMDBAR02"; public const string CommandBarUnsupportedComponent = "CMDBAR03"; public const string CommandBarShellNoModel = "CMDBAR04"; + private readonly SingleModelVerifier _modelVerifier; + private readonly TextureVerifier _textureVerifier; + public override string FriendlyName => "CommandBar"; + public ICommandBarGameManager CommandBar { get; } + + public CommandBarVerifier(IStarWarsGameEngine gameEngine, GameVerifySettings settings, IServiceProvider serviceProvider) + : base(gameEngine, settings, serviceProvider) + { + CommandBar = gameEngine.CommandBar; + _modelVerifier = new SingleModelVerifier(this); + _textureVerifier = new TextureVerifier(this); + } + public override void Verify(CancellationToken token) { - OnProgress(0.0, "Verifying CommandBar Shell"); + var progress = 0.0d; + OnProgress(progress, "Verifying MegaTexture"); + VerifyMegaTexture(token); + progress = 1 / 3.0; + OnProgress(progress, "Verifying CommandBar Shell"); VerifyCommandBarShellsGroups(); - OnProgress(0.5d, "Verifying CommandBar components"); - VerifyCommandBarComponents(); - OnProgress(1.0d, null); + progress = 2 / 3.0; + OnProgress(progress, "Verifying CommandBar components"); + VerifyCommandBarComponents(token, progress); + + foreach (var subError in _modelVerifier.VerifyErrors.Concat(_textureVerifier.VerifyErrors)) + AddError(subError); + + progress = 1.0; + OnProgress(progress, null); } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs index f5179a6..7aa19e6 100644 --- a/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/DuplicateVerifier.cs @@ -9,6 +9,8 @@ namespace AET.ModVerify.Verifiers.Commons; public sealed class DuplicateVerifier : GameVerifier { + public override string FriendlyName => "Duplicate Verifier"; + public DuplicateVerifier(GameVerifierBase parent) : base(parent) { } @@ -22,8 +24,6 @@ public DuplicateVerifier( { } - public override string FriendlyName => "Duplicates"; - public override void Verify(IDuplicateVerificationContext toVerify, IReadOnlyCollection contextInfo, CancellationToken token) { foreach (var crc32 in toVerify.GetCrcs()) diff --git a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs b/src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs similarity index 93% rename from src/ModVerify/Verifiers/Commons/ModelVerifier.cs rename to src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs index 7ca3eac..11a63bf 100644 --- a/src/ModVerify/Verifiers/Commons/ModelVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs @@ -22,12 +22,12 @@ public sealed class SingleModelVerifier : GameVerifier { private const string ProxyAltIdentifier = "_ALT"; - private readonly TextureVeifier _textureVerifier; + private readonly TextureVerifier _textureVerifier; private readonly IAlreadyVerifiedCache? _cache; public SingleModelVerifier(GameVerifierBase parent) : base(parent) { - _textureVerifier = new TextureVeifier(this); + _textureVerifier = new TextureVerifier(this); _cache = Services.GetService(); } @@ -37,28 +37,18 @@ public SingleModelVerifier( GameVerifySettings settings, IServiceProvider serviceProvider) : base(parent, engine, settings, serviceProvider) { - _textureVerifier = new TextureVeifier(this); + _textureVerifier = new TextureVerifier(this); _cache = serviceProvider.GetService(); } public override void Verify(string modelName, IReadOnlyCollection contextInfo, CancellationToken token) { - try - { - _textureVerifier.Error += OnTextureError; - var modelPath = BuildModelPath(modelName); - VerifyAlamoFile(modelPath, contextInfo, token); - } - finally - { - _textureVerifier.Error -= OnTextureError; - } - } + var modelPath = BuildModelPath(modelName); + VerifyAlamoFile(modelPath, contextInfo, token); - private void OnTextureError(object sender, VerificationErrorEventArgs e) - { - AddError(e.Error); + foreach (var textureError in _textureVerifier.VerifyErrors) + AddError(textureError); } private void VerifyAlamoFile(string modelPath, IReadOnlyCollection contextInfo, CancellationToken token) @@ -111,10 +101,7 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte } } - private void VerifyModelOrParticle( - IAloFile aloFile, - IReadOnlyCollection contextInfo, - CancellationToken token) + public void VerifyModelOrParticle(IAloFile aloFile, IReadOnlyCollection contextInfo, CancellationToken token) { switch (aloFile) { diff --git a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs b/src/ModVerify/Verifiers/Commons/TextureVerifier.cs similarity index 92% rename from src/ModVerify/Verifiers/Commons/TextureVeifier.cs rename to src/ModVerify/Verifiers/Commons/TextureVerifier.cs index 5fc9a55..e7709e3 100644 --- a/src/ModVerify/Verifiers/Commons/TextureVeifier.cs +++ b/src/ModVerify/Verifiers/Commons/TextureVerifier.cs @@ -8,13 +8,13 @@ namespace AET.ModVerify.Verifiers.Commons; -public sealed class TextureVeifier : GameVerifier +public sealed class TextureVerifier : GameVerifier { - public TextureVeifier(GameVerifierBase parent) : base(parent) + public TextureVerifier(GameVerifierBase parent) : base(parent) { } - public TextureVeifier( + public TextureVerifier( IGameVerifierInfo? parent, IStarWarsGameEngine gameEngine, GameVerifySettings settings, diff --git a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs index f89cfea..a5b3a93 100644 --- a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs +++ b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs @@ -20,7 +20,7 @@ sealed class GuiDialogsVerifier : GameVerifier Enum.GetValues(typeof(GuiComponentType)).OfType().ToArray(); private readonly IAlreadyVerifiedCache? _cache; - private readonly TextureVeifier _textureVerifier; + private readonly TextureVerifier _textureVerifier; public GuiDialogsVerifier( IStarWarsGameEngine gameEngine, @@ -29,21 +29,16 @@ public GuiDialogsVerifier( : base(gameEngine, settings, serviceProvider) { _cache = serviceProvider.GetService(); - _textureVerifier = new TextureVeifier(this); + _textureVerifier = new TextureVerifier(this); } public override void Verify(CancellationToken token) { - try - { - _textureVerifier.Error += OnTextureError; - VerifyMegaTexturesExist(token); - VerifyGuiTextures(); - } - finally - { - _textureVerifier.Error -= OnTextureError; - } + VerifyMegaTexturesExist(token); + VerifyGuiTextures(); + + foreach (var textureError in _textureVerifier.VerifyErrors) + AddError(textureError); } private void VerifyGuiTextures() diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 4478fea..56c2e60 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.Numerics; +using PG.StarWarsGame.Engine.GameObjects; namespace PG.StarWarsGame.Engine.CommandBar; @@ -27,7 +28,6 @@ internal partial class CommandBarGameManager( private readonly IMtdFileService _mtdFileService = serviceProvider.GetRequiredService(); private readonly Dictionary _groups = new(); - private bool _megaTextureExists; private FontData? _defaultFont; public ICollection Components => Entries; @@ -48,7 +48,7 @@ private set } } - public IMtdFile? MegaTextureFile + public IMtdFile? MtdFile { get { @@ -62,7 +62,41 @@ private set } } + public string? MegaTextureFileName + { + get + { + ThrowIfNotInitialized(); + return field; + } + private set + { + ThrowIfAlreadyInitialized(); + field = value; + } + } + + public Vector3 CommandBarScale { get; } public Vector3 CommandBarOffset { get; internal set; } + + public bool IconExists(GameObject gameObject) + { + ThrowIfNotInitialized(); + if (gameObject == null) + throw new ArgumentNullException(nameof(gameObject)); + + if (MtdFile is null) + return false; + + //if (string.IsNullOrEmpty(gameObject.IconName)) + // return false; + + //var crc = _hashingService.GetCrc32Upper(gameObject.IconName); + + //return MtdFile.Content.Contains(crc); + + return false; + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs index da82ef6..4835ed3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager_Initialization.cs @@ -201,7 +201,7 @@ private void SetMegaTexture() try { - MegaTextureFile = megaTexture is null ? null : _mtdFileService.Load(megaTexture); + MtdFile = megaTexture is null ? null : _mtdFileService.Load(megaTexture); } catch (BinaryCorruptedException e) { @@ -209,7 +209,9 @@ private void SetMegaTexture() Logger?.LogError(e, message); ErrorReporter.Assert(EngineAssert.Create(EngineAssertKind.CorruptBinary, mtdPath, [], message)); } - _megaTextureExists = GameRepository.TextureRepository.FileExists($"{CommandBarConstants.MegaTextureBaseName}.tga"); + + GameRepository.TextureRepository.FileExists($"{CommandBarConstants.MegaTextureBaseName}.tga", false, out _, out var actualFilePath); + MegaTextureFileName = FileSystem.Path.GetFileName(actualFilePath); } private void SetComponentGroup(IEnumerable components) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/ICommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/ICommandBarGameManager.cs index 665d217..6c2749d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/ICommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/ICommandBarGameManager.cs @@ -1,14 +1,19 @@ using System.Collections.Generic; using PG.StarWarsGame.Engine.CommandBar.Components; +using PG.StarWarsGame.Engine.GameObjects; using PG.StarWarsGame.Files.MTD.Files; namespace PG.StarWarsGame.Engine.CommandBar; public interface ICommandBarGameManager : IGameManager { - IMtdFile? MegaTextureFile { get; } + IMtdFile? MtdFile { get; } + + string? MegaTextureFileName { get; } ICollection Components { get; } IReadOnlyDictionary Groups { get; } + + bool IconExists(GameObject gameObject); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/IRepository.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/IRepository.cs index 4ca45db..89c2d86 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/IRepository.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/IRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; namespace PG.StarWarsGame.Engine.IO; @@ -9,6 +10,7 @@ public interface IRepository Stream OpenFile(ReadOnlySpan filePath, bool megFileOnly = false); bool FileExists(string filePath, bool megFileOnly = false); + bool FileExists(string filePath, bool megFileOnly, out bool inMeg, [NotNullWhen(true)] out string? actualFilePath); bool FileExists(ReadOnlySpan filePath, bool megFileOnly = false); bool FileExists(ReadOnlySpan filePath, bool megFileOnly, out bool pathTooLong); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/MultiPassRepository.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/MultiPassRepository.cs index 0fce4d3..fd95e5b 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/MultiPassRepository.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/MultiPassRepository.cs @@ -1,9 +1,10 @@ -using System; -using System.IO; -using System.IO.Abstractions; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine.IO.Repositories; using PG.StarWarsGame.Engine.Utilities; +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.IO.Abstractions; namespace PG.StarWarsGame.Engine.IO; @@ -30,6 +31,22 @@ public bool FileExists(string filePath, bool megFileOnly = false) return FileExists(filePath.AsSpan(), megFileOnly); } + public bool FileExists(string filePath, bool megFileOnly, out bool inMeg, [NotNullWhen(true)] out string? actualFilePath) + { + var multiPassSb = new ValueStringBuilder(stackalloc char[PGConstants.MaxMegEntryPathLength]); + var destinationSb = new ValueStringBuilder(stackalloc char[PGConstants.MaxMegEntryPathLength]); + var result = MultiPassAction(filePath, ref multiPassSb, ref destinationSb, megFileOnly); + var fileFound = result.FileFound; + inMeg = result.InMeg; + if (!fileFound) + actualFilePath = null; + else + actualFilePath = result.InMeg ? result.MegDataEntryReference.Path : result.FilePath.ToString(); + multiPassSb.Dispose(); + destinationSb.Dispose(); + return fileFound; + } + public bool FileExists(ReadOnlySpan filePath, bool megFileOnly = false) { return FileExists(filePath, megFileOnly, out _); diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/Repositories/GameRepository.Files.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/Repositories/GameRepository.Files.cs index 7abd1b9..d35254d 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/Repositories/GameRepository.Files.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/IO/Repositories/GameRepository.Files.cs @@ -1,14 +1,15 @@ -using System; +using AnakinRaW.CommonUtilities.FileSystem; +using Microsoft.Extensions.Logging; +using PG.StarWarsGame.Engine.IO.Utilities; +using PG.StarWarsGame.Engine.Utilities; +using PG.StarWarsGame.Files.MEG.Binary; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using AnakinRaW.CommonUtilities.FileSystem; -using Microsoft.Extensions.Logging; -using PG.StarWarsGame.Engine.IO.Utilities; -using PG.StarWarsGame.Engine.Utilities; -using PG.StarWarsGame.Files.MEG.Binary; namespace PG.StarWarsGame.Engine.IO.Repositories; @@ -32,6 +33,20 @@ public bool FileExists(string filePath, bool megFileOnly = false) return FileExists(filePath.AsSpan(), megFileOnly); } + public bool FileExists(string filePath, bool megFileOnly, out bool inMeg, [NotNullWhen(true)] out string? actualFilePath) + { + var sb = new ValueStringBuilder(stackalloc char[PGConstants.MaxMegEntryPathLength]); + var fileFound = FindFile(filePath, ref sb, megFileOnly); + var fileExists = fileFound.FileFound; + inMeg = fileFound.InMeg; + if (!fileExists) + actualFilePath = null; + else + actualFilePath = fileFound.InMeg ? fileFound.MegDataEntryReference.Path : fileFound.FilePath.ToString(); + sb.Dispose(); + return fileExists; + } + public bool FileExists(ReadOnlySpan filePath, bool megFileOnly = false) { return FileExists(filePath, megFileOnly, out _); From 4df3b3ce443c313168671f08e0ddab7067d5ed3c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Mar 2026 13:40:24 +0100 Subject: [PATCH 33/41] Verify GameObject icons --- .../GameObjectTypeVerifier.Icons.cs | 41 +++++++++++++++++++ .../GameObjects/GameObjectTypeVerifier.cs | 1 + .../CommandBar/CommandBarGameManager.cs | 10 ++--- .../GameObjects/GameObject.cs | 6 ++- .../Parsers/NamedObjects/GameObjectParser.cs | 9 +++- 5 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Icons.cs diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Icons.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Icons.cs new file mode 100644 index 0000000..36541bb --- /dev/null +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.Icons.cs @@ -0,0 +1,41 @@ +using AET.ModVerify.Reporting; +using PG.StarWarsGame.Engine.GameObjects; + +namespace AET.ModVerify.Verifiers.GameObjects; + +public sealed partial class GameObjectTypeVerifier +{ + private void VerifyIcons(GameObject gameObject, string[] context) + { + VerifyObjectIcon(gameObject, context); + } + + private void VerifyObjectIcon(GameObject gameObject, string[] context) + { + if (string.IsNullOrEmpty(gameObject.IconName)) + return; + + /* + * The engine loads game object icons with different strategies, depending on where the icon is displayed: + * 1. the game loads the texture from MTD and supports the faction prefixes e.g, r_ or e_ + * Faction prefixes have higher priority than the non-prefix versions. The player's faction (not the object owner) is used. + * This applies to all command bar components (such as build buttons) + * 2. the game loads the texture form MTD and does NOT support faction prefix. + * If the texture is not found, the game searches the texture with forced .dds name in the Textures folder. + * This applies to the GUI dialogs (such as battle summary) + * 3. the game only loads the texture from MTD NOT supporting faction prefix nor textures folder fallback. + * This applies (only) to the neutralize hero dialog + * + * We only verify whether the icon exists in the MTD data, as this is the primary case to all strategies + * (and it's what really should only be used for mods) + * Faction-specific icons are not verified as they are statically not decidable. + */ + + if (!GameEngine.CommandBar.IconExists(gameObject)) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, + $"Could not find icon '{gameObject.IconName}' for game object type '{gameObject.Name}'.", + VerificationSeverity.Warning, context, gameObject.IconName!)); + } + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs index 179ebfc..348ae7e 100644 --- a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs @@ -31,6 +31,7 @@ protected override void VerifyEntity(GameObject entity, string[] context, double { VerifyXRefs(entity, context); VerifyModels(entity, context, token); + VerifyIcons(entity, context); } protected override void PostEntityVerify(CancellationToken token) diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs index 56c2e60..a012a50 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/CommandBar/CommandBarGameManager.cs @@ -90,13 +90,11 @@ public bool IconExists(GameObject gameObject) if (MtdFile is null) return false; - //if (string.IsNullOrEmpty(gameObject.IconName)) - // return false; - - //var crc = _hashingService.GetCrc32Upper(gameObject.IconName); + if (string.IsNullOrEmpty(gameObject.IconName)) + return false; - //return MtdFile.Content.Contains(crc); + var crc = _hashingService.GetCrc32Upper(gameObject.IconName, PGConstants.DefaultPGEncoding); - return false; + return MtdFile.Content.Contains(crc); } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index 510f65b..d899e62 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -47,7 +47,8 @@ public sealed class GameObject : NamedXmlObject public string? DamagedSmokeAssetModel { get; internal set; } public IReadOnlyList<(string terrain, string model)> LandTerrainModelMappingValues { get; } - + public string? IconName { get; internal set; } + internal GameObject( string name, string classification, @@ -69,6 +70,7 @@ internal void ApplyBaseType(GameObject baseType) // The following properties must not be inherited from the base type: // ID, CRC, Name, Location, IsLoadingComplete, ClassificationName and VariantOfExistingType[Name], LuaScript + // TODO GalacticModel = baseType.GalacticModel; DestroyedGalacticModel = baseType.DestroyedGalacticModel; LandModel = baseType.LandModel; @@ -80,6 +82,8 @@ internal void ApplyBaseType(GameObject baseType) SpaceAnimOverrideModel = baseType.SpaceAnimOverrideModel; DamagedSmokeAssetModel = baseType.DamagedSmokeAssetModel; InternalLandTerrainModelMapping.ClearAddRange(baseType.InternalLandTerrainModelMapping); + + IconName = baseType.IconName; } internal void PostLoadFixup() diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index c9ce844..8d6d916 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -185,12 +185,17 @@ protected override void BuildMappings() PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.DamagedSmokeAssetModel = val); - + AddMapping( GameObjectXmlTags.GuiModelName, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.GuiModel = val); + AddMapping( + GameObjectXmlTags.IconName, + PetroglyphXmlStringParser.Instance.Parse, + (obj, val) => obj.IconName = val); + AddMapping( GameObjectXmlTags.VariantOfExistingType, PetroglyphXmlStringParser.Instance.Parse, @@ -215,5 +220,7 @@ internal static class GameObjectXmlTags public const string DamagedSmokeAssetName = "Damaged_Smoke_Asset_Name"; public const string VariantOfExistingType = "Variant_Of_Existing_Type"; + + public const string IconName = "Icon_Name"; } } \ No newline at end of file From 279e0bab3a5fae0fd10b5e65538720bde5e9b8f9 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Mar 2026 15:32:52 +0100 Subject: [PATCH 34/41] verify entity name length --- .../CommandBarVerifier.SingleComponent.cs | 13 +++++++++++++ .../Verifiers/GameObjects/GameObjectTypeVerifier.cs | 7 +++++++ .../Verifiers/SfxEvents/SfxEventVerifier.cs | 11 +++++++++-- src/ModVerify/Verifiers/VerifierErrorCodes.cs | 2 ++ .../GameObjects/GameObjectTypeGameManager.cs | 9 +++++++++ .../GameObjects/IGameObjectTypeGameManager.cs | 2 ++ .../PG.StarWarsGame.Engine/PGConstants.cs | 5 ++++- 7 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs index e71d39c..4a0d951 100644 --- a/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs +++ b/src/ModVerify/Verifiers/CommandBar/CommandBarVerifier.SingleComponent.cs @@ -1,4 +1,5 @@ using AET.ModVerify.Reporting; +using PG.StarWarsGame.Engine; using PG.StarWarsGame.Engine.CommandBar.Components; using System; using System.Threading; @@ -9,12 +10,24 @@ partial class CommandBarVerifier { private void VerifySingleComponent(CommandBarBaseComponent component, CancellationToken token) { + VerifyName(component); VerifyCommandBarModel(component, token); VerifyComponentBone(component); // TODO: Textures } + private void VerifyName(CommandBarBaseComponent component) + { + if (component.Name.Length > PGConstants.MaxCommandBarComponentNameBuffer) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.NameTooLong, + // Deliberately not reporting the buffer length as max, as it's considered to be internal data + $"The CommandBarShellComponent name '{component.Name}' is too long. Maximum length is {PGConstants.MaxCommandBarComponentName}.", + VerificationSeverity.Critical, [], component.Name)); + } + } + private void VerifyCommandBarModel(CommandBarBaseComponent component, CancellationToken token) { if (component is not CommandBarShellComponent shellComponent) diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs index 348ae7e..66d4672 100644 --- a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using AET.ModVerify.Reporting; using AET.ModVerify.Settings; using AET.ModVerify.Verifiers.Commons; using PG.StarWarsGame.Engine; @@ -29,6 +30,12 @@ public GameObjectTypeVerifier( protected override void VerifyEntity(GameObject entity, string[] context, double progress, CancellationToken token) { + if (entity.Name.Length >= PGConstants.MaxGameObjectTypeName) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.NameTooLong, + $"The GameObjectType name '{entity.Name}' is too long. Maximum length is {PGConstants.MaxGameObjectTypeName}.", + VerificationSeverity.Critical, entity.Name)); + } VerifyXRefs(entity, context); VerifyModels(entity, context, token); VerifyIcons(entity, context); diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs index d19c248..c688634 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.cs @@ -1,14 +1,15 @@ -using AET.ModVerify.Settings; +using AET.ModVerify.Reporting; +using AET.ModVerify.Settings; using AET.ModVerify.Verifiers.Commons; using AnakinRaW.CommonUtilities.FileSystem.Normalization; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine; +using PG.StarWarsGame.Engine.Audio.Sfx; using PG.StarWarsGame.Engine.Localization; using System; using System.Collections.Generic; using System.IO.Abstractions; using System.Threading; -using PG.StarWarsGame.Engine.Audio.Sfx; namespace AET.ModVerify.Verifiers.SfxEvents; @@ -45,6 +46,12 @@ public SfxEventVerifier( protected override void VerifyEntity(SfxEvent entity, string[] context, double progress, CancellationToken token) { + if (entity.Name.Length >= PGConstants.MaxSFXEventName) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.NameTooLong, + $"The SFXEvent name '{entity.Name}' is too long. Maximum length is {PGConstants.MaxSFXEventName}.", + VerificationSeverity.Critical, entity.Name)); + } VerifyPresetRef(entity, context); VerifySamples(entity, context, token); } diff --git a/src/ModVerify/Verifiers/VerifierErrorCodes.cs b/src/ModVerify/Verifiers/VerifierErrorCodes.cs index b6f365c..dca5326 100644 --- a/src/ModVerify/Verifiers/VerifierErrorCodes.cs +++ b/src/ModVerify/Verifiers/VerifierErrorCodes.cs @@ -20,6 +20,8 @@ public static class VerifierErrorCodes public const string Duplicate = "DUP00"; public const string MissingXRef = "XREF00"; + public const string NameTooLong = "NAME00"; + public const string MissingPreset = "SFX00"; public const string SampleNotPCM = "WAV00"; diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index cbcea6a..edf97cc 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -74,4 +74,13 @@ void AddTerrainMappingModels() } } } + + public GameObject? FindObjectType(string? name) + { + if (string.IsNullOrEmpty(name)) + return null; + var nameCrc = _hashingService.GetCrc32Upper(name, PGConstants.DefaultPGEncoding); + NamedEntries.TryGetFirstValue(nameCrc, out var gameObject); + return gameObject; + } } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs index 21e3ea0..ef72db3 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/IGameObjectTypeGameManager.cs @@ -20,4 +20,6 @@ public interface IGameObjectTypeGameManager : IGameManager /// An containing the names of the models associated with the specified . /// IEnumerable GetModels(GameObject gameObject); + + GameObject? FindObjectType(string name); } \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PGConstants.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/PGConstants.cs index b7a9218..a53709c 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PGConstants.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PGConstants.cs @@ -15,8 +15,11 @@ public static class PGConstants public const int MaxSFXEventDatabaseFileName = 259; public const int MaxSFXEventName = 255; public const int MaxGameObjectDatabaseFileName = 127; - public const int MaxCommandBarDatabaseFileName = 259; + public const int MaxCommandBarDatabaseFileName = 271; public const int MaxCommandBarComponentName = 255; + // The actual engine's buffer size that holds name. + public const int MaxCommandBarComponentNameBuffer = 263; + public const int MaxGameObjectTypeName = 127; public const int MaxGuiDialogMegaTextureFileName = 255; From ed528321ec4289da037a8250e387af9701a50b2a Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Mar 2026 16:27:40 +0100 Subject: [PATCH 35/41] support CompanyUnits --- .../GameObjectTypeVerifier.XRef.cs | 29 +++++++++- .../SfxEvents/SfxEventVerifier.XRef.cs | 2 +- .../Commons/MultiNameReferenceList.cs | 57 +++++++++++++++++++ .../GameObjects/GameObject.cs | 17 ++++-- .../GameObjects/GameObjectTypeGameManager.cs | 3 +- .../Parsers/NamedObjects/GameObjectParser.cs | 9 ++- 6 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/Commons/MultiNameReferenceList.cs diff --git a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs index 0bd952d..1bca0e9 100644 --- a/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs +++ b/src/ModVerify/Verifiers/GameObjects/GameObjectTypeVerifier.XRef.cs @@ -1,4 +1,5 @@ -using AET.ModVerify.Reporting; +using System.Linq; +using AET.ModVerify.Reporting; using PG.StarWarsGame.Engine.GameObjects; namespace AET.ModVerify.Verifiers.GameObjects; @@ -13,9 +14,31 @@ private void VerifyXRefs(GameObject gameObject, string[] context) this, VerifierErrorCodes.MissingXRef, $"Missing base type '{gameObject.VariantOfExistingTypeName}' for GameObject '{gameObject.Name}'", - VerificationSeverity.Critical, - context, + VerificationSeverity.Critical, + [..context, "VariantOfExistingType"], gameObject.VariantOfExistingTypeName)); } + + VerifyCompanyUnits(gameObject, context); + } + + private void VerifyCompanyUnits(GameObject gameObject, string[] context) + { + if (gameObject.GroundCompanyUnits.Count == 0) + return; + + var uniqueCompanyUnits = gameObject.GroundCompanyUnits + .Select(x => x.ToUpperInvariant()) + .Distinct(); + + foreach (var companyUnit in uniqueCompanyUnits) + { + if (GameEngine.GameObjectTypeManager.FindObjectType(companyUnit) is null) + { + AddError(VerificationError.Create(this, VerifierErrorCodes.MissingXRef, + $"Missing company unit '{companyUnit}' for GameObject '{gameObject.Name}'", + VerificationSeverity.Critical, [..context, "CompanyUnits"], companyUnit)); + } + } } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs index 187921d..ffdb772 100644 --- a/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs +++ b/src/ModVerify/Verifiers/SfxEvents/SfxEventVerifier.XRef.cs @@ -14,7 +14,7 @@ private void VerifyPresetRef(SfxEvent sfxEvent, string[] context) VerifierErrorCodes.MissingXRef, $"Missing preset '{sfxEvent.UsePresetName}' for SFXEvent '{sfxEvent.Name}'.", VerificationSeverity.Error, - context, + [..context, "Preset"], sfxEvent.UsePresetName)); } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Commons/MultiNameReferenceList.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Commons/MultiNameReferenceList.cs new file mode 100644 index 0000000..ff828a4 --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Commons/MultiNameReferenceList.cs @@ -0,0 +1,57 @@ +using System.Collections; +using System.Collections.Generic; + +namespace PG.StarWarsGame.Engine.Commons; + +public class MultiNameReferenceList : IReadOnlyList +{ + private bool _replace; + private readonly List _list = []; + + public string this[int index] => _list[index]; + + public int Count => _list.Count; + + public MultiNameReferenceList() + { + } + + public MultiNameReferenceList(MultiNameReferenceList list) + { + foreach (var name in list) + _list.Add(name); + + _replace = true; + } + + internal void AddRange(IEnumerable names) + { + if (_replace) + Clear(); + _replace = false; + _list.AddRange(names); + } + + internal void Add(string name) + { + if (_replace) + Clear(); + _replace = false; + _list.Add(name); + } + + internal void Clear() + { + _list.Clear(); + } + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs index d899e62..89823df 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObject.cs @@ -1,11 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using PG.Commons.Hashing; +using PG.Commons.Hashing; +using PG.StarWarsGame.Engine.Commons; using PG.StarWarsGame.Engine.Utilities; using PG.StarWarsGame.Files.XML; using PG.StarWarsGame.Files.XML.Data; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; namespace PG.StarWarsGame.Engine.GameObjects; @@ -47,8 +48,11 @@ public sealed class GameObject : NamedXmlObject public string? DamagedSmokeAssetModel { get; internal set; } public IReadOnlyList<(string terrain, string model)> LandTerrainModelMappingValues { get; } + public string? IconName { get; internal set; } + public MultiNameReferenceList GroundCompanyUnits { get; internal set; } = []; + internal GameObject( string name, string classification, @@ -82,8 +86,9 @@ internal void ApplyBaseType(GameObject baseType) SpaceAnimOverrideModel = baseType.SpaceAnimOverrideModel; DamagedSmokeAssetModel = baseType.DamagedSmokeAssetModel; InternalLandTerrainModelMapping.ClearAddRange(baseType.InternalLandTerrainModelMapping); - + IconName = baseType.IconName; + GroundCompanyUnits = new(baseType.GroundCompanyUnits); } internal void PostLoadFixup() diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs index edf97cc..14aba19 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GameObjects/GameObjectTypeGameManager.cs @@ -23,8 +23,7 @@ public GameObjectTypeGameManager( _gameObjects = []; GameObjects = new ReadOnlyCollection(_gameObjects); } - - + public IReadOnlyList GameObjects { get diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs index 8d6d916..f68f0f2 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/Xml/Parsers/NamedObjects/GameObjectParser.cs @@ -179,7 +179,13 @@ protected override void BuildMappings() GameObjectXmlTags.SpaceModelAnimOverrideName, PetroglyphXmlStringParser.Instance.Parse, (obj, val) => obj.SpaceAnimOverrideModel = val); - + + AddMapping( + GameObjectXmlTags.CompanyUnits, + PetroglyphXmlLooseStringListParser.Instance.Parse, + // The MULTI_OBJECT_REFERENCE parser never replaces (this is done by the MultiReferenceList itself) + (obj, val) => obj.GroundCompanyUnits.AddRange(val)); + AddMapping( GameObjectXmlTags.DamagedSmokeAssetName, PetroglyphXmlStringParser.Instance.Parse, @@ -222,5 +228,6 @@ internal static class GameObjectXmlTags public const string VariantOfExistingType = "Variant_Of_Existing_Type"; public const string IconName = "Icon_Name"; + public const string CompanyUnits = "Company_Units"; } } \ No newline at end of file From 1fce87b6edbb6bd5a220638a729b50e596a89f7f Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Mar 2026 16:55:14 +0100 Subject: [PATCH 36/41] change order of json properties --- .../Properties/launchSettings.json | 2 +- .../Resources/Baselines/baseline-foc.json | 3772 +++++++++++------ .../Json/JsonAggregatedVerificationError.cs | 2 +- .../Reporting/Json/JsonVerificationError.cs | 14 +- .../Json/JsonVerificationErrorBase.cs | 21 +- .../Reporting/Reporters/JSON/JsonReporter.cs | 6 +- .../Verifiers/Commons/SingleModelVerifier.cs | 2 +- src/ModVerify/Verifiers/VerifierErrorCodes.cs | 2 +- 8 files changed, 2441 insertions(+), 1380 deletions(-) diff --git a/src/ModVerify.CliApp/Properties/launchSettings.json b/src/ModVerify.CliApp/Properties/launchSettings.json index 06a3b72..46fa0fc 100644 --- a/src/ModVerify.CliApp/Properties/launchSettings.json +++ b/src/ModVerify.CliApp/Properties/launchSettings.json @@ -6,7 +6,7 @@ }, "Verify (Interactive)": { "commandName": "Project", - "commandLineArgs": "verify -o verifyResults --offline --minFailSeverity Information" + "commandLineArgs": "verify -o verifyResults --offline --minFailSeverity Information --searchBaseline" }, "Verify (Automatic Target Selection)": { "commandName": "Project", diff --git a/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json b/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json index ce70f8a..209033e 100644 --- a/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json +++ b/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json @@ -8,3040 +8,4100 @@ }, "minSeverity": "Information", "errors": [ + { + "id": "XML10", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8608\u0027", + "severity": "Information", + "asset": "Disabled_Darken", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_fast_forward_t\u0027" + ] + }, + { + "id": "XML10", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8569\u0027", + "severity": "Information", + "asset": "Disabled_Darken", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_fast_forward\u0027" + ] + }, + { + "id": "XML08", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML #0\u0027", + "severity": "Information", + "asset": "DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML" + ] + }, + { + "id": "XML08", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML #0\u0027", + "severity": "Information", + "asset": "DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML" + ] + }, + { + "id": "XML08", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\SPACEPROPS_UNDERWORLD.XML #0\u0027", + "severity": "Information", + "asset": "DATA\\XML\\SPACEPROPS_UNDERWORLD.XML", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\SPACEPROPS_UNDERWORLD.XML" + ] + }, + { + "id": "XML10", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8550\u0027", + "severity": "Information", + "asset": "Disabled_Darken", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_play_pause\u0027" + ] + }, { "id": "XML04", "verifiers": [ - "XMLError" + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" ], "message": "Expected double but got value \u002737\u0060\u0027. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #11571\u0027", "severity": "Warning", + "asset": "Size", "context": [ - "DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlFloatParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", "Size", "parentName=\u0027bm_text_steal\u0027" + ] + }, + { + "id": "XML10", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8589\u0027", + "severity": "Information", + "asset": "Disabled_Darken", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_play_pause_t\u0027" + ] + }, + { + "id": "XML10", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "The node \u0027Mega_Texture_Name\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8\u0027", + "severity": "Information", + "asset": "Mega_Texture_Name", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Mega_Texture_Name", + "parentName=\u0027i_main_commandbar\u0027" + ] + }, + { + "id": "XML08", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML #0\u0027", + "severity": "Information", + "asset": "DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML" + ] + }, + { + "id": "XML08", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" + ], + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML #0\u0027", + "severity": "Information", + "asset": "DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML" + ] + }, + { + "id": "XML08", + "verifiers": [ + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" ], - "asset": "Size" + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML #0\u0027", + "severity": "Information", + "asset": "DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML" + ] }, { "id": "XML04", "verifiers": [ - "XMLError" + "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" ], "message": "Expected integer but got \u002780, 20\u0027. File=\u0027DATA\\XML\\SFXEVENTSWEAPONS.XML #90\u0027", "severity": "Warning", + "asset": "Probability", "context": [ - "DATA\\XML\\SFXEVENTSWEAPONS.XML", + "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlIntegerParser", + "File: DATA\\XML\\SFXEVENTSWEAPONS.XML", "Probability", "parentName=\u0027Unit_TIE_Fighter_Fire\u0027" - ], - "asset": "Probability" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Reb_CelebHall.alo\u0027", + "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_Reb_CelebHall.alo" + "asset": "U000_LEI0313_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_ssd_debris\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO\u0027", + "message": "Audio file \u0027U000_LEI0502_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0502_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO" - ], - "asset": "p_ssd_debris" + "Unit_Remove_Corruption_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [W_SITH_LEFTHALL.ALO].", + "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0304_ENG.WAV", "context": [ - "W_SITH_LEFTHALL.ALO" - ], - "asset": "Cin_Reb_CelebHall_Wall.tga" + "Unit_Group_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_ImperialCraft.alo\u0027", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_ImperialCraft.alo" + "asset": "U000_LEI0201_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_Officer.alo\u0027", + "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_Officer.alo" + "asset": "U000_LEI0204_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_DStar_protons.alo\u0027", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_DStar_protons.alo" + "asset": "U000_LEI0208_ENG.WAV", + "context": [ + "Unit_Fleet_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Could not find texture \u0027w_grenade.tga\u0027 for context: [W_GRENADE.ALO].", + "message": "Audio file \u0027U000_MCF1601_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_MCF1601_ENG.WAV", "context": [ - "W_GRENADE.ALO" + "Unit_StarDest_MC30_Frigate" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "w_grenade.tga" + "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0210_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_03_STATION_D.ALO\u0027", + "message": "Audio file \u0027FS_BEETLE_3.WAV\u0027 could not be found.", "severity": "Error", + "asset": "FS_BEETLE_3.WAV", "context": [ - "DATA\\ART\\MODELS\\UB_03_STATION_D.ALO" + "SFX_Anim_Beetle_Footsteps" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "p_uwstation_death" + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0203_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", + "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_EI_Vader.alo" + "asset": "U000_LEI0309_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027MODELS\u0027", + "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "MODELS" + "asset": "U000_LEI0315_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_Wall.alo\u0027", + "message": "Audio file \u0027U000_LEI0504_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_DeathStar_Wall.alo" + "asset": "U000_LEI0504_ENG.WAV", + "context": [ + "Unit_Remove_Corruption_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", + "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0301_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "p_smoke_small_thin2" + "message": "Audio file \u0027U000_LEI0106_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0106_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_01_STATION_D.ALO\u0027", + "message": "Audio file \u0027U000_LEI0110_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0110_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UB_01_STATION_D.ALO" + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "p_uwstation_death" + "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0211_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Officer_Row.alo\u0027", + "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_Officer_Row.alo" + "asset": "U000_LEI0305_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO\u0027", + "message": "Audio file \u0027U000_LEI0105_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0105_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO" + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "Lensflare0" + "message": "Audio file \u0027U000_DEF3006_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_DEF3006_ENG.WAV", + "context": [ + "Unit_Corrupt_Sabateur" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_DeathStar_Hangar.alo\u0027", + "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_DeathStar_Hangar.alo" + "asset": "U000_LEI0212_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_EV_lambdaShuttle_150.alo" + "asset": "U000_LEI0207_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_smoke_small_thin4\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", + "message": "Audio file \u0027FS_BEETLE_4.WAV\u0027 could not be found.", "severity": "Error", + "asset": "FS_BEETLE_4.WAV", "context": [ - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "SFX_Anim_Beetle_Footsteps" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "p_smoke_small_thin4" + "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0303_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE.ALO\u0027", + "message": "Audio file \u0027U000_LEI0102_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0102_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\W_STARS_CINE.ALO" + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "Lensflare0" + "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0209_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_SKIPRAY.ALO\u0027.", + "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0307_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UV_SKIPRAY.ALO" + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "Default.fx" + "message": "Audio file \u0027C000_DST0102_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "C000_DST0102_ENG.WAV", + "context": [ + "EHD_Death_Star_Activate" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_IG88.ALO\u0027", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0202_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UI_IG88.ALO" + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "p_desert_ground_dust" + "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0306_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_p_proton_torpedo.alo\u0027", + "message": "Audio file \u0027U000_LEI0503_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_p_proton_torpedo.alo" + "asset": "U000_LEI0503_ENG.WAV", + "context": [ + "Unit_Remove_Corruption_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Fire_Huge.alo\u0027", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_Fire_Huge.alo" + "asset": "U000_LEI0205_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_04_STATION_D.ALO\u0027", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0205_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UB_04_STATION_D.ALO" + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "asset": "p_uwstation_death" + "message": "Audio file \u0027U000_LEI0107_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0107_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027TESTUNITMOVE_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "TESTUNITMOVE_ENG.WAV", + "context": [ + "Unit_Move_Gneneric_Test" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0101_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0101_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0312_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0201_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0308_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0208_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0207_ENG.WAV", + "context": [ + "Unit_Fleet_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0103_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0103_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0203_ENG.WAV", + "context": [ + "Unit_Fleet_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0206_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0304_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0314_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0303_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0201_ENG.WAV", + "context": [ + "Unit_Fleet_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0210_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_DEF3106_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_DEF3106_ENG.WAV", + "context": [ + "Unit_Weaken_Sabateur" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0311_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0311_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0208_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_TMC0212_ENG.WAV", + "context": [ + "Unit_Assist_Move_Tie_Mauler" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_ARC3106_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_ARC3106_ENG.WAV", + "context": [ + "Unit_Complete_Troops_Arc_Hammer" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0601_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0601_ENG.WAV", + "context": [ + "Unit_Increase_Production_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0403_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0403_ENG.WAV", + "context": [ + "Unit_Guard_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0604_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0604_ENG.WAV", + "context": [ + "Unit_Increase_Production_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0306_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0309_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0111_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0111_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0215_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027FS_BEETLE_2.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "FS_BEETLE_2.WAV", + "context": [ + "SFX_Anim_Beetle_Footsteps" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0213_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0213_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0115_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0115_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0315_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0203_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_TMC0212_ENG.WAV", + "context": [ + "Unit_Move_Tie_Mauler" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0202_ENG.WAV", + "context": [ + "Unit_Fleet_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0312_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0308_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0108_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0108_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0104_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0104_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0204_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" + ], + "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", + "severity": "Error", + "asset": "U000_LEI0313_ENG.WAV", + "context": [ + "Unit_Group_Attack_Leia" + ] + }, + { + "id": "FILE00", + "verifiers": [ + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027RV_nebulonb_D_death_00.ALO\u0027", + "message": "Audio file \u0027U000_LEI0603_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "RV_nebulonb_D_death_00.ALO" + "asset": "U000_LEI0603_ENG.WAV", + "context": [ + "Unit_Increase_Production_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_02_STATION_D.ALO\u0027", + "message": "Audio file \u0027U000_LEI0112_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0112_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UB_02_STATION_D.ALO" - ], - "asset": "p_uwstation_death" + "Unit_Select_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", + "message": "Audio file \u0027EGL_STAR_VIPER_SPINNING_1.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "W_Kamino_Reflect.ALO" + "asset": "EGL_STAR_VIPER_SPINNING_1.WAV", + "context": [ + "Unit_Star_Viper_Spinning_By" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO\u0027", + "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0307_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO" - ], - "asset": "p_smoke_small_thin2" + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_steam_small\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO\u0027", + "message": "Audio file \u0027AMB_URB_CLEAR_LOOP_1.WAV\u0027 could not be found.", "severity": "Error", + "asset": "AMB_URB_CLEAR_LOOP_1.WAV", "context": [ - "DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO" - ], - "asset": "p_steam_small" + "Weather_Ambient_Clear_Urban_Loop" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_EV_Stardestroyer_Warp.alo\u0027", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_EV_Stardestroyer_Warp.alo" + "asset": "U000_LEI0205_ENG.WAV", + "context": [ + "Unit_Fleet_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_DStar_TurretLasers.alo\u0027", + "message": "Audio file \u0027AMB_DES_CLEAR_LOOP_1.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_DStar_TurretLasers.alo" + "asset": "AMB_DES_CLEAR_LOOP_1.WAV", + "context": [ + "Weather_Ambient_Clear_Sandstorm_Loop" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_GreyGroup.alo\u0027", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_Rbel_GreyGroup.alo" + "asset": "U000_LEI0207_ENG.WAV", + "context": [ + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_Planet_Hoth_High.alo\u0027", + "message": "Audio file \u0027U000_LEI0501_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_Planet_Hoth_High.alo" + "asset": "U000_LEI0501_ENG.WAV", + "context": [ + "Unit_Remove_Corruption_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Trooper_Row.alo\u0027", + "message": "Audio file \u0027U000_MAL0503_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_Trooper_Row.alo" + "asset": "U000_MAL0503_ENG.WAV", + "context": [ + "Unit_Assist_Move_Missile_Launcher" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_SABOTEUR.ALO\u0027", + "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0314_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UI_SABOTEUR.ALO" - ], - "asset": "p_desert_ground_dust" + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO\u0027", + "message": "Audio file \u0027U000_LEI0602_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0602_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO" - ], - "asset": "Lensflare0" + "Unit_Increase_Production_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027W_AllShaders.ALO\u0027", + "message": "Audio file \u0027U000_LEI0114_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "W_AllShaders.ALO" + "asset": "U000_LEI0114_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO\u0027.", + "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0209_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO" - ], - "asset": "Default.fx" + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CINE_EV_StarDestroyer.ALO\u0027", + "message": "Audio file \u0027FS_BEETLE_1.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CINE_EV_StarDestroyer.ALO" + "asset": "FS_BEETLE_1.WAV", + "context": [ + "SFX_Anim_Beetle_Footsteps" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", + "message": "Audio file \u0027U000_LEI0404_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_EI_Palpatine.alo" + "asset": "U000_LEI0404_ENG.WAV", + "context": [ + "Unit_Guard_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Could not find texture \u0027Cin_DeathStar.tga\u0027 for context: [ALTTEST.ALO].", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0206_ENG.WAV", "context": [ - "ALTTEST.ALO" - ], - "asset": "Cin_DeathStar.tga" + "Unit_Fleet_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Could not find texture \u0027UB_girder_B.tga\u0027 for context: [UV_MDU_CAGE.ALO].", + "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0215_ENG.WAV", "context": [ - "UV_MDU_CAGE.ALO" - ], - "asset": "UB_girder_B.tga" + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027P_mptl-2a_Die\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_MPTL-2A.ALO\u0027", + "message": "Audio file \u0027U000_LEI0109_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0109_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\RV_MPTL-2A.ALO" - ], - "asset": "P_mptl-2a_Die" + "Unit_Select_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO\u0027.", + "message": "Audio file \u0027U000_ARC3105_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_ARC3105_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO" - ], - "asset": "Default.fx" + "Unit_Complete_Troops_Arc_Hammer" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_Planet_Alderaan_High.alo\u0027", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_Planet_Alderaan_High.alo" + "asset": "U000_LEI0206_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_hp_archammer-damage\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO\u0027", + "message": "Audio file \u0027U000_ARC3104_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_ARC3104_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO" - ], - "asset": "p_hp_archammer-damage" + "Unit_Produce_Troops_Arc_Hammer" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_05_STATION_D.ALO\u0027", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0202_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UB_05_STATION_D.ALO" - ], - "asset": "p_uwstation_death" + "Unit_Group_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027p_explosion_smoke_small_thin5\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO\u0027", + "message": "Audio file \u0027U000_LEI0402_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0402_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO" - ], - "asset": "p_explosion_smoke_small_thin5" + "Unit_Guard_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Probe_Droid.alo\u0027", + "message": "Audio file \u0027U000_LEI0113_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "CIN_Probe_Droid.alo" + "asset": "U000_LEI0113_ENG.WAV", + "context": [ + "Unit_Select_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_HIGH.ALO\u0027", + "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0212_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\W_STARS_HIGH.ALO" - ], - "asset": "Lensflare0" + "Unit_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027W_Volcano_Rock02.ALO\u0027", + "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "W_Volcano_Rock02.ALO" + "asset": "U000_LEI0305_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE.ALO\u0027", + "message": "Audio file \u0027U000_LEI0401_ENG.WAV\u0027 could not be found.", "severity": "Error", + "asset": "U000_LEI0401_ENG.WAV", "context": [ - "DATA\\ART\\MODELS\\UV_ECLIPSE.ALO" - ], - "asset": "lookat" + "Unit_Guard_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_Shuttle_Tyderium.alo\u0027", + "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "Cin_Shuttle_Tyderium.alo" + "asset": "U000_LEI0301_ENG.WAV", + "context": [ + "Unit_Attack_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", + "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" ], - "message": "Unable to find .ALO file \u0027W_SwampGasEmit.ALO\u0027", + "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "severity": "Error", - "context": [], - "asset": "W_SwampGasEmit.ALO" + "asset": "U000_LEI0211_ENG.WAV", + "context": [ + "Unit_Move_Leia" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" ], - "message": "Proxy particle \u0027P_heat_small01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_VCH.ALO\u0027", + "message": "Could not find GUI texture \u0027i_button_petro_sliver.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", + "asset": "i_button_petro_sliver.tga", "context": [ - "DATA\\ART\\MODELS\\NB_VCH.ALO" - ], - "asset": "P_heat_small01" + "IDC_MENU_PETRO_LOGO", + "MegaTexture" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_NavyRow.alo\u0027", + "message": "Could not find GUI texture \u0027underworld_logo_off.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", - "context": [], - "asset": "CIN_Rbel_NavyRow.alo" + "asset": "underworld_logo_off.tga", + "context": [ + "IDC_PLAY_FACTION_A_BUTTON_BIG", + "MegaTexture" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Fire_Medium.alo\u0027", + "message": "Could not find GUI texture \u0027underworld_logo_rollover.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", - "context": [], - "asset": "CIN_Fire_Medium.alo" + "asset": "underworld_logo_rollover.tga", + "context": [ + "IDC_PLAY_FACTION_A_BUTTON_BIG", + "MegaTexture" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" ], - "message": "Proxy particle \u0027p_ewok_drag_dirt\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO\u0027", + "message": "Could not find GUI texture \u0027underworld_logo_selected.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", + "asset": "underworld_logo_selected.tga", "context": [ - "DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO" - ], - "asset": "p_ewok_drag_dirt" + "IDC_PLAY_FACTION_A_BUTTON_BIG", + "MegaTexture" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" ], - "message": "Unable to find .ALO file \u0027W_Bush_Swmp00.ALO\u0027", + "message": "Could not find GUI texture \u0027i_dialogue_button_large_middle_off.tga\u0027 at location \u0027Repository\u0027.", "severity": "Error", - "context": [], - "asset": "W_Bush_Swmp00.ALO" + "asset": "i_dialogue_button_large_middle_off.tga", + "context": [ + "IDC_PLAY_FACTION_B_BUTTON_BIG", + "Repository" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027W_droid_steam.alo\u0027", + "message": "Proxy particle \u0027p_bomb_spin\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO\u0027", "severity": "Error", - "context": [], - "asset": "W_droid_steam.alo" + "asset": "p_bomb_spin", + "context": [ + "TIE_Bomber_Bombing_Run_Bomb", + "DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Biker_Row.alo\u0027", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "severity": "Error", - "context": [], - "asset": "CIN_Biker_Row.alo" + "asset": "Cin_Reb_CelebHall_Wall.tga", + "context": [ + "Cin_w_tile", + "W_TILE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027w_planet_volcanic.alo\u0027", + "message": "Unable to find .ALO file \u0027CIN_DeathStar_Hangar.alo\u0027", "severity": "Error", - "context": [], - "asset": "w_planet_volcanic.alo" + "asset": "CIN_DeathStar_Hangar.alo", + "context": [ + "Cin_DeathStar_Hangar" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO\u0027", + "message": "Could not find texture \u0027w_grenade.tga\u0027 for context: [Proj_Merc_Concussion_Grenade--\u003EW_GRENADE.ALO].", "severity": "Error", + "asset": "w_grenade.tga", "context": [ - "DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO" - ], - "asset": "p_smoke_small_thin2" + "Proj_Merc_Concussion_Grenade", + "W_GRENADE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO\u0027", + "message": "Unable to find .ALO file \u0027CIN_Biker_Row.alo\u0027", "severity": "Error", + "asset": "CIN_Biker_Row.alo", "context": [ - "DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO" - ], - "asset": "lookat" + "Cin_Biker_Row" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_REb_CelebCharacters.alo\u0027", + "message": "Unable to find .ALO file \u0027Cin_Planet_Alderaan_High.alo\u0027", "severity": "Error", - "context": [], - "asset": "CIN_REb_CelebCharacters.alo" + "asset": "Cin_Planet_Alderaan_High.alo", + "context": [ + "Alderaan_Backdrop_Large 6x" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", + "message": "Proxy particle \u0027P_mptl-2a_Die\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_MPTL-2A.ALO\u0027", "severity": "Error", - "context": [], - "asset": "Cin_DeathStar_High.alo" + "asset": "P_mptl-2a_Die", + "context": [ + "MPTL", + "DATA\\ART\\MODELS\\RV_MPTL-2A.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [W_SITH_LEFTHALL.ALO].", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE.ALO\u0027", "severity": "Error", + "asset": "Lensflare0", "context": [ - "W_SITH_LEFTHALL.ALO" - ], - "asset": "Cin_Reb_CelebHall_Wall_B.tga" + "Stars_Cinematic", + "DATA\\ART\\MODELS\\W_STARS_CINE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [UV_MDU_CAGE.ALO].", + "message": "Unable to find .ALO file \u0027Cin_DStar_Dish_close.alo\u0027", "severity": "Error", + "asset": "Cin_DStar_Dish_close.alo", "context": [ - "UV_MDU_CAGE.ALO" - ], - "asset": "NB_YsalamiriTree_B.tga" + "Death_Star_Dish_Close" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_Coruscant.alo\u0027", + "message": "Proxy particle \u0027p_ssd_debris\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO\u0027", "severity": "Error", - "context": [], - "asset": "Cin_Coruscant.alo" + "asset": "p_ssd_debris", + "context": [ + "Eclipse_Super_Star_Destroyer_Death_Clone", + "DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027p_prison_light\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", + "asset": "Cin_DeathStar_High.alo", "context": [ - "DATA\\ART\\MODELS\\NB_PRISON.ALO" - ], - "asset": "p_prison_light" + "Death_Star_Whole" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027p_cold_tiny01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_SCH.ALO\u0027", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_05_STATION_D.ALO\u0027", "severity": "Error", + "asset": "p_uwstation_death", "context": [ - "DATA\\ART\\MODELS\\NB_SCH.ALO" - ], - "asset": "p_cold_tiny01" + "Underworld_Star_Base_5_Death_Clone", + "DATA\\ART\\MODELS\\UB_05_STATION_D.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_NavyTrooper_Row.alo\u0027", + "message": "Unable to find .ALO file \u0027Cin_DStar_LeverPanel.alo\u0027", "severity": "Error", - "context": [], - "asset": "CIN_NavyTrooper_Row.alo" + "asset": "Cin_DStar_LeverPanel.alo", + "context": [ + "Death_Star_LeverPanel" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO\u0027.", + "message": "Unable to find .ALO file \u0027w_planet_volcanic.alo\u0027", "severity": "Error", + "asset": "w_planet_volcanic.alo", "context": [ - "DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO" - ], - "asset": "Default.fx" + "Volcanic_Backdrop_Large" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier.alo\u0027", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_Wall.alo\u0027", "severity": "Error", - "context": [], - "asset": "CIN_Rbel_Soldier.alo" + "asset": "Cin_DeathStar_Wall.alo", + "context": [ + "Death_Star_Hangar_Outside" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO\u0027", + "message": "Unable to find .ALO file \u0027W_Bush_Swmp00.ALO\u0027", "severity": "Error", + "asset": "W_Bush_Swmp00.ALO", "context": [ - "DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO" - ], - "asset": "p_desert_ground_dust" + "Prop_Swamp_Bush00" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Lambda_Mouth.alo\u0027", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_SABOTEUR.ALO\u0027", "severity": "Error", - "context": [], - "asset": "CIN_Lambda_Mouth.alo" + "asset": "p_desert_ground_dust", + "context": [ + "Underworld_Saboteur", + "DATA\\ART\\MODELS\\UI_SABOTEUR.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Could not find texture \u0027p_particle_master\u0027 for context: [P_DIRT_EMITTER_TEST1.ALO].", + "message": "Could not find texture \u0027UB_girder_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "severity": "Error", + "asset": "UB_girder_B.tga", "context": [ - "P_DIRT_EMITTER_TEST1.ALO" - ], - "asset": "p_particle_master" + "Underworld_Ysalamiri_Cage", + "UV_MDU_CAGE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "severity": "Error", - "context": [], - "asset": "Cin_bridge.alo" + "asset": "Cin_bridge.alo", + "context": [ + "UM05_PROP_BRIDGE" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027W_Vol_Steam01.ALO\u0027", + "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "severity": "Error", - "context": [], - "asset": "W_Vol_Steam01.ALO" + "asset": "Cin_EI_Vader.alo", + "context": [ + "Cin_Vader_Shot_6-9" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_grey.alo\u0027", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "severity": "Error", - "context": [], - "asset": "CIN_Rbel_grey.alo" + "asset": "Cin_Reb_CelebHall_Wall.tga", + "context": [ + "Cin_sith_lefthall", + "W_SITH_LEFTHALL.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027w_sith_arch.alo\u0027", + "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "severity": "Error", - "context": [], - "asset": "w_sith_arch.alo" + "asset": "Cin_EV_lambdaShuttle_150.alo", + "context": [ + "Lambda_Shuttle_150X6-9" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", + "message": "Unable to find .ALO file \u0027CIN_Officer_Row.alo\u0027", "severity": "Error", - "context": [], - "asset": "Cin_rv_XWingProp.alo" + "asset": "CIN_Officer_Row.alo", + "context": [ + "Cin_Officer_Row" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_DStar_Dish_close.alo\u0027", + "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "severity": "Error", - "context": [], - "asset": "Cin_DStar_Dish_close.alo" + "asset": "Cin_EI_Vader.alo", + "context": [ + "Cin_Vader" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVeifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [EV_TIE_PHANTOM.ALO].", + "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "severity": "Error", + "asset": "W_Kamino_Reflect.ALO", "context": [ - "EV_TIE_PHANTOM.ALO" - ], - "asset": "W_TE_Rock_f_02_b.tga" + "Prop_Kamino_Reflection_00" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027pe_bwing_yellow\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_BWING.ALO\u0027", + "message": "Unable to find .ALO file \u0027Cin_Coruscant.alo\u0027", "severity": "Error", + "asset": "Cin_Coruscant.alo", "context": [ - "DATA\\ART\\MODELS\\RV_BWING.ALO" - ], - "asset": "pe_bwing_yellow" + "Corusant_Backdrop_Large 6x" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Lambda_Head.alo\u0027", + "message": "Unable to find .ALO file \u0027CIN_Probe_Droid.alo\u0027", "severity": "Error", - "context": [], - "asset": "CIN_Lambda_Head.alo" + "asset": "CIN_Probe_Droid.alo", + "context": [ + "Empire_Droid" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027p_explosion_small_delay00\u0027 not found for model \u0027DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO\u0027", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "severity": "Error", + "asset": "p_smoke_small_thin2", "context": [ - "DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO" - ], - "asset": "p_explosion_small_delay00" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_DStar_LeverPanel.alo\u0027", + "message": "Proxy particle \u0027P_heat_small01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_VCH.ALO\u0027", "severity": "Error", - "context": [], - "asset": "Cin_DStar_LeverPanel.alo" + "asset": "P_heat_small01", + "context": [ + "Volcanic_Civilian_Spawn_House_Independent_AI", + "DATA\\ART\\MODELS\\NB_VCH.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027p_splash_wake_lava.alo\u0027", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO\u0027", "severity": "Error", - "context": [], - "asset": "p_splash_wake_lava.alo" + "asset": "p_desert_ground_dust", + "context": [ + "Kyle_Katarn", + "DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_LOW.ALO\u0027", + "message": "Unable to find .ALO file \u0027w_sith_arch.alo\u0027", "severity": "Error", + "asset": "w_sith_arch.alo", "context": [ - "DATA\\ART\\MODELS\\W_STARS_LOW.ALO" - ], - "asset": "Lensflare0" + "Cin_sith_arch" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\EI_MARAJADE.ALO\u0027", + "message": "Unable to find .ALO file \u0027CIN_Reb_CelebHall.alo\u0027", "severity": "Error", + "asset": "CIN_Reb_CelebHall.alo", "context": [ - "DATA\\ART\\MODELS\\EI_MARAJADE.ALO" - ], - "asset": "p_desert_ground_dust" + "REb_CelebHall" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Proxy particle \u0027p_bomb_spin\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO\u0027", + "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "severity": "Error", + "asset": "Cin_rv_XWingProp.alo", "context": [ - "DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO" - ], - "asset": "p_bomb_spin" + "Grounded_Xwing" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027Cin_EV_TieAdvanced.alo\u0027", + "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier.alo\u0027", "severity": "Error", - "context": [], - "asset": "Cin_EV_TieAdvanced.alo" + "asset": "CIN_Rbel_Soldier.alo", + "context": [ + "Cin_Rebel_soldier" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.ReferencedModelsVerifier", + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier_Group.alo\u0027", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_LOW.ALO\u0027", "severity": "Error", - "context": [], - "asset": "CIN_Rbel_Soldier_Group.alo" + "asset": "Lensflare0", + "context": [ + "Stars_Low", + "DATA\\ART\\MODELS\\W_STARS_LOW.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027W_AllShaders.ALO\u0027", "severity": "Error", + "asset": "W_AllShaders.ALO", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0213_ENG.WAV" + "Prop_AllShaders" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0113_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_smoke_small_thin4\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "severity": "Error", + "asset": "p_smoke_small_thin4", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0113_ENG.WAV" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0603_ENG.WAV\u0027 could not be found.", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO\u0027.", "severity": "Error", + "asset": "Default.fx", "context": [ - "Unit_Increase_Production_Leia" - ], - "asset": "U000_LEI0603_ENG.WAV" + "Lancet_Air_Artillery", + "DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CINE_EV_StarDestroyer.ALO\u0027", "severity": "Error", + "asset": "CINE_EV_StarDestroyer.ALO", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0309_ENG.WAV" + "CIN_Star_Destroyer3X" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_NavyTrooper_Row.alo\u0027", "severity": "Error", + "asset": "CIN_NavyTrooper_Row.alo", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0212_ENG.WAV" + "Cin_NavyTrooper_Row" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_MAL0503_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Rbel_GreyGroup.alo\u0027", "severity": "Error", + "asset": "CIN_Rbel_GreyGroup.alo", "context": [ - "Unit_Assist_Move_Missile_Launcher" - ], - "asset": "U000_MAL0503_ENG.WAV" + "Cin_Rebel_GreyGroup" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_MCF1601_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "severity": "Error", + "asset": "Cin_EV_lambdaShuttle_150.alo", "context": [ - "Unit_StarDest_MC30_Frigate" - ], - "asset": "U000_MCF1601_ENG.WAV" + "Lambda_Shuttle_150" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0111_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027W_Vol_Steam01.ALO\u0027", "severity": "Error", + "asset": "W_Vol_Steam01.ALO", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0111_ENG.WAV" + "Prop_Vol_Steam01" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_ARC3106_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\EI_MARAJADE.ALO\u0027", "severity": "Error", + "asset": "p_desert_ground_dust", "context": [ - "Unit_Complete_Troops_Arc_Hammer" - ], - "asset": "U000_ARC3106_ENG.WAV" + "Mara_Jade", + "DATA\\ART\\MODELS\\EI_MARAJADE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Trooper_Row.alo\u0027", "severity": "Error", + "asset": "CIN_Trooper_Row.alo", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0303_ENG.WAV" + "Cin_Trooper_Row" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0404_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_hp_archammer-damage\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO\u0027", "severity": "Error", + "asset": "p_hp_archammer-damage", "context": [ - "Unit_Guard_Leia" - ], - "asset": "U000_LEI0404_ENG.WAV" + "Arc_Hammer", + "DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027TESTUNITMOVE_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "severity": "Error", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", "context": [ - "Unit_Move_Gneneric_Test" - ], - "asset": "TESTUNITMOVE_ENG.WAV" + "Cin_sith_lefthall", + "W_SITH_LEFTHALL.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0401_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_ewok_drag_dirt\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO\u0027", "severity": "Error", + "asset": "p_ewok_drag_dirt", "context": [ - "Unit_Guard_Leia" - ], - "asset": "U000_LEI0401_ENG.WAV" + "Ewok_Handler", + "DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027EGL_STAR_VIPER_SPINNING_1.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_Officer.alo\u0027", "severity": "Error", + "asset": "Cin_Officer.alo", "context": [ - "Unit_Star_Viper_Spinning_By" - ], - "asset": "EGL_STAR_VIPER_SPINNING_1.WAV" + "FIN_Officer" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_ImperialCraft.alo\u0027", "severity": "Error", + "asset": "Cin_ImperialCraft.alo", "context": [ - "Unit_Move_Tie_Mauler" - ], - "asset": "U000_TMC0212_ENG.WAV" + "Intro2_ImperialCraft" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0110_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Ysalamiri_Tree--\u003ENB_YSALAMIRI_TREE.ALO].", "severity": "Error", + "asset": "NB_YsalamiriTree_B.tga", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0110_ENG.WAV" + "Ysalamiri_Tree", + "NB_YSALAMIRI_TREE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_01_STATION_D.ALO\u0027", "severity": "Error", + "asset": "p_uwstation_death", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0314_ENG.WAV" + "Underworld_Star_Base_1_Death_Clone", + "DATA\\ART\\MODELS\\UB_01_STATION_D.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", + "asset": "Cin_DeathStar_High.alo", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0305_ENG.WAV" + "UM05_PROP_DSTAR" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0112_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_prison_light\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "severity": "Error", + "asset": "p_prison_light", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0112_ENG.WAV" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_explosion_smoke_small_thin5\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO\u0027", "severity": "Error", + "asset": "p_explosion_smoke_small_thin5", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0209_ENG.WAV" + "Noghri_Spawn_House", + "DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO\u0027", "severity": "Error", + "asset": "Lensflare0", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0211_ENG.WAV" + "Stars_Medium", + "DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_steam_small\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO\u0027", "severity": "Error", + "asset": "p_steam_small", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0205_ENG.WAV" + "R_Ground_Heavy_Vehicle_Factory", + "DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0115_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Lambda_Head.alo\u0027", "severity": "Error", + "asset": "CIN_Lambda_Head.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0115_ENG.WAV" + "Cin_Lambda_Head" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0604_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_IG88.ALO\u0027", "severity": "Error", + "asset": "p_desert_ground_dust", "context": [ - "Unit_Increase_Production_Leia" - ], - "asset": "U000_LEI0604_ENG.WAV" + "IG-88", + "DATA\\ART\\MODELS\\UI_IG88.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0602_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", + "asset": "Cin_DeathStar_High.alo", "context": [ - "Unit_Increase_Production_Leia" - ], - "asset": "U000_LEI0602_ENG.WAV" + "Death_Star_Whole_small" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027W_Volcano_Rock02.ALO\u0027", "severity": "Error", + "asset": "W_Volcano_Rock02.ALO", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0315_ENG.WAV" + "Prop_Volcano_RockForm03" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_DEF3006_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_HIGH.ALO\u0027", "severity": "Error", + "asset": "Lensflare0", "context": [ - "Unit_Corrupt_Sabateur" - ], - "asset": "U000_DEF3006_ENG.WAV" + "Stars_High", + "DATA\\ART\\MODELS\\W_STARS_HIGH.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_EV_Stardestroyer_Warp.alo\u0027", "severity": "Error", + "asset": "Cin_EV_Stardestroyer_Warp.alo", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0210_ENG.WAV" + "Star_Destroyer_Warp" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0105_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier_Group.alo\u0027", "severity": "Error", + "asset": "CIN_Rbel_Soldier_Group.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0105_ENG.WAV" + "Cin_Rebel_SoldierRow" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_SKIPRAY.ALO\u0027.", "severity": "Error", + "asset": "Default.fx", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0208_ENG.WAV" + "Skipray_Bombing_Run", + "DATA\\ART\\MODELS\\UV_SKIPRAY.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0106_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Lambda_Mouth.alo\u0027", "severity": "Error", + "asset": "CIN_Lambda_Mouth.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0106_ENG.WAV" + "Cin_Lambda_Mouth" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Fire_Huge.alo\u0027", "severity": "Error", + "asset": "CIN_Fire_Huge.alo", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0202_ENG.WAV" + "Fin_Fire_Huge" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [TIE_Phantom--\u003EEV_TIE_PHANTOM.ALO].", "severity": "Error", + "asset": "W_TE_Rock_f_02_b.tga", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0306_ENG.WAV" + "TIE_Phantom", + "EV_TIE_PHANTOM.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0101_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_REb_CelebCharacters.alo\u0027", "severity": "Error", + "asset": "CIN_REb_CelebCharacters.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0101_ENG.WAV" + "REb_CelebCharacters" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027C000_DST0102_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "severity": "Error", + "asset": "Cin_EI_Palpatine.alo", "context": [ - "EHD_Death_Star_Activate" - ], - "asset": "C000_DST0102_ENG.WAV" + "Cin_Emperor_Shot_6-9" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0103_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "severity": "Error", + "asset": "Cin_rv_XWingProp.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0103_ENG.WAV" + "Cin_X-WingProp" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0403_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027Cin_DeathStar.tga\u0027 for context: [Test_Base_Hector--\u003EALTTEST.ALO].", "severity": "Error", + "asset": "Cin_DeathStar.tga", "context": [ - "Unit_Guard_Leia" - ], - "asset": "U000_LEI0403_ENG.WAV" + "Test_Base_Hector", + "ALTTEST.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027FS_BEETLE_2.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_Shuttle_Tyderium.alo\u0027", "severity": "Error", + "asset": "Cin_Shuttle_Tyderium.alo", "context": [ - "SFX_Anim_Beetle_Footsteps" - ], - "asset": "FS_BEETLE_2.WAV" + "Intro2_Shuttle_Tyderium" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO\u0027.", "severity": "Error", + "asset": "Default.fx", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0201_ENG.WAV" + "Crusader_Gunship", + "DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027p_splash_wake_lava.alo\u0027", "severity": "Error", + "asset": "p_splash_wake_lava.alo", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0203_ENG.WAV" + "Splash_Wake_Lava" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0114_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "severity": "Error", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0114_ENG.WAV" + "Cin_w_tile", + "W_TILE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027FS_BEETLE_1.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027p_particle_master\u0027 for context: [Test_Particle--\u003EP_DIRT_EMITTER_TEST1.ALO].", "severity": "Error", + "asset": "p_particle_master", "context": [ - "SFX_Anim_Beetle_Footsteps" - ], - "asset": "FS_BEETLE_1.WAV" + "Test_Particle", + "P_DIRT_EMITTER_TEST1.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO\u0027", "severity": "Error", + "asset": "p_smoke_small_thin2", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0304_ENG.WAV" + "MonCalamari_Spawn_House", + "DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "severity": "Error", + "asset": "Cin_EI_Palpatine.alo", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0301_ENG.WAV" + "Cin_Emperor_Shot_5" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0503_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "severity": "Error", + "asset": "Cin_Reb_CelebHall_Wall.tga", "context": [ - "Unit_Remove_Corruption_Leia" - ], - "asset": "U000_LEI0503_ENG.WAV" + "Cin_sith_console", + "W_SITH_CONSOLE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0109_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_03_STATION_D.ALO\u0027", "severity": "Error", + "asset": "p_uwstation_death", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0109_ENG.WAV" + "Underworld_Star_Base_3_Death_Clone", + "DATA\\ART\\MODELS\\UB_03_STATION_D.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_02_STATION_D.ALO\u0027", "severity": "Error", + "asset": "p_uwstation_death", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0308_ENG.WAV" + "Underworld_Star_Base_2_Death_Clone", + "DATA\\ART\\MODELS\\UB_02_STATION_D.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0402_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_EV_TieAdvanced.alo\u0027", "severity": "Error", + "asset": "Cin_EV_TieAdvanced.alo", "context": [ - "Unit_Guard_Leia" - ], - "asset": "U000_LEI0402_ENG.WAV" + "Fin_Vader_TIE" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0108_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [The_Peacebringer--\u003EUV_KRAYTCLASSDESTROYER_TYBER.ALO].", "severity": "Error", + "asset": "W_TE_Rock_f_02_b.tga", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0108_ENG.WAV" + "The_Peacebringer", + "UV_KRAYTCLASSDESTROYER_TYBER.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_cold_tiny01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_SCH.ALO\u0027", "severity": "Error", + "asset": "p_cold_tiny01", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0307_ENG.WAV" + "Arctic_Civilian_Spawn_House", + "DATA\\ART\\MODELS\\NB_SCH.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_DStar_protons.alo\u0027", "severity": "Error", + "asset": "Cin_DStar_protons.alo", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0311_ENG.WAV" + "Protons_DStar_Xplode" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0102_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027W_droid_steam.alo\u0027", "severity": "Error", + "asset": "W_droid_steam.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0102_ENG.WAV" + "Prop_Droid_Steam" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0104_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Rbel_NavyRow.alo\u0027", "severity": "Error", + "asset": "CIN_Rbel_NavyRow.alo", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0104_ENG.WAV" + "Cin_Rebel_NavyRow" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027FS_BEETLE_3.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_DStar_TurretLasers.alo\u0027", "severity": "Error", + "asset": "Cin_DStar_TurretLasers.alo", "context": [ - "SFX_Anim_Beetle_Footsteps" - ], - "asset": "FS_BEETLE_3.WAV" + "TurretLasers_DStar_Xplode" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "severity": "Error", + "asset": "W_Kamino_Reflect.ALO", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0313_ENG.WAV" + "Prop_Kamino_Reflection_01" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027pe_bwing_yellow\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_BWING.ALO\u0027", "severity": "Error", + "asset": "pe_bwing_yellow", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0206_ENG.WAV" + "B-Wing", + "DATA\\ART\\MODELS\\RV_BWING.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_ARC3104_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "severity": "Error", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", "context": [ - "Unit_Produce_Troops_Arc_Hammer" - ], - "asset": "U000_ARC3104_ENG.WAV" + "Cin_sith_console", + "W_SITH_CONSOLE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [F9TZ_Cloaking_Transport--\u003EUV_F9TZTRANSPORT.ALO].", "severity": "Error", + "asset": "W_TE_Rock_f_02_b.tga", "context": [ - "Unit_Attack_Leia" - ], - "asset": "U000_LEI0312_ENG.WAV" + "F9TZ_Cloaking_Transport", + "UV_F9TZTRANSPORT.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "severity": "Error", + "asset": "Cin_bridge.alo", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0215_ENG.WAV" + "Imperial_Bridge" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier" ], - "message": "Audio file \u0027U000_LEI0107_ENG.WAV\u0027 could not be found.", - "severity": "Error", + "message": "Could not find icon \u0027i_button_general_dodonna.tga\u0027 for game object type \u0027General_Dodonna\u0027.", + "severity": "Warning", + "asset": "i_button_general_dodonna.tga", "context": [ - "Unit_Select_Leia" - ], - "asset": "U000_LEI0107_ENG.WAV" + "General_Dodonna" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0501_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_explosion_small_delay00\u0027 not found for model \u0027DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO\u0027", "severity": "Error", + "asset": "p_explosion_small_delay00", "context": [ - "Unit_Remove_Corruption_Leia" - ], - "asset": "U000_LEI0501_ENG.WAV" + "Imperial_Command_Center", + "DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027AMB_DES_CLEAR_LOOP_1.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO\u0027", "severity": "Error", + "asset": "p_smoke_small_thin2", "context": [ - "Weather_Ambient_Clear_Sandstorm_Loop" - ], - "asset": "AMB_DES_CLEAR_LOOP_1.WAV" + "Ground_Empire_Hypervelocity_Gun", + "DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0504_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027W_SwampGasEmit.ALO\u0027", "severity": "Error", + "asset": "W_SwampGasEmit.ALO", "context": [ - "Unit_Remove_Corruption_Leia" - ], - "asset": "U000_LEI0504_ENG.WAV" + "Prop_SwampGasEmitter" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0502_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE.ALO\u0027", "severity": "Error", + "asset": "lookat", "context": [ - "Unit_Remove_Corruption_Leia" - ], - "asset": "U000_LEI0502_ENG.WAV" + "Eclipse_Prop", + "DATA\\ART\\MODELS\\UV_ECLIPSE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_DEF3106_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Rbel_grey.alo\u0027", "severity": "Error", + "asset": "CIN_Rbel_grey.alo", "context": [ - "Unit_Weaken_Sabateur" - ], - "asset": "U000_DEF3106_ENG.WAV" + "Cin_Rebel_Grey" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_ARC3105_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", + "asset": "Cin_DeathStar_High.alo", "context": [ - "Unit_Complete_Troops_Arc_Hammer" - ], - "asset": "U000_ARC3105_ENG.WAV" + "Death_Star_Whole_Vsmall" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0601_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_p_proton_torpedo.alo\u0027", "severity": "Error", + "asset": "CIN_p_proton_torpedo.alo", "context": [ - "Unit_Increase_Production_Leia" - ], - "asset": "U000_LEI0601_ENG.WAV" + "Cin_Proj_Ground_Proton_Torpedo" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO\u0027", "severity": "Error", + "asset": "lookat", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0204_ENG.WAV" + "Eclipse_Super_Star_Destroyer", + "DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027CIN_Fire_Medium.alo\u0027", "severity": "Error", + "asset": "CIN_Fire_Medium.alo", "context": [ - "Unit_Move_Leia" - ], - "asset": "U000_LEI0207_ENG.WAV" + "Fin_Fire_Medium" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027FS_BEETLE_4.WAV\u0027 could not be found.", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_04_STATION_D.ALO\u0027", "severity": "Error", + "asset": "p_uwstation_death", "context": [ - "SFX_Anim_Beetle_Footsteps" - ], - "asset": "FS_BEETLE_4.WAV" + "Underworld_Star_Base_4_Death_Clone", + "DATA\\ART\\MODELS\\UB_04_STATION_D.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.AudioFilesVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Audio file \u0027AMB_URB_CLEAR_LOOP_1.WAV\u0027 could not be found.", + "message": "Unable to find .ALO file \u0027Cin_Planet_Hoth_High.alo\u0027", "severity": "Error", + "asset": "Cin_Planet_Hoth_High.alo", "context": [ - "Weather_Ambient_Clear_Urban_Loop" - ], - "asset": "AMB_URB_CLEAR_LOOP_1.WAV" + "Hoth_Backdrop_Large 6x" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Could not find GUI texture \u0027i_dialogue_button_large_middle_off.tga\u0027 at location \u0027Repository\u0027.", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO\u0027", "severity": "Error", + "asset": "Lensflare0", "context": [ - "IDC_PLAY_FACTION_B_BUTTON_BIG", - "Repository" - ], - "asset": "i_dialogue_button_large_middle_off.tga" + "Stars_Lua_Cinematic", + "DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Could not find GUI texture \u0027underworld_logo_selected.tga\u0027 at location \u0027MegaTexture\u0027.", + "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "severity": "Error", + "asset": "NB_YsalamiriTree_B.tga", "context": [ - "IDC_PLAY_FACTION_A_BUTTON_BIG", - "MegaTexture" - ], - "asset": "underworld_logo_selected.tga" + "Underworld_Ysalamiri_Cage", + "UV_MDU_CAGE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", + "AET.ModVerify.Verifiers.Commons.TextureVerifier" ], - "message": "Could not find GUI texture \u0027underworld_logo_off.tga\u0027 at location \u0027MegaTexture\u0027.", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [Vengeance_Frigate--\u003EUV_VENGEANCE.ALO].", "severity": "Error", + "asset": "W_TE_Rock_f_02_b.tga", "context": [ - "IDC_PLAY_FACTION_A_BUTTON_BIG", - "MegaTexture" - ], - "asset": "underworld_logo_off.tga" + "Vengeance_Frigate", + "UV_VENGEANCE.ALO" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier" ], - "message": "Could not find GUI texture \u0027i_button_petro_sliver.tga\u0027 at location \u0027MegaTexture\u0027.", - "severity": "Error", + "message": "Could not find icon \u0027i_button_ni_nightsister_ranger.tga\u0027 for game object type \u0027Dathomir_Night_Sister\u0027.", + "severity": "Warning", + "asset": "i_button_ni_nightsister_ranger.tga", "context": [ - "IDC_MENU_PETRO_LOGO", - "MegaTexture" - ], - "asset": "i_button_petro_sliver.tga" + "Dathomir_Night_Sister" + ] }, { "id": "FILE00", "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" + "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", + "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" ], - "message": "Could not find GUI texture \u0027underworld_logo_rollover.tga\u0027 at location \u0027MegaTexture\u0027.", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO\u0027.", "severity": "Error", + "asset": "Default.fx", "context": [ - "IDC_PLAY_FACTION_A_BUTTON_BIG", - "MegaTexture" - ], - "asset": "underworld_logo_rollover.tga" + "Empire_Offensive_Sensor_Node", + "DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO" + ] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_planet_land_forces\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027radar_blip\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_planet_land_forces" + "asset": "radar_blip", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_ground_sell\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_power\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_ground_sell" + "asset": "st_power", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_bracket_medium\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_hero\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_bracket_medium" + "asset": "g_hero", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027b_planet_right\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_bounty_hunter\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "b_planet_right" + "asset": "g_bounty_hunter", + "context": [] }, { "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_credit_bar\u0027 is not supported by the game.", - "severity": "Information", - "context": [], - "asset": "g_credit_bar" + "message": "The CommandBar component \u0027generic_collision\u0027 is not connected to a shell component.", + "severity": "Warning", + "asset": "generic_collision", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027zoomed_header_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027objective_header_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "zoomed_header_text" + "asset": "objective_header_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_space_level_pips\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tactical_sell\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_space_level_pips" + "asset": "tactical_sell", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027bribed_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027garrison_slot_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "bribed_icon" + "asset": "garrison_slot_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_header_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027cs_ability_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_header_text" + "asset": "cs_ability_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tutorial_text_back\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_bracket_small\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tutorial_text_back" + "asset": "st_bracket_small", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_back\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027zoomed_right_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_back" + "asset": "zoomed_right_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tooltip_icon_land\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_text" + "asset": "tooltip_icon_land", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027balance_pip\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027b_quick_ref\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "balance_pip" + "asset": "b_quick_ref", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027objective_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027zoomed_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "objective_text" + "asset": "zoomed_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027skirmish_upgrade\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_shields\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "skirmish_upgrade" + "asset": "st_shields", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027surface_mod_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027zoomed_cost_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "surface_mod_icon" + "asset": "zoomed_cost_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_hero_health\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_space_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_hero_health" + "asset": "g_space_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027bribe_display\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_health_bar\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "bribe_display" + "asset": "st_health_bar", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_build\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_radar_view\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_build" + "asset": "g_radar_view", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027garrison_slot_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_planet_ring\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "garrison_slot_icon" + "asset": "g_planet_ring", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_conflict\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_shields_large\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_conflict" + "asset": "st_shields_large", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tooltip_name\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tooltip_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tooltip_name" + "asset": "tooltip_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027garrison_respawn_counter\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_ground_level\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "garrison_respawn_counter" + "asset": "g_ground_level", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_ability_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_hero_health\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_ability_icon" + "asset": "st_hero_health", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_shields_medium\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027bribed_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_shields_medium" + "asset": "bribed_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_health\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027zoomed_back\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_health" + "asset": "zoomed_back", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_weather\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_space_level_pips\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_weather" + "asset": "g_space_level_pips", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR03", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_health_medium\u0027 is not connected to a shell component.", - "severity": "Warning", - "context": [], - "asset": "st_health_medium" + "message": "The CommandBar component \u0027g_credit_bar\u0027 is not supported by the game.", + "severity": "Information", + "asset": "g_credit_bar", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_power\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027help_back\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_power" + "asset": "help_back", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_ground_level_pips\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027zoomed_header_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_ground_level_pips" + "asset": "zoomed_header_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027zoomed_cost_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_hero_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "zoomed_cost_text" + "asset": "g_hero_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027bm_title_4011\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tooltip_back\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "bm_title_4011" + "asset": "tooltip_back", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_planet_name\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_conflict\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_planet_name" + "asset": "g_conflict", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_shields_large\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_health\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_shields_large" + "asset": "st_health", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_hero_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_hero_icon" + "asset": "encyclopedia_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027generic_flytext\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_planet_ability\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "generic_flytext" + "asset": "g_planet_ability", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027reinforcement_counter\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_back\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "reinforcement_counter" + "asset": "encyclopedia_back", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_planet_value\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027objective_back\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_planet_value" + "asset": "objective_back", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027radar_blip\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027generic_flytext\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "radar_blip" + "asset": "generic_flytext", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_political_control\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027bm_title_4011\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_political_control" + "asset": "bm_title_4011", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_planet_ring\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tutorial_text_back\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_planet_ring" + "asset": "tutorial_text_back", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_garrison_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027surface_mod_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_garrison_icon" + "asset": "surface_mod_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_right_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_corruption_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_right_text" + "asset": "g_corruption_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027b_quick_ref\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_right_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "b_quick_ref" + "asset": "encyclopedia_right_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027objective_back\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_grab_bar\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "objective_back" + "asset": "st_grab_bar", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_center_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027b_planet_right\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_center_text" + "asset": "b_planet_right", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_shields\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_control_group\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_shields" + "asset": "st_control_group", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_grab_bar\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_center_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_grab_bar" + "asset": "encyclopedia_center_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_smuggler\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027zoomed_center_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_smuggler" + "asset": "zoomed_center_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_enemy_hero\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_cost_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_enemy_hero" + "asset": "encyclopedia_cost_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027cs_ability_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027garrison_respawn_counter\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "cs_ability_text" + "asset": "garrison_respawn_counter", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_cost_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_enemy_hero\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_cost_text" + "asset": "g_enemy_hero", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_planet_ability\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027balance_pip\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_planet_ability" + "asset": "balance_pip", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_control_group\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_ground_level_pips\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_control_group" + "asset": "g_ground_level_pips", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027gui_dialog_tooltip\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_ground_sell\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "gui_dialog_tooltip" + "asset": "g_ground_sell", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027remote_bomb_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tutorial_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "remote_bomb_icon" + "asset": "tutorial_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tutorial_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_political_control\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tutorial_text" + "asset": "g_political_control", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_space_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027objective_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_space_icon" + "asset": "objective_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_bracket_large\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_planet_land_forces\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_bracket_large" + "asset": "g_planet_land_forces", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027zoomed_back\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_corruption_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "zoomed_back" + "asset": "g_corruption_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027encyclopedia_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_credit_bar\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "encyclopedia_icon" + "asset": "g_credit_bar", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027zoomed_right_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_smuggler\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "zoomed_right_text" + "asset": "g_smuggler", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027b_beacon_t\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_ability_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "b_beacon_t" + "asset": "st_ability_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_bounty_hunter\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027b_beacon_t\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_bounty_hunter" + "asset": "b_beacon_t", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_credit_bar\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_radar_blip\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_credit_bar" + "asset": "g_radar_blip", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_hero\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_planet_value\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_hero" + "asset": "g_planet_value", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027bm_title_4010\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_health_large\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "bm_title_4010" + "asset": "st_health_large", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_planet_fleet\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027skirmish_upgrade\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_planet_fleet" + "asset": "skirmish_upgrade", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_corruption_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_space_level\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_corruption_icon" + "asset": "g_space_level", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_smuggled\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027objective_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_smuggled" + "asset": "objective_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027help_back\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tooltip_left_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "help_back" + "asset": "tooltip_left_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_bracket_small\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_garrison_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_bracket_small" + "asset": "st_garrison_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027objective_header_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027cs_ability_button\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "objective_header_text" + "asset": "cs_ability_button", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_corruption_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_build\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_corruption_text" + "asset": "g_build", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_ground_level\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_health_medium\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_ground_level" + "asset": "st_health_medium", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027lt_weather_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_smuggled\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "lt_weather_icon" + "asset": "g_smuggled", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027cs_ability_button\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_bracket_medium\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "cs_ability_button" + "asset": "st_bracket_medium", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_radar_view\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027remote_bomb_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_radar_view" + "asset": "remote_bomb_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027objective_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_weather\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "objective_icon" + "asset": "g_weather", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tooltip_back\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_planet_name\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tooltip_back" + "asset": "g_planet_name", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027zoomed_center_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_header_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "zoomed_center_text" + "asset": "encyclopedia_header_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_health_bar\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_shields_medium\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_health_bar" + "asset": "st_shields_medium", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027zoomed_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_planet_fleet\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "zoomed_text" + "asset": "g_planet_fleet", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027generic_collision\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tooltip_name\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "generic_collision" + "asset": "tooltip_name", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tooltip_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027g_ground_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tooltip_icon" + "asset": "g_ground_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_radar_blip\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_hero_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_radar_blip" + "asset": "st_hero_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_hero_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027st_bracket_large\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_hero_icon" + "asset": "st_bracket_large", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_space_level\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027bribe_display\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_space_level" + "asset": "bribe_display", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027b_planet_left\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027bm_title_4010\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "b_planet_left" + "asset": "bm_title_4010", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tooltip_icon_land\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027reinforcement_counter\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tooltip_icon_land" + "asset": "reinforcement_counter", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027g_ground_icon\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027b_planet_left\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_ground_icon" + "asset": "b_planet_left", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tooltip_price\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027lt_weather_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tooltip_price" + "asset": "lt_weather_icon", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tooltip_left_text\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027encyclopedia_text\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tooltip_left_text" + "asset": "encyclopedia_text", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027st_health_large\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027tooltip_price\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "st_health_large" + "asset": "tooltip_price", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], - "message": "The CommandBar component \u0027tactical_sell\u0027 is not connected to a shell component.", + "message": "The CommandBar component \u0027gui_dialog_tooltip\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "tactical_sell" + "asset": "gui_dialog_tooltip", + "context": [] }, { - "id": "CMDBAR05", + "id": "CMDBAR04", "verifiers": [ - "AET.ModVerify.Verifiers.CommandBarVerifier" + "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" ], "message": "The CommandBar component \u0027g_special_ability\u0027 is not connected to a shell component.", "severity": "Warning", - "context": [], - "asset": "g_special_ability" + "asset": "g_special_ability", + "context": [] } ] } \ No newline at end of file diff --git a/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs b/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs index 5a9cbb3..de435fb 100644 --- a/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs +++ b/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs @@ -16,7 +16,7 @@ public JsonAggregatedVerificationError( string message, VerificationSeverity severity, IEnumerable>? contexts, - string? asset) : base(id, verifierChain, message, severity, asset) + string? asset) : base(id, severity, asset, message, verifierChain) { Contexts = contexts ?? []; } diff --git a/src/ModVerify/Reporting/Json/JsonVerificationError.cs b/src/ModVerify/Reporting/Json/JsonVerificationError.cs index 0e23283..f94f9f3 100644 --- a/src/ModVerify/Reporting/Json/JsonVerificationError.cs +++ b/src/ModVerify/Reporting/Json/JsonVerificationError.cs @@ -8,22 +8,22 @@ internal class JsonVerificationError : JsonVerificationErrorBase { [JsonPropertyName("context")] [JsonPropertyOrder(99)] - public IEnumerable? ContextEntries { get; } + public IEnumerable ContextEntries { get; } [JsonConstructor] public JsonVerificationError( - string id, - IReadOnlyList? verifierChain, + string id, + VerificationSeverity severity, + string? asset, string message, - VerificationSeverity severity, - IEnumerable? contextEntries, - string? asset) : base(id, verifierChain, message, severity, asset) + IReadOnlyList? verifierChain, + IEnumerable contextEntries) : base(id, severity, asset, message, verifierChain) { ContextEntries = contextEntries; } public JsonVerificationError(VerificationError error) : base(error) { - ContextEntries = error.ContextEntries.Any() ? error.ContextEntries : null; + ContextEntries = error.ContextEntries.Any() ? error.ContextEntries : []; } } \ No newline at end of file diff --git a/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs b/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs index 06af012..bd3b875 100644 --- a/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs +++ b/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs @@ -11,12 +11,6 @@ internal abstract class JsonVerificationErrorBase [JsonPropertyName("id")] public string Id { get; } - [JsonPropertyName("verifiers")] - public IReadOnlyList VerifierChain { get; } - - [JsonPropertyName("message")] - public string Message { get; } - [JsonPropertyName("severity")] [JsonConverter(typeof(JsonStringEnumConverter))] public VerificationSeverity Severity { get; } @@ -24,12 +18,17 @@ internal abstract class JsonVerificationErrorBase [JsonPropertyName("asset")] public string Asset { get; } - protected JsonVerificationErrorBase( - string id, - IReadOnlyList? verifierChain, - string message, + [JsonPropertyName("message")] + public string Message { get; } + + [JsonPropertyName("verifiers")] + public IReadOnlyList VerifierChain { get; } + + protected JsonVerificationErrorBase(string id, VerificationSeverity severity, - string? asset) + string? asset, + string message, + IReadOnlyList? verifierChain) { Id = id; VerifierChain = verifierChain ?? []; diff --git a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs index d9cdebe..7e2defc 100644 --- a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs +++ b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs @@ -30,7 +30,8 @@ private JsonVerificationReport CreateJsonReport(VerificationResult result) if (Settings.AggregateResults) { errors = result.Errors - .OrderBy(x => x.Id) + .OrderByDescending(x => x.Severity) + .ThenBy(x => x.Id) .GroupBy(x => new GroupKey(x.Asset, x.Id, x.VerifierChain)) .Select, JsonVerificationErrorBase>(g => { @@ -45,7 +46,8 @@ private JsonVerificationReport CreateJsonReport(VerificationResult result) else { errors = result.Errors - .OrderBy(x => x.Id) + .OrderByDescending(x => x.Severity) + .ThenBy(x => x.Id) .Select(x => new JsonVerificationError(x)); } diff --git a/src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs b/src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs index 11a63bf..8dc6360 100644 --- a/src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/SingleModelVerifier.cs @@ -85,7 +85,7 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte { var aloFilePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), modelPath.AsSpan()).ToString(); var message = $"'{aloFilePath}' is corrupted: {e.Message}"; - AddError(VerificationError.Create(this, VerifierErrorCodes.FileCorrupt, message, + AddError(VerificationError.Create(this, VerifierErrorCodes.BinaryFileCorrupt, message, VerificationSeverity.Critical, contextInfo, aloFilePath)); return; } diff --git a/src/ModVerify/Verifiers/VerifierErrorCodes.cs b/src/ModVerify/Verifiers/VerifierErrorCodes.cs index dca5326..04a900d 100644 --- a/src/ModVerify/Verifiers/VerifierErrorCodes.cs +++ b/src/ModVerify/Verifiers/VerifierErrorCodes.cs @@ -10,7 +10,7 @@ public static class VerifierErrorCodes public const string GenericExceptionErrorCode = "MV00"; - public const string FileCorrupt = "ENG00"; + public const string BinaryFileCorrupt = "BIN00"; public const string FileNotFound = "FILE00"; From 031f865ffa522af1a2f57dfaaf8135b4f00783a3 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Mar 2026 17:22:27 +0100 Subject: [PATCH 37/41] make verifier chain an optional feature for reporting --- src/ModVerify.CliApp/App/VerifyAction.cs | 5 +- .../Resources/Baselines/baseline-foc.json | 3144 +++++------------ src/ModVerify/ModVerify.csproj | 2 +- .../Baseline/VerificationBaseline.cs | 3 +- .../Json/JsonAggregatedVerificationError.cs | 4 +- .../Reporting/Json/JsonVerificationError.cs | 3 +- .../Json/JsonVerificationErrorBase.cs | 10 +- .../Reporting/Reporters/JSON/JsonReporter.cs | 7 +- .../Reporters/JSON/JsonReporterSettings.cs | 1 - .../Reporting/Reporters/ReporterSettings.cs | 1 + src/ModVerify/Reporting/VerificationError.cs | 5 +- .../Schemas/{2.1 => 2.2}/baseline.json | 11 +- 12 files changed, 986 insertions(+), 2210 deletions(-) rename src/ModVerify/Resources/Schemas/{2.1 => 2.2}/baseline.json (92%) diff --git a/src/ModVerify.CliApp/App/VerifyAction.cs b/src/ModVerify.CliApp/App/VerifyAction.cs index f30305c..e17d7bc 100644 --- a/src/ModVerify.CliApp/App/VerifyAction.cs +++ b/src/ModVerify.CliApp/App/VerifyAction.cs @@ -73,6 +73,7 @@ private IReadOnlyCollection CreateReporters() reporters.Add(IVerificationReporter.CreateConsole(new ConsoleReporterSettings { + Verbose = Settings.ReportSettings.Verbose, MinimumReportSeverity = Settings.VerifierServiceSettings.FailFastSettings.IsFailFast ? VerificationSeverity.Information : VerificationSeverity.Error @@ -83,11 +84,13 @@ private IReadOnlyCollection CreateReporters() { OutputDirectory = outputDirectory, MinimumReportSeverity = Settings.ReportSettings.MinimumReportSeverity, - AggregateResults = true + AggregateResults = true, + Verbose = Settings.ReportSettings.Verbose }, ServiceProvider)); reporters.Add(IVerificationReporter.CreateText(new TextFileReporterSettings { + Verbose = Settings.ReportSettings.Verbose, OutputDirectory = outputDirectory!, MinimumReportSeverity = Settings.ReportSettings.MinimumReportSeverity }, ServiceProvider)); diff --git a/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json b/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json index 209033e..7eb4e06 100644 --- a/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json +++ b/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json @@ -1,5 +1,5 @@ { - "version": "2.1", + "version": "2.2", "target": { "name": "Forces of Corruption (SteamGold)", "engine": "Foc", @@ -9,82 +9,64 @@ "minSeverity": "Information", "errors": [ { - "id": "XML10", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8608\u0027", + "id": "XML08", "severity": "Information", - "asset": "Disabled_Darken", + "asset": "DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML #0\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", - "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Disabled_Darken", - "parentName=\u0027b_fast_forward_t\u0027" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML" ] }, { - "id": "XML10", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8569\u0027", - "severity": "Information", - "asset": "Disabled_Darken", + "id": "XML04", + "severity": "Warning", + "asset": "Probability", + "message": "Expected integer but got \u002780, 20\u0027. File=\u0027DATA\\XML\\SFXEVENTSWEAPONS.XML #90\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", - "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Disabled_Darken", - "parentName=\u0027b_fast_forward\u0027" + "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlIntegerParser", + "File: DATA\\XML\\SFXEVENTSWEAPONS.XML", + "Probability", + "parentName=\u0027Unit_TIE_Fighter_Fire\u0027" ] }, { "id": "XML08", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML #0\u0027", "severity": "Information", - "asset": "DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML", + "asset": "DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML" + "File: DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML" ] }, { "id": "XML08", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML #0\u0027", "severity": "Information", - "asset": "DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML", + "asset": "DATA\\XML\\SPACEPROPS_UNDERWORLD.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\SPACEPROPS_UNDERWORLD.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML" + "File: DATA\\XML\\SPACEPROPS_UNDERWORLD.XML" ] }, { - "id": "XML08", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\SPACEPROPS_UNDERWORLD.XML #0\u0027", + "id": "XML10", "severity": "Information", - "asset": "DATA\\XML\\SPACEPROPS_UNDERWORLD.XML", + "asset": "Mega_Texture_Name", + "message": "The node \u0027Mega_Texture_Name\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\SPACEPROPS_UNDERWORLD.XML" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Mega_Texture_Name", + "parentName=\u0027i_main_commandbar\u0027" ] }, { "id": "XML10", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8550\u0027", "severity": "Information", "asset": "Disabled_Darken", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8550\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", @@ -93,28 +75,22 @@ ] }, { - "id": "XML04", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "Expected double but got value \u002737\u0060\u0027. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #11571\u0027", - "severity": "Warning", - "asset": "Size", + "id": "XML10", + "severity": "Information", + "asset": "Disabled_Darken", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8569\u0027", "context": [ - "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlFloatParser", + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Size", - "parentName=\u0027bm_text_steal\u0027" + "Disabled_Darken", + "parentName=\u0027b_fast_forward\u0027" ] }, { "id": "XML10", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8589\u0027", "severity": "Information", "asset": "Disabled_Darken", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8589\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", @@ -123,41 +99,32 @@ ] }, { - "id": "XML10", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "The node \u0027Mega_Texture_Name\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8\u0027", - "severity": "Information", - "asset": "Mega_Texture_Name", + "id": "XML04", + "severity": "Warning", + "asset": "Size", + "message": "Expected double but got value \u002737\u0060\u0027. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #11571\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlFloatParser", "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Mega_Texture_Name", - "parentName=\u0027i_main_commandbar\u0027" + "Size", + "parentName=\u0027bm_text_steal\u0027" ] }, { "id": "XML08", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML #0\u0027", "severity": "Information", - "asset": "DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML", + "asset": "DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML" + "File: DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML" ] }, { "id": "XML08", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML #0\u0027", "severity": "Information", "asset": "DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", "File: DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML" @@ -165,1431 +132,985 @@ }, { "id": "XML08", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML #0\u0027", "severity": "Information", - "asset": "DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML", + "asset": "DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_HERO_REBEL_ROGUE_SQUADRON.XML" + "File: DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML" ] }, { - "id": "XML04", - "verifiers": [ - "AET.ModVerify.Reporting.Engine.XmlParseErrorReporter" - ], - "message": "Expected integer but got \u002780, 20\u0027. File=\u0027DATA\\XML\\SFXEVENTSWEAPONS.XML #90\u0027", - "severity": "Warning", - "asset": "Probability", + "id": "XML10", + "severity": "Information", + "asset": "Disabled_Darken", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8608\u0027", "context": [ - "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlIntegerParser", - "File: DATA\\XML\\SFXEVENTSWEAPONS.XML", - "Probability", - "parentName=\u0027Unit_TIE_Fighter_Fire\u0027" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_fast_forward_t\u0027" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0313_ENG.WAV", + "asset": "U000_LEI0101_ENG.WAV", + "message": "Audio file \u0027U000_LEI0101_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0502_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0502_ENG.WAV", + "asset": "U000_LEI0312_ENG.WAV", + "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "severity": "Error", "asset": "U000_LEI0304_ENG.WAV", + "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0201_ENG.WAV", + "asset": "U000_LEI0404_ENG.WAV", + "message": "Audio file \u0027U000_LEI0404_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Guard_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0204_ENG.WAV", + "asset": "U000_LEI0502_ENG.WAV", + "message": "Audio file \u0027U000_LEI0502_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0208_ENG.WAV", + "asset": "U000_LEI0315_ENG.WAV", + "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_MCF1601_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_MCF1601_ENG.WAV", + "asset": "U000_LEI0307_ENG.WAV", + "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_StarDest_MC30_Frigate" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0210_ENG.WAV", + "asset": "U000_LEI0402_ENG.WAV", + "message": "Audio file \u0027U000_LEI0402_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Guard_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027FS_BEETLE_3.WAV\u0027 could not be found.", "severity": "Error", - "asset": "FS_BEETLE_3.WAV", + "asset": "U000_LEI0304_ENG.WAV", + "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0203_ENG.WAV", + "asset": "U000_MAL0503_ENG.WAV", + "message": "Audio file \u0027U000_MAL0503_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Assist_Move_Missile_Launcher" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0309_ENG.WAV", + "asset": "U000_LEI0103_ENG.WAV", + "message": "Audio file \u0027U000_LEI0103_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0315_ENG.WAV", + "asset": "U000_LEI0309_ENG.WAV", + "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0504_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0504_ENG.WAV", + "asset": "U000_LEI0202_ENG.WAV", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0301_ENG.WAV", + "asset": "U000_DEF3006_ENG.WAV", + "message": "Audio file \u0027U000_DEF3006_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Corrupt_Sabateur" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0106_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0106_ENG.WAV", + "asset": "U000_LEI0210_ENG.WAV", + "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0110_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0110_ENG.WAV", + "asset": "U000_LEI0208_ENG.WAV", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0211_ENG.WAV", + "asset": "U000_LEI0112_ENG.WAV", + "message": "Audio file \u0027U000_LEI0112_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0305_ENG.WAV", + "asset": "U000_LEI0301_ENG.WAV", + "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0105_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0105_ENG.WAV", + "asset": "U000_LEI0307_ENG.WAV", + "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_DEF3006_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_DEF3006_ENG.WAV", + "asset": "FS_BEETLE_1.WAV", + "message": "Audio file \u0027FS_BEETLE_1.WAV\u0027 could not be found.", "context": [ - "Unit_Corrupt_Sabateur" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0212_ENG.WAV", + "asset": "U000_LEI0206_ENG.WAV", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0207_ENG.WAV", + "asset": "U000_LEI0203_ENG.WAV", + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027FS_BEETLE_4.WAV\u0027 could not be found.", "severity": "Error", - "asset": "FS_BEETLE_4.WAV", + "asset": "U000_LEI0212_ENG.WAV", + "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0303_ENG.WAV", + "asset": "FS_BEETLE_3.WAV", + "message": "Audio file \u0027FS_BEETLE_3.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0102_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0102_ENG.WAV", + "asset": "U000_ARC3106_ENG.WAV", + "message": "Audio file \u0027U000_ARC3106_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Complete_Troops_Arc_Hammer" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0209_ENG.WAV", + "asset": "U000_LEI0604_ENG.WAV", + "message": "Audio file \u0027U000_LEI0604_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0307_ENG.WAV", + "asset": "U000_ARC3104_ENG.WAV", + "message": "Audio file \u0027U000_ARC3104_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Produce_Troops_Arc_Hammer" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027C000_DST0102_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "C000_DST0102_ENG.WAV", + "asset": "FS_BEETLE_2.WAV", + "message": "Audio file \u0027FS_BEETLE_2.WAV\u0027 could not be found.", "context": [ - "EHD_Death_Star_Activate" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0202_ENG.WAV", + "asset": "U000_LEI0208_ENG.WAV", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0306_ENG.WAV", + "asset": "EGL_STAR_VIPER_SPINNING_1.WAV", + "message": "Audio file \u0027EGL_STAR_VIPER_SPINNING_1.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Star_Viper_Spinning_By" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0503_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0503_ENG.WAV", + "asset": "U000_LEI0306_ENG.WAV", + "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0205_ENG.WAV", + "asset": "U000_TMC0212_ENG.WAV", + "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Assist_Move_Tie_Mauler" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0205_ENG.WAV", + "asset": "U000_LEI0303_ENG.WAV", + "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0107_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0107_ENG.WAV", + "asset": "U000_LEI0303_ENG.WAV", + "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027TESTUNITMOVE_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "TESTUNITMOVE_ENG.WAV", + "asset": "U000_LEI0201_ENG.WAV", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Gneneric_Test" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0101_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0101_ENG.WAV", + "asset": "U000_LEI0114_ENG.WAV", + "message": "Audio file \u0027U000_LEI0114_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0312_ENG.WAV", + "asset": "U000_LEI0601_ENG.WAV", + "message": "Audio file \u0027U000_LEI0601_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0201_ENG.WAV", + "asset": "U000_LEI0105_ENG.WAV", + "message": "Audio file \u0027U000_LEI0105_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0308_ENG.WAV", + "asset": "U000_LEI0207_ENG.WAV", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0208_ENG.WAV", + "asset": "U000_LEI0308_ENG.WAV", + "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0207_ENG.WAV", + "asset": "U000_LEI0113_ENG.WAV", + "message": "Audio file \u0027U000_LEI0113_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0103_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0103_ENG.WAV", + "asset": "AMB_DES_CLEAR_LOOP_1.WAV", + "message": "Audio file \u0027AMB_DES_CLEAR_LOOP_1.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Weather_Ambient_Clear_Sandstorm_Loop" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0203_ENG.WAV", + "asset": "U000_LEI0309_ENG.WAV", + "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0206_ENG.WAV", + "asset": "U000_LEI0108_ENG.WAV", + "message": "Audio file \u0027U000_LEI0108_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0304_ENG.WAV", + "asset": "U000_LEI0305_ENG.WAV", + "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0314_ENG.WAV", + "asset": "U000_LEI0501_ENG.WAV", + "message": "Audio file \u0027U000_LEI0501_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0303_ENG.WAV", + "asset": "U000_LEI0201_ENG.WAV", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "severity": "Error", "asset": "U000_LEI0201_ENG.WAV", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0210_ENG.WAV", + "asset": "U000_LEI0204_ENG.WAV", + "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_DEF3106_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_DEF3106_ENG.WAV", + "asset": "U000_LEI0202_ENG.WAV", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Weaken_Sabateur" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0311_ENG.WAV", + "asset": "U000_LEI0203_ENG.WAV", + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0311_ENG.WAV", + "asset": "U000_LEI0503_ENG.WAV", + "message": "Audio file \u0027U000_LEI0503_ENG.WAV\u0027 could not be found.", + "context": [ + "Unit_Remove_Corruption_Leia" + ] + }, + { + "id": "FILE00", + "severity": "Error", + "asset": "U000_LEI0312_ENG.WAV", + "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0208_ENG.WAV", + "asset": "U000_LEI0313_ENG.WAV", + "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_TMC0212_ENG.WAV", + "asset": "U000_LEI0210_ENG.WAV", + "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Assist_Move_Tie_Mauler" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_ARC3106_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_ARC3106_ENG.WAV", + "asset": "U000_LEI0206_ENG.WAV", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Complete_Troops_Arc_Hammer" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0601_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0601_ENG.WAV", + "asset": "C000_DST0102_ENG.WAV", + "message": "Audio file \u0027C000_DST0102_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "EHD_Death_Star_Activate" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0403_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0403_ENG.WAV", + "asset": "U000_LEI0401_ENG.WAV", + "message": "Audio file \u0027U000_LEI0401_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Guard_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0604_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0604_ENG.WAV", + "asset": "U000_LEI0602_ENG.WAV", + "message": "Audio file \u0027U000_LEI0602_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0306_ENG.WAV", + "asset": "U000_LEI0104_ENG.WAV", + "message": "Audio file \u0027U000_LEI0104_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0309_ENG.WAV", + "asset": "U000_LEI0202_ENG.WAV", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0111_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0111_ENG.WAV", + "asset": "U000_MCF1601_ENG.WAV", + "message": "Audio file \u0027U000_MCF1601_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_StarDest_MC30_Frigate" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0215_ENG.WAV", + "asset": "U000_LEI0211_ENG.WAV", + "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027FS_BEETLE_2.WAV\u0027 could not be found.", "severity": "Error", - "asset": "FS_BEETLE_2.WAV", + "asset": "U000_LEI0205_ENG.WAV", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0213_ENG.WAV", + "asset": "U000_LEI0301_ENG.WAV", + "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0213_ENG.WAV", + "asset": "U000_LEI0311_ENG.WAV", + "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0115_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0115_ENG.WAV", + "asset": "U000_LEI0203_ENG.WAV", + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0315_ENG.WAV", + "asset": "U000_LEI0311_ENG.WAV", + "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0203_ENG.WAV", + "asset": "U000_DEF3106_ENG.WAV", + "message": "Audio file \u0027U000_DEF3106_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Weaken_Sabateur" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_TMC0212_ENG.WAV", + "asset": "U000_LEI0305_ENG.WAV", + "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Tie_Mauler" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0202_ENG.WAV", - "context": [ - "Unit_Fleet_Move_Leia" + "asset": "U000_LEI0314_ENG.WAV", + "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", + "context": [ + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0312_ENG.WAV", + "asset": "U000_LEI0107_ENG.WAV", + "message": "Audio file \u0027U000_LEI0107_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0308_ENG.WAV", + "asset": "U000_LEI0215_ENG.WAV", + "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0108_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0108_ENG.WAV", + "asset": "U000_LEI0504_ENG.WAV", + "message": "Audio file \u0027U000_LEI0504_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0104_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0104_ENG.WAV", + "asset": "U000_LEI0110_ENG.WAV", + "message": "Audio file \u0027U000_LEI0110_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0204_ENG.WAV", + "asset": "FS_BEETLE_4.WAV", + "message": "Audio file \u0027FS_BEETLE_4.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0313_ENG.WAV", + "asset": "U000_LEI0207_ENG.WAV", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0603_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0603_ENG.WAV", + "asset": "U000_LEI0204_ENG.WAV", + "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0112_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0112_ENG.WAV", + "asset": "U000_LEI0106_ENG.WAV", + "message": "Audio file \u0027U000_LEI0106_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027EGL_STAR_VIPER_SPINNING_1.WAV\u0027 could not be found.", - "severity": "Error", - "asset": "EGL_STAR_VIPER_SPINNING_1.WAV", - "context": [ - "Unit_Star_Viper_Spinning_By" - ] - }, - { - "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0307_ENG.WAV", + "asset": "U000_LEI0313_ENG.WAV", + "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027AMB_URB_CLEAR_LOOP_1.WAV\u0027 could not be found.", "severity": "Error", - "asset": "AMB_URB_CLEAR_LOOP_1.WAV", + "asset": "U000_LEI0109_ENG.WAV", + "message": "Audio file \u0027U000_LEI0109_ENG.WAV\u0027 could not be found.", "context": [ - "Weather_Ambient_Clear_Urban_Loop" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0205_ENG.WAV", + "asset": "U000_TMC0212_ENG.WAV", + "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Move_Tie_Mauler" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027AMB_DES_CLEAR_LOOP_1.WAV\u0027 could not be found.", "severity": "Error", - "asset": "AMB_DES_CLEAR_LOOP_1.WAV", + "asset": "U000_LEI0403_ENG.WAV", + "message": "Audio file \u0027U000_LEI0403_ENG.WAV\u0027 could not be found.", "context": [ - "Weather_Ambient_Clear_Sandstorm_Loop" + "Unit_Guard_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0207_ENG.WAV", + "asset": "U000_LEI0209_ENG.WAV", + "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0501_ENG.WAV\u0027 could not be found.", - "severity": "Error", - "asset": "U000_LEI0501_ENG.WAV", - "context": [ - "Unit_Remove_Corruption_Leia" - ] - }, - { - "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_MAL0503_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_MAL0503_ENG.WAV", + "asset": "U000_LEI0212_ENG.WAV", + "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Assist_Move_Missile_Launcher" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0314_ENG.WAV", + "asset": "U000_LEI0205_ENG.WAV", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0602_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0602_ENG.WAV", + "asset": "U000_LEI0115_ENG.WAV", + "message": "Audio file \u0027U000_LEI0115_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0114_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0114_ENG.WAV", + "asset": "U000_LEI0315_ENG.WAV", + "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "severity": "Error", "asset": "U000_LEI0209_ENG.WAV", + "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027FS_BEETLE_1.WAV\u0027 could not be found.", "severity": "Error", - "asset": "FS_BEETLE_1.WAV", + "asset": "U000_LEI0205_ENG.WAV", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0404_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0404_ENG.WAV", + "asset": "U000_LEI0314_ENG.WAV", + "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0206_ENG.WAV", + "asset": "U000_LEI0308_ENG.WAV", + "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0215_ENG.WAV", + "asset": "U000_LEI0213_ENG.WAV", + "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0109_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0109_ENG.WAV", + "asset": "U000_LEI0208_ENG.WAV", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_ARC3105_ENG.WAV\u0027 could not be found.", "severity": "Error", "asset": "U000_ARC3105_ENG.WAV", + "message": "Audio file \u0027U000_ARC3105_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Complete_Troops_Arc_Hammer" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0206_ENG.WAV", + "asset": "U000_LEI0306_ENG.WAV", + "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_ARC3104_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_ARC3104_ENG.WAV", + "asset": "AMB_URB_CLEAR_LOOP_1.WAV", + "message": "Audio file \u0027AMB_URB_CLEAR_LOOP_1.WAV\u0027 could not be found.", "context": [ - "Unit_Produce_Troops_Arc_Hammer" + "Weather_Ambient_Clear_Urban_Loop" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0202_ENG.WAV", + "asset": "U000_LEI0102_ENG.WAV", + "message": "Audio file \u0027U000_LEI0102_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0402_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0402_ENG.WAV", + "asset": "U000_LEI0207_ENG.WAV", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0113_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0113_ENG.WAV", + "asset": "U000_LEI0111_ENG.WAV", + "message": "Audio file \u0027U000_LEI0111_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0212_ENG.WAV", + "asset": "TESTUNITMOVE_ENG.WAV", + "message": "Audio file \u0027TESTUNITMOVE_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Move_Gneneric_Test" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0305_ENG.WAV", + "asset": "U000_LEI0211_ENG.WAV", + "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0401_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0401_ENG.WAV", + "asset": "U000_LEI0215_ENG.WAV", + "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0301_ENG.WAV", + "asset": "U000_LEI0603_ENG.WAV", + "message": "Audio file \u0027U000_LEI0603_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.SfxEvents.SfxEventVerifier", - "AET.ModVerify.Verifiers.Commons.AudioFileVerifier" - ], - "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "severity": "Error", - "asset": "U000_LEI0211_ENG.WAV", + "asset": "U000_LEI0213_ENG.WAV", + "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" - ], - "message": "Could not find GUI texture \u0027i_button_petro_sliver.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", - "asset": "i_button_petro_sliver.tga", + "asset": "U000_LEI0206_ENG.WAV", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "context": [ - "IDC_MENU_PETRO_LOGO", - "MegaTexture" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" - ], - "message": "Could not find GUI texture \u0027underworld_logo_off.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", - "asset": "underworld_logo_off.tga", + "asset": "underworld_logo_selected.tga", + "message": "Could not find GUI texture \u0027underworld_logo_selected.tga\u0027 at location \u0027MegaTexture\u0027.", "context": [ "IDC_PLAY_FACTION_A_BUTTON_BIG", "MegaTexture" @@ -1597,12 +1118,9 @@ }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" - ], - "message": "Could not find GUI texture \u0027underworld_logo_rollover.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", - "asset": "underworld_logo_rollover.tga", + "asset": "underworld_logo_off.tga", + "message": "Could not find GUI texture \u0027underworld_logo_off.tga\u0027 at location \u0027MegaTexture\u0027.", "context": [ "IDC_PLAY_FACTION_A_BUTTON_BIG", "MegaTexture" @@ -1610,25 +1128,19 @@ }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" - ], - "message": "Could not find GUI texture \u0027underworld_logo_selected.tga\u0027 at location \u0027MegaTexture\u0027.", "severity": "Error", - "asset": "underworld_logo_selected.tga", + "asset": "i_button_petro_sliver.tga", + "message": "Could not find GUI texture \u0027i_button_petro_sliver.tga\u0027 at location \u0027MegaTexture\u0027.", "context": [ - "IDC_PLAY_FACTION_A_BUTTON_BIG", + "IDC_MENU_PETRO_LOGO", "MegaTexture" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GuiDialogs.GuiDialogsVerifier" - ], - "message": "Could not find GUI texture \u0027i_dialogue_button_large_middle_off.tga\u0027 at location \u0027Repository\u0027.", "severity": "Error", "asset": "i_dialogue_button_large_middle_off.tga", + "message": "Could not find GUI texture \u0027i_dialogue_button_large_middle_off.tga\u0027 at location \u0027Repository\u0027.", "context": [ "IDC_PLAY_FACTION_B_BUTTON_BIG", "Repository" @@ -1636,2471 +1148,1735 @@ }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_bomb_spin\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO\u0027", "severity": "Error", - "asset": "p_bomb_spin", + "asset": "underworld_logo_rollover.tga", + "message": "Could not find GUI texture \u0027underworld_logo_rollover.tga\u0027 at location \u0027MegaTexture\u0027.", "context": [ - "TIE_Bomber_Bombing_Run_Bomb", - "DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO" + "IDC_PLAY_FACTION_A_BUTTON_BIG", + "MegaTexture" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall.tga", + "asset": "lookat", + "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE.ALO\u0027", "context": [ - "Cin_w_tile", - "W_TILE.ALO" + "Eclipse_Prop", + "DATA\\ART\\MODELS\\UV_ECLIPSE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_DeathStar_Hangar.alo\u0027", "severity": "Error", - "asset": "CIN_DeathStar_Hangar.alo", + "asset": "CIN_NavyTrooper_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_NavyTrooper_Row.alo\u0027", "context": [ - "Cin_DeathStar_Hangar" + "Cin_NavyTrooper_Row" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027w_grenade.tga\u0027 for context: [Proj_Merc_Concussion_Grenade--\u003EW_GRENADE.ALO].", "severity": "Error", - "asset": "w_grenade.tga", + "asset": "p_smoke_small_thin4", + "message": "Proxy particle \u0027p_smoke_small_thin4\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "context": [ - "Proj_Merc_Concussion_Grenade", - "W_GRENADE.ALO" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Biker_Row.alo\u0027", "severity": "Error", - "asset": "CIN_Biker_Row.alo", + "asset": "CIN_Lambda_Head.alo", + "message": "Unable to find .ALO file \u0027CIN_Lambda_Head.alo\u0027", "context": [ - "Cin_Biker_Row" + "Cin_Lambda_Head" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_Planet_Alderaan_High.alo\u0027", "severity": "Error", - "asset": "Cin_Planet_Alderaan_High.alo", + "asset": "Cin_DStar_LeverPanel.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_LeverPanel.alo\u0027", "context": [ - "Alderaan_Backdrop_Large 6x" + "Death_Star_LeverPanel" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027P_mptl-2a_Die\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_MPTL-2A.ALO\u0027", "severity": "Error", - "asset": "P_mptl-2a_Die", + "asset": "W_Vol_Steam01.ALO", + "message": "Unable to find .ALO file \u0027W_Vol_Steam01.ALO\u0027", "context": [ - "MPTL", - "DATA\\ART\\MODELS\\RV_MPTL-2A.ALO" + "Prop_Vol_Steam01" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE.ALO\u0027", "severity": "Error", - "asset": "Lensflare0", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [TIE_Phantom--\u003EEV_TIE_PHANTOM.ALO].", "context": [ - "Stars_Cinematic", - "DATA\\ART\\MODELS\\W_STARS_CINE.ALO" + "TIE_Phantom", + "EV_TIE_PHANTOM.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DStar_Dish_close.alo\u0027", "severity": "Error", - "asset": "Cin_DStar_Dish_close.alo", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO\u0027", "context": [ - "Death_Star_Dish_Close" + "Kyle_Katarn", + "DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_ssd_debris\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO\u0027", "severity": "Error", - "asset": "p_ssd_debris", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_IG88.ALO\u0027", "context": [ - "Eclipse_Super_Star_Destroyer_Death_Clone", - "DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO" + "IG-88", + "DATA\\ART\\MODELS\\UI_IG88.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", + "asset": "Cin_DStar_TurretLasers.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_TurretLasers.alo\u0027", "context": [ - "Death_Star_Whole" + "TurretLasers_DStar_Xplode" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_05_STATION_D.ALO\u0027", "severity": "Error", - "asset": "p_uwstation_death", + "asset": "CIN_Fire_Medium.alo", + "message": "Unable to find .ALO file \u0027CIN_Fire_Medium.alo\u0027", "context": [ - "Underworld_Star_Base_5_Death_Clone", - "DATA\\ART\\MODELS\\UB_05_STATION_D.ALO" + "Fin_Fire_Medium" + ] + }, + { + "id": "FILE00", + "severity": "Warning", + "asset": "i_button_general_dodonna.tga", + "message": "Could not find icon \u0027i_button_general_dodonna.tga\u0027 for game object type \u0027General_Dodonna\u0027.", + "context": [ + "General_Dodonna" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DStar_LeverPanel.alo\u0027", "severity": "Error", - "asset": "Cin_DStar_LeverPanel.alo", + "asset": "W_SwampGasEmit.ALO", + "message": "Unable to find .ALO file \u0027W_SwampGasEmit.ALO\u0027", "context": [ - "Death_Star_LeverPanel" + "Prop_SwampGasEmitter" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027w_planet_volcanic.alo\u0027", "severity": "Error", - "asset": "w_planet_volcanic.alo", + "asset": "p_smoke_small_thin2", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO\u0027", "context": [ - "Volcanic_Backdrop_Large" + "MonCalamari_Spawn_House", + "DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_Wall.alo\u0027", "severity": "Error", - "asset": "Cin_DeathStar_Wall.alo", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "context": [ - "Death_Star_Hangar_Outside" + "Cin_w_tile", + "W_TILE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_Bush_Swmp00.ALO\u0027", "severity": "Error", - "asset": "W_Bush_Swmp00.ALO", + "asset": "CIN_Trooper_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_Trooper_Row.alo\u0027", "context": [ - "Prop_Swamp_Bush00" + "Cin_Trooper_Row" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_SABOTEUR.ALO\u0027", "severity": "Error", - "asset": "p_desert_ground_dust", + "asset": "Cin_Planet_Hoth_High.alo", + "message": "Unable to find .ALO file \u0027Cin_Planet_Hoth_High.alo\u0027", "context": [ - "Underworld_Saboteur", - "DATA\\ART\\MODELS\\UI_SABOTEUR.ALO" + "Hoth_Backdrop_Large 6x" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027UB_girder_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "severity": "Error", - "asset": "UB_girder_B.tga", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_05_STATION_D.ALO\u0027", "context": [ - "Underworld_Ysalamiri_Cage", - "UV_MDU_CAGE.ALO" + "Underworld_Star_Base_5_Death_Clone", + "DATA\\ART\\MODELS\\UB_05_STATION_D.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "severity": "Error", - "asset": "Cin_bridge.alo", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO\u0027.", "context": [ - "UM05_PROP_BRIDGE" + "Empire_Offensive_Sensor_Node", + "DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "severity": "Error", - "asset": "Cin_EI_Vader.alo", + "asset": "w_sith_arch.alo", + "message": "Unable to find .ALO file \u0027w_sith_arch.alo\u0027", "context": [ - "Cin_Vader_Shot_6-9" + "Cin_sith_arch" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall.tga", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "Cin_sith_lefthall", - "W_SITH_LEFTHALL.ALO" + "Death_Star_Whole" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "severity": "Error", - "asset": "Cin_EV_lambdaShuttle_150.alo", + "asset": "P_heat_small01", + "message": "Proxy particle \u0027P_heat_small01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_VCH.ALO\u0027", "context": [ - "Lambda_Shuttle_150X6-9" + "Volcanic_Civilian_Spawn_House_Independent_AI", + "DATA\\ART\\MODELS\\NB_VCH.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Officer_Row.alo\u0027", "severity": "Error", - "asset": "CIN_Officer_Row.alo", + "asset": "p_hp_archammer-damage", + "message": "Proxy particle \u0027p_hp_archammer-damage\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO\u0027", "context": [ - "Cin_Officer_Row" + "Arc_Hammer", + "DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "severity": "Error", - "asset": "Cin_EI_Vader.alo", + "asset": "p_ewok_drag_dirt", + "message": "Proxy particle \u0027p_ewok_drag_dirt\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO\u0027", "context": [ - "Cin_Vader" + "Ewok_Handler", + "DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "severity": "Error", - "asset": "W_Kamino_Reflect.ALO", + "asset": "CIN_Reb_CelebHall.alo", + "message": "Unable to find .ALO file \u0027CIN_Reb_CelebHall.alo\u0027", "context": [ - "Prop_Kamino_Reflection_00" + "REb_CelebHall" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_Coruscant.alo\u0027", "severity": "Error", - "asset": "Cin_Coruscant.alo", + "asset": "p_splash_wake_lava.alo", + "message": "Unable to find .ALO file \u0027p_splash_wake_lava.alo\u0027", "context": [ - "Corusant_Backdrop_Large 6x" + "Splash_Wake_Lava" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Probe_Droid.alo\u0027", "severity": "Error", - "asset": "CIN_Probe_Droid.alo", + "asset": "Cin_EV_Stardestroyer_Warp.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_Stardestroyer_Warp.alo\u0027", "context": [ - "Empire_Droid" + "Star_Destroyer_Warp" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "severity": "Error", - "asset": "p_smoke_small_thin2", + "asset": "NB_YsalamiriTree_B.tga", + "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "context": [ - "Imperial_Prison_Facility", - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "Underworld_Ysalamiri_Cage", + "UV_MDU_CAGE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027P_heat_small01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_VCH.ALO\u0027", "severity": "Error", - "asset": "P_heat_small01", + "asset": "Cin_DStar_Dish_close.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_Dish_close.alo\u0027", "context": [ - "Volcanic_Civilian_Spawn_House_Independent_AI", - "DATA\\ART\\MODELS\\NB_VCH.ALO" + "Death_Star_Dish_Close" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO\u0027", "severity": "Error", - "asset": "p_desert_ground_dust", + "asset": "Cin_Shuttle_Tyderium.alo", + "message": "Unable to find .ALO file \u0027Cin_Shuttle_Tyderium.alo\u0027", "context": [ - "Kyle_Katarn", - "DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO" + "Intro2_Shuttle_Tyderium" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027w_sith_arch.alo\u0027", "severity": "Error", - "asset": "w_sith_arch.alo", + "asset": "UB_girder_B.tga", + "message": "Could not find texture \u0027UB_girder_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "context": [ - "Cin_sith_arch" + "Underworld_Ysalamiri_Cage", + "UV_MDU_CAGE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Reb_CelebHall.alo\u0027", "severity": "Error", - "asset": "CIN_Reb_CelebHall.alo", + "asset": "w_grenade.tga", + "message": "Could not find texture \u0027w_grenade.tga\u0027 for context: [Proj_Merc_Concussion_Grenade--\u003EW_GRENADE.ALO].", "context": [ - "REb_CelebHall" + "Proj_Merc_Concussion_Grenade", + "W_GRENADE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "severity": "Error", - "asset": "Cin_rv_XWingProp.alo", + "asset": "CIN_Rbel_GreyGroup.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_GreyGroup.alo\u0027", "context": [ - "Grounded_Xwing" + "Cin_Rebel_GreyGroup" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier.alo\u0027", "severity": "Error", "asset": "CIN_Rbel_Soldier.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier.alo\u0027", "context": [ "Cin_Rebel_soldier" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_LOW.ALO\u0027", "severity": "Error", - "asset": "Lensflare0", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "Stars_Low", - "DATA\\ART\\MODELS\\W_STARS_LOW.ALO" + "Death_Star_Whole_Vsmall" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_AllShaders.ALO\u0027", "severity": "Error", - "asset": "W_AllShaders.ALO", + "asset": "Cin_EV_TieAdvanced.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_TieAdvanced.alo\u0027", "context": [ - "Prop_AllShaders" + "Fin_Vader_TIE" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_smoke_small_thin4\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "severity": "Error", - "asset": "p_smoke_small_thin4", + "asset": "CIN_Rbel_Soldier_Group.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier_Group.alo\u0027", "context": [ - "Imperial_Prison_Facility", - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "Cin_Rebel_SoldierRow" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO\u0027.", "severity": "Error", - "asset": "Default.fx", + "asset": "Cin_ImperialCraft.alo", + "message": "Unable to find .ALO file \u0027Cin_ImperialCraft.alo\u0027", "context": [ - "Lancet_Air_Artillery", - "DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO" + "Intro2_ImperialCraft" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CINE_EV_StarDestroyer.ALO\u0027", "severity": "Error", - "asset": "CINE_EV_StarDestroyer.ALO", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [F9TZ_Cloaking_Transport--\u003EUV_F9TZTRANSPORT.ALO].", "context": [ - "CIN_Star_Destroyer3X" + "F9TZ_Cloaking_Transport", + "UV_F9TZTRANSPORT.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_NavyTrooper_Row.alo\u0027", "severity": "Error", - "asset": "CIN_NavyTrooper_Row.alo", + "asset": "Cin_bridge.alo", + "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "context": [ - "Cin_NavyTrooper_Row" + "UM05_PROP_BRIDGE" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_GreyGroup.alo\u0027", "severity": "Error", - "asset": "CIN_Rbel_GreyGroup.alo", + "asset": "CIN_Rbel_grey.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_grey.alo\u0027", "context": [ - "Cin_Rebel_GreyGroup" + "Cin_Rebel_Grey" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "severity": "Error", - "asset": "Cin_EV_lambdaShuttle_150.alo", + "asset": "Cin_DeathStar.tga", + "message": "Could not find texture \u0027Cin_DeathStar.tga\u0027 for context: [Test_Base_Hector--\u003EALTTEST.ALO].", "context": [ - "Lambda_Shuttle_150" + "Test_Base_Hector", + "ALTTEST.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_Vol_Steam01.ALO\u0027", "severity": "Error", - "asset": "W_Vol_Steam01.ALO", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO\u0027.", "context": [ - "Prop_Vol_Steam01" + "Crusader_Gunship", + "DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\EI_MARAJADE.ALO\u0027", "severity": "Error", - "asset": "p_desert_ground_dust", + "asset": "Cin_bridge.alo", + "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "context": [ - "Mara_Jade", - "DATA\\ART\\MODELS\\EI_MARAJADE.ALO" + "Imperial_Bridge" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Trooper_Row.alo\u0027", "severity": "Error", - "asset": "CIN_Trooper_Row.alo", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO\u0027.", "context": [ - "Cin_Trooper_Row" + "Lancet_Air_Artillery", + "DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_hp_archammer-damage\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO\u0027", "severity": "Error", - "asset": "p_hp_archammer-damage", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_LOW.ALO\u0027", "context": [ - "Arc_Hammer", - "DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO" + "Stars_Low", + "DATA\\ART\\MODELS\\W_STARS_LOW.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "asset": "Cin_Officer.alo", + "message": "Unable to find .ALO file \u0027Cin_Officer.alo\u0027", "context": [ - "Cin_sith_lefthall", - "W_SITH_LEFTHALL.ALO" + "FIN_Officer" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_ewok_drag_dirt\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO\u0027", "severity": "Error", - "asset": "p_ewok_drag_dirt", + "asset": "Cin_Reb_CelebHall_Wall.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "context": [ - "Ewok_Handler", - "DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO" + "Cin_sith_lefthall", + "W_SITH_LEFTHALL.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_Officer.alo\u0027", "severity": "Error", - "asset": "Cin_Officer.alo", + "asset": "p_explosion_smoke_small_thin5", + "message": "Proxy particle \u0027p_explosion_smoke_small_thin5\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO\u0027", "context": [ - "FIN_Officer" + "Noghri_Spawn_House", + "DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_ImperialCraft.alo\u0027", "severity": "Error", - "asset": "Cin_ImperialCraft.alo", + "asset": "CIN_REb_CelebCharacters.alo", + "message": "Unable to find .ALO file \u0027CIN_REb_CelebCharacters.alo\u0027", "context": [ - "Intro2_ImperialCraft" + "REb_CelebCharacters" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Ysalamiri_Tree--\u003ENB_YSALAMIRI_TREE.ALO].", "severity": "Error", - "asset": "NB_YsalamiriTree_B.tga", + "asset": "W_Volcano_Rock02.ALO", + "message": "Unable to find .ALO file \u0027W_Volcano_Rock02.ALO\u0027", "context": [ - "Ysalamiri_Tree", - "NB_YSALAMIRI_TREE.ALO" + "Prop_Volcano_RockForm03" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_01_STATION_D.ALO\u0027", "severity": "Error", - "asset": "p_uwstation_death", + "asset": "p_prison_light", + "message": "Proxy particle \u0027p_prison_light\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "context": [ - "Underworld_Star_Base_1_Death_Clone", - "DATA\\ART\\MODELS\\UB_01_STATION_D.ALO" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [The_Peacebringer--\u003EUV_KRAYTCLASSDESTROYER_TYBER.ALO].", "context": [ - "UM05_PROP_DSTAR" + "The_Peacebringer", + "UV_KRAYTCLASSDESTROYER_TYBER.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_prison_light\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "severity": "Error", - "asset": "p_prison_light", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "context": [ - "Imperial_Prison_Facility", - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "Cin_sith_console", + "W_SITH_CONSOLE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_explosion_smoke_small_thin5\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO\u0027", "severity": "Error", - "asset": "p_explosion_smoke_small_thin5", + "asset": "CINE_EV_StarDestroyer.ALO", + "message": "Unable to find .ALO file \u0027CINE_EV_StarDestroyer.ALO\u0027", "context": [ - "Noghri_Spawn_House", - "DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO" + "CIN_Star_Destroyer3X" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO\u0027", "severity": "Error", - "asset": "Lensflare0", + "asset": "P_mptl-2a_Die", + "message": "Proxy particle \u0027P_mptl-2a_Die\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_MPTL-2A.ALO\u0027", "context": [ - "Stars_Medium", - "DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO" + "MPTL", + "DATA\\ART\\MODELS\\RV_MPTL-2A.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_steam_small\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO\u0027", "severity": "Error", - "asset": "p_steam_small", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_SKIPRAY.ALO\u0027.", "context": [ - "R_Ground_Heavy_Vehicle_Factory", - "DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO" + "Skipray_Bombing_Run", + "DATA\\ART\\MODELS\\UV_SKIPRAY.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Lambda_Head.alo\u0027", "severity": "Error", - "asset": "CIN_Lambda_Head.alo", + "asset": "NB_YsalamiriTree_B.tga", + "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Ysalamiri_Tree--\u003ENB_YSALAMIRI_TREE.ALO].", "context": [ - "Cin_Lambda_Head" + "Ysalamiri_Tree", + "NB_YSALAMIRI_TREE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_IG88.ALO\u0027", "severity": "Error", - "asset": "p_desert_ground_dust", + "asset": "p_smoke_small_thin2", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO\u0027", "context": [ - "IG-88", - "DATA\\ART\\MODELS\\UI_IG88.ALO" + "Ground_Empire_Hypervelocity_Gun", + "DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_03_STATION_D.ALO\u0027", "context": [ - "Death_Star_Whole_small" + "Underworld_Star_Base_3_Death_Clone", + "DATA\\ART\\MODELS\\UB_03_STATION_D.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_Volcano_Rock02.ALO\u0027", "severity": "Error", - "asset": "W_Volcano_Rock02.ALO", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE.ALO\u0027", "context": [ - "Prop_Volcano_RockForm03" + "Stars_Cinematic", + "DATA\\ART\\MODELS\\W_STARS_CINE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_HIGH.ALO\u0027", "severity": "Error", - "asset": "Lensflare0", + "asset": "Cin_EI_Vader.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "context": [ - "Stars_High", - "DATA\\ART\\MODELS\\W_STARS_HIGH.ALO" + "Cin_Vader" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EV_Stardestroyer_Warp.alo\u0027", "severity": "Error", - "asset": "Cin_EV_Stardestroyer_Warp.alo", + "asset": "Cin_EI_Vader.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "context": [ - "Star_Destroyer_Warp" + "Cin_Vader_Shot_6-9" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier_Group.alo\u0027", "severity": "Error", - "asset": "CIN_Rbel_Soldier_Group.alo", + "asset": "CIN_Rbel_NavyRow.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_NavyRow.alo\u0027", "context": [ - "Cin_Rebel_SoldierRow" + "Cin_Rebel_NavyRow" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_SKIPRAY.ALO\u0027.", "severity": "Error", - "asset": "Default.fx", + "asset": "Cin_Reb_CelebHall_Wall.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "context": [ - "Skipray_Bombing_Run", - "DATA\\ART\\MODELS\\UV_SKIPRAY.ALO" + "Cin_w_tile", + "W_TILE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Lambda_Mouth.alo\u0027", "severity": "Error", - "asset": "CIN_Lambda_Mouth.alo", + "asset": "p_ssd_debris", + "message": "Proxy particle \u0027p_ssd_debris\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO\u0027", "context": [ - "Cin_Lambda_Mouth" + "Eclipse_Super_Star_Destroyer_Death_Clone", + "DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Fire_Huge.alo\u0027", "severity": "Error", - "asset": "CIN_Fire_Huge.alo", + "asset": "W_AllShaders.ALO", + "message": "Unable to find .ALO file \u0027W_AllShaders.ALO\u0027", "context": [ - "Fin_Fire_Huge" + "Prop_AllShaders" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [TIE_Phantom--\u003EEV_TIE_PHANTOM.ALO].", "severity": "Error", "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [Vengeance_Frigate--\u003EUV_VENGEANCE.ALO].", "context": [ - "TIE_Phantom", - "EV_TIE_PHANTOM.ALO" + "Vengeance_Frigate", + "UV_VENGEANCE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_REb_CelebCharacters.alo\u0027", "severity": "Error", - "asset": "CIN_REb_CelebCharacters.alo", + "asset": "Cin_Coruscant.alo", + "message": "Unable to find .ALO file \u0027Cin_Coruscant.alo\u0027", "context": [ - "REb_CelebCharacters" + "Corusant_Backdrop_Large 6x" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "severity": "Error", - "asset": "Cin_EI_Palpatine.alo", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "context": [ - "Cin_Emperor_Shot_6-9" + "Cin_sith_lefthall", + "W_SITH_LEFTHALL.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "severity": "Error", - "asset": "Cin_rv_XWingProp.alo", + "asset": "CIN_Probe_Droid.alo", + "message": "Unable to find .ALO file \u0027CIN_Probe_Droid.alo\u0027", "context": [ - "Cin_X-WingProp" + "Empire_Droid" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_DeathStar.tga\u0027 for context: [Test_Base_Hector--\u003EALTTEST.ALO].", "severity": "Error", - "asset": "Cin_DeathStar.tga", + "asset": "w_planet_volcanic.alo", + "message": "Unable to find .ALO file \u0027w_planet_volcanic.alo\u0027", "context": [ - "Test_Base_Hector", - "ALTTEST.ALO" + "Volcanic_Backdrop_Large" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_Shuttle_Tyderium.alo\u0027", "severity": "Error", - "asset": "Cin_Shuttle_Tyderium.alo", + "asset": "Cin_DStar_protons.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_protons.alo\u0027", "context": [ - "Intro2_Shuttle_Tyderium" + "Protons_DStar_Xplode" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO\u0027.", "severity": "Error", - "asset": "Default.fx", + "asset": "Cin_EI_Palpatine.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "context": [ - "Crusader_Gunship", - "DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO" + "Cin_Emperor_Shot_6-9" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027p_splash_wake_lava.alo\u0027", "severity": "Error", - "asset": "p_splash_wake_lava.alo", + "asset": "Cin_EV_lambdaShuttle_150.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "context": [ - "Splash_Wake_Lava" + "Lambda_Shuttle_150" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "asset": "Cin_Reb_CelebHall_Wall.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "context": [ - "Cin_w_tile", - "W_TILE.ALO" + "Cin_sith_console", + "W_SITH_CONSOLE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027p_particle_master\u0027 for context: [Test_Particle--\u003EP_DIRT_EMITTER_TEST1.ALO].", "severity": "Error", - "asset": "p_particle_master", + "asset": "CIN_Officer_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_Officer_Row.alo\u0027", "context": [ - "Test_Particle", - "P_DIRT_EMITTER_TEST1.ALO" + "Cin_Officer_Row" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO\u0027", "severity": "Error", - "asset": "p_smoke_small_thin2", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "MonCalamari_Spawn_House", - "DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO" + "Death_Star_Whole_small" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "severity": "Error", - "asset": "Cin_EI_Palpatine.alo", + "asset": "Cin_Planet_Alderaan_High.alo", + "message": "Unable to find .ALO file \u0027Cin_Planet_Alderaan_High.alo\u0027", "context": [ - "Cin_Emperor_Shot_5" + "Alderaan_Backdrop_Large 6x" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall.tga", + "asset": "Cin_rv_XWingProp.alo", + "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "context": [ - "Cin_sith_console", - "W_SITH_CONSOLE.ALO" + "Cin_X-WingProp" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_03_STATION_D.ALO\u0027", "severity": "Error", - "asset": "p_uwstation_death", + "asset": "W_Kamino_Reflect.ALO", + "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "context": [ - "Underworld_Star_Base_3_Death_Clone", - "DATA\\ART\\MODELS\\UB_03_STATION_D.ALO" + "Prop_Kamino_Reflection_00" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_02_STATION_D.ALO\u0027", "severity": "Error", - "asset": "p_uwstation_death", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "Underworld_Star_Base_2_Death_Clone", - "DATA\\ART\\MODELS\\UB_02_STATION_D.ALO" + "UM05_PROP_DSTAR" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_EV_TieAdvanced.alo\u0027", "severity": "Error", - "asset": "Cin_EV_TieAdvanced.alo", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_04_STATION_D.ALO\u0027", "context": [ - "Fin_Vader_TIE" + "Underworld_Star_Base_4_Death_Clone", + "DATA\\ART\\MODELS\\UB_04_STATION_D.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [The_Peacebringer--\u003EUV_KRAYTCLASSDESTROYER_TYBER.ALO].", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", + "asset": "CIN_p_proton_torpedo.alo", + "message": "Unable to find .ALO file \u0027CIN_p_proton_torpedo.alo\u0027", "context": [ - "The_Peacebringer", - "UV_KRAYTCLASSDESTROYER_TYBER.ALO" + "Cin_Proj_Ground_Proton_Torpedo" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_cold_tiny01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_SCH.ALO\u0027", "severity": "Error", - "asset": "p_cold_tiny01", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_01_STATION_D.ALO\u0027", "context": [ - "Arctic_Civilian_Spawn_House", - "DATA\\ART\\MODELS\\NB_SCH.ALO" + "Underworld_Star_Base_1_Death_Clone", + "DATA\\ART\\MODELS\\UB_01_STATION_D.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DStar_protons.alo\u0027", "severity": "Error", - "asset": "Cin_DStar_protons.alo", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\EI_MARAJADE.ALO\u0027", "context": [ - "Protons_DStar_Xplode" + "Mara_Jade", + "DATA\\ART\\MODELS\\EI_MARAJADE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_droid_steam.alo\u0027", "severity": "Error", - "asset": "W_droid_steam.alo", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_SABOTEUR.ALO\u0027", "context": [ - "Prop_Droid_Steam" + "Underworld_Saboteur", + "DATA\\ART\\MODELS\\UI_SABOTEUR.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_NavyRow.alo\u0027", "severity": "Error", - "asset": "CIN_Rbel_NavyRow.alo", + "asset": "pe_bwing_yellow", + "message": "Proxy particle \u0027pe_bwing_yellow\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_BWING.ALO\u0027", "context": [ - "Cin_Rebel_NavyRow" + "B-Wing", + "DATA\\ART\\MODELS\\RV_BWING.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DStar_TurretLasers.alo\u0027", "severity": "Error", - "asset": "Cin_DStar_TurretLasers.alo", + "asset": "p_explosion_small_delay00", + "message": "Proxy particle \u0027p_explosion_small_delay00\u0027 not found for model \u0027DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO\u0027", "context": [ - "TurretLasers_DStar_Xplode" + "Imperial_Command_Center", + "DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "severity": "Error", - "asset": "W_Kamino_Reflect.ALO", + "asset": "Cin_rv_XWingProp.alo", + "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "context": [ - "Prop_Kamino_Reflection_01" + "Grounded_Xwing" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027pe_bwing_yellow\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_BWING.ALO\u0027", "severity": "Error", - "asset": "pe_bwing_yellow", + "asset": "CIN_Biker_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_Biker_Row.alo\u0027", "context": [ - "B-Wing", - "DATA\\ART\\MODELS\\RV_BWING.ALO" + "Cin_Biker_Row" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "asset": "CIN_Lambda_Mouth.alo", + "message": "Unable to find .ALO file \u0027CIN_Lambda_Mouth.alo\u0027", "context": [ - "Cin_sith_console", - "W_SITH_CONSOLE.ALO" + "Cin_Lambda_Mouth" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [F9TZ_Cloaking_Transport--\u003EUV_F9TZTRANSPORT.ALO].", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", + "asset": "Cin_EV_lambdaShuttle_150.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "context": [ - "F9TZ_Cloaking_Transport", - "UV_F9TZTRANSPORT.ALO" + "Lambda_Shuttle_150X6-9" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "severity": "Error", - "asset": "Cin_bridge.alo", + "asset": "lookat", + "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO\u0027", "context": [ - "Imperial_Bridge" + "Eclipse_Super_Star_Destroyer", + "DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier" - ], - "message": "Could not find icon \u0027i_button_general_dodonna.tga\u0027 for game object type \u0027General_Dodonna\u0027.", - "severity": "Warning", - "asset": "i_button_general_dodonna.tga", + "severity": "Error", + "asset": "p_particle_master", + "message": "Could not find texture \u0027p_particle_master\u0027 for context: [Test_Particle--\u003EP_DIRT_EMITTER_TEST1.ALO].", "context": [ - "General_Dodonna" + "Test_Particle", + "P_DIRT_EMITTER_TEST1.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_explosion_small_delay00\u0027 not found for model \u0027DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO\u0027", "severity": "Error", - "asset": "p_explosion_small_delay00", + "asset": "p_steam_small", + "message": "Proxy particle \u0027p_steam_small\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO\u0027", "context": [ - "Imperial_Command_Center", - "DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO" + "R_Ground_Heavy_Vehicle_Factory", + "DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO\u0027", "severity": "Error", - "asset": "p_smoke_small_thin2", + "asset": "CIN_DeathStar_Hangar.alo", + "message": "Unable to find .ALO file \u0027CIN_DeathStar_Hangar.alo\u0027", "context": [ - "Ground_Empire_Hypervelocity_Gun", - "DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO" + "Cin_DeathStar_Hangar" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027W_SwampGasEmit.ALO\u0027", "severity": "Error", - "asset": "W_SwampGasEmit.ALO", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO\u0027", "context": [ - "Prop_SwampGasEmitter" + "Stars_Medium", + "DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE.ALO\u0027", "severity": "Error", - "asset": "lookat", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_HIGH.ALO\u0027", "context": [ - "Eclipse_Prop", - "DATA\\ART\\MODELS\\UV_ECLIPSE.ALO" + "Stars_High", + "DATA\\ART\\MODELS\\W_STARS_HIGH.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Rbel_grey.alo\u0027", "severity": "Error", - "asset": "CIN_Rbel_grey.alo", + "asset": "Cin_EI_Palpatine.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "context": [ - "Cin_Rebel_Grey" + "Cin_Emperor_Shot_5" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", + "asset": "p_bomb_spin", + "message": "Proxy particle \u0027p_bomb_spin\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO\u0027", "context": [ - "Death_Star_Whole_Vsmall" + "TIE_Bomber_Bombing_Run_Bomb", + "DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_p_proton_torpedo.alo\u0027", - "severity": "Error", - "asset": "CIN_p_proton_torpedo.alo", + "severity": "Warning", + "asset": "i_button_ni_nightsister_ranger.tga", + "message": "Could not find icon \u0027i_button_ni_nightsister_ranger.tga\u0027 for game object type \u0027Dathomir_Night_Sister\u0027.", "context": [ - "Cin_Proj_Ground_Proton_Torpedo" + "Dathomir_Night_Sister" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO\u0027", "severity": "Error", - "asset": "lookat", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO\u0027", "context": [ - "Eclipse_Super_Star_Destroyer", - "DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO" + "Stars_Lua_Cinematic", + "DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027CIN_Fire_Medium.alo\u0027", "severity": "Error", - "asset": "CIN_Fire_Medium.alo", + "asset": "Cin_DeathStar_Wall.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_Wall.alo\u0027", "context": [ - "Fin_Fire_Medium" + "Death_Star_Hangar_Outside" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_04_STATION_D.ALO\u0027", "severity": "Error", - "asset": "p_uwstation_death", + "asset": "CIN_Fire_Huge.alo", + "message": "Unable to find .ALO file \u0027CIN_Fire_Huge.alo\u0027", "context": [ - "Underworld_Star_Base_4_Death_Clone", - "DATA\\ART\\MODELS\\UB_04_STATION_D.ALO" + "Fin_Fire_Huge" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Unable to find .ALO file \u0027Cin_Planet_Hoth_High.alo\u0027", "severity": "Error", - "asset": "Cin_Planet_Hoth_High.alo", + "asset": "W_Kamino_Reflect.ALO", + "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "context": [ - "Hoth_Backdrop_Large 6x" + "Prop_Kamino_Reflection_01" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO\u0027", "severity": "Error", - "asset": "Lensflare0", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_02_STATION_D.ALO\u0027", "context": [ - "Stars_Lua_Cinematic", - "DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO" + "Underworld_Star_Base_2_Death_Clone", + "DATA\\ART\\MODELS\\UB_02_STATION_D.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "severity": "Error", - "asset": "NB_YsalamiriTree_B.tga", + "asset": "p_cold_tiny01", + "message": "Proxy particle \u0027p_cold_tiny01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_SCH.ALO\u0027", "context": [ - "Underworld_Ysalamiri_Cage", - "UV_MDU_CAGE.ALO" + "Arctic_Civilian_Spawn_House", + "DATA\\ART\\MODELS\\NB_SCH.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier", - "AET.ModVerify.Verifiers.Commons.TextureVerifier" - ], - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [Vengeance_Frigate--\u003EUV_VENGEANCE.ALO].", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", + "asset": "p_smoke_small_thin2", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "context": [ - "Vengeance_Frigate", - "UV_VENGEANCE.ALO" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier" - ], - "message": "Could not find icon \u0027i_button_ni_nightsister_ranger.tga\u0027 for game object type \u0027Dathomir_Night_Sister\u0027.", - "severity": "Warning", - "asset": "i_button_ni_nightsister_ranger.tga", + "severity": "Error", + "asset": "W_Bush_Swmp00.ALO", + "message": "Unable to find .ALO file \u0027W_Bush_Swmp00.ALO\u0027", "context": [ - "Dathomir_Night_Sister" + "Prop_Swamp_Bush00" ] }, { "id": "FILE00", - "verifiers": [ - "AET.ModVerify.Verifiers.GameObjects.GameObjectTypeVerifier", - "AET.ModVerify.Verifiers.Commons.SingleModelVerifier" - ], - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO\u0027.", "severity": "Error", - "asset": "Default.fx", + "asset": "W_droid_steam.alo", + "message": "Unable to find .ALO file \u0027W_droid_steam.alo\u0027", "context": [ - "Empire_Offensive_Sensor_Node", - "DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO" + "Prop_Droid_Steam" ] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027radar_blip\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "radar_blip", + "asset": "st_hero_icon", + "message": "The CommandBar component \u0027st_hero_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_power\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_power", + "asset": "st_health_medium", + "message": "The CommandBar component \u0027st_health_medium\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_hero\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_hero", + "asset": "st_health_large", + "message": "The CommandBar component \u0027st_health_large\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_bounty_hunter\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_bounty_hunter", + "asset": "gui_dialog_tooltip", + "message": "The CommandBar component \u0027gui_dialog_tooltip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027generic_collision\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "generic_collision", + "asset": "st_shields_medium", + "message": "The CommandBar component \u0027st_shields_medium\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027objective_header_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "objective_header_text", + "asset": "g_special_ability", + "message": "The CommandBar component \u0027g_special_ability\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tactical_sell\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tactical_sell", + "asset": "generic_collision", + "message": "The CommandBar component \u0027generic_collision\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027garrison_slot_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "garrison_slot_icon", + "asset": "encyclopedia_cost_text", + "message": "The CommandBar component \u0027encyclopedia_cost_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027cs_ability_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "cs_ability_text", + "asset": "zoomed_right_text", + "message": "The CommandBar component \u0027zoomed_right_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_bracket_small\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_bracket_small", + "asset": "b_planet_left", + "message": "The CommandBar component \u0027b_planet_left\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027zoomed_right_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "zoomed_right_text", + "asset": "garrison_slot_icon", + "message": "The CommandBar component \u0027garrison_slot_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tooltip_icon_land\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tooltip_icon_land", + "asset": "zoomed_header_text", + "message": "The CommandBar component \u0027zoomed_header_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027b_quick_ref\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "b_quick_ref", + "asset": "encyclopedia_icon", + "message": "The CommandBar component \u0027encyclopedia_icon\u0027 is not connected to a shell component.", "context": [] }, { - "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027zoomed_text\u0027 is not connected to a shell component.", - "severity": "Warning", - "asset": "zoomed_text", + "id": "CMDBAR03", + "severity": "Information", + "asset": "g_credit_bar", + "message": "The CommandBar component \u0027g_credit_bar\u0027 is not supported by the game.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_shields\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_shields", + "asset": "g_planet_ring", + "message": "The CommandBar component \u0027g_planet_ring\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027zoomed_cost_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "zoomed_cost_text", + "asset": "g_space_level_pips", + "message": "The CommandBar component \u0027g_space_level_pips\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_space_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_space_icon", + "asset": "garrison_respawn_counter", + "message": "The CommandBar component \u0027garrison_respawn_counter\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_health_bar\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_health_bar", + "asset": "b_beacon_t", + "message": "The CommandBar component \u0027b_beacon_t\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_radar_view\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_radar_view", + "asset": "st_power", + "message": "The CommandBar component \u0027st_power\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_planet_ring\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_planet_ring", + "asset": "g_build", + "message": "The CommandBar component \u0027g_build\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_shields_large\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_shields_large", + "asset": "g_planet_value", + "message": "The CommandBar component \u0027g_planet_value\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tooltip_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tooltip_icon", + "asset": "st_bracket_large", + "message": "The CommandBar component \u0027st_bracket_large\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_ground_level\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_ground_level", + "asset": "tutorial_text_back", + "message": "The CommandBar component \u0027tutorial_text_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_hero_health\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_hero_health", + "asset": "g_space_icon", + "message": "The CommandBar component \u0027g_space_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027bribed_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "bribed_icon", + "asset": "bm_title_4011", + "message": "The CommandBar component \u0027bm_title_4011\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027zoomed_back\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "zoomed_back", + "asset": "st_bracket_small", + "message": "The CommandBar component \u0027st_bracket_small\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_space_level_pips\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_space_level_pips", + "asset": "balance_pip", + "message": "The CommandBar component \u0027balance_pip\u0027 is not connected to a shell component.", "context": [] }, { - "id": "CMDBAR03", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_credit_bar\u0027 is not supported by the game.", - "severity": "Information", - "asset": "g_credit_bar", + "id": "CMDBAR04", + "severity": "Warning", + "asset": "g_corruption_text", + "message": "The CommandBar component \u0027g_corruption_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027help_back\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "help_back", + "asset": "tooltip_price", + "message": "The CommandBar component \u0027tooltip_price\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027zoomed_header_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "zoomed_header_text", + "asset": "g_ground_level_pips", + "message": "The CommandBar component \u0027g_ground_level_pips\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_hero_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_hero_icon", + "asset": "zoomed_center_text", + "message": "The CommandBar component \u0027zoomed_center_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tooltip_back\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tooltip_back", + "asset": "zoomed_text", + "message": "The CommandBar component \u0027zoomed_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_conflict\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_conflict", + "asset": "g_planet_name", + "message": "The CommandBar component \u0027g_planet_name\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_health\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_health", + "asset": "g_planet_land_forces", + "message": "The CommandBar component \u0027g_planet_land_forces\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_icon", + "asset": "reinforcement_counter", + "message": "The CommandBar component \u0027reinforcement_counter\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_planet_ability\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_planet_ability", + "asset": "g_radar_blip", + "message": "The CommandBar component \u0027g_radar_blip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_back\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_back", + "asset": "tooltip_left_text", + "message": "The CommandBar component \u0027tooltip_left_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027objective_back\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "objective_back", + "asset": "objective_text", + "message": "The CommandBar component \u0027objective_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027generic_flytext\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "generic_flytext", + "asset": "st_grab_bar", + "message": "The CommandBar component \u0027st_grab_bar\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027bm_title_4011\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "bm_title_4011", + "asset": "g_smuggled", + "message": "The CommandBar component \u0027g_smuggled\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tutorial_text_back\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tutorial_text_back", + "asset": "skirmish_upgrade", + "message": "The CommandBar component \u0027skirmish_upgrade\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027surface_mod_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "surface_mod_icon", + "asset": "g_space_level", + "message": "The CommandBar component \u0027g_space_level\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_corruption_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_corruption_text", + "asset": "objective_header_text", + "message": "The CommandBar component \u0027objective_header_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_right_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_right_text", + "asset": "tactical_sell", + "message": "The CommandBar component \u0027tactical_sell\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_grab_bar\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_grab_bar", + "asset": "g_weather", + "message": "The CommandBar component \u0027g_weather\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027b_planet_right\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "b_planet_right", + "asset": "zoomed_cost_text", + "message": "The CommandBar component \u0027zoomed_cost_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_control_group\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_control_group", + "asset": "encyclopedia_text", + "message": "The CommandBar component \u0027encyclopedia_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_center_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_center_text", + "asset": "g_ground_level", + "message": "The CommandBar component \u0027g_ground_level\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027zoomed_center_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "zoomed_center_text", + "asset": "tooltip_icon_land", + "message": "The CommandBar component \u0027tooltip_icon_land\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_cost_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_cost_text", + "asset": "bm_title_4010", + "message": "The CommandBar component \u0027bm_title_4010\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027garrison_respawn_counter\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "garrison_respawn_counter", + "asset": "generic_flytext", + "message": "The CommandBar component \u0027generic_flytext\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_enemy_hero\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_enemy_hero", + "asset": "bribed_icon", + "message": "The CommandBar component \u0027bribed_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027balance_pip\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "balance_pip", + "asset": "g_planet_fleet", + "message": "The CommandBar component \u0027g_planet_fleet\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_ground_level_pips\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_ground_level_pips", + "asset": "tooltip_back", + "message": "The CommandBar component \u0027tooltip_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_ground_sell\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_ground_sell", + "asset": "st_health_bar", + "message": "The CommandBar component \u0027st_health_bar\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tutorial_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tutorial_text", + "asset": "cs_ability_text", + "message": "The CommandBar component \u0027cs_ability_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_political_control\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_political_control", + "asset": "help_back", + "message": "The CommandBar component \u0027help_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027objective_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "objective_icon", + "asset": "g_enemy_hero", + "message": "The CommandBar component \u0027g_enemy_hero\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_planet_land_forces\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_planet_land_forces", + "asset": "st_shields", + "message": "The CommandBar component \u0027st_shields\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_corruption_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_corruption_icon", + "asset": "surface_mod_icon", + "message": "The CommandBar component \u0027surface_mod_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_credit_bar\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_credit_bar", + "asset": "st_hero_health", + "message": "The CommandBar component \u0027st_hero_health\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_smuggler\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_smuggler", + "asset": "objective_back", + "message": "The CommandBar component \u0027objective_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_ability_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_ability_icon", + "asset": "st_control_group", + "message": "The CommandBar component \u0027st_control_group\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027b_beacon_t\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "b_beacon_t", + "asset": "radar_blip", + "message": "The CommandBar component \u0027radar_blip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_radar_blip\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_radar_blip", + "asset": "encyclopedia_center_text", + "message": "The CommandBar component \u0027encyclopedia_center_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_planet_value\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_planet_value", + "asset": "g_political_control", + "message": "The CommandBar component \u0027g_political_control\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_health_large\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_health_large", + "asset": "g_corruption_icon", + "message": "The CommandBar component \u0027g_corruption_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027skirmish_upgrade\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "skirmish_upgrade", + "asset": "st_shields_large", + "message": "The CommandBar component \u0027st_shields_large\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_space_level\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_space_level", + "asset": "st_ability_icon", + "message": "The CommandBar component \u0027st_ability_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027objective_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "objective_text", + "asset": "cs_ability_button", + "message": "The CommandBar component \u0027cs_ability_button\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tooltip_left_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tooltip_left_text", + "asset": "objective_icon", + "message": "The CommandBar component \u0027objective_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_garrison_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_garrison_icon", + "asset": "g_smuggler", + "message": "The CommandBar component \u0027g_smuggler\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027cs_ability_button\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "cs_ability_button", + "asset": "g_conflict", + "message": "The CommandBar component \u0027g_conflict\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_build\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_build", + "asset": "g_planet_ability", + "message": "The CommandBar component \u0027g_planet_ability\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_health_medium\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_health_medium", + "asset": "encyclopedia_back", + "message": "The CommandBar component \u0027encyclopedia_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_smuggled\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_smuggled", + "asset": "remote_bomb_icon", + "message": "The CommandBar component \u0027remote_bomb_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_bracket_medium\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_bracket_medium", + "asset": "encyclopedia_header_text", + "message": "The CommandBar component \u0027encyclopedia_header_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027remote_bomb_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "remote_bomb_icon", + "asset": "tutorial_text", + "message": "The CommandBar component \u0027tutorial_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_weather\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_weather", + "asset": "tooltip_icon", + "message": "The CommandBar component \u0027tooltip_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_planet_name\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_planet_name", + "asset": "encyclopedia_right_text", + "message": "The CommandBar component \u0027encyclopedia_right_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_header_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_header_text", + "asset": "bribe_display", + "message": "The CommandBar component \u0027bribe_display\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_shields_medium\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_shields_medium", + "asset": "g_radar_view", + "message": "The CommandBar component \u0027g_radar_view\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_planet_fleet\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_planet_fleet", + "asset": "g_bounty_hunter", + "message": "The CommandBar component \u0027g_bounty_hunter\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tooltip_name\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tooltip_name", + "asset": "g_hero_icon", + "message": "The CommandBar component \u0027g_hero_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_ground_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_ground_icon", + "asset": "g_credit_bar", + "message": "The CommandBar component \u0027g_credit_bar\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_hero_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_hero_icon", + "asset": "b_quick_ref", + "message": "The CommandBar component \u0027b_quick_ref\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027st_bracket_large\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "st_bracket_large", + "asset": "g_ground_sell", + "message": "The CommandBar component \u0027g_ground_sell\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027bribe_display\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "bribe_display", + "asset": "st_health", + "message": "The CommandBar component \u0027st_health\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027bm_title_4010\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "bm_title_4010", + "asset": "g_hero", + "message": "The CommandBar component \u0027g_hero\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027reinforcement_counter\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "reinforcement_counter", + "asset": "tooltip_name", + "message": "The CommandBar component \u0027tooltip_name\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027b_planet_left\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "b_planet_left", + "asset": "zoomed_back", + "message": "The CommandBar component \u0027zoomed_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027lt_weather_icon\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "lt_weather_icon", + "asset": "st_garrison_icon", + "message": "The CommandBar component \u0027st_garrison_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027encyclopedia_text\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "encyclopedia_text", + "asset": "lt_weather_icon", + "message": "The CommandBar component \u0027lt_weather_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027tooltip_price\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "tooltip_price", + "asset": "g_ground_icon", + "message": "The CommandBar component \u0027g_ground_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027gui_dialog_tooltip\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "gui_dialog_tooltip", + "asset": "st_bracket_medium", + "message": "The CommandBar component \u0027st_bracket_medium\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", - "verifiers": [ - "AET.ModVerify.Verifiers.CommandBar.CommandBarVerifier" - ], - "message": "The CommandBar component \u0027g_special_ability\u0027 is not connected to a shell component.", "severity": "Warning", - "asset": "g_special_ability", + "asset": "b_planet_right", + "message": "The CommandBar component \u0027b_planet_right\u0027 is not connected to a shell component.", "context": [] } ] diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj index 8fce201..2b50f16 100644 --- a/src/ModVerify/ModVerify.csproj +++ b/src/ModVerify/ModVerify.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/ModVerify/Reporting/Baseline/VerificationBaseline.cs b/src/ModVerify/Reporting/Baseline/VerificationBaseline.cs index d734e6e..80f95b8 100644 --- a/src/ModVerify/Reporting/Baseline/VerificationBaseline.cs +++ b/src/ModVerify/Reporting/Baseline/VerificationBaseline.cs @@ -13,7 +13,7 @@ namespace AET.ModVerify.Reporting.Baseline; public sealed class VerificationBaseline : IReadOnlyCollection { - public static readonly Version LatestVersion = new(2, 1); + public static readonly Version LatestVersion = new(2, 2); public static readonly string LatestVersionString = LatestVersion.ToString(2); public static readonly VerificationBaseline Empty = new(VerificationSeverity.Information, [], null); @@ -61,7 +61,6 @@ public void ToJson(Stream stream) { JsonSerializer.Serialize(stream, new JsonVerificationBaseline(this), ModVerifyJsonSettings.JsonSettings); } - public Task ToJsonAsync(Stream stream) { return JsonSerializer.SerializeAsync(stream, new JsonVerificationBaseline(this), ModVerifyJsonSettings.JsonSettings); diff --git a/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs b/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs index de435fb..a60b3de 100644 --- a/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs +++ b/src/ModVerify/Reporting/Json/JsonAggregatedVerificationError.cs @@ -23,7 +23,9 @@ public JsonAggregatedVerificationError( public JsonAggregatedVerificationError( VerificationError error, - IEnumerable> contexts) : base(error) + IEnumerable> contexts, + bool verbose = false) + : base(error, verbose) { Contexts = contexts; } diff --git a/src/ModVerify/Reporting/Json/JsonVerificationError.cs b/src/ModVerify/Reporting/Json/JsonVerificationError.cs index f94f9f3..8094058 100644 --- a/src/ModVerify/Reporting/Json/JsonVerificationError.cs +++ b/src/ModVerify/Reporting/Json/JsonVerificationError.cs @@ -22,7 +22,8 @@ public JsonVerificationError( ContextEntries = contextEntries; } - public JsonVerificationError(VerificationError error) : base(error) + public JsonVerificationError(VerificationError error, bool verbose = false) + : base(error, verbose) { ContextEntries = error.ContextEntries.Any() ? error.ContextEntries : []; } diff --git a/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs b/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs index bd3b875..b7aa298 100644 --- a/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs +++ b/src/ModVerify/Reporting/Json/JsonVerificationErrorBase.cs @@ -22,7 +22,8 @@ internal abstract class JsonVerificationErrorBase public string Message { get; } [JsonPropertyName("verifiers")] - public IReadOnlyList VerifierChain { get; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IReadOnlyList? VerifierChain { get; } protected JsonVerificationErrorBase(string id, VerificationSeverity severity, @@ -31,16 +32,15 @@ protected JsonVerificationErrorBase(string id, IReadOnlyList? verifierChain) { Id = id; - VerifierChain = verifierChain ?? []; + VerifierChain = verifierChain; Message = message; Severity = severity; Asset = asset ?? string.Empty; } - - protected JsonVerificationErrorBase(VerificationError error) + protected JsonVerificationErrorBase(VerificationError error, bool verbose = false) { Id = error.Id; - VerifierChain = error.VerifierChain.Select(x => x.Name).ToList(); + VerifierChain = verbose ? error.VerifierChain.Select(x => x.Name).ToList() : null; Message = error.Message; Severity = error.Severity; Asset = error.Asset; diff --git a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs index 7e2defc..ac11bb6 100644 --- a/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs +++ b/src/ModVerify/Reporting/Reporters/JSON/JsonReporter.cs @@ -37,10 +37,9 @@ private JsonVerificationReport CreateJsonReport(VerificationResult result) { var first = g.First(); var contexts = g.Select(x => x.ContextEntries).ToList(); - if (contexts.Count == 1) - return new JsonVerificationError(first); - return new JsonAggregatedVerificationError(first, contexts); + return new JsonVerificationError(first, Settings.Verbose); + return new JsonAggregatedVerificationError(first, contexts, Settings.Verbose); }); } else @@ -48,7 +47,7 @@ private JsonVerificationReport CreateJsonReport(VerificationResult result) errors = result.Errors .OrderByDescending(x => x.Severity) .ThenBy(x => x.Id) - .Select(x => new JsonVerificationError(x)); + .Select(x => new JsonVerificationError(x, Settings.Verbose)); } return new JsonVerificationReport diff --git a/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs b/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs index 7ccbba9..a2503ed 100644 --- a/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs +++ b/src/ModVerify/Reporting/Reporters/JSON/JsonReporterSettings.cs @@ -1,5 +1,4 @@ namespace AET.ModVerify.Reporting.Reporters; - public record JsonReporterSettings : FileBasedReporterSettings { public bool AggregateResults { get; init; } diff --git a/src/ModVerify/Reporting/Reporters/ReporterSettings.cs b/src/ModVerify/Reporting/Reporters/ReporterSettings.cs index 73332eb..6cd56d3 100644 --- a/src/ModVerify/Reporting/Reporters/ReporterSettings.cs +++ b/src/ModVerify/Reporting/Reporters/ReporterSettings.cs @@ -3,4 +3,5 @@ public record ReporterSettings { public VerificationSeverity MinimumReportSeverity { get; init; } = VerificationSeverity.Information; + public bool Verbose { get; init; } } \ No newline at end of file diff --git a/src/ModVerify/Reporting/VerificationError.cs b/src/ModVerify/Reporting/VerificationError.cs index 334b7c6..2e95327 100644 --- a/src/ModVerify/Reporting/VerificationError.cs +++ b/src/ModVerify/Reporting/VerificationError.cs @@ -122,8 +122,11 @@ public override string ToString() $"{Id}: Message={Message}; Asset='{Asset}'; Context=[{string.Join(",", ContextEntries)}];"; } - private static IReadOnlyList RestoreVerifierChain(IReadOnlyList errorVerifierChain) + private static IReadOnlyList RestoreVerifierChain(IReadOnlyList? errorVerifierChain) { + if (errorVerifierChain is null) + return []; + var verifierChain = new List(); IGameVerifierInfo? previousVerifier = null; diff --git a/src/ModVerify/Resources/Schemas/2.1/baseline.json b/src/ModVerify/Resources/Schemas/2.2/baseline.json similarity index 92% rename from src/ModVerify/Resources/Schemas/2.1/baseline.json rename to src/ModVerify/Resources/Schemas/2.2/baseline.json index da37c4d..d893b4d 100644 --- a/src/ModVerify/Resources/Schemas/2.1/baseline.json +++ b/src/ModVerify/Resources/Schemas/2.2/baseline.json @@ -1,5 +1,5 @@ { - "$id": "https://AlamoEngine-Tools.github.io/schemas/mod-verify/2.1/baseline", + "$id": "https://AlamoEngine-Tools.github.io/schemas/mod-verify/2.2/baseline", "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Represents a baseline for AET ModVerify", "type": "object", @@ -73,12 +73,6 @@ "severity": { "$ref": "#/$defs/severity" }, - "verifiers": { - "type": "array", - "items": { - "type": "string" - } - }, "context": { "type": "array", "items": { @@ -91,7 +85,6 @@ "message", "asset", "severity", - "verifiers", "context" ], "additionalProperties": false @@ -99,7 +92,7 @@ }, "properties": { "version": { - "const": "2.1" + "const": "2.2" }, "minSeverity": { "$ref": "#/$defs/severity" From 6140c8886b638f71afcfc8e6b9bd963e376d5fe4 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Sun, 22 Mar 2026 23:18:45 +0100 Subject: [PATCH 38/41] perf opted --- src/ModVerify/ModVerifyServiceExtensions.cs | 4 +- .../Verifiers/AlreadyVerifiedCache.cs | 28 ----- .../Verifiers/Caching/AlreadyVerifiedCache.cs | 31 ++++++ .../Caching/IAlreadyVerifiedCache.cs | 8 ++ .../Verifiers/Caching/VerifiedCacheEntry.cs | 14 +++ .../Verifiers/Commons/AudioFileVerifier.cs | 25 ++++- .../Verifiers/Commons/SingleModelVerifier.cs | 105 +++++++++++------- .../GuiDialogs/GuiDialogsVerifier.cs | 51 +++++---- .../Verifiers/IAlreadyVerifiedCache.cs | 11 -- .../GuiDialog/ComponentTextureEntry.cs | 5 +- 10 files changed, 178 insertions(+), 104 deletions(-) delete mode 100644 src/ModVerify/Verifiers/AlreadyVerifiedCache.cs create mode 100644 src/ModVerify/Verifiers/Caching/AlreadyVerifiedCache.cs create mode 100644 src/ModVerify/Verifiers/Caching/IAlreadyVerifiedCache.cs create mode 100644 src/ModVerify/Verifiers/Caching/VerifiedCacheEntry.cs delete mode 100644 src/ModVerify/Verifiers/IAlreadyVerifiedCache.cs diff --git a/src/ModVerify/ModVerifyServiceExtensions.cs b/src/ModVerify/ModVerifyServiceExtensions.cs index 41fbeaa..04567e7 100644 --- a/src/ModVerify/ModVerifyServiceExtensions.cs +++ b/src/ModVerify/ModVerifyServiceExtensions.cs @@ -1,4 +1,4 @@ -using AET.ModVerify.Verifiers; +using AET.ModVerify.Verifiers.Caching; using Microsoft.Extensions.DependencyInjection; namespace AET.ModVerify; @@ -14,7 +14,7 @@ public IServiceCollection AddModVerify() public IServiceCollection RegisterVerifierCache() { - return serviceCollection.AddSingleton(sp => new AlreadyVerifiedCache(sp)); + return serviceCollection.AddSingleton(new AlreadyVerifiedCache()); } } } \ No newline at end of file diff --git a/src/ModVerify/Verifiers/AlreadyVerifiedCache.cs b/src/ModVerify/Verifiers/AlreadyVerifiedCache.cs deleted file mode 100644 index 530ca4e..0000000 --- a/src/ModVerify/Verifiers/AlreadyVerifiedCache.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Concurrent; -using Microsoft.Extensions.DependencyInjection; -using PG.Commons.Hashing; -using PG.StarWarsGame.Engine; - -namespace AET.ModVerify.Verifiers; - -internal sealed class AlreadyVerifiedCache(IServiceProvider serviceProvider) : IAlreadyVerifiedCache -{ - private readonly ICrc32HashingService _crc32Hashing = serviceProvider.GetRequiredService(); - private readonly ConcurrentDictionary _cachedChecksums = new(); - - public bool TryAddEntry(string entry) - { - return TryAddEntry(entry.AsSpan()); - } - - public bool TryAddEntry(ReadOnlySpan entry) - { - return TryAddEntry(_crc32Hashing.GetCrc32Upper(entry, PGConstants.DefaultPGEncoding)); - } - - public bool TryAddEntry(Crc32 checksum) - { - return _cachedChecksums.TryAdd(checksum, 0); - } -} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Caching/AlreadyVerifiedCache.cs b/src/ModVerify/Verifiers/Caching/AlreadyVerifiedCache.cs new file mode 100644 index 0000000..c6dda7c --- /dev/null +++ b/src/ModVerify/Verifiers/Caching/AlreadyVerifiedCache.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace AET.ModVerify.Verifiers.Caching; + +internal sealed class AlreadyVerifiedCache : IAlreadyVerifiedCache +{ + private readonly Dictionary _cachedEntries = new(); + + public bool TryAddEntry(string entry, bool assetExists) + { + var upper = entry.ToUpperInvariant(); + +#if NETSTANDARD2_1 || NET + return _cachedEntries.TryAdd(upper, assetExists); +#else + var alreadyVerified = _cachedEntries.ContainsKey(upper); + if (alreadyVerified) + return false; + + _cachedEntries[upper] = assetExists; + return true; +#endif + } + + public VerifiedCacheEntry GetEntry(string entry) + { + var upper = entry.ToUpperInvariant(); + var alreadyVerified = _cachedEntries.TryGetValue(upper, out var exists); + return alreadyVerified ? new VerifiedCacheEntry(true, exists) : default; + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Caching/IAlreadyVerifiedCache.cs b/src/ModVerify/Verifiers/Caching/IAlreadyVerifiedCache.cs new file mode 100644 index 0000000..68f39b4 --- /dev/null +++ b/src/ModVerify/Verifiers/Caching/IAlreadyVerifiedCache.cs @@ -0,0 +1,8 @@ +namespace AET.ModVerify.Verifiers.Caching; + +public interface IAlreadyVerifiedCache +{ + bool TryAddEntry(string entry, bool assetExists); + + VerifiedCacheEntry GetEntry(string entry); +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Caching/VerifiedCacheEntry.cs b/src/ModVerify/Verifiers/Caching/VerifiedCacheEntry.cs new file mode 100644 index 0000000..252a7c0 --- /dev/null +++ b/src/ModVerify/Verifiers/Caching/VerifiedCacheEntry.cs @@ -0,0 +1,14 @@ +namespace AET.ModVerify.Verifiers.Caching; + +public readonly struct VerifiedCacheEntry +{ + public bool AlreadyVerified { get; } + + public bool AssetExists { get; } + + public VerifiedCacheEntry(bool alreadyVerified, bool assetExists) + { + AlreadyVerified = alreadyVerified; + AssetExists = assetExists; + } +} \ No newline at end of file diff --git a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs index 077324a..4537a64 100644 --- a/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs +++ b/src/ModVerify/Verifiers/Commons/AudioFileVerifier.cs @@ -6,6 +6,7 @@ using PG.StarWarsGame.Engine; using System.Threading; using Microsoft.Extensions.DependencyInjection; +using AET.ModVerify.Verifiers.Caching; namespace AET.ModVerify.Verifiers.Commons; @@ -30,9 +31,30 @@ public AudioFileVerifier(IGameVerifierInfo? parent, public override void Verify(AudioFileInfo sampleInfo, IReadOnlyCollection contextInfo, CancellationToken token) { + var cached = _alreadyVerifiedCache?.GetEntry(sampleInfo.SampleName); + + if (cached?.AlreadyVerified is true) + { + if (!cached.Value.AssetExists) + { + AddError(VerificationError.Create( + this, + VerifierErrorCodes.FileNotFound, + $"Audio file '{sampleInfo.SampleName}' could not be found.", + VerificationSeverity.Error, + [.. contextInfo], + sampleInfo.SampleName)); + } + return; + } + + var sampleString = sampleInfo.SampleName; using var sampleStream = Repository.TryOpenFile(sampleString.AsSpan()); + + _alreadyVerifiedCache?.TryAddEntry(sampleInfo.SampleName, sampleStream is not null); + if (sampleStream is null) { AddError(VerificationError.Create( @@ -45,9 +67,6 @@ public override void Verify(AudioFileInfo sampleInfo, IReadOnlyCollection contextInfo, CancellationToken token) { + var cacheEntry = _cache?.GetEntry(modelName); + if (cacheEntry?.AlreadyVerified is true) + { + if (!cacheEntry.Value.AssetExists) + { + var error = VerificationError.Create( + this, + VerifierErrorCodes.FileNotFound, + $"Unable to find .ALO file '{modelName}'", + VerificationSeverity.Error, + contextInfo, + modelName); + AddError(error); + } + return; + } var modelPath = BuildModelPath(modelName); - VerifyAlamoFile(modelPath, contextInfo, token); + VerifyAlamoFile(modelPath, contextInfo, token, out var modelExists); - foreach (var textureError in _textureVerifier.VerifyErrors) - AddError(textureError); - } - - private void VerifyAlamoFile(string modelPath, IReadOnlyCollection contextInfo, CancellationToken token) - { - token.ThrowIfCancellationRequested(); - - var modelName = FileSystem.Path.GetFileName(modelPath.AsSpan()); - - // We always want to report that a file was not found, so that error reports show all XRefs to the not found model. - if (!GameEngine.GameRepository.ModelRepository.FileExists(modelPath)) + if (!modelExists) { - var modelNameString = modelName.ToString(); var error = VerificationError.Create( this, VerifierErrorCodes.FileNotFound, - $"Unable to find .ALO file '{modelNameString}'", + $"Unable to find .ALO file '{modelName}'", VerificationSeverity.Error, contextInfo, - modelNameString); + modelName); AddError(error); } - if (_cache?.TryAddEntry(modelName) is false) - return; + _cache?.TryAddEntry(modelName, modelExists); + + foreach (var textureError in _textureVerifier.VerifyErrors) + AddError(textureError); + } + + public void VerifyModelOrParticle( + IAloFile aloFile, + IReadOnlyCollection contextInfo, + CancellationToken token) + { + switch (aloFile) + { + case IAloModelFile model: + VerifyModel(model, contextInfo, token); + break; + case IAloParticleFile particle: + VerifyParticle(particle, contextInfo); + break; + default: + throw new InvalidOperationException("The data stream is neither a model nor particle."); + } + } + + private void VerifyAlamoFile( + string modelPath, + IReadOnlyCollection contextInfo, + CancellationToken token, + out bool modelExists) + { + token.ThrowIfCancellationRequested(); + + modelExists = true; IAloFile? aloFile = null; try @@ -90,8 +126,13 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte return; } + // Because throwsException is true, we know that if aloFile is null, + // the file does not exist if (aloFile is null) + { + modelExists = false; return; + } VerifyModelOrParticle(aloFile, contextInfo, token); } @@ -101,21 +142,6 @@ private void VerifyAlamoFile(string modelPath, IReadOnlyCollection conte } } - public void VerifyModelOrParticle(IAloFile aloFile, IReadOnlyCollection contextInfo, CancellationToken token) - { - switch (aloFile) - { - case IAloModelFile model: - VerifyModel(model, contextInfo, token); - break; - case IAloParticleFile particle: - VerifyParticle(particle, contextInfo); - break; - default: - throw new InvalidOperationException("The data stream is neither a model nor particle."); - } - } - private void VerifyParticle(IAloParticleFile file, IReadOnlyCollection contextInfo) { foreach (var texture in file.Content.Textures) @@ -220,22 +246,21 @@ private void VerifyProxyExists(IPetroglyphFileHolder model, string proxy, IReadO var proxyPath = BuildModelPath(proxyName); var modelFilePath = FileSystem.Path.GetGameStrippedPath(Repository.Path.AsSpan(), model.FilePath.AsSpan()).ToString(); + + VerifyAlamoFile(proxyPath, [..contextInfo, modelFilePath], token, out var proxyExists); - if (!Repository.ModelRepository.FileExists(proxyPath)) + if (!proxyExists) { var message = $"Proxy particle '{proxyName}' not found for model '{modelFilePath}'"; var error = VerificationError.Create( this, VerifierErrorCodes.FileNotFound, - message, - VerificationSeverity.Error, - [..contextInfo, modelFilePath], + message, + VerificationSeverity.Error, + [.. contextInfo, modelFilePath], proxyName); AddError(error); - return; } - - VerifyAlamoFile(proxyPath, [..contextInfo, modelFilePath], token); } private void VerifyShaderExists(IPetroglyphFileHolder model, string shader, IReadOnlyCollection contextInfo) diff --git a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs index a5b3a93..c305539 100644 --- a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs +++ b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs @@ -1,5 +1,6 @@ using AET.ModVerify.Reporting; using AET.ModVerify.Settings; +using AET.ModVerify.Verifiers.Caching; using AET.ModVerify.Verifiers.Commons; using Microsoft.Extensions.DependencyInjection; using PG.StarWarsGame.Engine; @@ -8,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading; namespace AET.ModVerify.Verifiers.GuiDialogs; @@ -84,12 +86,13 @@ private void VerifyMegaTexturesExist(CancellationToken token) private void VerifyGuiComponentTexturesExist(string component) { var middleButtonInRepoMode = false; - - + var entriesForComponent = GetTextureEntriesForComponents(component, out var defined); if (!defined) return; + // TODO: Button Middle needs to be checked first as the engine checks this first + foreach (var componentType in GuiComponentTypes) { try @@ -97,7 +100,8 @@ private void VerifyGuiComponentTexturesExist(string component) if (!entriesForComponent.TryGetValue(componentType, out var texture)) continue; - if (_cache?.TryAddEntry(texture.Texture) == false) + var cached = _cache?.GetEntry(texture.Texture); + if (cached?.AlreadyVerified is true) { // If we are in a special case we don't want to skip if (!middleButtonInRepoMode && @@ -107,14 +111,14 @@ componentType is not GuiComponentType.Scanlines && continue; } - if (!GameEngine.GuiDialogManager.TextureExists( - texture, - out var origin, - out var isNone, - middleButtonInRepoMode) - && !isNone) + var exists = GameEngine.GuiDialogManager.TextureExists( + texture, + out var origin, + out var isNone, + middleButtonInRepoMode); + + if (!exists && !isNone) { - if (origin == GuiTextureOrigin.MegaTexture && texture.Texture.Length > MtdFileConstants.MaxFileNameSize) { AddError(VerificationError.Create(this, VerifierErrorCodes.FilePathTooLong, @@ -123,29 +127,38 @@ componentType is not GuiComponentType.Scanlines && } else { - var message = $"Could not find GUI texture '{texture.Texture}' at location '{origin}'."; - - if (texture.Texture.Length > PGConstants.MaxMegEntryPathLength) - message += " The file name is too long."; - - AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, - message, VerificationSeverity.Error, - [component, origin.ToString()], texture.Texture)); + AddNotFoundError(texture, component, origin); } } if (componentType is GuiComponentType.ButtonMiddle && origin is GuiTextureOrigin.Repository) middleButtonInRepoMode = true; + + _cache?.TryAddEntry(texture.Texture, exists); } finally { - if (componentType >= GuiComponentType.ButtonRightDisabled) middleButtonInRepoMode = false; } } } + private void AddNotFoundError(ComponentTextureEntry texture, string component, GuiTextureOrigin? origin) + { + var sb = new StringBuilder($"Could not find GUI texture '{texture.Texture}'"); + if (origin is not null) + sb.Append($" at location '{origin}'"); + sb.Append('.'); + + if (texture.Texture.Length > PGConstants.MaxMegEntryPathLength) + sb.Append(" The file name is too long."); + + AddError(VerificationError.Create(this, VerifierErrorCodes.FileNotFound, + sb.ToString(), VerificationSeverity.Error, + [component, origin.ToString()], texture.Texture)); + } + private IReadOnlyDictionary GetTextureEntriesForComponents(string component, out bool defined) { if (component == DefaultComponentIdentifier) diff --git a/src/ModVerify/Verifiers/IAlreadyVerifiedCache.cs b/src/ModVerify/Verifiers/IAlreadyVerifiedCache.cs deleted file mode 100644 index 1fe8ad5..0000000 --- a/src/ModVerify/Verifiers/IAlreadyVerifiedCache.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using PG.Commons.Hashing; - -namespace AET.ModVerify.Verifiers; - -public interface IAlreadyVerifiedCache -{ - public bool TryAddEntry(string entry); - public bool TryAddEntry(ReadOnlySpan entry); - public bool TryAddEntry(Crc32 checksum); -} \ No newline at end of file diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ComponentTextureEntry.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ComponentTextureEntry.cs index f1ffb04..6d188e7 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ComponentTextureEntry.cs +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ComponentTextureEntry.cs @@ -1,5 +1,8 @@ -namespace PG.StarWarsGame.Engine.GuiDialog; +using System.Diagnostics; +namespace PG.StarWarsGame.Engine.GuiDialog; + +[DebuggerDisplay("Type:{ComponentType}, Texture: {Texture}")] public readonly struct ComponentTextureEntry(GuiComponentType componentType, string texture, bool isOverride) { public string Texture { get; } = texture; From 86ab563c4b1630fdb2cac6d7accb59225704a583 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Wed, 25 Mar 2026 12:54:24 +0100 Subject: [PATCH 39/41] improve precision for gui textures verifier --- .../GuiDialogs/GuiDialogsVerifier.cs | 30 ++++++++++++------- .../GuiDialog/ExtensionMethods.cs | 22 ++++++++++++++ 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ExtensionMethods.cs diff --git a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs index c305539..a33f900 100644 --- a/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs +++ b/src/ModVerify/Verifiers/GuiDialogs/GuiDialogsVerifier.cs @@ -18,7 +18,7 @@ sealed class GuiDialogsVerifier : GameVerifier { internal const string DefaultComponentIdentifier = "<>"; - private static readonly GuiComponentType[] GuiComponentTypes = + private static readonly IReadOnlyList GuiComponentTypes = Enum.GetValues(typeof(GuiComponentType)).OfType().ToArray(); private readonly IAlreadyVerifiedCache? _cache; @@ -85,13 +85,18 @@ private void VerifyMegaTexturesExist(CancellationToken token) private void VerifyGuiComponentTexturesExist(string component) { - var middleButtonInRepoMode = false; + var buttonSpecialMode = false; var entriesForComponent = GetTextureEntriesForComponents(component, out var defined); if (!defined) return; - // TODO: Button Middle needs to be checked first as the engine checks this first + if (entriesForComponent.TryGetValue(GuiComponentType.ButtonMiddle, out var middleTexture)) + { + GameEngine.GuiDialogManager.TextureExists(middleTexture, out var origin, out _); + if (origin == GuiTextureOrigin.Repository) + buttonSpecialMode = true; + } foreach (var componentType in GuiComponentTypes) { @@ -100,11 +105,17 @@ private void VerifyGuiComponentTexturesExist(string component) if (!entriesForComponent.TryGetValue(componentType, out var texture)) continue; + if (buttonSpecialMode && componentType.IsButton() && !componentType.SupportsSpecialTextureMode()) + { + // If we are in special button mode, non-supported button textures won't be loaded anyway. + continue; + } + var cached = _cache?.GetEntry(texture.Texture); if (cached?.AlreadyVerified is true) { // If we are in a special case we don't want to skip - if (!middleButtonInRepoMode && + if (!buttonSpecialMode && componentType is not GuiComponentType.ButtonMiddle && componentType is not GuiComponentType.Scanlines && componentType is not GuiComponentType.FrameBackground) @@ -115,7 +126,7 @@ componentType is not GuiComponentType.Scanlines && texture, out var origin, out var isNone, - middleButtonInRepoMode); + buttonSpecialMode); if (!exists && !isNone) { @@ -130,16 +141,13 @@ componentType is not GuiComponentType.Scanlines && AddNotFoundError(texture, component, origin); } } - - if (componentType is GuiComponentType.ButtonMiddle && origin is GuiTextureOrigin.Repository) - middleButtonInRepoMode = true; - + _cache?.TryAddEntry(texture.Texture, exists); } finally { - if (componentType >= GuiComponentType.ButtonRightDisabled) - middleButtonInRepoMode = false; + if (!componentType.IsButton()) + buttonSpecialMode = false; } } } diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ExtensionMethods.cs b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ExtensionMethods.cs new file mode 100644 index 0000000..dff28af --- /dev/null +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/GuiDialog/ExtensionMethods.cs @@ -0,0 +1,22 @@ +namespace PG.StarWarsGame.Engine.GuiDialog; + +public static class ExtensionMethods +{ + extension(GuiComponentType componentType) + { + public bool IsButton() + { + return componentType <= GuiComponentType.ButtonRightDisabled; + } + + public bool SupportsSpecialTextureMode() + { + return componentType is GuiComponentType.ButtonMiddle + or GuiComponentType.ButtonMiddleMouseOver + or GuiComponentType.ButtonMiddlePressed + or GuiComponentType.ButtonMiddleDisabled + or GuiComponentType.Scanlines + or GuiComponentType.FrameBackground; + } + } +} \ No newline at end of file From 3e00730249cc3f4dbc46a1034c8db710ebf63a09 Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Wed, 25 Mar 2026 12:54:29 +0100 Subject: [PATCH 40/41] update baseline --- .../Resources/Baselines/baseline-foc.json | 1874 ++++++++--------- 1 file changed, 932 insertions(+), 942 deletions(-) diff --git a/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json b/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json index 7eb4e06..39b65f9 100644 --- a/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json +++ b/src/ModVerify.CliApp/Resources/Baselines/baseline-foc.json @@ -9,13 +9,15 @@ "minSeverity": "Information", "errors": [ { - "id": "XML08", - "severity": "Information", - "asset": "DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML", - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML #0\u0027", + "id": "XML04", + "severity": "Warning", + "asset": "Size", + "message": "Expected double but got value \u002737\u0060\u0027. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #11571\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML" + "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlFloatParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Size", + "parentName=\u0027bm_text_steal\u0027" ] }, { @@ -41,13 +43,15 @@ ] }, { - "id": "XML08", + "id": "XML10", "severity": "Information", - "asset": "DATA\\XML\\SPACEPROPS_UNDERWORLD.XML", - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\SPACEPROPS_UNDERWORLD.XML #0\u0027", + "asset": "Disabled_Darken", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8608\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\SPACEPROPS_UNDERWORLD.XML" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_fast_forward_t\u0027" ] }, { @@ -63,154 +67,150 @@ ] }, { - "id": "XML10", + "id": "XML08", "severity": "Information", - "asset": "Disabled_Darken", - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8550\u0027", + "asset": "DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML #0\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", - "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Disabled_Darken", - "parentName=\u0027b_play_pause\u0027" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_SPACE_UNDERWORLD_INTERCEPTOR4.XML" ] }, { - "id": "XML10", + "id": "XML08", "severity": "Information", - "asset": "Disabled_Darken", - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8569\u0027", + "asset": "DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML #0\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", - "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Disabled_Darken", - "parentName=\u0027b_fast_forward\u0027" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML" ] }, { "id": "XML10", "severity": "Information", "asset": "Disabled_Darken", - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8589\u0027", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8569\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", "Disabled_Darken", - "parentName=\u0027b_play_pause_t\u0027" - ] - }, - { - "id": "XML04", - "severity": "Warning", - "asset": "Size", - "message": "Expected double but got value \u002737\u0060\u0027. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #11571\u0027", - "context": [ - "Parser: PG.StarWarsGame.Files.XML.Parsers.PetroglyphXmlFloatParser", - "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", - "Size", - "parentName=\u0027bm_text_steal\u0027" + "parentName=\u0027b_fast_forward\u0027" ] }, { "id": "XML08", "severity": "Information", - "asset": "DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML", - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML #0\u0027", + "asset": "DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML" + "File: DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML" ] }, { "id": "XML08", "severity": "Information", - "asset": "DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML", - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML #0\u0027", + "asset": "DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML #0\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\GROUNDSTRUCTURES_UNDERWORLD.XML" + "File: DATA\\XML\\UNITS_LAND_REBEL_GALLOFREE_HTT.XML" ] }, { - "id": "XML08", + "id": "XML10", "severity": "Information", - "asset": "DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML", - "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML #0\u0027", + "asset": "Disabled_Darken", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8589\u0027", "context": [ - "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", - "File: DATA\\XML\\UNITS_SPACE_EMPIRE_TIE_DEFENDER.XML" + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", + "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", + "Disabled_Darken", + "parentName=\u0027b_play_pause_t\u0027" ] }, { "id": "XML10", "severity": "Information", "asset": "Disabled_Darken", - "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8608\u0027", + "message": "The node \u0027Disabled_Darken\u0027 is not supported. File=\u0027DATA\\XML\\COMMANDBARCOMPONENTS.XML #8550\u0027", "context": [ "Parser: PG.StarWarsGame.Engine.Xml.Parsers.CommandBarComponentParser", "File: DATA\\XML\\COMMANDBARCOMPONENTS.XML", "Disabled_Darken", - "parentName=\u0027b_fast_forward_t\u0027" + "parentName=\u0027b_play_pause\u0027" + ] + }, + { + "id": "XML08", + "severity": "Information", + "asset": "DATA\\XML\\SPACEPROPS_UNDERWORLD.XML", + "message": "XML header is not the first entry of the XML file. File=\u0027DATA\\XML\\SPACEPROPS_UNDERWORLD.XML #0\u0027", + "context": [ + "Parser: PG.StarWarsGame.Engine.Xml.Parsers.GameObjectFileParser", + "File: DATA\\XML\\SPACEPROPS_UNDERWORLD.XML" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0101_ENG.WAV", - "message": "Audio file \u0027U000_LEI0101_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0210_ENG.WAV", + "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0312_ENG.WAV", - "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0207_ENG.WAV", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0304_ENG.WAV", - "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0205_ENG.WAV", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0404_ENG.WAV", - "message": "Audio file \u0027U000_LEI0404_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0207_ENG.WAV", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0502_ENG.WAV", - "message": "Audio file \u0027U000_LEI0502_ENG.WAV\u0027 could not be found.", + "asset": "U000_DEF3006_ENG.WAV", + "message": "Audio file \u0027U000_DEF3006_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Corrupt_Sabateur" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0315_ENG.WAV", - "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", + "asset": "U000_ARC3104_ENG.WAV", + "message": "Audio file \u0027U000_ARC3104_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Produce_Troops_Arc_Hammer" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0307_ENG.WAV", - "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0315_ENG.WAV", + "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] @@ -218,35 +218,35 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0402_ENG.WAV", - "message": "Audio file \u0027U000_LEI0402_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0201_ENG.WAV", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0304_ENG.WAV", - "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0211_ENG.WAV", + "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_MAL0503_ENG.WAV", - "message": "Audio file \u0027U000_MAL0503_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0303_ENG.WAV", + "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Assist_Move_Missile_Launcher" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0103_ENG.WAV", - "message": "Audio file \u0027U000_LEI0103_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0111_ENG.WAV", + "message": "Audio file \u0027U000_LEI0111_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] @@ -254,35 +254,35 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0309_ENG.WAV", - "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", + "asset": "AMB_URB_CLEAR_LOOP_1.WAV", + "message": "Audio file \u0027AMB_URB_CLEAR_LOOP_1.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Weather_Ambient_Clear_Urban_Loop" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0202_ENG.WAV", - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", + "asset": "FS_BEETLE_3.WAV", + "message": "Audio file \u0027FS_BEETLE_3.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_DEF3006_ENG.WAV", - "message": "Audio file \u0027U000_DEF3006_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0205_ENG.WAV", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Corrupt_Sabateur" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0210_ENG.WAV", - "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0215_ENG.WAV", + "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Move_Leia" ] @@ -290,17 +290,17 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0208_ENG.WAV", - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0504_ENG.WAV", + "message": "Audio file \u0027U000_LEI0504_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0112_ENG.WAV", - "message": "Audio file \u0027U000_LEI0112_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0104_ENG.WAV", + "message": "Audio file \u0027U000_LEI0104_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] @@ -308,8 +308,8 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0301_ENG.WAV", - "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0303_ENG.WAV", + "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Attack_Leia" ] @@ -317,116 +317,89 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0307_ENG.WAV", - "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0202_ENG.WAV", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "FS_BEETLE_1.WAV", - "message": "Audio file \u0027FS_BEETLE_1.WAV\u0027 could not be found.", + "asset": "U000_LEI0212_ENG.WAV", + "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0206_ENG.WAV", - "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0105_ENG.WAV", + "message": "Audio file \u0027U000_LEI0105_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0203_ENG.WAV", - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0311_ENG.WAV", + "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0212_ENG.WAV", - "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0110_ENG.WAV", + "message": "Audio file \u0027U000_LEI0110_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "FS_BEETLE_3.WAV", - "message": "Audio file \u0027FS_BEETLE_3.WAV\u0027 could not be found.", + "asset": "U000_LEI0313_ENG.WAV", + "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_ARC3106_ENG.WAV", - "message": "Audio file \u0027U000_ARC3106_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0103_ENG.WAV", + "message": "Audio file \u0027U000_LEI0103_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Complete_Troops_Arc_Hammer" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0604_ENG.WAV", - "message": "Audio file \u0027U000_LEI0604_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0308_ENG.WAV", + "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_ARC3104_ENG.WAV", - "message": "Audio file \u0027U000_ARC3104_ENG.WAV\u0027 could not be found.", + "asset": "U000_TMC0212_ENG.WAV", + "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Produce_Troops_Arc_Hammer" + "Unit_Assist_Move_Tie_Mauler" ] }, { "id": "FILE00", "severity": "Error", - "asset": "FS_BEETLE_2.WAV", - "message": "Audio file \u0027FS_BEETLE_2.WAV\u0027 could not be found.", - "context": [ - "SFX_Anim_Beetle_Footsteps" - ] - }, - { - "id": "FILE00", - "severity": "Error", - "asset": "U000_LEI0208_ENG.WAV", - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", - "context": [ - "Unit_Fleet_Move_Leia" - ] - }, - { - "id": "FILE00", - "severity": "Error", - "asset": "EGL_STAR_VIPER_SPINNING_1.WAV", - "message": "Audio file \u0027EGL_STAR_VIPER_SPINNING_1.WAV\u0027 could not be found.", - "context": [ - "Unit_Star_Viper_Spinning_By" - ] - }, - { - "id": "FILE00", - "severity": "Error", - "asset": "U000_LEI0306_ENG.WAV", - "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0304_ENG.WAV", + "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] @@ -434,35 +407,35 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_TMC0212_ENG.WAV", - "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0101_ENG.WAV", + "message": "Audio file \u0027U000_LEI0101_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Assist_Move_Tie_Mauler" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0303_ENG.WAV", - "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0211_ENG.WAV", + "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0303_ENG.WAV", - "message": "Audio file \u0027U000_LEI0303_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0305_ENG.WAV", + "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0201_ENG.WAV", - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0208_ENG.WAV", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Fleet_Move_Leia" ] @@ -470,26 +443,26 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0114_ENG.WAV", - "message": "Audio file \u0027U000_LEI0114_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0311_ENG.WAV", + "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0601_ENG.WAV", - "message": "Audio file \u0027U000_LEI0601_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0314_ENG.WAV", + "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0105_ENG.WAV", - "message": "Audio file \u0027U000_LEI0105_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0108_ENG.WAV", + "message": "Audio file \u0027U000_LEI0108_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] @@ -497,8 +470,8 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0207_ENG.WAV", - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0213_ENG.WAV", + "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Move_Leia" ] @@ -506,10 +479,10 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0308_ENG.WAV", - "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0202_ENG.WAV", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Move_Leia" ] }, { @@ -533,8 +506,17 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0309_ENG.WAV", - "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0107_ENG.WAV", + "message": "Audio file \u0027U000_LEI0107_ENG.WAV\u0027 could not be found.", + "context": [ + "Unit_Select_Leia" + ] + }, + { + "id": "FILE00", + "severity": "Error", + "asset": "U000_LEI0305_ENG.WAV", + "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] @@ -542,17 +524,17 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0108_ENG.WAV", - "message": "Audio file \u0027U000_LEI0108_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0209_ENG.WAV", + "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0305_ENG.WAV", - "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0308_ENG.WAV", + "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] @@ -560,89 +542,89 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0501_ENG.WAV", - "message": "Audio file \u0027U000_LEI0501_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0207_ENG.WAV", + "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0201_ENG.WAV", - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", + "asset": "U000_MAL0503_ENG.WAV", + "message": "Audio file \u0027U000_MAL0503_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Assist_Move_Missile_Launcher" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0201_ENG.WAV", - "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0102_ENG.WAV", + "message": "Audio file \u0027U000_LEI0102_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0204_ENG.WAV", - "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0306_ENG.WAV", + "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0202_ENG.WAV", - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", + "asset": "FS_BEETLE_2.WAV", + "message": "Audio file \u0027FS_BEETLE_2.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0203_ENG.WAV", - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0312_ENG.WAV", + "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0503_ENG.WAV", - "message": "Audio file \u0027U000_LEI0503_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0402_ENG.WAV", + "message": "Audio file \u0027U000_LEI0402_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Guard_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0312_ENG.WAV", - "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0309_ENG.WAV", + "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0313_ENG.WAV", - "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0501_ENG.WAV", + "message": "Audio file \u0027U000_LEI0501_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0210_ENG.WAV", - "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0201_ENG.WAV", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Move_Leia" ] @@ -650,89 +632,89 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0206_ENG.WAV", - "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", + "asset": "U000_MCF1601_ENG.WAV", + "message": "Audio file \u0027U000_MCF1601_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_StarDest_MC30_Frigate" ] }, { "id": "FILE00", "severity": "Error", - "asset": "C000_DST0102_ENG.WAV", - "message": "Audio file \u0027C000_DST0102_ENG.WAV\u0027 could not be found.", + "asset": "TESTUNITMOVE_ENG.WAV", + "message": "Audio file \u0027TESTUNITMOVE_ENG.WAV\u0027 could not be found.", "context": [ - "EHD_Death_Star_Activate" + "Unit_Move_Gneneric_Test" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0401_ENG.WAV", - "message": "Audio file \u0027U000_LEI0401_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0114_ENG.WAV", + "message": "Audio file \u0027U000_LEI0114_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0602_ENG.WAV", - "message": "Audio file \u0027U000_LEI0602_ENG.WAV\u0027 could not be found.", + "asset": "U000_ARC3105_ENG.WAV", + "message": "Audio file \u0027U000_ARC3105_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "Unit_Complete_Troops_Arc_Hammer" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0104_ENG.WAV", - "message": "Audio file \u0027U000_LEI0104_ENG.WAV\u0027 could not be found.", + "asset": "EGL_STAR_VIPER_SPINNING_1.WAV", + "message": "Audio file \u0027EGL_STAR_VIPER_SPINNING_1.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Star_Viper_Spinning_By" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0202_ENG.WAV", - "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0401_ENG.WAV", + "message": "Audio file \u0027U000_LEI0401_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Guard_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_MCF1601_ENG.WAV", - "message": "Audio file \u0027U000_MCF1601_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0213_ENG.WAV", + "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_StarDest_MC30_Frigate" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0211_ENG.WAV", - "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0212_ENG.WAV", + "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0205_ENG.WAV", - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0115_ENG.WAV", + "message": "Audio file \u0027U000_LEI0115_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0301_ENG.WAV", - "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0306_ENG.WAV", + "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Attack_Leia" ] @@ -740,28 +722,28 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0311_ENG.WAV", - "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0601_ENG.WAV", + "message": "Audio file \u0027U000_LEI0601_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0203_ENG.WAV", - "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", + "asset": "U000_ARC3106_ENG.WAV", + "message": "Audio file \u0027U000_ARC3106_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Complete_Troops_Arc_Hammer" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0311_ENG.WAV", - "message": "Audio file \u0027U000_LEI0311_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0602_ENG.WAV", + "message": "Audio file \u0027U000_LEI0602_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Increase_Production_Leia" ] }, { @@ -776,10 +758,10 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0305_ENG.WAV", - "message": "Audio file \u0027U000_LEI0305_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0403_ENG.WAV", + "message": "Audio file \u0027U000_LEI0403_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Guard_Leia" ] }, { @@ -788,248 +770,248 @@ "asset": "U000_LEI0314_ENG.WAV", "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0107_ENG.WAV", - "message": "Audio file \u0027U000_LEI0107_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0203_ENG.WAV", + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0215_ENG.WAV", - "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0205_ENG.WAV", + "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0504_ENG.WAV", - "message": "Audio file \u0027U000_LEI0504_ENG.WAV\u0027 could not be found.", + "asset": "U000_TMC0212_ENG.WAV", + "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Remove_Corruption_Leia" + "Unit_Move_Tie_Mauler" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0110_ENG.WAV", - "message": "Audio file \u0027U000_LEI0110_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0203_ENG.WAV", + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "FS_BEETLE_4.WAV", - "message": "Audio file \u0027FS_BEETLE_4.WAV\u0027 could not be found.", + "asset": "U000_LEI0307_ENG.WAV", + "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "context": [ - "SFX_Anim_Beetle_Footsteps" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0207_ENG.WAV", - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0203_ENG.WAV", + "message": "Audio file \u0027U000_LEI0203_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0204_ENG.WAV", - "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0201_ENG.WAV", + "message": "Audio file \u0027U000_LEI0201_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Fleet_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0106_ENG.WAV", - "message": "Audio file \u0027U000_LEI0106_ENG.WAV\u0027 could not be found.", + "asset": "FS_BEETLE_1.WAV", + "message": "Audio file \u0027FS_BEETLE_1.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0313_ENG.WAV", - "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0204_ENG.WAV", + "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0109_ENG.WAV", - "message": "Audio file \u0027U000_LEI0109_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0206_ENG.WAV", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_TMC0212_ENG.WAV", - "message": "Audio file \u0027U000_TMC0212_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0603_ENG.WAV", + "message": "Audio file \u0027U000_LEI0603_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Tie_Mauler" + "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0403_ENG.WAV", - "message": "Audio file \u0027U000_LEI0403_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0313_ENG.WAV", + "message": "Audio file \u0027U000_LEI0313_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Guard_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0209_ENG.WAV", - "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0301_ENG.WAV", + "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0212_ENG.WAV", - "message": "Audio file \u0027U000_LEI0212_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0312_ENG.WAV", + "message": "Audio file \u0027U000_LEI0312_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0205_ENG.WAV", - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0404_ENG.WAV", + "message": "Audio file \u0027U000_LEI0404_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Guard_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0115_ENG.WAV", - "message": "Audio file \u0027U000_LEI0115_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0604_ENG.WAV", + "message": "Audio file \u0027U000_LEI0604_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Select_Leia" + "Unit_Increase_Production_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0315_ENG.WAV", - "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0210_ENG.WAV", + "message": "Audio file \u0027U000_LEI0210_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Attack_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0209_ENG.WAV", - "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0307_ENG.WAV", + "message": "Audio file \u0027U000_LEI0307_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0205_ENG.WAV", - "message": "Audio file \u0027U000_LEI0205_ENG.WAV\u0027 could not be found.", + "asset": "C000_DST0102_ENG.WAV", + "message": "Audio file \u0027C000_DST0102_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "EHD_Death_Star_Activate" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0314_ENG.WAV", - "message": "Audio file \u0027U000_LEI0314_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0215_ENG.WAV", + "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0308_ENG.WAV", - "message": "Audio file \u0027U000_LEI0308_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0206_ENG.WAV", + "message": "Audio file \u0027U000_LEI0206_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0213_ENG.WAV", - "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0202_ENG.WAV", + "message": "Audio file \u0027U000_LEI0202_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Leia" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0208_ENG.WAV", - "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0304_ENG.WAV", + "message": "Audio file \u0027U000_LEI0304_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_ARC3105_ENG.WAV", - "message": "Audio file \u0027U000_ARC3105_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0315_ENG.WAV", + "message": "Audio file \u0027U000_LEI0315_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Complete_Troops_Arc_Hammer" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0306_ENG.WAV", - "message": "Audio file \u0027U000_LEI0306_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0112_ENG.WAV", + "message": "Audio file \u0027U000_LEI0112_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Attack_Leia" + "Unit_Select_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "AMB_URB_CLEAR_LOOP_1.WAV", - "message": "Audio file \u0027AMB_URB_CLEAR_LOOP_1.WAV\u0027 could not be found.", + "asset": "FS_BEETLE_4.WAV", + "message": "Audio file \u0027FS_BEETLE_4.WAV\u0027 could not be found.", "context": [ - "Weather_Ambient_Clear_Urban_Loop" + "SFX_Anim_Beetle_Footsteps" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0102_ENG.WAV", - "message": "Audio file \u0027U000_LEI0102_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0109_ENG.WAV", + "message": "Audio file \u0027U000_LEI0109_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] @@ -1037,17 +1019,17 @@ { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0207_ENG.WAV", - "message": "Audio file \u0027U000_LEI0207_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0309_ENG.WAV", + "message": "Audio file \u0027U000_LEI0309_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Fleet_Move_Leia" + "Unit_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0111_ENG.WAV", - "message": "Audio file \u0027U000_LEI0111_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0106_ENG.WAV", + "message": "Audio file \u0027U000_LEI0106_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Select_Leia" ] @@ -1055,44 +1037,44 @@ { "id": "FILE00", "severity": "Error", - "asset": "TESTUNITMOVE_ENG.WAV", - "message": "Audio file \u0027TESTUNITMOVE_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0301_ENG.WAV", + "message": "Audio file \u0027U000_LEI0301_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Move_Gneneric_Test" + "Unit_Group_Attack_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0211_ENG.WAV", - "message": "Audio file \u0027U000_LEI0211_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0209_ENG.WAV", + "message": "Audio file \u0027U000_LEI0209_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0215_ENG.WAV", - "message": "Audio file \u0027U000_LEI0215_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0208_ENG.WAV", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Group_Move_Leia" + "Unit_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0603_ENG.WAV", - "message": "Audio file \u0027U000_LEI0603_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0503_ENG.WAV", + "message": "Audio file \u0027U000_LEI0503_ENG.WAV\u0027 could not be found.", "context": [ - "Unit_Increase_Production_Leia" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "U000_LEI0213_ENG.WAV", - "message": "Audio file \u0027U000_LEI0213_ENG.WAV\u0027 could not be found.", + "asset": "U000_LEI0208_ENG.WAV", + "message": "Audio file \u0027U000_LEI0208_ENG.WAV\u0027 could not be found.", "context": [ "Unit_Group_Move_Leia" ] @@ -1109,30 +1091,28 @@ { "id": "FILE00", "severity": "Error", - "asset": "underworld_logo_selected.tga", - "message": "Could not find GUI texture \u0027underworld_logo_selected.tga\u0027 at location \u0027MegaTexture\u0027.", + "asset": "U000_LEI0502_ENG.WAV", + "message": "Audio file \u0027U000_LEI0502_ENG.WAV\u0027 could not be found.", "context": [ - "IDC_PLAY_FACTION_A_BUTTON_BIG", - "MegaTexture" + "Unit_Remove_Corruption_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "underworld_logo_off.tga", - "message": "Could not find GUI texture \u0027underworld_logo_off.tga\u0027 at location \u0027MegaTexture\u0027.", + "asset": "U000_LEI0204_ENG.WAV", + "message": "Audio file \u0027U000_LEI0204_ENG.WAV\u0027 could not be found.", "context": [ - "IDC_PLAY_FACTION_A_BUTTON_BIG", - "MegaTexture" + "Unit_Group_Move_Leia" ] }, { "id": "FILE00", "severity": "Error", - "asset": "i_button_petro_sliver.tga", - "message": "Could not find GUI texture \u0027i_button_petro_sliver.tga\u0027 at location \u0027MegaTexture\u0027.", + "asset": "underworld_logo_off.tga", + "message": "Could not find GUI texture \u0027underworld_logo_off.tga\u0027 at location \u0027MegaTexture\u0027.", "context": [ - "IDC_MENU_PETRO_LOGO", + "IDC_PLAY_FACTION_A_BUTTON_BIG", "MegaTexture" ] }, @@ -1159,512 +1139,533 @@ { "id": "FILE00", "severity": "Error", - "asset": "lookat", - "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE.ALO\u0027", + "asset": "underworld_logo_selected.tga", + "message": "Could not find GUI texture \u0027underworld_logo_selected.tga\u0027 at location \u0027MegaTexture\u0027.", "context": [ - "Eclipse_Prop", - "DATA\\ART\\MODELS\\UV_ECLIPSE.ALO" + "IDC_PLAY_FACTION_A_BUTTON_BIG", + "MegaTexture" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_NavyTrooper_Row.alo", - "message": "Unable to find .ALO file \u0027CIN_NavyTrooper_Row.alo\u0027", + "asset": "lookat", + "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO\u0027", "context": [ - "Cin_NavyTrooper_Row" + "Eclipse_Super_Star_Destroyer", + "DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_smoke_small_thin4", - "message": "Proxy particle \u0027p_smoke_small_thin4\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", + "asset": "w_planet_volcanic.alo", + "message": "Unable to find .ALO file \u0027w_planet_volcanic.alo\u0027", "context": [ - "Imperial_Prison_Facility", - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "Volcanic_Backdrop_Large" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Lambda_Head.alo", - "message": "Unable to find .ALO file \u0027CIN_Lambda_Head.alo\u0027", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_SKIPRAY.ALO\u0027.", "context": [ - "Cin_Lambda_Head" + "Skipray_Bombing_Run", + "DATA\\ART\\MODELS\\UV_SKIPRAY.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DStar_LeverPanel.alo", - "message": "Unable to find .ALO file \u0027Cin_DStar_LeverPanel.alo\u0027", + "asset": "pe_bwing_yellow", + "message": "Proxy particle \u0027pe_bwing_yellow\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_BWING.ALO\u0027", "context": [ - "Death_Star_LeverPanel" + "B-Wing", + "DATA\\ART\\MODELS\\RV_BWING.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_Vol_Steam01.ALO", - "message": "Unable to find .ALO file \u0027W_Vol_Steam01.ALO\u0027", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "Prop_Vol_Steam01" + "Death_Star_Whole_small" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [TIE_Phantom--\u003EEV_TIE_PHANTOM.ALO].", + "asset": "CIN_Rbel_NavyRow.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_NavyRow.alo\u0027", "context": [ - "TIE_Phantom", - "EV_TIE_PHANTOM.ALO" + "Cin_Rebel_NavyRow" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_desert_ground_dust", - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO\u0027", + "asset": "W_AllShaders.ALO", + "message": "Unable to find .ALO file \u0027W_AllShaders.ALO\u0027", "context": [ - "Kyle_Katarn", - "DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO" + "Prop_AllShaders" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_desert_ground_dust", - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_IG88.ALO\u0027", + "asset": "p_prison_light", + "message": "Proxy particle \u0027p_prison_light\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "context": [ - "IG-88", - "DATA\\ART\\MODELS\\UI_IG88.ALO" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DStar_TurretLasers.alo", - "message": "Unable to find .ALO file \u0027Cin_DStar_TurretLasers.alo\u0027", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "TurretLasers_DStar_Xplode" + "Death_Star_Whole_Vsmall" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Fire_Medium.alo", - "message": "Unable to find .ALO file \u0027CIN_Fire_Medium.alo\u0027", + "asset": "W_Vol_Steam01.ALO", + "message": "Unable to find .ALO file \u0027W_Vol_Steam01.ALO\u0027", "context": [ - "Fin_Fire_Medium" + "Prop_Vol_Steam01" ] }, { "id": "FILE00", - "severity": "Warning", - "asset": "i_button_general_dodonna.tga", - "message": "Could not find icon \u0027i_button_general_dodonna.tga\u0027 for game object type \u0027General_Dodonna\u0027.", + "severity": "Error", + "asset": "Cin_Coruscant.alo", + "message": "Unable to find .ALO file \u0027Cin_Coruscant.alo\u0027", "context": [ - "General_Dodonna" + "Corusant_Backdrop_Large 6x" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_SwampGasEmit.ALO", - "message": "Unable to find .ALO file \u0027W_SwampGasEmit.ALO\u0027", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO\u0027.", "context": [ - "Prop_SwampGasEmitter" + "Crusader_Gunship", + "DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_smoke_small_thin2", - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO\u0027", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_HIGH.ALO\u0027", "context": [ - "MonCalamari_Spawn_House", - "DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO" + "Stars_High", + "DATA\\ART\\MODELS\\W_STARS_HIGH.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall_B.tga", - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", + "asset": "lookat", + "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE.ALO\u0027", "context": [ - "Cin_w_tile", - "W_TILE.ALO" + "Eclipse_Prop", + "DATA\\ART\\MODELS\\UV_ECLIPSE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Trooper_Row.alo", - "message": "Unable to find .ALO file \u0027CIN_Trooper_Row.alo\u0027", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_05_STATION_D.ALO\u0027", "context": [ - "Cin_Trooper_Row" + "Underworld_Star_Base_5_Death_Clone", + "DATA\\ART\\MODELS\\UB_05_STATION_D.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Planet_Hoth_High.alo", - "message": "Unable to find .ALO file \u0027Cin_Planet_Hoth_High.alo\u0027", + "asset": "Cin_DeathStar.tga", + "message": "Could not find texture \u0027Cin_DeathStar.tga\u0027 for context: [Test_Base_Hector--\u003EALTTEST.ALO].", "context": [ - "Hoth_Backdrop_Large 6x" + "Test_Base_Hector", + "ALTTEST.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_uwstation_death", - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_05_STATION_D.ALO\u0027", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO\u0027", "context": [ - "Underworld_Star_Base_5_Death_Clone", - "DATA\\ART\\MODELS\\UB_05_STATION_D.ALO" + "Stars_Lua_Cinematic", + "DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Default.fx", - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO\u0027.", + "asset": "Cin_DStar_LeverPanel.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_LeverPanel.alo\u0027", "context": [ - "Empire_Offensive_Sensor_Node", - "DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO" + "Death_Star_LeverPanel" ] }, { "id": "FILE00", "severity": "Error", - "asset": "w_sith_arch.alo", - "message": "Unable to find .ALO file \u0027w_sith_arch.alo\u0027", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_LOW.ALO\u0027", "context": [ - "Cin_sith_arch" + "Stars_Low", + "DATA\\ART\\MODELS\\W_STARS_LOW.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [Vengeance_Frigate--\u003EUV_VENGEANCE.ALO].", "context": [ - "Death_Star_Whole" + "Vengeance_Frigate", + "UV_VENGEANCE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "P_heat_small01", - "message": "Proxy particle \u0027P_heat_small01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_VCH.ALO\u0027", + "asset": "Cin_rv_XWingProp.alo", + "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "context": [ - "Volcanic_Civilian_Spawn_House_Independent_AI", - "DATA\\ART\\MODELS\\NB_VCH.ALO" + "Cin_X-WingProp" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_hp_archammer-damage", - "message": "Proxy particle \u0027p_hp_archammer-damage\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO\u0027", + "asset": "CIN_Lambda_Mouth.alo", + "message": "Unable to find .ALO file \u0027CIN_Lambda_Mouth.alo\u0027", "context": [ - "Arc_Hammer", - "DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO" + "Cin_Lambda_Mouth" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_ewok_drag_dirt", - "message": "Proxy particle \u0027p_ewok_drag_dirt\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO\u0027", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_04_STATION_D.ALO\u0027", "context": [ - "Ewok_Handler", - "DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO" + "Underworld_Star_Base_4_Death_Clone", + "DATA\\ART\\MODELS\\UB_04_STATION_D.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Reb_CelebHall.alo", - "message": "Unable to find .ALO file \u0027CIN_Reb_CelebHall.alo\u0027", + "asset": "Cin_EV_lambdaShuttle_150.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "context": [ - "REb_CelebHall" + "Lambda_Shuttle_150X6-9" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_splash_wake_lava.alo", - "message": "Unable to find .ALO file \u0027p_splash_wake_lava.alo\u0027", + "asset": "CIN_Rbel_Soldier_Group.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier_Group.alo\u0027", "context": [ - "Splash_Wake_Lava" + "Cin_Rebel_SoldierRow" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EV_Stardestroyer_Warp.alo", - "message": "Unable to find .ALO file \u0027Cin_EV_Stardestroyer_Warp.alo\u0027", + "asset": "Cin_EI_Palpatine.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "context": [ - "Star_Destroyer_Warp" + "Cin_Emperor_Shot_5" ] }, { "id": "FILE00", "severity": "Error", - "asset": "NB_YsalamiriTree_B.tga", - "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "context": [ - "Underworld_Ysalamiri_Cage", - "UV_MDU_CAGE.ALO" + "Cin_sith_console", + "W_SITH_CONSOLE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DStar_Dish_close.alo", - "message": "Unable to find .ALO file \u0027Cin_DStar_Dish_close.alo\u0027", + "asset": "Cin_rv_XWingProp.alo", + "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", "context": [ - "Death_Star_Dish_Close" + "Grounded_Xwing" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Shuttle_Tyderium.alo", - "message": "Unable to find .ALO file \u0027Cin_Shuttle_Tyderium.alo\u0027", + "asset": "Cin_EV_Stardestroyer_Warp.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_Stardestroyer_Warp.alo\u0027", "context": [ - "Intro2_Shuttle_Tyderium" + "Star_Destroyer_Warp" ] }, { "id": "FILE00", "severity": "Error", - "asset": "UB_girder_B.tga", - "message": "Could not find texture \u0027UB_girder_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", + "asset": "p_particle_master", + "message": "Could not find texture \u0027p_particle_master\u0027 for context: [Test_Particle--\u003EP_DIRT_EMITTER_TEST1.ALO].", "context": [ - "Underworld_Ysalamiri_Cage", - "UV_MDU_CAGE.ALO" + "Test_Particle", + "P_DIRT_EMITTER_TEST1.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "w_grenade.tga", - "message": "Could not find texture \u0027w_grenade.tga\u0027 for context: [Proj_Merc_Concussion_Grenade--\u003EW_GRENADE.ALO].", + "asset": "W_Bush_Swmp00.ALO", + "message": "Unable to find .ALO file \u0027W_Bush_Swmp00.ALO\u0027", "context": [ - "Proj_Merc_Concussion_Grenade", - "W_GRENADE.ALO" + "Prop_Swamp_Bush00" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Rbel_GreyGroup.alo", - "message": "Unable to find .ALO file \u0027CIN_Rbel_GreyGroup.alo\u0027", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [The_Peacebringer--\u003EUV_KRAYTCLASSDESTROYER_TYBER.ALO].", "context": [ - "Cin_Rebel_GreyGroup" + "The_Peacebringer", + "UV_KRAYTCLASSDESTROYER_TYBER.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Rbel_Soldier.alo", - "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier.alo\u0027", + "asset": "Cin_Reb_CelebHall_Wall_B.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "context": [ - "Cin_Rebel_soldier" + "Cin_sith_lefthall", + "W_SITH_LEFTHALL.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", + "asset": "Cin_Shuttle_Tyderium.alo", + "message": "Unable to find .ALO file \u0027Cin_Shuttle_Tyderium.alo\u0027", "context": [ - "Death_Star_Whole_Vsmall" + "Intro2_Shuttle_Tyderium" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EV_TieAdvanced.alo", - "message": "Unable to find .ALO file \u0027Cin_EV_TieAdvanced.alo\u0027", + "asset": "p_smoke_small_thin2", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "context": [ - "Fin_Vader_TIE" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Rbel_Soldier_Group.alo", - "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier_Group.alo\u0027", + "asset": "P_mptl-2a_Die", + "message": "Proxy particle \u0027P_mptl-2a_Die\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_MPTL-2A.ALO\u0027", "context": [ - "Cin_Rebel_SoldierRow" + "MPTL", + "DATA\\ART\\MODELS\\RV_MPTL-2A.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_ImperialCraft.alo", - "message": "Unable to find .ALO file \u0027Cin_ImperialCraft.alo\u0027", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "Intro2_ImperialCraft" + "UM05_PROP_DSTAR" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [F9TZ_Cloaking_Transport--\u003EUV_F9TZTRANSPORT.ALO].", + "asset": "CIN_Rbel_GreyGroup.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_GreyGroup.alo\u0027", "context": [ - "F9TZ_Cloaking_Transport", - "UV_F9TZTRANSPORT.ALO" + "Cin_Rebel_GreyGroup" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_bridge.alo", - "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", + "asset": "Cin_Officer.alo", + "message": "Unable to find .ALO file \u0027Cin_Officer.alo\u0027", "context": [ - "UM05_PROP_BRIDGE" + "FIN_Officer" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Rbel_grey.alo", - "message": "Unable to find .ALO file \u0027CIN_Rbel_grey.alo\u0027", + "asset": "CIN_Reb_CelebHall.alo", + "message": "Unable to find .ALO file \u0027CIN_Reb_CelebHall.alo\u0027", "context": [ - "Cin_Rebel_Grey" + "REb_CelebHall" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DeathStar.tga", - "message": "Could not find texture \u0027Cin_DeathStar.tga\u0027 for context: [Test_Base_Hector--\u003EALTTEST.ALO].", + "asset": "p_ewok_drag_dirt", + "message": "Proxy particle \u0027p_ewok_drag_dirt\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO\u0027", "context": [ - "Test_Base_Hector", - "ALTTEST.ALO" + "Ewok_Handler", + "DATA\\ART\\MODELS\\UI_EWOK_HANDLER.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Default.fx", - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO\u0027.", + "asset": "p_steam_small", + "message": "Proxy particle \u0027p_steam_small\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO\u0027", "context": [ - "Crusader_Gunship", - "DATA\\ART\\MODELS\\UV_CRUSADERCLASSCORVETTE.ALO" + "R_Ground_Heavy_Vehicle_Factory", + "DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_bridge.alo", - "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", + "asset": "Cin_DeathStar_Wall.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_Wall.alo\u0027", "context": [ - "Imperial_Bridge" + "Death_Star_Hangar_Outside" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Default.fx", - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO\u0027.", + "asset": "W_Kamino_Reflect.ALO", + "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "context": [ - "Lancet_Air_Artillery", - "DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO" + "Prop_Kamino_Reflection_00" + ] + }, + { + "id": "FILE00", + "severity": "Warning", + "asset": "i_button_general_dodonna.tga", + "message": "Could not find icon \u0027i_button_general_dodonna.tga\u0027 for game object type \u0027General_Dodonna\u0027.", + "context": [ + "General_Dodonna" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Lensflare0", - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_LOW.ALO\u0027", + "asset": "p_cold_tiny01", + "message": "Proxy particle \u0027p_cold_tiny01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_SCH.ALO\u0027", "context": [ - "Stars_Low", - "DATA\\ART\\MODELS\\W_STARS_LOW.ALO" + "Arctic_Civilian_Spawn_House", + "DATA\\ART\\MODELS\\NB_SCH.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Officer.alo", - "message": "Unable to find .ALO file \u0027Cin_Officer.alo\u0027", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\EI_MARAJADE.ALO\u0027", "context": [ - "FIN_Officer" + "Mara_Jade", + "DATA\\ART\\MODELS\\EI_MARAJADE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall.tga", - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", + "asset": "p_smoke_small_thin2", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO\u0027", "context": [ - "Cin_sith_lefthall", - "W_SITH_LEFTHALL.ALO" + "Ground_Empire_Hypervelocity_Gun", + "DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_explosion_smoke_small_thin5", - "message": "Proxy particle \u0027p_explosion_smoke_small_thin5\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO\u0027", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_02_STATION_D.ALO\u0027", "context": [ - "Noghri_Spawn_House", - "DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO" + "Underworld_Star_Base_2_Death_Clone", + "DATA\\ART\\MODELS\\UB_02_STATION_D.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_REb_CelebCharacters.alo", - "message": "Unable to find .ALO file \u0027CIN_REb_CelebCharacters.alo\u0027", + "asset": "p_splash_wake_lava.alo", + "message": "Unable to find .ALO file \u0027p_splash_wake_lava.alo\u0027", "context": [ - "REb_CelebCharacters" + "Splash_Wake_Lava" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_Volcano_Rock02.ALO", - "message": "Unable to find .ALO file \u0027W_Volcano_Rock02.ALO\u0027", + "asset": "Cin_Reb_CelebHall_Wall.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", "context": [ - "Prop_Volcano_RockForm03" + "Cin_sith_console", + "W_SITH_CONSOLE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_prison_light", - "message": "Proxy particle \u0027p_prison_light\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", + "asset": "Cin_EV_TieAdvanced.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_TieAdvanced.alo\u0027", "context": [ - "Imperial_Prison_Facility", - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "Fin_Vader_TIE" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [The_Peacebringer--\u003EUV_KRAYTCLASSDESTROYER_TYBER.ALO].", + "asset": "p_uwstation_death", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_03_STATION_D.ALO\u0027", "context": [ - "The_Peacebringer", - "UV_KRAYTCLASSDESTROYER_TYBER.ALO" + "Underworld_Star_Base_3_Death_Clone", + "DATA\\ART\\MODELS\\UB_03_STATION_D.ALO" + ] + }, + { + "id": "FILE00", + "severity": "Error", + "asset": "CIN_Trooper_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_Trooper_Row.alo\u0027", + "context": [ + "Cin_Trooper_Row" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall_B.tga", - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", + "asset": "CIN_Officer_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_Officer_Row.alo\u0027", "context": [ - "Cin_sith_console", - "W_SITH_CONSOLE.ALO" + "Cin_Officer_Row" ] }, { @@ -1679,146 +1680,143 @@ { "id": "FILE00", "severity": "Error", - "asset": "P_mptl-2a_Die", - "message": "Proxy particle \u0027P_mptl-2a_Die\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_MPTL-2A.ALO\u0027", + "asset": "Cin_EV_lambdaShuttle_150.alo", + "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", "context": [ - "MPTL", - "DATA\\ART\\MODELS\\RV_MPTL-2A.ALO" + "Lambda_Shuttle_150" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Default.fx", - "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_SKIPRAY.ALO\u0027.", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO\u0027", "context": [ - "Skipray_Bombing_Run", - "DATA\\ART\\MODELS\\UV_SKIPRAY.ALO" + "Stars_Medium", + "DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "NB_YsalamiriTree_B.tga", - "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Ysalamiri_Tree--\u003ENB_YSALAMIRI_TREE.ALO].", + "asset": "Cin_DStar_TurretLasers.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_TurretLasers.alo\u0027", "context": [ - "Ysalamiri_Tree", - "NB_YSALAMIRI_TREE.ALO" + "TurretLasers_DStar_Xplode" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_smoke_small_thin2", - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO\u0027", + "asset": "CIN_Rbel_Soldier.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_Soldier.alo\u0027", "context": [ - "Ground_Empire_Hypervelocity_Gun", - "DATA\\ART\\MODELS\\RB_HYPERVELOCITYGUN.ALO" + "Cin_Rebel_soldier" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_uwstation_death", - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_03_STATION_D.ALO\u0027", + "asset": "p_smoke_small_thin4", + "message": "Proxy particle \u0027p_smoke_small_thin4\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", "context": [ - "Underworld_Star_Base_3_Death_Clone", - "DATA\\ART\\MODELS\\UB_03_STATION_D.ALO" + "Imperial_Prison_Facility", + "DATA\\ART\\MODELS\\NB_PRISON.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Lensflare0", - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE.ALO\u0027", + "asset": "Cin_ImperialCraft.alo", + "message": "Unable to find .ALO file \u0027Cin_ImperialCraft.alo\u0027", "context": [ - "Stars_Cinematic", - "DATA\\ART\\MODELS\\W_STARS_CINE.ALO" + "Intro2_ImperialCraft" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EI_Vader.alo", - "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", + "asset": "W_SwampGasEmit.ALO", + "message": "Unable to find .ALO file \u0027W_SwampGasEmit.ALO\u0027", "context": [ - "Cin_Vader" + "Prop_SwampGasEmitter" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EI_Vader.alo", - "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_IG88.ALO\u0027", "context": [ - "Cin_Vader_Shot_6-9" + "IG-88", + "DATA\\ART\\MODELS\\UI_IG88.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Rbel_NavyRow.alo", - "message": "Unable to find .ALO file \u0027CIN_Rbel_NavyRow.alo\u0027", + "asset": "Cin_Planet_Hoth_High.alo", + "message": "Unable to find .ALO file \u0027Cin_Planet_Hoth_High.alo\u0027", "context": [ - "Cin_Rebel_NavyRow" + "Hoth_Backdrop_Large 6x" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Reb_CelebHall_Wall.tga", - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", + "asset": "NB_YsalamiriTree_B.tga", + "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Ysalamiri_Tree--\u003ENB_YSALAMIRI_TREE.ALO].", "context": [ - "Cin_w_tile", - "W_TILE.ALO" + "Ysalamiri_Tree", + "NB_YSALAMIRI_TREE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_ssd_debris", - "message": "Proxy particle \u0027p_ssd_debris\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO\u0027", + "asset": "CIN_DeathStar_Hangar.alo", + "message": "Unable to find .ALO file \u0027CIN_DeathStar_Hangar.alo\u0027", "context": [ - "Eclipse_Super_Star_Destroyer_Death_Clone", - "DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO" + "Cin_DeathStar_Hangar" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_AllShaders.ALO", - "message": "Unable to find .ALO file \u0027W_AllShaders.ALO\u0027", + "asset": "Lensflare0", + "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE.ALO\u0027", "context": [ - "Prop_AllShaders" + "Stars_Cinematic", + "DATA\\ART\\MODELS\\W_STARS_CINE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_TE_Rock_f_02_b.tga", - "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [Vengeance_Frigate--\u003EUV_VENGEANCE.ALO].", + "asset": "w_sith_arch.alo", + "message": "Unable to find .ALO file \u0027w_sith_arch.alo\u0027", "context": [ - "Vengeance_Frigate", - "UV_VENGEANCE.ALO" + "Cin_sith_arch" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Coruscant.alo", - "message": "Unable to find .ALO file \u0027Cin_Coruscant.alo\u0027", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [F9TZ_Cloaking_Transport--\u003EUV_F9TZTRANSPORT.ALO].", "context": [ - "Corusant_Backdrop_Large 6x" + "F9TZ_Cloaking_Transport", + "UV_F9TZTRANSPORT.ALO" ] }, { "id": "FILE00", "severity": "Error", "asset": "Cin_Reb_CelebHall_Wall_B.tga", - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall_B.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "context": [ - "Cin_sith_lefthall", - "W_SITH_LEFTHALL.ALO" + "Cin_w_tile", + "W_TILE.ALO" ] }, { @@ -1833,369 +1831,361 @@ { "id": "FILE00", "severity": "Error", - "asset": "w_planet_volcanic.alo", - "message": "Unable to find .ALO file \u0027w_planet_volcanic.alo\u0027", - "context": [ - "Volcanic_Backdrop_Large" - ] - }, - { - "id": "FILE00", - "severity": "Error", - "asset": "Cin_DStar_protons.alo", - "message": "Unable to find .ALO file \u0027Cin_DStar_protons.alo\u0027", + "asset": "CIN_Fire_Medium.alo", + "message": "Unable to find .ALO file \u0027CIN_Fire_Medium.alo\u0027", "context": [ - "Protons_DStar_Xplode" + "Fin_Fire_Medium" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EI_Palpatine.alo", - "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", + "asset": "Cin_Planet_Alderaan_High.alo", + "message": "Unable to find .ALO file \u0027Cin_Planet_Alderaan_High.alo\u0027", "context": [ - "Cin_Emperor_Shot_6-9" + "Alderaan_Backdrop_Large 6x" ] }, { "id": "FILE00", - "severity": "Error", - "asset": "Cin_EV_lambdaShuttle_150.alo", - "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", + "severity": "Warning", + "asset": "i_button_ni_nightsister_ranger.tga", + "message": "Could not find icon \u0027i_button_ni_nightsister_ranger.tga\u0027 for game object type \u0027Dathomir_Night_Sister\u0027.", "context": [ - "Lambda_Shuttle_150" + "Dathomir_Night_Sister" ] }, { "id": "FILE00", "severity": "Error", "asset": "Cin_Reb_CelebHall_Wall.tga", - "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_console--\u003EW_SITH_CONSOLE.ALO].", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_w_tile--\u003EW_TILE.ALO].", "context": [ - "Cin_sith_console", - "W_SITH_CONSOLE.ALO" + "Cin_w_tile", + "W_TILE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Officer_Row.alo", - "message": "Unable to find .ALO file \u0027CIN_Officer_Row.alo\u0027", + "asset": "W_Kamino_Reflect.ALO", + "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", "context": [ - "Cin_Officer_Row" + "Prop_Kamino_Reflection_01" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", + "asset": "CIN_Lambda_Head.alo", + "message": "Unable to find .ALO file \u0027CIN_Lambda_Head.alo\u0027", "context": [ - "Death_Star_Whole_small" + "Cin_Lambda_Head" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_Planet_Alderaan_High.alo", - "message": "Unable to find .ALO file \u0027Cin_Planet_Alderaan_High.alo\u0027", + "asset": "p_explosion_small_delay00", + "message": "Proxy particle \u0027p_explosion_small_delay00\u0027 not found for model \u0027DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO\u0027", "context": [ - "Alderaan_Backdrop_Large 6x" + "Imperial_Command_Center", + "DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_rv_XWingProp.alo", - "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", + "asset": "p_smoke_small_thin2", + "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO\u0027", "context": [ - "Cin_X-WingProp" + "MonCalamari_Spawn_House", + "DATA\\ART\\MODELS\\NB_MONCAL_BUILDING.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_Kamino_Reflect.ALO", - "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", + "asset": "W_Volcano_Rock02.ALO", + "message": "Unable to find .ALO file \u0027W_Volcano_Rock02.ALO\u0027", "context": [ - "Prop_Kamino_Reflection_00" + "Prop_Volcano_RockForm03" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DeathStar_High.alo", - "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", + "asset": "Cin_EI_Vader.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "context": [ - "UM05_PROP_DSTAR" + "Cin_Vader_Shot_6-9" ] }, { "id": "FILE00", "severity": "Error", "asset": "p_uwstation_death", - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_04_STATION_D.ALO\u0027", + "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_01_STATION_D.ALO\u0027", "context": [ - "Underworld_Star_Base_4_Death_Clone", - "DATA\\ART\\MODELS\\UB_04_STATION_D.ALO" + "Underworld_Star_Base_1_Death_Clone", + "DATA\\ART\\MODELS\\UB_01_STATION_D.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_p_proton_torpedo.alo", - "message": "Unable to find .ALO file \u0027CIN_p_proton_torpedo.alo\u0027", + "asset": "Cin_Reb_CelebHall_Wall.tga", + "message": "Could not find texture \u0027Cin_Reb_CelebHall_Wall.tga\u0027 for context: [Cin_sith_lefthall--\u003EW_SITH_LEFTHALL.ALO].", "context": [ - "Cin_Proj_Ground_Proton_Torpedo" + "Cin_sith_lefthall", + "W_SITH_LEFTHALL.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_uwstation_death", - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_01_STATION_D.ALO\u0027", + "asset": "CIN_NavyTrooper_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_NavyTrooper_Row.alo\u0027", "context": [ - "Underworld_Star_Base_1_Death_Clone", - "DATA\\ART\\MODELS\\UB_01_STATION_D.ALO" + "Cin_NavyTrooper_Row" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_desert_ground_dust", - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\EI_MARAJADE.ALO\u0027", + "asset": "p_ssd_debris", + "message": "Proxy particle \u0027p_ssd_debris\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO\u0027", "context": [ - "Mara_Jade", - "DATA\\ART\\MODELS\\EI_MARAJADE.ALO" + "Eclipse_Super_Star_Destroyer_Death_Clone", + "DATA\\ART\\MODELS\\UV_ECLIPSE_UC_DC.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_desert_ground_dust", - "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_SABOTEUR.ALO\u0027", + "asset": "Cin_EI_Vader.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Vader.alo\u0027", "context": [ - "Underworld_Saboteur", - "DATA\\ART\\MODELS\\UI_SABOTEUR.ALO" + "Cin_Vader" ] }, { "id": "FILE00", "severity": "Error", - "asset": "pe_bwing_yellow", - "message": "Proxy particle \u0027pe_bwing_yellow\u0027 not found for model \u0027DATA\\ART\\MODELS\\RV_BWING.ALO\u0027", + "asset": "p_explosion_smoke_small_thin5", + "message": "Proxy particle \u0027p_explosion_smoke_small_thin5\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO\u0027", "context": [ - "B-Wing", - "DATA\\ART\\MODELS\\RV_BWING.ALO" + "Noghri_Spawn_House", + "DATA\\ART\\MODELS\\NB_NOGHRI_HUT.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_explosion_small_delay00", - "message": "Proxy particle \u0027p_explosion_small_delay00\u0027 not found for model \u0027DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO\u0027", + "asset": "p_hp_archammer-damage", + "message": "Proxy particle \u0027p_hp_archammer-damage\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO\u0027", "context": [ - "Imperial_Command_Center", - "DATA\\ART\\MODELS\\EB_COMMANDCENTER.ALO" + "Arc_Hammer", + "DATA\\ART\\MODELS\\EV_ARCHAMMER.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_rv_XWingProp.alo", - "message": "Unable to find .ALO file \u0027Cin_rv_XWingProp.alo\u0027", + "asset": "NB_YsalamiriTree_B.tga", + "message": "Could not find texture \u0027NB_YsalamiriTree_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "context": [ - "Grounded_Xwing" + "Underworld_Ysalamiri_Cage", + "UV_MDU_CAGE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Biker_Row.alo", - "message": "Unable to find .ALO file \u0027CIN_Biker_Row.alo\u0027", + "asset": "Cin_bridge.alo", + "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "context": [ - "Cin_Biker_Row" + "UM05_PROP_BRIDGE" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Lambda_Mouth.alo", - "message": "Unable to find .ALO file \u0027CIN_Lambda_Mouth.alo\u0027", + "asset": "Cin_DStar_protons.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_protons.alo\u0027", "context": [ - "Cin_Lambda_Mouth" + "Protons_DStar_Xplode" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EV_lambdaShuttle_150.alo", - "message": "Unable to find .ALO file \u0027Cin_EV_lambdaShuttle_150.alo\u0027", + "asset": "Cin_DeathStar_High.alo", + "message": "Unable to find .ALO file \u0027Cin_DeathStar_High.alo\u0027", "context": [ - "Lambda_Shuttle_150X6-9" + "Death_Star_Whole" ] }, { "id": "FILE00", "severity": "Error", - "asset": "lookat", - "message": "Proxy particle \u0027lookat\u0027 not found for model \u0027DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO\u0027", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO\u0027.", "context": [ - "Eclipse_Super_Star_Destroyer", - "DATA\\ART\\MODELS\\UV_ECLIPSE_UC.ALO" + "Lancet_Air_Artillery", + "DATA\\ART\\MODELS\\EV_TIE_LANCET.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_particle_master", - "message": "Could not find texture \u0027p_particle_master\u0027 for context: [Test_Particle--\u003EP_DIRT_EMITTER_TEST1.ALO].", + "asset": "UB_girder_B.tga", + "message": "Could not find texture \u0027UB_girder_B.tga\u0027 for context: [Underworld_Ysalamiri_Cage--\u003EUV_MDU_CAGE.ALO].", "context": [ - "Test_Particle", - "P_DIRT_EMITTER_TEST1.ALO" + "Underworld_Ysalamiri_Cage", + "UV_MDU_CAGE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_steam_small", - "message": "Proxy particle \u0027p_steam_small\u0027 not found for model \u0027DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO\u0027", + "asset": "Cin_bridge.alo", + "message": "Unable to find .ALO file \u0027Cin_bridge.alo\u0027", "context": [ - "R_Ground_Heavy_Vehicle_Factory", - "DATA\\ART\\MODELS\\RB_HEAVYVEHICLEFACTORY.ALO" + "Imperial_Bridge" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_DeathStar_Hangar.alo", - "message": "Unable to find .ALO file \u0027CIN_DeathStar_Hangar.alo\u0027", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\UI_SABOTEUR.ALO\u0027", "context": [ - "Cin_DeathStar_Hangar" + "Underworld_Saboteur", + "DATA\\ART\\MODELS\\UI_SABOTEUR.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Lensflare0", - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO\u0027", + "asset": "CIN_p_proton_torpedo.alo", + "message": "Unable to find .ALO file \u0027CIN_p_proton_torpedo.alo\u0027", "context": [ - "Stars_Medium", - "DATA\\ART\\MODELS\\W_STARS_MEDIUM.ALO" + "Cin_Proj_Ground_Proton_Torpedo" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Lensflare0", - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_HIGH.ALO\u0027", + "asset": "CIN_Rbel_grey.alo", + "message": "Unable to find .ALO file \u0027CIN_Rbel_grey.alo\u0027", "context": [ - "Stars_High", - "DATA\\ART\\MODELS\\W_STARS_HIGH.ALO" + "Cin_Rebel_Grey" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_EI_Palpatine.alo", - "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", + "asset": "Default.fx", + "message": "Shader effect \u0027Default.fx\u0027 not found for model \u0027DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO\u0027.", "context": [ - "Cin_Emperor_Shot_5" + "Empire_Offensive_Sensor_Node", + "DATA\\ART\\MODELS\\EV_MDU_SENSORNODE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_bomb_spin", - "message": "Proxy particle \u0027p_bomb_spin\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO\u0027", + "asset": "w_grenade.tga", + "message": "Could not find texture \u0027w_grenade.tga\u0027 for context: [Proj_Merc_Concussion_Grenade--\u003EW_GRENADE.ALO].", "context": [ - "TIE_Bomber_Bombing_Run_Bomb", - "DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO" + "Proj_Merc_Concussion_Grenade", + "W_GRENADE.ALO" ] }, { "id": "FILE00", - "severity": "Warning", - "asset": "i_button_ni_nightsister_ranger.tga", - "message": "Could not find icon \u0027i_button_ni_nightsister_ranger.tga\u0027 for game object type \u0027Dathomir_Night_Sister\u0027.", + "severity": "Error", + "asset": "CIN_Fire_Huge.alo", + "message": "Unable to find .ALO file \u0027CIN_Fire_Huge.alo\u0027", "context": [ - "Dathomir_Night_Sister" + "Fin_Fire_Huge" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Lensflare0", - "message": "Proxy particle \u0027Lensflare0\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO\u0027", + "asset": "Cin_EI_Palpatine.alo", + "message": "Unable to find .ALO file \u0027Cin_EI_Palpatine.alo\u0027", "context": [ - "Stars_Lua_Cinematic", - "DATA\\ART\\MODELS\\W_STARS_CINE_LUA.ALO" + "Cin_Emperor_Shot_6-9" ] }, { "id": "FILE00", "severity": "Error", - "asset": "Cin_DeathStar_Wall.alo", - "message": "Unable to find .ALO file \u0027Cin_DeathStar_Wall.alo\u0027", + "asset": "p_desert_ground_dust", + "message": "Proxy particle \u0027p_desert_ground_dust\u0027 not found for model \u0027DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO\u0027", "context": [ - "Death_Star_Hangar_Outside" + "Kyle_Katarn", + "DATA\\ART\\MODELS\\RI_KYLEKATARN.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "CIN_Fire_Huge.alo", - "message": "Unable to find .ALO file \u0027CIN_Fire_Huge.alo\u0027", + "asset": "P_heat_small01", + "message": "Proxy particle \u0027P_heat_small01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_VCH.ALO\u0027", "context": [ - "Fin_Fire_Huge" + "Volcanic_Civilian_Spawn_House_Independent_AI", + "DATA\\ART\\MODELS\\NB_VCH.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_Kamino_Reflect.ALO", - "message": "Unable to find .ALO file \u0027W_Kamino_Reflect.ALO\u0027", + "asset": "CIN_REb_CelebCharacters.alo", + "message": "Unable to find .ALO file \u0027CIN_REb_CelebCharacters.alo\u0027", "context": [ - "Prop_Kamino_Reflection_01" + "REb_CelebCharacters" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_uwstation_death", - "message": "Proxy particle \u0027p_uwstation_death\u0027 not found for model \u0027DATA\\ART\\MODELS\\UB_02_STATION_D.ALO\u0027", + "asset": "W_TE_Rock_f_02_b.tga", + "message": "Could not find texture \u0027W_TE_Rock_f_02_b.tga\u0027 for context: [TIE_Phantom--\u003EEV_TIE_PHANTOM.ALO].", "context": [ - "Underworld_Star_Base_2_Death_Clone", - "DATA\\ART\\MODELS\\UB_02_STATION_D.ALO" + "TIE_Phantom", + "EV_TIE_PHANTOM.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_cold_tiny01", - "message": "Proxy particle \u0027p_cold_tiny01\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_SCH.ALO\u0027", + "asset": "CIN_Biker_Row.alo", + "message": "Unable to find .ALO file \u0027CIN_Biker_Row.alo\u0027", "context": [ - "Arctic_Civilian_Spawn_House", - "DATA\\ART\\MODELS\\NB_SCH.ALO" + "Cin_Biker_Row" ] }, { "id": "FILE00", "severity": "Error", - "asset": "p_smoke_small_thin2", - "message": "Proxy particle \u0027p_smoke_small_thin2\u0027 not found for model \u0027DATA\\ART\\MODELS\\NB_PRISON.ALO\u0027", + "asset": "p_bomb_spin", + "message": "Proxy particle \u0027p_bomb_spin\u0027 not found for model \u0027DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO\u0027", "context": [ - "Imperial_Prison_Facility", - "DATA\\ART\\MODELS\\NB_PRISON.ALO" + "TIE_Bomber_Bombing_Run_Bomb", + "DATA\\ART\\MODELS\\W_THERMAL_DETONATOR_EMPIRE.ALO" ] }, { "id": "FILE00", "severity": "Error", - "asset": "W_Bush_Swmp00.ALO", - "message": "Unable to find .ALO file \u0027W_Bush_Swmp00.ALO\u0027", + "asset": "Cin_DStar_Dish_close.alo", + "message": "Unable to find .ALO file \u0027Cin_DStar_Dish_close.alo\u0027", "context": [ - "Prop_Swamp_Bush00" + "Death_Star_Dish_Close" ] }, { @@ -2210,43 +2200,43 @@ { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_hero_icon", - "message": "The CommandBar component \u0027st_hero_icon\u0027 is not connected to a shell component.", + "asset": "b_planet_left", + "message": "The CommandBar component \u0027b_planet_left\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_health_medium", - "message": "The CommandBar component \u0027st_health_medium\u0027 is not connected to a shell component.", + "asset": "encyclopedia_header_text", + "message": "The CommandBar component \u0027encyclopedia_header_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_health_large", - "message": "The CommandBar component \u0027st_health_large\u0027 is not connected to a shell component.", + "asset": "st_control_group", + "message": "The CommandBar component \u0027st_control_group\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "gui_dialog_tooltip", - "message": "The CommandBar component \u0027gui_dialog_tooltip\u0027 is not connected to a shell component.", + "asset": "tutorial_text_back", + "message": "The CommandBar component \u0027tutorial_text_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_shields_medium", - "message": "The CommandBar component \u0027st_shields_medium\u0027 is not connected to a shell component.", + "asset": "encyclopedia_back", + "message": "The CommandBar component \u0027encyclopedia_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_special_ability", - "message": "The CommandBar component \u0027g_special_ability\u0027 is not connected to a shell component.", + "asset": "g_build", + "message": "The CommandBar component \u0027g_build\u0027 is not connected to a shell component.", "context": [] }, { @@ -2259,239 +2249,232 @@ { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_cost_text", - "message": "The CommandBar component \u0027encyclopedia_cost_text\u0027 is not connected to a shell component.", + "asset": "objective_back", + "message": "The CommandBar component \u0027objective_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "zoomed_right_text", - "message": "The CommandBar component \u0027zoomed_right_text\u0027 is not connected to a shell component.", + "asset": "st_shields_large", + "message": "The CommandBar component \u0027st_shields_large\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "b_planet_left", - "message": "The CommandBar component \u0027b_planet_left\u0027 is not connected to a shell component.", + "asset": "zoomed_cost_text", + "message": "The CommandBar component \u0027zoomed_cost_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "garrison_slot_icon", - "message": "The CommandBar component \u0027garrison_slot_icon\u0027 is not connected to a shell component.", + "asset": "st_bracket_medium", + "message": "The CommandBar component \u0027st_bracket_medium\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "zoomed_header_text", - "message": "The CommandBar component \u0027zoomed_header_text\u0027 is not connected to a shell component.", + "asset": "g_smuggled", + "message": "The CommandBar component \u0027g_smuggled\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_icon", - "message": "The CommandBar component \u0027encyclopedia_icon\u0027 is not connected to a shell component.", - "context": [] - }, - { - "id": "CMDBAR03", - "severity": "Information", - "asset": "g_credit_bar", - "message": "The CommandBar component \u0027g_credit_bar\u0027 is not supported by the game.", + "asset": "skirmish_upgrade", + "message": "The CommandBar component \u0027skirmish_upgrade\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_planet_ring", - "message": "The CommandBar component \u0027g_planet_ring\u0027 is not connected to a shell component.", + "asset": "st_ability_icon", + "message": "The CommandBar component \u0027st_ability_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_space_level_pips", - "message": "The CommandBar component \u0027g_space_level_pips\u0027 is not connected to a shell component.", + "asset": "g_bounty_hunter", + "message": "The CommandBar component \u0027g_bounty_hunter\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "garrison_respawn_counter", - "message": "The CommandBar component \u0027garrison_respawn_counter\u0027 is not connected to a shell component.", + "asset": "radar_blip", + "message": "The CommandBar component \u0027radar_blip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "b_beacon_t", - "message": "The CommandBar component \u0027b_beacon_t\u0027 is not connected to a shell component.", + "asset": "g_weather", + "message": "The CommandBar component \u0027g_weather\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_power", - "message": "The CommandBar component \u0027st_power\u0027 is not connected to a shell component.", + "asset": "st_health_medium", + "message": "The CommandBar component \u0027st_health_medium\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_build", - "message": "The CommandBar component \u0027g_build\u0027 is not connected to a shell component.", + "asset": "tutorial_text", + "message": "The CommandBar component \u0027tutorial_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_planet_value", - "message": "The CommandBar component \u0027g_planet_value\u0027 is not connected to a shell component.", + "asset": "garrison_slot_icon", + "message": "The CommandBar component \u0027garrison_slot_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_bracket_large", - "message": "The CommandBar component \u0027st_bracket_large\u0027 is not connected to a shell component.", + "asset": "encyclopedia_right_text", + "message": "The CommandBar component \u0027encyclopedia_right_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tutorial_text_back", - "message": "The CommandBar component \u0027tutorial_text_back\u0027 is not connected to a shell component.", + "asset": "g_planet_ring", + "message": "The CommandBar component \u0027g_planet_ring\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_space_icon", - "message": "The CommandBar component \u0027g_space_icon\u0027 is not connected to a shell component.", + "asset": "tooltip_price", + "message": "The CommandBar component \u0027tooltip_price\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "bm_title_4011", - "message": "The CommandBar component \u0027bm_title_4011\u0027 is not connected to a shell component.", + "asset": "bribe_display", + "message": "The CommandBar component \u0027bribe_display\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_bracket_small", - "message": "The CommandBar component \u0027st_bracket_small\u0027 is not connected to a shell component.", + "asset": "tooltip_icon_land", + "message": "The CommandBar component \u0027tooltip_icon_land\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "balance_pip", - "message": "The CommandBar component \u0027balance_pip\u0027 is not connected to a shell component.", + "asset": "encyclopedia_center_text", + "message": "The CommandBar component \u0027encyclopedia_center_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_corruption_text", - "message": "The CommandBar component \u0027g_corruption_text\u0027 is not connected to a shell component.", + "asset": "st_bracket_small", + "message": "The CommandBar component \u0027st_bracket_small\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tooltip_price", - "message": "The CommandBar component \u0027tooltip_price\u0027 is not connected to a shell component.", + "asset": "g_ground_sell", + "message": "The CommandBar component \u0027g_ground_sell\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_ground_level_pips", - "message": "The CommandBar component \u0027g_ground_level_pips\u0027 is not connected to a shell component.", + "asset": "st_shields_medium", + "message": "The CommandBar component \u0027st_shields_medium\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "zoomed_center_text", - "message": "The CommandBar component \u0027zoomed_center_text\u0027 is not connected to a shell component.", + "asset": "g_corruption_text", + "message": "The CommandBar component \u0027g_corruption_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "zoomed_text", - "message": "The CommandBar component \u0027zoomed_text\u0027 is not connected to a shell component.", + "asset": "st_health_bar", + "message": "The CommandBar component \u0027st_health_bar\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_planet_name", - "message": "The CommandBar component \u0027g_planet_name\u0027 is not connected to a shell component.", + "asset": "b_quick_ref", + "message": "The CommandBar component \u0027b_quick_ref\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_planet_land_forces", - "message": "The CommandBar component \u0027g_planet_land_forces\u0027 is not connected to a shell component.", + "asset": "g_special_ability", + "message": "The CommandBar component \u0027g_special_ability\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "reinforcement_counter", - "message": "The CommandBar component \u0027reinforcement_counter\u0027 is not connected to a shell component.", + "asset": "g_hero_icon", + "message": "The CommandBar component \u0027g_hero_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_radar_blip", - "message": "The CommandBar component \u0027g_radar_blip\u0027 is not connected to a shell component.", + "asset": "st_hero_health", + "message": "The CommandBar component \u0027st_hero_health\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tooltip_left_text", - "message": "The CommandBar component \u0027tooltip_left_text\u0027 is not connected to a shell component.", + "asset": "bribed_icon", + "message": "The CommandBar component \u0027bribed_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "objective_text", - "message": "The CommandBar component \u0027objective_text\u0027 is not connected to a shell component.", + "asset": "g_credit_bar", + "message": "The CommandBar component \u0027g_credit_bar\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_grab_bar", - "message": "The CommandBar component \u0027st_grab_bar\u0027 is not connected to a shell component.", + "asset": "g_space_icon", + "message": "The CommandBar component \u0027g_space_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_smuggled", - "message": "The CommandBar component \u0027g_smuggled\u0027 is not connected to a shell component.", + "asset": "bm_title_4010", + "message": "The CommandBar component \u0027bm_title_4010\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "skirmish_upgrade", - "message": "The CommandBar component \u0027skirmish_upgrade\u0027 is not connected to a shell component.", + "asset": "help_back", + "message": "The CommandBar component \u0027help_back\u0027 is not connected to a shell component.", "context": [] }, { @@ -2504,232 +2487,239 @@ { "id": "CMDBAR04", "severity": "Warning", - "asset": "objective_header_text", - "message": "The CommandBar component \u0027objective_header_text\u0027 is not connected to a shell component.", + "asset": "g_planet_ability", + "message": "The CommandBar component \u0027g_planet_ability\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tactical_sell", - "message": "The CommandBar component \u0027tactical_sell\u0027 is not connected to a shell component.", + "asset": "st_shields", + "message": "The CommandBar component \u0027st_shields\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_weather", - "message": "The CommandBar component \u0027g_weather\u0027 is not connected to a shell component.", + "asset": "b_planet_right", + "message": "The CommandBar component \u0027b_planet_right\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "zoomed_cost_text", - "message": "The CommandBar component \u0027zoomed_cost_text\u0027 is not connected to a shell component.", + "asset": "st_health_large", + "message": "The CommandBar component \u0027st_health_large\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_text", - "message": "The CommandBar component \u0027encyclopedia_text\u0027 is not connected to a shell component.", + "asset": "bm_title_4011", + "message": "The CommandBar component \u0027bm_title_4011\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_ground_level", - "message": "The CommandBar component \u0027g_ground_level\u0027 is not connected to a shell component.", + "asset": "g_ground_level_pips", + "message": "The CommandBar component \u0027g_ground_level_pips\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tooltip_icon_land", - "message": "The CommandBar component \u0027tooltip_icon_land\u0027 is not connected to a shell component.", + "asset": "g_political_control", + "message": "The CommandBar component \u0027g_political_control\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "bm_title_4010", - "message": "The CommandBar component \u0027bm_title_4010\u0027 is not connected to a shell component.", + "asset": "st_hero_icon", + "message": "The CommandBar component \u0027st_hero_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "generic_flytext", - "message": "The CommandBar component \u0027generic_flytext\u0027 is not connected to a shell component.", + "asset": "objective_text", + "message": "The CommandBar component \u0027objective_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "bribed_icon", - "message": "The CommandBar component \u0027bribed_icon\u0027 is not connected to a shell component.", + "asset": "zoomed_text", + "message": "The CommandBar component \u0027zoomed_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_planet_fleet", - "message": "The CommandBar component \u0027g_planet_fleet\u0027 is not connected to a shell component.", + "asset": "garrison_respawn_counter", + "message": "The CommandBar component \u0027garrison_respawn_counter\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tooltip_back", - "message": "The CommandBar component \u0027tooltip_back\u0027 is not connected to a shell component.", + "asset": "st_grab_bar", + "message": "The CommandBar component \u0027st_grab_bar\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_health_bar", - "message": "The CommandBar component \u0027st_health_bar\u0027 is not connected to a shell component.", + "asset": "zoomed_center_text", + "message": "The CommandBar component \u0027zoomed_center_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "cs_ability_text", - "message": "The CommandBar component \u0027cs_ability_text\u0027 is not connected to a shell component.", + "asset": "g_space_level_pips", + "message": "The CommandBar component \u0027g_space_level_pips\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "help_back", - "message": "The CommandBar component \u0027help_back\u0027 is not connected to a shell component.", + "asset": "generic_flytext", + "message": "The CommandBar component \u0027generic_flytext\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_enemy_hero", - "message": "The CommandBar component \u0027g_enemy_hero\u0027 is not connected to a shell component.", + "asset": "gui_dialog_tooltip", + "message": "The CommandBar component \u0027gui_dialog_tooltip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_shields", - "message": "The CommandBar component \u0027st_shields\u0027 is not connected to a shell component.", + "asset": "st_health", + "message": "The CommandBar component \u0027st_health\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "surface_mod_icon", - "message": "The CommandBar component \u0027surface_mod_icon\u0027 is not connected to a shell component.", + "asset": "g_planet_name", + "message": "The CommandBar component \u0027g_planet_name\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_hero_health", - "message": "The CommandBar component \u0027st_hero_health\u0027 is not connected to a shell component.", + "asset": "zoomed_header_text", + "message": "The CommandBar component \u0027zoomed_header_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "objective_back", - "message": "The CommandBar component \u0027objective_back\u0027 is not connected to a shell component.", + "asset": "g_conflict", + "message": "The CommandBar component \u0027g_conflict\u0027 is not connected to a shell component.", + "context": [] + }, + { + "id": "CMDBAR03", + "severity": "Information", + "asset": "g_credit_bar", + "message": "The CommandBar component \u0027g_credit_bar\u0027 is not supported by the game.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_control_group", - "message": "The CommandBar component \u0027st_control_group\u0027 is not connected to a shell component.", + "asset": "zoomed_back", + "message": "The CommandBar component \u0027zoomed_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "radar_blip", - "message": "The CommandBar component \u0027radar_blip\u0027 is not connected to a shell component.", + "asset": "zoomed_right_text", + "message": "The CommandBar component \u0027zoomed_right_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_center_text", - "message": "The CommandBar component \u0027encyclopedia_center_text\u0027 is not connected to a shell component.", + "asset": "st_power", + "message": "The CommandBar component \u0027st_power\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_political_control", - "message": "The CommandBar component \u0027g_political_control\u0027 is not connected to a shell component.", + "asset": "st_bracket_large", + "message": "The CommandBar component \u0027st_bracket_large\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_corruption_icon", - "message": "The CommandBar component \u0027g_corruption_icon\u0027 is not connected to a shell component.", + "asset": "g_ground_icon", + "message": "The CommandBar component \u0027g_ground_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_shields_large", - "message": "The CommandBar component \u0027st_shields_large\u0027 is not connected to a shell component.", + "asset": "g_planet_land_forces", + "message": "The CommandBar component \u0027g_planet_land_forces\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_ability_icon", - "message": "The CommandBar component \u0027st_ability_icon\u0027 is not connected to a shell component.", + "asset": "tooltip_back", + "message": "The CommandBar component \u0027tooltip_back\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "cs_ability_button", - "message": "The CommandBar component \u0027cs_ability_button\u0027 is not connected to a shell component.", + "asset": "b_beacon_t", + "message": "The CommandBar component \u0027b_beacon_t\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "objective_icon", - "message": "The CommandBar component \u0027objective_icon\u0027 is not connected to a shell component.", + "asset": "balance_pip", + "message": "The CommandBar component \u0027balance_pip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_smuggler", - "message": "The CommandBar component \u0027g_smuggler\u0027 is not connected to a shell component.", + "asset": "g_corruption_icon", + "message": "The CommandBar component \u0027g_corruption_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_conflict", - "message": "The CommandBar component \u0027g_conflict\u0027 is not connected to a shell component.", + "asset": "g_radar_blip", + "message": "The CommandBar component \u0027g_radar_blip\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_planet_ability", - "message": "The CommandBar component \u0027g_planet_ability\u0027 is not connected to a shell component.", + "asset": "g_hero", + "message": "The CommandBar component \u0027g_hero\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_back", - "message": "The CommandBar component \u0027encyclopedia_back\u0027 is not connected to a shell component.", + "asset": "encyclopedia_cost_text", + "message": "The CommandBar component \u0027encyclopedia_cost_text\u0027 is not connected to a shell component.", "context": [] }, { @@ -2742,141 +2732,141 @@ { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_header_text", - "message": "The CommandBar component \u0027encyclopedia_header_text\u0027 is not connected to a shell component.", + "asset": "surface_mod_icon", + "message": "The CommandBar component \u0027surface_mod_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tutorial_text", - "message": "The CommandBar component \u0027tutorial_text\u0027 is not connected to a shell component.", + "asset": "cs_ability_button", + "message": "The CommandBar component \u0027cs_ability_button\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tooltip_icon", - "message": "The CommandBar component \u0027tooltip_icon\u0027 is not connected to a shell component.", + "asset": "encyclopedia_text", + "message": "The CommandBar component \u0027encyclopedia_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "encyclopedia_right_text", - "message": "The CommandBar component \u0027encyclopedia_right_text\u0027 is not connected to a shell component.", + "asset": "objective_icon", + "message": "The CommandBar component \u0027objective_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "bribe_display", - "message": "The CommandBar component \u0027bribe_display\u0027 is not connected to a shell component.", + "asset": "st_garrison_icon", + "message": "The CommandBar component \u0027st_garrison_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_radar_view", - "message": "The CommandBar component \u0027g_radar_view\u0027 is not connected to a shell component.", + "asset": "g_enemy_hero", + "message": "The CommandBar component \u0027g_enemy_hero\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_bounty_hunter", - "message": "The CommandBar component \u0027g_bounty_hunter\u0027 is not connected to a shell component.", + "asset": "g_radar_view", + "message": "The CommandBar component \u0027g_radar_view\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_hero_icon", - "message": "The CommandBar component \u0027g_hero_icon\u0027 is not connected to a shell component.", + "asset": "tactical_sell", + "message": "The CommandBar component \u0027tactical_sell\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_credit_bar", - "message": "The CommandBar component \u0027g_credit_bar\u0027 is not connected to a shell component.", + "asset": "cs_ability_text", + "message": "The CommandBar component \u0027cs_ability_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "b_quick_ref", - "message": "The CommandBar component \u0027b_quick_ref\u0027 is not connected to a shell component.", + "asset": "g_smuggler", + "message": "The CommandBar component \u0027g_smuggler\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_ground_sell", - "message": "The CommandBar component \u0027g_ground_sell\u0027 is not connected to a shell component.", + "asset": "reinforcement_counter", + "message": "The CommandBar component \u0027reinforcement_counter\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_health", - "message": "The CommandBar component \u0027st_health\u0027 is not connected to a shell component.", + "asset": "g_planet_fleet", + "message": "The CommandBar component \u0027g_planet_fleet\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_hero", - "message": "The CommandBar component \u0027g_hero\u0027 is not connected to a shell component.", + "asset": "tooltip_left_text", + "message": "The CommandBar component \u0027tooltip_left_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "tooltip_name", - "message": "The CommandBar component \u0027tooltip_name\u0027 is not connected to a shell component.", + "asset": "objective_header_text", + "message": "The CommandBar component \u0027objective_header_text\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "zoomed_back", - "message": "The CommandBar component \u0027zoomed_back\u0027 is not connected to a shell component.", + "asset": "lt_weather_icon", + "message": "The CommandBar component \u0027lt_weather_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_garrison_icon", - "message": "The CommandBar component \u0027st_garrison_icon\u0027 is not connected to a shell component.", + "asset": "g_planet_value", + "message": "The CommandBar component \u0027g_planet_value\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "lt_weather_icon", - "message": "The CommandBar component \u0027lt_weather_icon\u0027 is not connected to a shell component.", + "asset": "tooltip_icon", + "message": "The CommandBar component \u0027tooltip_icon\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "g_ground_icon", - "message": "The CommandBar component \u0027g_ground_icon\u0027 is not connected to a shell component.", + "asset": "g_ground_level", + "message": "The CommandBar component \u0027g_ground_level\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "st_bracket_medium", - "message": "The CommandBar component \u0027st_bracket_medium\u0027 is not connected to a shell component.", + "asset": "tooltip_name", + "message": "The CommandBar component \u0027tooltip_name\u0027 is not connected to a shell component.", "context": [] }, { "id": "CMDBAR04", "severity": "Warning", - "asset": "b_planet_right", - "message": "The CommandBar component \u0027b_planet_right\u0027 is not connected to a shell component.", + "asset": "encyclopedia_icon", + "message": "The CommandBar component \u0027encyclopedia_icon\u0027 is not connected to a shell component.", "context": [] } ] From eb296620992ea0be33e4b03d091943fb5f826a5c Mon Sep 17 00:00:00 2001 From: AnakinRaW Date: Wed, 25 Mar 2026 12:56:06 +0100 Subject: [PATCH 41/41] update deps --- modules/ModdingToolBase | 2 +- src/ModVerify.CliApp/ModVerify.CliApp.csproj | 6 +++--- src/ModVerify/ModVerify.csproj | 2 +- .../PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj | 2 +- test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/ModdingToolBase b/modules/ModdingToolBase index da06a41..da072f4 160000 --- a/modules/ModdingToolBase +++ b/modules/ModdingToolBase @@ -1 +1 @@ -Subproject commit da06a410b8fa954fdc36676953f7e918c86992c9 +Subproject commit da072f43e6b85aab35b43d11f6b36eab61bdcfa6 diff --git a/src/ModVerify.CliApp/ModVerify.CliApp.csproj b/src/ModVerify.CliApp/ModVerify.CliApp.csproj index f6abc83..f7b7ff8 100644 --- a/src/ModVerify.CliApp/ModVerify.CliApp.csproj +++ b/src/ModVerify.CliApp/ModVerify.CliApp.csproj @@ -30,12 +30,12 @@ - - + + - + diff --git a/src/ModVerify/ModVerify.csproj b/src/ModVerify/ModVerify.csproj index 2b50f16..96656cc 100644 --- a/src/ModVerify/ModVerify.csproj +++ b/src/ModVerify/ModVerify.csproj @@ -26,7 +26,7 @@ - + diff --git a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj index 260c9e4..8d201e4 100644 --- a/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj +++ b/src/PetroglyphTools/PG.StarWarsGame.Engine/PG.StarWarsGame.Engine.csproj @@ -25,7 +25,7 @@ - + diff --git a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj index 5a852b4..f28c11c 100644 --- a/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj +++ b/test/ModVerify.CliApp.Test/ModVerify.CliApp.Test.csproj @@ -13,10 +13,10 @@ - - - - + + + +