Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

object validation as per openloco #37

Merged
merged 5 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions Core/DatFileParsing/SawyerStreamReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@ namespace OpenLoco.ObjectEditor.DatFileParsing
{
public static class SawyerStreamReader
{
public static List<S5Header> LoadVariableCountS5Headers(ReadOnlySpan<byte> data, int count)
public static List<S5Header> LoadVariableCountS5Headers(ReadOnlySpan<byte> data, int max)
{
List<S5Header> result = [];
for (var i = 0; i < count; ++i)
for (var i = 0; i < max; ++i)
{
var header = S5Header.Read(data[..S5Header.StructLength]);
if (header.Checksum != 0 || header.Flags != 255)
if (data[0] != 0xFF)
{
result.Add(header);
var header = S5Header.Read(data[..S5Header.StructLength]);
if (header.Checksum != 0 || header.Flags != 255)
{
result.Add(header);
}
}

data = data[S5Header.StructLength..];
Expand Down Expand Up @@ -148,12 +151,33 @@ public static (DatFileInfo DatFileInfo, ILocoObject? LocoObject) LoadFullObjectF
locoStructPostLoad.PostLoad();
}

ValidateLocoStruct(s5Header, locoStruct, logger);

// add to object manager
SObjectManager.Add(newObj);

return new(new DatFileInfo(s5Header, objectHeader), newObj);
}

static void ValidateLocoStruct(S5Header s5Header, ILocoStruct locoStruct, ILogger? logger)
{
try
{
if (!locoStruct.Validate())
{
logger?.Warning($"\"{s5Header.Name}\" failed validation");
}
else
{
logger?.Info($"\"{s5Header.Name}\" validated successfully");
}
}
catch (NotImplementedException)
{
logger?.Debug2($"{s5Header.ObjectType} object type is missing validation function");
}
}

static string CStringToString(ReadOnlySpan<byte> data, Encoding enc)
{
var ptr = 0;
Expand Down
17 changes: 16 additions & 1 deletion Core/Objects/Airport/AirportObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand Down Expand Up @@ -164,5 +164,20 @@ public ReadOnlySpan<byte> Save()

return ms.ToArray();
}

public bool Validate()
{
if (CostIndex > 32)
{
return false;
}

if (-SellCostFactor > BuildCostFactor)
{
return false;
}

return BuildCostFactor > 0;
}
}
}
7 changes: 5 additions & 2 deletions Core/Objects/Airport/MovementEdge.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.DatFileParsing;

namespace Core.Objects
Expand All @@ -12,5 +12,8 @@ public record MovementEdge(
[property: LocoStructOffset(0x03)] uint8_t var_03,
[property: LocoStructOffset(0x04)] uint32_t MustBeClearEdges, // Which edges must be clear to use the transition edge. should probably be some kind of flags?
[property: LocoStructOffset(0x08)] uint32_t AtLeastOneClearEdges // Which edges must have at least one clear to use transition edge. should probably be some kind of flags?
) : ILocoStruct;
) : ILocoStruct
{
public bool Validate() => true;
}
}
7 changes: 5 additions & 2 deletions Core/Objects/Airport/MovementNode.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.DatFileParsing;

namespace Core.Objects
Expand All @@ -10,5 +10,8 @@ public record MovementNode(
[property: LocoStructOffset(0x02)] int16_t Y,
[property: LocoStructOffset(0x04)] int16_t Z,
[property: LocoStructOffset(0x06)] AirportMovementNodeFlags Flags
) : ILocoStruct;
) : ILocoStruct
{
public bool Validate() => true;
}
}
38 changes: 36 additions & 2 deletions Core/Objects/BridgeObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;
using OpenLoco.ObjectEditor.Headers;
Expand Down Expand Up @@ -61,5 +61,39 @@ public ReadOnlySpan<byte> Save()

return headers.SelectMany(h => h.Write().ToArray()).ToArray();
}

public bool Validate()
{
if (CostIndex > 32)
{
return false;
}

if (-SellCostFactor > BaseCostFactor)
{
return false;
}
if (BaseCostFactor <= 0)
{
return false;
}
if (HeightCostFactor < 0)
{
return false;
}
if (var_06 != 16 && var_06 != 32)
{
return false;
}
if (SpanLength != 1 && SpanLength != 2 && SpanLength != 4)
{
return false;
}
if (NumCompatibleTrackMods > 7)
{
return false;
}
return NumCompatibleRoadMods <= 7;
}
}
}
}
4 changes: 4 additions & 0 deletions Core/Objects/BuildingObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,13 @@
// produced cargo
foreach (var obj in ProducedCargo.Fill(MaxProducedCargoType, S5Header.NullHeader))
{
ms.Write(obj.Write());

Check warning on line 144 in Core/Objects/BuildingObject.cs

View workflow job for this annotation

GitHub Actions / build (Release)

Dereference of a possibly null reference.
}

// required cargo
foreach (var obj in RequiredCargo.Fill(MaxRequiredCargoType, S5Header.NullHeader))
{
ms.Write(obj.Write());

Check warning on line 150 in Core/Objects/BuildingObject.cs

View workflow job for this annotation

GitHub Actions / build (Release)

Dereference of a possibly null reference.
}

foreach (var unk in ElevatorAnimationHeights)
Expand All @@ -161,5 +161,9 @@

return ms.ToArray();
}

public bool Validate()
=> NumAnimations is not 0 and not > 63
&& NumVariations is not 0 and <= 31;
}
}
11 changes: 8 additions & 3 deletions Core/Objects/CargoObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand Down Expand Up @@ -53,5 +53,10 @@ public record CargoObject(
[property: LocoStructOffset(0x1B)] uint16_t PaymentFactor,
[property: LocoStructOffset(0x1D)] uint8_t PaymentIndex,
[property: LocoStructOffset(0x1E)] uint8_t UnitSize
) : ILocoStruct;
}
) : ILocoStruct
{
public bool Validate()
=> var_02 <= 3840
&& CargoTransferTime != 0;
}
}
7 changes: 5 additions & 2 deletions Core/Objects/CliffEdgeObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand All @@ -11,5 +11,8 @@ namespace OpenLoco.ObjectEditor.Objects
public record CliffEdgeObject(
[property: LocoStructOffset(0x00), LocoString, Browsable(false)] string_id Name,
[property: LocoStructOffset(0x02), LocoString, Browsable(false)] image_id Image
) : ILocoStruct;
) : ILocoStruct
{
public bool Validate() => true;
}
}
6 changes: 5 additions & 1 deletion Core/Objects/ClimateObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand All @@ -18,5 +18,9 @@ public record ClimateObject(
) : ILocoStruct
{
public const int Seasons = 4;

public bool Validate()
=> WinterSnowLine <= SummerSnowLine
&& FirstSeason < 4;
}
}
21 changes: 19 additions & 2 deletions Core/Objects/CompetitorObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand All @@ -13,7 +13,7 @@ public record CompetitorObject(
[property: LocoStructOffset(0x00), LocoString, Browsable(false)] string_id LastName,
[property: LocoStructOffset(0x04)] uint32_t var_04,
[property: LocoStructOffset(0x08)] uint32_t var_08,
[property: LocoStructOffset(0x0C)] uint8_t Emotions,
[property: LocoStructOffset(0x0C)] uint32_t Emotions,
[property: LocoStructOffset(0x10), Browsable(false), LocoArrayLength(CompetitorObject.ImagesLength)] image_id[] Images,
[property: LocoStructOffset(0x34)] uint8_t Intelligence,
[property: LocoStructOffset(0x35)] uint8_t Aggressiveness,
Expand All @@ -22,5 +22,22 @@ public record CompetitorObject(
) : ILocoStruct
{
public const int ImagesLength = 9;

public bool Validate()
{
if ((Emotions & (1 << 0)) == 0)
{
return false;
}
if (Intelligence < 1 || Intelligence > 9)
{
return false;
}
if (Aggressiveness < 1 || Aggressiveness > 9)
{
return false;
}
return Competitiveness >= 1 && Competitiveness <= 9;
}
}
}
18 changes: 16 additions & 2 deletions Core/Objects/CurrencyObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand All @@ -15,5 +15,19 @@ public record CurrencyObject(
[property: LocoStructOffset(0x06), Browsable(false)] image_id ObjectIcon,
[property: LocoStructOffset(0x0A)] uint8_t Separator,
[property: LocoStructOffset(0x0B)] uint8_t Factor
) : ILocoStruct;
) : ILocoStruct
{
public bool Validate()
{
if (Separator > 4)
{
return false;
}
if (Factor > 3)
{
return false;
}
return true;
}
}
}
16 changes: 15 additions & 1 deletion Core/Objects/DockObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;
using OpenLoco.ObjectEditor.Types;
Expand Down Expand Up @@ -78,5 +78,19 @@ public ReadOnlySpan<byte> Save()
.Concat(var_1C)
.Concat(new byte[] { 0xFF })
.ToArray();
public bool Validate()
{
if (CostIndex > 32)
{
return false;
}

if (-SellCostFactor > BuildCostFactor)
{
return false;
}

return BuildCostFactor > 0;
}
}
}
7 changes: 5 additions & 2 deletions Core/Objects/HillShapesObject.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.Data;
using OpenLoco.ObjectEditor.DatFileParsing;

Expand All @@ -15,5 +15,8 @@ public record HillShapesObject(
[property: LocoStructOffset(0x04), Browsable(false)] image_id Image,
[property: LocoStructOffset(0x08), Browsable(false)] image_id ImageHill,
[property: LocoStructOffset(0x0C), LocoArrayLength(0x0E - 0x0C), Browsable(false)] uint8_t[] pad_0C
) : ILocoStruct;
) : ILocoStruct
{
public bool Validate() => true;
}
}
11 changes: 9 additions & 2 deletions Core/Objects/Industry/BuildingPartAnimation.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using OpenLoco.ObjectEditor.DatFileParsing;

namespace Core.Objects
Expand All @@ -9,5 +9,12 @@ namespace Core.Objects
public record BuildingPartAnimation(
[property: LocoStructOffset(0x00)] uint8_t NumFrames, // Must be a power of 2 (0 = no part animation, could still have animation sequence)
[property: LocoStructOffset(0x01)] uint8_t AnimationSpeed // Also encodes in bit 7 if the animation is position modified
) : ILocoStruct;
) : ILocoStruct
{
public bool Validate()
=> IsPowerOfTwo(NumFrames);

static bool IsPowerOfTwo(uint8_t x)
=> (x & (x - 1)) == 0 && x > 0;
}
}
Loading
Loading