diff --git a/LegendsViewer.Backend/Legends/Enums/SiteType.cs b/LegendsViewer.Backend/Legends/Enums/SiteType.cs index 8bedefe..602b872 100644 --- a/LegendsViewer.Backend/Legends/Enums/SiteType.cs +++ b/LegendsViewer.Backend/Legends/Enums/SiteType.cs @@ -29,5 +29,11 @@ public enum SiteType ImportantLocation, Fort, Monastery, - Castle + Castle, + [Description("Mysterious Palace")] + MysteriousPalace, + [Description("Mysterious Dungeon")] + MysteriousDungeon, + [Description("Mysterious Lair")] + MysteriousLair } diff --git a/LegendsViewer.Backend/Legends/Events/SiteRetired.cs b/LegendsViewer.Backend/Legends/Events/SiteRetired.cs index dd4194d..2a4f318 100644 --- a/LegendsViewer.Backend/Legends/Events/SiteRetired.cs +++ b/LegendsViewer.Backend/Legends/Events/SiteRetired.cs @@ -26,21 +26,12 @@ public SiteRetired(List properties, World world) } if (Site != null) { - Site.OwnerHistory.Last().EndYear = Year; - Site.OwnerHistory.Last().EndCause = "retired"; world.AddPlayerRelatedDwarfObjects(Site); } if (SiteEntity != null) { - SiteEntity.SiteHistory.Last(s => s.Site == Site).EndYear = Year; - SiteEntity.SiteHistory.Last(s => s.Site == Site).EndCause = "retired"; world.AddPlayerRelatedDwarfObjects(SiteEntity); } - if (Civ != null) - { - Civ.SiteHistory.Last(s => s.Site == Site).EndYear = Year; - Civ.SiteHistory.Last(s => s.Site == Site).EndCause = "retired"; - } Civ.AddEvent(this); SiteEntity.AddEvent(this); diff --git a/LegendsViewer.Backend/Legends/Parser/FilteredStream.cs b/LegendsViewer.Backend/Legends/Parser/FilteredStream.cs new file mode 100644 index 0000000..2b3c4fd --- /dev/null +++ b/LegendsViewer.Backend/Legends/Parser/FilteredStream.cs @@ -0,0 +1,67 @@ +namespace LegendsViewer.Backend.Legends.Parser; + +public class FilteredStream : Stream +{ + private readonly Stream _baseStream; + + public FilteredStream(Stream baseStream) + { + _baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); + } + + public override bool CanRead => _baseStream.CanRead; + + public override bool CanSeek => _baseStream.CanSeek; + + public override bool CanWrite => _baseStream.CanWrite; + + public override long Length => _baseStream.Length; + + public override long Position { get => _baseStream.Position; set => _baseStream.Position = value; } + + public override void Flush() + { + _baseStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + byte[] tempBuffer = new byte[count]; + int bytesRead = _baseStream.Read(tempBuffer, 0, count); + + if (bytesRead == 0) return 0; + + int wrote = 0; + for (int i = 0; i < bytesRead; i++) + { + if (tempBuffer[i] < 32) + { + // Replace non-printable characters with a space (ASCII 32) + buffer[offset + wrote] = (byte)' '; + } + else + { + buffer[offset + wrote] = tempBuffer[i]; + } + + wrote++; + } + + return wrote; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _baseStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _baseStream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _baseStream.Write(buffer, offset, count); + } +} \ No newline at end of file diff --git a/LegendsViewer.Backend/Legends/Parser/XMLParser.cs b/LegendsViewer.Backend/Legends/Parser/XMLParser.cs index b7a142d..138e9ca 100644 --- a/LegendsViewer.Backend/Legends/Parser/XMLParser.cs +++ b/LegendsViewer.Backend/Legends/Parser/XMLParser.cs @@ -21,7 +21,9 @@ public class XmlParser : IDisposable protected XmlParser(World world, string xmlFile) { World = world; - XmlReader = XmlReader.Create(xmlFile, new XmlReaderSettings { Async = true, IgnoreWhitespace = true, IgnoreComments = true, IgnoreProcessingInstructions = true }); + XmlReader = XmlReader.Create( + new FilteredStream(new FileStream(xmlFile, FileMode.Open)), + new XmlReaderSettings { Async = true, IgnoreWhitespace = true, IgnoreComments = true, IgnoreProcessingInstructions = true }); } public XmlParser(World world, string xmlFile, string? xmlPlusFile) : this(world, xmlFile) diff --git a/LegendsViewer.Backend/Legends/WorldObjects/Artifact.cs b/LegendsViewer.Backend/Legends/WorldObjects/Artifact.cs index 8ccf6a5..8b71608 100644 --- a/LegendsViewer.Backend/Legends/WorldObjects/Artifact.cs +++ b/LegendsViewer.Backend/Legends/WorldObjects/Artifact.cs @@ -10,6 +10,8 @@ namespace LegendsViewer.Backend.Legends.WorldObjects; public class Artifact : WorldObject, IHasCoordinates { + private const string DefaultName = "Untitled"; + [JsonIgnore] public HistoricalFigure? Creator { get; set; } public string? CreatorLink => Creator?.ToLink(true, this); @@ -53,7 +55,7 @@ public Artifact(List properties, World world) : base(properties, world) { Icon = HtmlStyleUtil.GetIconString("diamond-stone"); - Name = "Untitled"; + Name = DefaultName; Type = "Unknown"; Subtype = ""; @@ -61,7 +63,7 @@ public Artifact(List properties, World world) { switch (property.Name) { - case "name": Name = Formatting.InitCaps(property.Value); break; + case "name": Name = Formatting.InitCaps(CheckArtifactName(property.Value)); break; case "item": if (property.SubProperties != null) { @@ -71,7 +73,7 @@ public Artifact(List properties, World world) switch (subProperty.Name) { case "name_string": - Item = Formatting.InitCaps(subProperty.Value); + Item = Formatting.InitCaps(CheckArtifactName(subProperty.Value)); break; case "page_number": PageCount = Convert.ToInt32(subProperty.Value); @@ -119,6 +121,42 @@ public Artifact(List properties, World world) { Coordinates.AddRange(Site.Coordinates); } + if (Name == DefaultName && !string.IsNullOrEmpty(Item)) + { + Name = Item; + } + } + + private static string CheckArtifactName(ReadOnlySpan text) + { + // Determine the start and end characters to replace if needed + char firstChar = text.Length > 0 ? text[0] : '\0'; + char lastChar = text.Length > 1 ? text[^1] : '\0'; + + // If no replacements are necessary, return the original string + if (firstChar != ' ' && lastChar != ' ') + { + return text.ToString(); + } + + // Allocate a new array to modify the content if changes are needed + Span result = stackalloc char[text.Length]; + text.CopyTo(result); + + // Replace the first character if it's a space + if (firstChar == ' ') + { + result[0] = '‹'; + } + + // Replace the last character if it's a space + if (lastChar == ' ') + { + result[^1] = '›'; + } + + // Convert the modified span back to a string + return new string(result); } public void Resolve(World world) diff --git a/LegendsViewer.Backend/Legends/WorldObjects/Site.cs b/LegendsViewer.Backend/Legends/WorldObjects/Site.cs index c5b30d3..f2872b8 100644 --- a/LegendsViewer.Backend/Legends/WorldObjects/Site.cs +++ b/LegendsViewer.Backend/Legends/WorldObjects/Site.cs @@ -225,6 +225,9 @@ public Site(List properties, World world) case "fort": SiteType = SiteType.Fort; break; case "monastery": SiteType = SiteType.Monastery; break; case "castle": SiteType = SiteType.Castle; break; + case "mysterious palace": SiteType = SiteType.MysteriousPalace; break; + case "mysterious dungeon": SiteType = SiteType.MysteriousDungeon; break; + case "mysterious lair": SiteType = SiteType.MysteriousLair; break; default: property.Known = false; break; @@ -357,6 +360,15 @@ private void SetIconByType(SiteType siteType) case SiteType.Castle: Icon = HtmlStyleUtil.GetIconString("castle"); break; + case SiteType.MysteriousPalace: + Icon = HtmlStyleUtil.GetIconString("shield-crown"); + break; + case SiteType.MysteriousDungeon: + Icon = HtmlStyleUtil.GetIconString("checkbox-multiple-blank"); + break; + case SiteType.MysteriousLair: + Icon = HtmlStyleUtil.GetIconString("checkbox-multiple-blank-circle"); + break; default: Icon = HtmlStyleUtil.GetIconString("home-modern"); break; diff --git a/LegendsViewer.Backend/LegendsViewer.Backend.csproj b/LegendsViewer.Backend/LegendsViewer.Backend.csproj index cf88032..d379587 100644 --- a/LegendsViewer.Backend/LegendsViewer.Backend.csproj +++ b/LegendsViewer.Backend/LegendsViewer.Backend.csproj @@ -5,7 +5,7 @@ enable enable LegendsViewer - 1.1.0.0 + 1.1.1.0 Resources/AppIcon.ico