Skip to content

Commit 5f8b885

Browse files
authored
Viewmodel unit tests (#204)
* add viewmodel unit tests * run gog tests as well
1 parent 000c6b0 commit 5f8b885

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1146
-596
lines changed

Dat/Loaders/BridgeObjectLoader.cs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Definitions.ObjectModels;
44
using Definitions.ObjectModels.Objects.Bridge;
55
using Definitions.ObjectModels.Types;
6+
using static Dat.Loaders.BridgeObjectLoader;
67

78
namespace Dat.Loaders;
89

@@ -37,7 +38,7 @@ public static LocoObject Load(Stream stream)
3738
model.ClearHeight = br.ReadUInt16();
3839
model.DeckDepth = br.ReadInt16();
3940
model.SpanLength = br.ReadByte();
40-
model.PillarSpacing = br.ReadByte(); // This is a bitfield, see https
41+
model.PillarSpacing = ((DatSupportPillarSpacing)br.ReadByte()).Convert(); // This is a bitfield, see https
4142
model.MaxSpeed = (Speed16)br.ReadInt16();
4243
model.MaxHeight = (MicroZ)br.ReadByte();
4344
model.CostIndex = br.ReadByte();
@@ -82,7 +83,7 @@ public static void Save(Stream stream, LocoObject obj)
8283
bw.Write(model.ClearHeight);
8384
bw.Write(model.DeckDepth);
8485
bw.Write(model.SpanLength);
85-
bw.Write(model.PillarSpacing); // This is a bitfield, see https://
86+
bw.Write((uint8_t)model.PillarSpacing); // This is a bitfield, see https://
8687
bw.Write(model.MaxSpeed);
8788
bw.Write(model.MaxHeight);
8889
bw.Write(model.CostIndex);
@@ -111,6 +112,45 @@ public static void Save(Stream stream, LocoObject obj)
111112
SawyerStreamWriter.WriteImageTable(stream, obj.GraphicsElements);
112113
}
113114
}
115+
116+
[Flags]
117+
public enum DatSupportPillarSpacing : uint8_t
118+
{
119+
Tile0A = 1 << 0,
120+
Tile0B = 1 << 1,
121+
Tile1A = 1 << 2,
122+
Tile1B = 1 << 3,
123+
Tile2A = 1 << 4,
124+
Tile2B = 1 << 5,
125+
Tile3A = 1 << 6,
126+
Tile3B = 1 << 7,
127+
}
128+
129+
[Flags]
130+
internal enum DatBridgeDisabledTrackFlags : uint16_t
131+
{
132+
None = 0,
133+
Slope = 1 << 0,
134+
SteepSlope = 1 << 1,
135+
CurveSlope = 1 << 2,
136+
Diagonal = 1 << 3,
137+
VerySmallCurve = 1 << 4,
138+
SmallCurve = 1 << 5,
139+
Curve = 1 << 6,
140+
LargeCurve = 1 << 7,
141+
SBendCurve = 1 << 8,
142+
OneSided = 1 << 9,
143+
StartsAtHalfHeight = 1 << 10, // Not used. From RCT2
144+
Junction = 1 << 11,
145+
}
146+
147+
[Flags]
148+
internal enum DatBridgeObjectFlags : uint8_t
149+
{
150+
None = 0,
151+
HasRoof = 1 << 0,
152+
}
153+
114154
}
115155

116156
static class BridgeFlagsConverter
@@ -131,27 +171,11 @@ public static BridgeDisabledTrackFlags Convert(this DatBridgeDisabledTrackFlags
131171
=> (BridgeDisabledTrackFlags)datBridgeDisabledTrackFlags;
132172
}
133173

134-
[Flags]
135-
internal enum DatBridgeDisabledTrackFlags : uint16_t
174+
static class SupportPillarSpacingFlagsConverter
136175
{
137-
None = 0,
138-
Slope = 1 << 0,
139-
SteepSlope = 1 << 1,
140-
CurveSlope = 1 << 2,
141-
Diagonal = 1 << 3,
142-
VerySmallCurve = 1 << 4,
143-
SmallCurve = 1 << 5,
144-
Curve = 1 << 6,
145-
LargeCurve = 1 << 7,
146-
SBendCurve = 1 << 8,
147-
OneSided = 1 << 9,
148-
StartsAtHalfHeight = 1 << 10, // Not used. From RCT2
149-
Junction = 1 << 11,
150-
}
176+
public static DatSupportPillarSpacing Convert(this SupportPillarSpacing supportPillarSpacing)
177+
=> (DatSupportPillarSpacing)supportPillarSpacing;
151178

152-
[Flags]
153-
internal enum DatBridgeObjectFlags : uint8_t
154-
{
155-
None = 0,
156-
HasRoof = 1 << 0,
179+
public static SupportPillarSpacing Convert(this DatSupportPillarSpacing datSupportPillarSpacing)
180+
=> (SupportPillarSpacing)datSupportPillarSpacing;
157181
}

Dat/Loaders/CliffEdgeObjectLoader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Dat.Data;
22
using Dat.FileParsing;
33
using Definitions.ObjectModels;
4-
using Definitions.ObjectModels.Objects.Cliff;
4+
using Definitions.ObjectModels.Objects.CliffEdge;
55
using Definitions.ObjectModels.Types;
66
using System.ComponentModel;
77

Dat/Loaders/IndustryObjectLoader.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Definitions.ObjectModels;
44
using Definitions.ObjectModels.Objects.Industry;
55
using Definitions.ObjectModels.Types;
6+
using System.Diagnostics;
67
using static Dat.Loaders.IndustryObjectLoader;
78

89
namespace Dat.Loaders;
@@ -112,16 +113,9 @@ private static void LoadVariable(LocoBinaryReader br, IndustryObject model, byte
112113
// animation sequences
113114
for (var i = 0; i < Constants.AnimationSequencesCount; ++i)
114115
{
115-
var size = br.PeekByte();
116-
byte[] arr = [];
117-
if (size != 0)
118-
{
119-
br.SkipByte(); // skip size byte
120-
arr = br.ReadBytes(size - 1);
121-
}
122-
123-
model.AnimationSequences.Add([.. arr]);
124-
br.SkipTerminator();
116+
var size = br.ReadByte();
117+
var seq = br.ReadBytes(size);
118+
model.AnimationSequences.Add([.. seq]);
125119
}
126120

127121
// unk

Dat/Loaders/Vehicle/VehicleObjectLoader.cs

Lines changed: 80 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Common;
12
using Dat.Data;
23
using Dat.FileParsing;
34
using Definitions.ObjectModels;
@@ -14,14 +15,15 @@ public static class Constants
1415
{
1516
public const int CompatibleVehicleCount = 8;
1617
public const int RequiredTrackExtrasCount = 4;
17-
public const int CarComponentsCount = 4;
18-
public const int AnimationCount = 2;
19-
public const int CompatibleCargoTypesLength = 2;
18+
public const int MaxCarComponents = 4;
19+
public const int MaxCompatibleCargoCategories = 2;
2020
public const int CargoTypeSpriteOffsetsLength = 32;
2121
public const int MaxUnionSoundStructLength = 0x1B;
2222
public const int MaxBodySprites = 4;
2323
public const int MaxBogieSprites = 2;
2424
public const int MaxStartSounds = 3;
25+
public const int MaxSimpleAnimations = 2;
26+
public const int Var135PadSize = 0x15A - 0x135;
2527
}
2628

2729
public static class StructSizes
@@ -71,14 +73,14 @@ private static void LoadVariable(LocoBinaryReader br, VehicleObject model, byte
7173
}
7274

7375
// required track extra
74-
model.RequiredTrackExtras = br.ReadS5HeaderList(numRequiredTrackExtras);
76+
model.RequiredTrackExtras = br.ReadS5HeaderList(numRequiredTrackExtras).ToArray();
7577

7678
// compatible cargo
77-
for (var i = 0; i < Constants.CompatibleCargoTypesLength; ++i)
79+
for (var i = 0; i < Constants.MaxCompatibleCargoCategories; ++i)
7880
{
79-
model.CompatibleCargoCategories.Add([]);
81+
model.CompatibleCargoCategories[i] = [];
8082
var index = model.NumSimultaneousCargoTypes;
81-
model.MaxCargo.Add(br.ReadByte());
83+
model.MaxCargo[index] = br.ReadByte();
8284

8385
if (model.MaxCargo[index] == 0)
8486
{
@@ -122,7 +124,7 @@ private static void LoadVariable(LocoBinaryReader br, VehicleObject model, byte
122124
}
123125

124126
// compatible vehicles
125-
model.CompatibleVehicles = br.ReadS5HeaderList(numCompatibleVehicles);
127+
model.CompatibleVehicles = br.ReadS5HeaderList(numCompatibleVehicles).ToArray();
126128

127129
// rack rail
128130
if (model.Flags.HasFlag(VehicleObjectFlags.RackRail))
@@ -139,7 +141,7 @@ private static void LoadVariable(LocoBinaryReader br, VehicleObject model, byte
139141
// driving start sounds
140142
const int mask = 127;
141143
var count = numStartSounds & mask;
142-
model.StartSounds = br.ReadS5HeaderList(count);
144+
model.StartSounds = br.ReadS5HeaderList(count).ToArray();
143145
}
144146

145147
private static void LoadFixed(LocoBinaryReader br, VehicleObject model, out byte numRequiredTrackExtras, out byte numCompatibleVehicles, out byte numStartSounds)
@@ -159,19 +161,19 @@ private static void LoadFixed(LocoBinaryReader br, VehicleObject model, out byte
159161
numCompatibleVehicles = br.ReadByte();
160162
br.SkipUInt16(Constants.CompatibleVehicleCount);
161163
br.SkipByte(Constants.RequiredTrackExtrasCount);
162-
model.CarComponents = br.ReadCarComponents(Constants.CarComponentsCount);
164+
model.CarComponents = br.ReadCarComponents(Constants.MaxCarComponents);
163165
model.BodySprites = br.ReadBodySprites(Constants.MaxBodySprites);
164166
model.BogieSprites = br.ReadBogieSprites(Constants.MaxBogieSprites);
165167
model.Power = br.ReadUInt16();
166168
model.Speed = br.ReadInt16();
167169
model.RackSpeed = br.ReadInt16();
168170
model.Weight = br.ReadUInt16();
169171
model.Flags = ((DatVehicleObjectFlags)br.ReadUInt16()).Convert();
170-
br.SkipByte(Constants.CompatibleCargoTypesLength * 1); // MaxCargo, read in LoadVariable
171-
br.SkipByte(Constants.CompatibleCargoTypesLength * 4); // CompatibleCargoCategories, read in LoadVariable
172+
br.SkipByte(Constants.MaxCompatibleCargoCategories * 1); // MaxCargo, read in LoadVariable
173+
br.SkipByte(Constants.MaxCompatibleCargoCategories * 4); // CompatibleCargoCategories, read in LoadVariable
172174
br.SkipByte(Constants.CargoTypeSpriteOffsetsLength * 1); // CargoTypeSpriteOffsets, read in LoadVariable
173175
br.SkipByte(); // NumSimultaneousCargoTypes, manipulated in LoadVariable
174-
model.Animation = br.ReadSimpleAnimations(Constants.AnimationCount);
176+
model.Animation = br.ReadSimpleAnimations(Constants.MaxSimpleAnimations);
175177
model.ShipWakeOffset = br.ReadByte(); // the distance between each wake of the boat. 0 will be a single wake. anything > 0 gives dual wakes
176178
model.DesignedYear = br.ReadUInt16();
177179
model.ObsoleteYear = br.ReadUInt16();
@@ -216,29 +218,29 @@ public static void Save(Stream stream, LocoObject obj)
216218
bw.Write((uint8_t)model.Type.Convert());
217219
bw.Write(model.NumCarComponents);
218220
bw.WriteEmptyObjectId(); // TrackTypeId, not part of object definition
219-
bw.Write((uint8_t)model.RequiredTrackExtras.Count);
221+
bw.Write((uint8_t)model.RequiredTrackExtras.Length);
220222
bw.Write(model.CostIndex);
221223
bw.Write(model.CostFactor);
222224
bw.Write(model.Reliability);
223225
bw.Write(model.RunCostIndex);
224226
bw.Write(model.RunCostFactor);
225227
bw.Write((uint8_t)model.SpecialColourSchemeIndex.Convert());
226-
bw.Write((uint8_t)model.CompatibleVehicles.Count);
228+
bw.Write((uint8_t)model.CompatibleVehicles.Length);
227229
bw.WriteEmptyBytes(Constants.CompatibleVehicleCount * 2);
228230
bw.WriteEmptyBytes(Constants.RequiredTrackExtrasCount);
229-
bw.Write(model.CarComponents);
230-
bw.Write(model.BodySprites);
231-
bw.Write(model.BogieSprites);
231+
bw.Write(model.CarComponents.Fill(Constants.MaxCarComponents, new VehicleObjectCar()).ToArray());
232+
bw.Write(model.BodySprites.Fill(Constants.MaxBodySprites, new BodySprite()).ToArray());
233+
bw.Write(model.BogieSprites.Fill(Constants.MaxBogieSprites, new BogieSprite()).ToArray());
232234
bw.Write(model.Power);
233235
bw.Write(model.Speed);
234236
bw.Write(model.RackSpeed);
235237
bw.Write(model.Weight);
236238
bw.Write((uint16_t)model.Flags.Convert());
237-
bw.WriteEmptyBytes(Constants.CompatibleCargoTypesLength * 1); // MaxCargo, read in LoadVariable
238-
bw.WriteEmptyBytes(Constants.CompatibleCargoTypesLength * 4); // CompatibleCargoCategories, read in LoadVariable
239+
bw.WriteEmptyBytes(Constants.MaxCompatibleCargoCategories * 1); // MaxCargo, read in LoadVariable
240+
bw.WriteEmptyBytes(Constants.MaxCompatibleCargoCategories * 4); // CompatibleCargoCategories, read in LoadVariable
239241
bw.WriteEmptyBytes(Constants.CargoTypeSpriteOffsetsLength * 1); // CargoTypeSpriteOffsets, read in LoadVariable
240242
bw.WriteEmptyBytes(1); // NumSimultaneousCargoTypes, manipulated in LoadVariable
241-
bw.Write(model.Animation);
243+
bw.Write(model.Animation.Fill(Constants.MaxSimpleAnimations, new SimpleAnimation()).ToArray());
242244
bw.Write(model.ShipWakeOffset); // the distance between each wake of the boat. 0 will be a single wake. anything > 0 gives dual wakes
243245
bw.Write(model.DesignedYear);
244246
bw.Write(model.ObsoleteYear);
@@ -270,8 +272,8 @@ public static void Save(Stream stream, LocoObject obj)
270272
throw new ArgumentOutOfRangeException(nameof(model.DrivingSoundType), model.DrivingSoundType, null);
271273
}
272274

273-
bw.Write(model.var_135);
274-
bw.Write((uint8_t)model.StartSounds.Count);
275+
bw.Write(model.var_135.Fill(Constants.Var135PadSize, (byte)0).ToArray());
276+
bw.Write((uint8_t)model.StartSounds.Length);
275277
bw.WriteEmptyBytes(Constants.MaxStartSounds * 1); // StartSounds, not part of object
276278

277279
// sanity check
@@ -281,66 +283,70 @@ public static void Save(Stream stream, LocoObject obj)
281283
SawyerStreamWriter.WriteStringTable(stream, obj.StringTable);
282284

283285
// variable
284-
{
285-
// track type
286-
if (!model.Flags.HasFlag(VehicleObjectFlags.AnyRoadType) && (model.Mode == TransportMode.Rail || model.Mode == TransportMode.Road))
287-
{
288-
bw.WriteS5Header(model.TrackType);
289-
}
286+
SaveVariable(model, bw);
290287

291-
// track extras
292-
foreach (var x in model.RequiredTrackExtras)
293-
{
294-
bw.WriteS5Header(x);
295-
}
288+
// image table
289+
SawyerStreamWriter.WriteImageTable(stream, obj.GraphicsElements);
290+
}
291+
}
296292

297-
// cargo types
298-
for (var i = 0; i < Constants.CompatibleCargoTypesLength; ++i) // CompatibleCargoTypesLength should == CompatibleCargoCategories.Length
299-
{
300-
if (model.MaxCargo.Count < i || model.MaxCargo[i] == 0)
301-
{
302-
bw.WriteEmptyBytes(1); // write a 0 for MaxCargo - this indicates no more cargo and we skip the rest
303-
continue;
304-
}
305-
else
306-
{
307-
bw.Write(model.MaxCargo[i]);
308-
}
309-
310-
foreach (var cc in model.CompatibleCargoCategories[i])
311-
{
312-
bw.Write(BitConverter.GetBytes((uint16_t)cc));
313-
bw.Write(model.CargoTypeSpriteOffsets[cc]);
314-
}
315-
316-
bw.Write(BitConverter.GetBytes((uint16_t)CargoCategory.NULL));
317-
}
293+
private static void SaveVariable(VehicleObject model, LocoBinaryWriter bw)
294+
{
295+
// track type
296+
if (!model.Flags.HasFlag(VehicleObjectFlags.AnyRoadType) && (model.Mode == TransportMode.Rail || model.Mode == TransportMode.Road))
297+
{
298+
bw.WriteS5Header(model.TrackType);
299+
}
300+
301+
// track extras
302+
foreach (var x in model.RequiredTrackExtras)
303+
{
304+
bw.WriteS5Header(x);
305+
}
306+
307+
// cargo types
308+
for (var i = 0; i < Constants.MaxCompatibleCargoCategories; ++i) // CompatibleCargoTypesLength should == CompatibleCargoCategories.Length
309+
{
310+
if (model.MaxCargo.Length < i || model.MaxCargo[i] == 0)
311+
{
312+
bw.WriteEmptyBytes(1); // write a 0 for MaxCargo - this indicates no more cargo and we skip the rest
313+
continue;
314+
}
315+
else
316+
{
317+
bw.Write(model.MaxCargo[i]);
318+
}
318319

319-
// animation
320-
bw.WriteS5HeaderList(model.AnimationHeaders);
320+
var compatibleCargoCategories = model.CompatibleCargoCategories.Fill(Constants.MaxCompatibleCargoCategories, []).ToArray();
321+
foreach (var cc in compatibleCargoCategories[i])
322+
{
323+
bw.Write(BitConverter.GetBytes((uint16_t)cc));
324+
bw.Write(model.CargoTypeSpriteOffsets[cc]);
325+
}
321326

322-
// compatible vehicles
323-
bw.WriteS5HeaderList(model.CompatibleVehicles);
327+
bw.Write(BitConverter.GetBytes((uint16_t)CargoCategory.NULL));
328+
}
324329

325-
// rack rail
326-
if (model.Flags.HasFlag(VehicleObjectFlags.RackRail))
327-
{
328-
bw.WriteS5Header(model.RackRail);
329-
}
330+
// animation
331+
bw.WriteS5HeaderList(model.AnimationHeaders);
330332

331-
// driving sound
332-
if (model.DrivingSoundType != DrivingSoundType.None)
333-
{
334-
bw.WriteS5Header(model.Sound);
335-
}
333+
// compatible vehicles
334+
bw.WriteS5HeaderList(model.CompatibleVehicles);
336335

337-
// driving start sounds
338-
bw.WriteS5HeaderList(model.StartSounds);
339-
}
336+
// rack rail
337+
if (model.Flags.HasFlag(VehicleObjectFlags.RackRail))
338+
{
339+
bw.WriteS5Header(model.RackRail);
340+
}
340341

341-
// image table
342-
SawyerStreamWriter.WriteImageTable(stream, obj.GraphicsElements);
342+
// driving sound
343+
if (model.DrivingSoundType != DrivingSoundType.None)
344+
{
345+
bw.WriteS5Header(model.Sound);
343346
}
347+
348+
// driving start sounds
349+
bw.WriteS5HeaderList(model.StartSounds);
344350
}
345351
}
346352

0 commit comments

Comments
 (0)