Skip to content

Commit ac34a32

Browse files
committed
add requireobjects structure and checksum calculation
1 parent b85161f commit ac34a32

File tree

2 files changed

+109
-30
lines changed

2 files changed

+109
-30
lines changed

Dat/Types/SCV5/S5File.cs

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,87 @@
1-
using OpenLoco.Common;
21
using OpenLoco.Dat.Data;
32
using OpenLoco.Dat.FileParsing;
43
using System.ComponentModel;
54

65
namespace OpenLoco.Dat.Types.SCV5
76
{
7+
public static class ObjectManager
8+
{
9+
public static readonly S5Header FillHeader = new S5Header(uint.MaxValue, "ÿÿÿÿÿÿÿÿ", uint.MaxValue);
10+
11+
public static List<S5Header> GetStructuredHeaders(List<S5Header> allHeaders)
12+
{
13+
var structuredList = new List<S5Header>(S5File.RequiredObjectsCount);
14+
var grouped = allHeaders.GroupBy(x => x.ObjectType).ToDictionary(x => x.Key, x => x.Select(y => y).ToList());
15+
16+
for (var i = 0; i < Limits.kMaxObjectTypes; ++i)
17+
{
18+
var ot = (ObjectType)i;
19+
var count = GetMaxObjectCount(ot);
20+
21+
for (var hdr = 0; hdr < count; ++hdr)
22+
{
23+
if (grouped.TryGetValue(ot, out var hdrs))
24+
{
25+
var item = hdr < hdrs.Count ? hdrs[hdr] : FillHeader;
26+
structuredList.Add(item);
27+
}
28+
else
29+
{
30+
structuredList.Add(FillHeader);
31+
}
32+
}
33+
}
34+
35+
if (structuredList.Count != S5File.RequiredObjectsCount)
36+
{
37+
throw new ArgumentOutOfRangeException(nameof(allHeaders), $"The constructed list didn't have exactly {S5File.RequiredObjectsCount} objects, so it is invalid.");
38+
}
39+
40+
return structuredList;
41+
}
42+
43+
public static int GetMaxObjectCount(ObjectType objectType)
44+
=> objectType switch
45+
{
46+
ObjectType.InterfaceSkin => 1,
47+
ObjectType.Sound => 128,
48+
ObjectType.Currency => 1,
49+
ObjectType.Steam => 32,
50+
ObjectType.CliffEdge => 8,
51+
ObjectType.Water => 1,
52+
ObjectType.Land => 32,
53+
ObjectType.TownNames => 1,
54+
ObjectType.Cargo => 32,
55+
ObjectType.Wall => 32,
56+
ObjectType.TrainSignal => 16,
57+
ObjectType.LevelCrossing => 4,
58+
ObjectType.StreetLight => 1,
59+
ObjectType.Tunnel => 16,
60+
ObjectType.Bridge => 8,
61+
ObjectType.TrainStation => 16,
62+
ObjectType.TrackExtra => 8,
63+
ObjectType.Track => 8,
64+
ObjectType.RoadStation => 16,
65+
ObjectType.RoadExtra => 4,
66+
ObjectType.Road => 8,
67+
ObjectType.Airport => 8,
68+
ObjectType.Dock => 8,
69+
ObjectType.Vehicle => 224,
70+
ObjectType.Tree => 64,
71+
ObjectType.Snow => 1,
72+
ObjectType.Climate => 1,
73+
ObjectType.HillShapes => 1,
74+
ObjectType.Building => 128,
75+
ObjectType.Scaffolding => 1,
76+
ObjectType.Industry => 16,
77+
ObjectType.Region => 1,
78+
ObjectType.Competitor => 32,
79+
ObjectType.ScenarioText => 1,
80+
_ => throw new NotImplementedException()
81+
};
82+
}
83+
84+
885
[TypeConverter(typeof(ExpandableObjectConverter))]
986
[LocoStructSize(StructLength)]
1087
public record S5File(
@@ -52,9 +129,9 @@ public byte[] Write()
52129
}
53130

54131
// required
55-
var reqData = RequiredObjects.Fill(RequiredObjectsCount, S5Header.NullHeader).Select(x => x.Write().ToArray()).ToList();
56-
ReadOnlySpan<byte> req = [.. reqData.SelectMany(x => x)];
57-
var required = SawyerStreamWriter.WriteChunkCore(req, SawyerEncoding.Rotate);
132+
var structured = ObjectManager.GetStructuredHeaders(RequiredObjects);
133+
var reqData = structured.ConvertAll(x => x.Write().ToArray()).SelectMany(x => x);
134+
var required = SawyerStreamWriter.WriteChunkCore([.. reqData], SawyerEncoding.Rotate);
58135

59136
// gamestate
60137
byte[] gameState;
@@ -81,9 +158,9 @@ public byte[] Write()
81158

82159
tiles = SawyerStreamWriter.WriteChunkCore(OriginalTileElementData, SawyerEncoding.RunLengthMulti);
83160

84-
var checksum = BitConverter.GetBytes((uint32_t)0);
85-
86-
return [.. hdr, .. save, .. scenario, .. packed, .. required, .. gameState, .. tiles, .. checksum];
161+
byte[] data = [.. hdr, .. save, .. scenario, .. packed, .. required, .. gameState, .. tiles];
162+
var checksum = data.Sum(x => x);
163+
return [.. data, .. BitConverter.GetBytes((uint32_t)checksum)];
87164
}
88165

89166
public static S5File Read(ReadOnlySpan<byte> data)

Gui/ViewModels/DatTypes/SCV5ViewModel.cs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
using System.Collections.Generic;
1111
using System.ComponentModel;
1212
using System.ComponentModel.DataAnnotations;
13+
using System.IO;
1314
using System.Linq;
15+
using System.Threading.Tasks;
1416

1517
namespace OpenLoco.Gui.ViewModels
1618
{
@@ -172,35 +174,35 @@ void DrawMap()
172174
}
173175
}
174176

175-
public override void Save() => logger?.Warning("Save is not currently implemented");
177+
//public override void Save() => logger?.Warning("Save is not currently implemented");
176178

177-
public override void SaveAs() => logger?.Warning("SaveAs is not currently implemented");
179+
//public override void SaveAs() => logger?.Warning("SaveAs is not currently implemented");
178180

179-
//public override void Save()
180-
// => Save(CurrentFile.Filename);
181+
public override void Save()
182+
=> Save(CurrentFile.Filename);
181183

182-
//public override void SaveAs()
183-
//{
184-
// var saveFile = Task.Run(async () => await PlatformSpecific.SaveFilePicker(PlatformSpecific.SCV5FileTypes)).Result;
185-
// if (saveFile == null)
186-
// {
187-
// return;
188-
// }
184+
public override void SaveAs()
185+
{
186+
var saveFile = Task.Run(async () => await PlatformSpecific.SaveFilePicker(PlatformSpecific.SCV5FileTypes)).Result;
187+
if (saveFile == null)
188+
{
189+
return;
190+
}
189191

190-
// Save(saveFile.Path.LocalPath);
191-
//}
192+
Save(saveFile.Path.LocalPath);
193+
}
192194

193-
//void Save(string filename)
194-
//{
195-
// logger?.Info($"Saving scenario/save/landscape to {filename}");
195+
void Save(string filename)
196+
{
197+
logger?.Info($"Saving scenario/save/landscape to {filename}");
196198

197-
// var newFile = CurrentS5File with
198-
// {
199-
// RequiredObjects = [.. RequiredObjects.Select(x => x.GetAsUnderlyingType())],
200-
// };
199+
var newFile = CurrentS5File with
200+
{
201+
RequiredObjects = [.. RequiredObjects.Select(x => x.GetAsUnderlyingType())],
202+
};
201203

202-
// var bytes = newFile.Write();
203-
// File.WriteAllBytes(filename, bytes);
204-
//}
204+
var bytes = newFile.Write();
205+
File.WriteAllBytes(filename, bytes);
206+
}
205207
}
206208
}

0 commit comments

Comments
 (0)