1
- using OpenLoco . Common ;
2
1
using OpenLoco . Dat . Data ;
3
2
using OpenLoco . Dat . FileParsing ;
4
3
using System . ComponentModel ;
5
4
6
5
namespace OpenLoco . Dat . Types . SCV5
7
6
{
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
+
8
85
[ TypeConverter ( typeof ( ExpandableObjectConverter ) ) ]
9
86
[ LocoStructSize ( StructLength ) ]
10
87
public record S5File (
@@ -52,9 +129,9 @@ public byte[] Write()
52
129
}
53
130
54
131
// 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 ) ;
58
135
59
136
// gamestate
60
137
byte [ ] gameState ;
@@ -81,9 +158,9 @@ public byte[] Write()
81
158
82
159
tiles = SawyerStreamWriter . WriteChunkCore ( OriginalTileElementData , SawyerEncoding . RunLengthMulti ) ;
83
160
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 ) ] ;
87
164
}
88
165
89
166
public static S5File Read ( ReadOnlySpan < byte > data )
0 commit comments