Skip to content

Commit

Permalink
start xml reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
AnakinRaW committed Jul 22, 2024
1 parent d2f27bb commit a677fb9
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ internal class GameDatabaseCreationPipeline(GameRepository repository, IServiceP
private ParseXmlDatabaseFromContainerStep<GameObject> _parseGameObjects = null!;
private ParseXmlDatabaseFromContainerStep<SfxEvent> _parseSfxEvents = null!;

private ParallelRunner _parseXmlRunner = null!;
// We cannot use parallel processing here, in order to avoid races of the error event
private StepRunner _parseXmlRunner = null!;

public GameDatabase GameDatabase { get; private set; } = null!;


protected override Task<bool> PrepareCoreAsync()
{
_parseXmlRunner = new ParallelRunner(4, ServiceProvider);
_parseXmlRunner = new StepRunner(ServiceProvider);
foreach (var xmlParserStep in CreateXmlParserSteps())
_parseXmlRunner.AddStep(xmlParserStep);

Expand All @@ -35,6 +36,8 @@ protected override Task<bool> PrepareCoreAsync()

private IEnumerable<PipelineStep> CreateXmlParserSteps()
{
// TODO: Use same load order as the engine!

yield return _parseGameConstants = new ParseSingletonXmlStep<GameConstants>("GameConstants",
"DATA\\XML\\GAMECONSTANTS.XML", repository, ServiceProvider);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using PG.StarWarsGame.Engine.DataTypes;
using PG.StarWarsGame.Files.XML;
using PG.StarWarsGame.Files.XML.Parsers;
using PG.StarWarsGame.Files.XML.Parsers.Primitives;

namespace PG.StarWarsGame.Engine.Xml.Parsers.Data;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;
using PG.Commons.Hashing;
using PG.StarWarsGame.Engine.DataTypes;
using PG.StarWarsGame.Engine.Xml.Tags;
Expand Down Expand Up @@ -74,7 +73,7 @@ public override SfxEvent Parse(XElement element, out Crc32 nameCrc)
return new SfxEvent(name, nameCrc, properties, XmlLocationInfo.FromElement(element));
}

protected override bool OnParsed(string tag, object value, ValueListDictionary<string, object?> properties, string? elementName)
protected override bool OnParsed(XElement element, string tag, object value, ValueListDictionary<string, object?> properties, string? outerElementName)
{
if (tag == SfxEventXmlTags.UsePreset)
{
Expand All @@ -83,7 +82,11 @@ protected override bool OnParsed(string tag, object value, ValueListDictionary<s
if (presetNameCrc != default && ParsedElements.TryGetFirstValue(presetNameCrc, out var preset))
CopySfxPreset(properties, preset);
else
Logger?.LogWarning($"Cannot to find preset '{presetName}' for SFXEvent '{elementName ?? "NONE"}'");
{
var location = XmlLocationInfo.FromElement(element);
OnParseError(new ParseErrorEventArgs(location.XmlFile, element, XmlParseErrorKind.MissingReference,
$"Cannot to find preset '{presetName}' for SFXEvent '{outerElementName ?? "NONE"}'"));
}
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,43 @@ internal class SfxEventFileParser(IServiceProvider serviceProvider)
protected override void Parse(XElement element, IValueListDictionary<Crc32, SfxEvent> parsedElements)
{
var parser = new SfxEventParser(parsedElements, ServiceProvider);
foreach (var xElement in element.Elements())

try
{
var sfxEvent = parser.Parse(xElement, out var nameCrc);
if (nameCrc == default)
Logger?.LogWarning($"SFXEvent has no name at location '{XmlLocationInfo.FromElement(xElement)}'");
parsedElements.Add(nameCrc, sfxEvent);
parser.ParseError += OnInnerParseError;
if (!element.HasElements)
{
OnParseError(ParseErrorEventArgs.FromEmptyRoot(XmlLocationInfo.FromElement(element).XmlFile, element));
return;
}

foreach (var xElement in element.Elements())
{
var sfxEvent = parser.Parse(xElement, out var nameCrc);
if (nameCrc == default)
{
var location = XmlLocationInfo.FromElement(xElement);
OnParseError(new ParseErrorEventArgs(location.XmlFile, xElement, XmlParseErrorKind.MissingAttribute,
$"SFXEvent has no name at location '{location}'"));
}
parsedElements.Add(nameCrc, sfxEvent);
}
}
finally
{
parser.ParseError -= OnInnerParseError;
}
}

protected override void OnParseError(ParseErrorEventArgs e)
{
Logger?.LogWarning($"Error while parsing {e.File}: {e.Message}");
base.OnParseError(e);
}

private void OnInnerParseError(object sender, ParseErrorEventArgs e)
{
OnParseError(e);
}

public override SfxEvent Parse(XElement element)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ public abstract class XmlObjectParser<T>(IReadOnlyValueListDictionary<Crc32, T>

var value = parser.Parse(elm);

if (OnParsed(tagName, value, xmlProperties, name))
if (OnParsed(elm, tagName, value, xmlProperties, name))
xmlProperties.Add(tagName, value);
}
return xmlProperties;
}

protected virtual bool OnParsed(string tag, object value, ValueListDictionary<string, object?> properties, string? elementName)
protected virtual bool OnParsed(XElement element, string tag, object value, ValueListDictionary<string, object?> properties, string? outerElementName)
{
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Xml.Linq;
using AnakinRaW.CommonUtilities;

namespace PG.StarWarsGame.Files.XML;

public class ParseErrorEventArgs : EventArgs
{
public string File { get; }

public XElement? Element { get; }

public XmlParseErrorKind ErrorKind { get; }

public string Message { get; }

public ParseErrorEventArgs(string file, XElement? element, XmlParseErrorKind errorKind, string message)
{
ThrowHelper.ThrowIfNullOrEmpty(file);
File = file;
Element = element;
ErrorKind = errorKind;
Message = message;
}

public static ParseErrorEventArgs FromMissingFile(string file)
{
ThrowHelper.ThrowIfNullOrEmpty(file);
return new ParseErrorEventArgs(file, null, XmlParseErrorKind.MissingFile, $"XML file '{file}' not found.");
}

public static ParseErrorEventArgs FromEmptyRoot(string file, XElement element)
{
ThrowHelper.ThrowIfNullOrEmpty(file);
return new ParseErrorEventArgs(file, element, XmlParseErrorKind.EmptyRoot, $"XML file '{file}' has an empty root node.");
}
}

public enum XmlParseErrorKind
{
/// <summary>
/// The error not specified any further.
/// </summary>
Unknown,
/// <summary>
/// The XML file could not be found.
/// </summary>
MissingFile,
/// <summary>
/// The root node of an XML file is empty.
/// </summary>
EmptyRoot,
/// <summary>
/// A tag's value is syntactically correct, but the semantics of value are not valid. For example,
/// when the input is '-1' but an uint type is expected.
/// </summary>
InvalidValue,
/// <summary>
/// A tag's value is has an invalid syntax.
/// </summary>
MalformedValue,
/// <summary>
/// The value is too long
/// </summary>
TooLongData,
/// <summary>
/// The data is missing an XML attribute. Usually this is the Name attribute.
/// </summary>
MissingAttribute,
/// <summary>
/// The data points to a non-existing reference.
/// </summary>
MissingReference,
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using System.Xml.Linq;
using System;
using System.Xml.Linq;

namespace PG.StarWarsGame.Files.XML.Parsers;

public interface IPetroglyphXmlParser
{
public object Parse(XElement element);
event EventHandler<ParseErrorEventArgs> ParseError;

object Parse(XElement element);
}

public interface IPetroglyphXmlParser<T> : IPetroglyphXmlParser
{
public new T Parse(XElement element);
new T Parse(XElement element);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public void ParseFile(Stream xmlStream, IValueListDictionary<Crc32, T> parsedEnt
private XElement? GetRootElement(Stream xmlStream)
{
var fileName = xmlStream.GetFilePath();
if (string.IsNullOrEmpty(fileName))
throw new InvalidOperationException("Unable to parse XML from unnamed stream. Either parse from a file or MEG stream.");

var xmlReader = XmlReader.Create(xmlStream, new XmlReaderSettings(), fileName);

var options = LoadOptions.SetBaseUri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace PG.StarWarsGame.Files.XML.Parsers;

public abstract class PetroglyphXmlParser<T> : IPetroglyphXmlParser<T>
{
public event EventHandler<ParseErrorEventArgs>? ParseError;

protected IServiceProvider ServiceProvider { get; }

protected ILogger? Logger { get; }
Expand All @@ -23,6 +25,11 @@ protected PetroglyphXmlParser(IServiceProvider serviceProvider)

public abstract T Parse(XElement element);

protected virtual void OnParseError(ParseErrorEventArgs e)
{
ParseError?.Invoke(this, e);
}

object IPetroglyphXmlParser.Parse(XElement element)
{
return Parse(element);

Check warning on line 35 in src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlParser.cs

View workflow job for this annotation

GitHub Actions / Build & Test (windows-latest)

Possible null reference return.

Check warning on line 35 in src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlParser.cs

View workflow job for this annotation

GitHub Actions / Build & Test (ubuntu-latest)

Possible null reference return.

Check warning on line 35 in src/PetroglyphTools/PG.StarWarsGame.Files.XML/Parsers/PetroglyphXmlParser.cs

View workflow job for this annotation

GitHub Actions / Build & Test (ubuntu-latest)

Possible null reference return.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace PG.StarWarsGame.Files.XML.Parsers.Primitives;
// Used e.g, by <Land_Terrain_Model_Mapping>
// 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 : PetroglyphXmlPrimitiveElementParser<IList<(string key, string value)>>
{
internal CommaSeparatedStringKeyValueListParser(IServiceProvider serviceProvider) : base(serviceProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ public sealed class PetroglyphXmlByteParser : PetroglyphXmlPrimitiveElementParse
{
internal PetroglyphXmlByteParser(IServiceProvider serviceProvider) : base(serviceProvider)
{

}

public override byte Parse(XElement element)
Expand All @@ -18,10 +17,17 @@ public override byte Parse(XElement element)
var asByte = (byte)intValue;
if (intValue != asByte)
{
var location = XmlLocationInfo.FromElement(element);
Logger?.LogWarning($"Expected a byte value (0 - 255) but got value '{intValue}' at {location}");
var location = XmlLocationInfo.FromElement(element);
OnParseError(new ParseErrorEventArgs(location.XmlFile, element, XmlParseErrorKind.InvalidValue,
$"Expected a byte value (0 - 255) but got value '{intValue}' at {location}"));
}

return asByte;
}

protected override void OnParseError(ParseErrorEventArgs e)
{
Logger?.LogWarning(e.Message);
base.OnParseError(e);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.Extensions.Logging;
using System;
using System;
using System.Globalization;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;

namespace PG.StarWarsGame.Files.XML.Parsers.Primitives;

Expand All @@ -17,9 +17,16 @@ public override float Parse(XElement element)
if (!double.TryParse(element.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var doubleValue))
{
var location = XmlLocationInfo.FromElement(element);
Logger?.LogWarning($"Expected double but got value '{element.Value}' at {location}");
OnParseError(new ParseErrorEventArgs(location.XmlFile, element, XmlParseErrorKind.MalformedValue,
$"Expected double but got value '{element.Value}' at {location}"));
return 0.0f;
}
return (float)doubleValue;
}

protected override void OnParseError(ParseErrorEventArgs e)
{
Logger?.LogWarning(e.Message);
base.OnParseError(e);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using Microsoft.Extensions.Logging;
using System;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;

namespace PG.StarWarsGame.Files.XML.Parsers.Primitives;

Expand All @@ -18,11 +18,18 @@ public override int Parse(XElement element)

if (!int.TryParse(element.Value, out var i))
{
var location = XmlLocationInfo.FromElement(element);
Logger?.LogWarning($"Expected integer but got '{element.Value}' at {location}");
var location = XmlLocationInfo.FromElement(element);
OnParseError(new ParseErrorEventArgs(location.XmlFile, element, XmlParseErrorKind.MalformedValue,
$"Expected integer but got '{element.Value}' at {location}"));
return 0;
}

return i;
}

protected override void OnParseError(ParseErrorEventArgs e)
{
Logger?.LogWarning(e.Message);
base.OnParseError(e);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Microsoft.Extensions.Logging;

namespace PG.StarWarsGame.Files.XML.Parsers.Primitives;

Expand Down Expand Up @@ -30,12 +30,21 @@ public override IList<string> Parse(XElement element)

if (trimmedValued.Length > 0x2000)
{
Logger?.LogWarning($"Input value is too long '{trimmedValued.Length}' at {XmlLocationInfo.FromElement(element)}");
var location = XmlLocationInfo.FromElement(element);
OnParseError(new ParseErrorEventArgs(location.XmlFile, element, XmlParseErrorKind.TooLongData,
$"Input value is too long '{trimmedValued.Length}' at {XmlLocationInfo.FromElement(element)}"));

return Array.Empty<string>();
}

var entries = trimmedValued.Split(Separators, StringSplitOptions.RemoveEmptyEntries);

return entries;
}

protected override void OnParseError(ParseErrorEventArgs e)
{
Logger?.LogWarning(e.Message);
base.OnParseError(e);
}
}
Loading

0 comments on commit a677fb9

Please sign in to comment.