1
1
using System ;
2
+ using System . Collections ;
2
3
using System . Collections . Generic ;
3
4
using System . IO ;
5
+ using System . Linq ;
4
6
5
7
namespace TerrainPatcher
6
8
{
@@ -21,16 +23,20 @@ public static void PatchTerrain(
21
23
try
22
24
{
23
25
Mod . LogInfo ( $ "Applying patch '{ patchName } '") ;
24
- ApplyPatchFile ( patchFile , forceOriginal ) ;
26
+ ApplyPatchFile ( patchName , patchFile , forceOriginal ) ;
25
27
}
26
28
catch ( Exception ex )
27
29
{
28
- Mod . LogError ( $ "Problem applying '{ patchName } ': { ex } ") ;
30
+ Mod . LogError ( $ "Problem applying patch '{ patchName } ': { ex } ") ;
29
31
}
30
32
}
31
33
32
34
// Applies a terrain patch.
33
- internal static void ApplyPatchFile ( Stream patchFile , bool forceOriginal = false )
35
+ internal static void ApplyPatchFile (
36
+ string patchName ,
37
+ Stream patchFile ,
38
+ bool forceOriginal = false
39
+ )
34
40
{
35
41
if ( patchFile is null )
36
42
{
@@ -69,9 +75,9 @@ internal static void ApplyPatchFile(Stream patchFile, bool forceOriginal = false
69
75
Int3 id = batchId . Value ;
70
76
71
77
// Lists all batches as they are patched.
72
- Mod . LogInfo ( $ "- Patching batch ( { id . x } , { id . y } , { id . z } ) ") ;
78
+ Mod . LogInfo ( $ "Patching batch [ { id . x } , { id . y } , { id . z } ] for patch ' { patchName } ' ") ;
73
79
74
- ApplyBatchPatch ( reader , id , forceOriginal ) ;
80
+ ApplyBatchPatch ( patchName , reader , id , forceOriginal ) ;
75
81
}
76
82
catch ( EndOfStreamException ex )
77
83
{
@@ -94,12 +100,33 @@ internal static void ApplyPatchFile(Stream patchFile, bool forceOriginal = false
94
100
}
95
101
96
102
// All batches that have been patched.
97
- // The Int3 is the ID of the batch and the string is the file name.
98
- internal static readonly Dictionary < Int3 , string > patchedBatches =
99
- new Dictionary < Int3 , string > { } ;
103
+ // The Int3 is the ID of the batch.
104
+ internal static readonly Dictionary < Int3 , PatchedBatch > patchedBatches =
105
+ new Dictionary < Int3 , PatchedBatch > { } ;
106
+
107
+ // A batch that has been modified.
108
+ internal struct PatchedBatch
109
+ {
110
+ internal PatchedBatch ( string fileName )
111
+ {
112
+ this . fileName = fileName ;
113
+ this . octreePatches = new List < string > ? [ Constants . OCTREES_PER_BATCH ] ;
114
+ }
115
+
116
+ // The name of the new batch file.
117
+ internal string fileName ;
118
+
119
+ // A list of the patch names that have been applied for each octree.
120
+ internal List < string > ? [ ] octreePatches ;
121
+ }
100
122
101
123
// Loads a batch into patchedBatches if necessary, then applies the patch.
102
- private static void ApplyBatchPatch ( BinaryReader patch , Int3 batchId , bool forceOriginal )
124
+ private static void ApplyBatchPatch (
125
+ string patchName ,
126
+ BinaryReader patch ,
127
+ Int3 batchId ,
128
+ bool forceOriginal
129
+ )
103
130
{
104
131
lock ( patchedBatches )
105
132
{
@@ -109,7 +136,7 @@ private static void ApplyBatchPatch(BinaryReader patch, Int3 batchId, bool force
109
136
}
110
137
}
111
138
112
- PatchOctrees ( batchId , patch ) ;
139
+ PatchOctrees ( patchName , batchId , patch ) ;
113
140
}
114
141
115
142
// Creates a new tempfile for a batch and stores it in patchedBatches.
@@ -128,10 +155,9 @@ string GetPath(string origDir) => Path.Combine(
128
155
) ;
129
156
130
157
// Search each directory.
131
- string [ ] dirs = Constants . ORIG_BATCH_DIRS ;
132
- for ( int i = 0 ; i < dirs . Length ; i ++ )
158
+ foreach ( string dir in Constants . ORIG_BATCH_DIRS )
133
159
{
134
- string origPath = GetPath ( dirs [ i ] ) ;
160
+ string origPath = GetPath ( dir ) ;
135
161
136
162
if ( File . Exists ( origPath ) )
137
163
{
@@ -143,7 +169,7 @@ string GetPath(string origDir) => Path.Combine(
143
169
{
144
170
File . Copy ( origPath , newPath , overwrite : true ) ;
145
171
146
- patchedBatches [ batchId ] = newPath ;
172
+ patchedBatches . Add ( batchId , new PatchedBatch ( newPath ) ) ;
147
173
return ;
148
174
}
149
175
}
@@ -164,28 +190,56 @@ string GetPath(string origDir) => Path.Combine(
164
190
writer . Write ( ( uint ) 0 ) ;
165
191
}
166
192
167
- patchedBatches [ batchId ] = newPath ;
193
+ patchedBatches . Add ( batchId , new PatchedBatch ( newPath ) ) ;
168
194
}
169
195
}
170
196
171
197
// Patches the contents of a batch, assuming it's already in patchedBatches.
172
- private static void PatchOctrees ( Int3 batchId , BinaryReader patch )
198
+ private static void PatchOctrees ( string patchName , Int3 batchId , BinaryReader patch )
173
199
{
200
+ string fileName = patchedBatches [ batchId ] . fileName ;
201
+
174
202
// Copy the contents of the original file into memory.
175
- byte [ ] bytes = File . ReadAllBytes ( patchedBatches [ batchId ] ) ;
203
+ byte [ ] bytes = File . ReadAllBytes ( fileName ) ;
176
204
var original = new BinaryReader ( new MemoryStream ( buffer : bytes , writable : false ) ) ;
177
205
178
206
original . ReadUInt32 ( ) ; // Discard version bytes.
179
207
208
+ BitArray patchedOctrees ;
209
+
180
210
// Apply the patch to the target file.
181
- using ( FileStream file = File . Open ( patchedBatches [ batchId ] , FileMode . Create ) )
211
+ using ( FileStream file = File . Open ( fileName , FileMode . Create ) )
182
212
{
183
213
var target = new BinaryWriter ( file ) ;
184
214
185
215
target . WriteUInt32 ( Constants . BATCH_VERSION ) ; // Prepend version bytes.
186
216
187
217
// Call the terrain patcher.
188
- TerrainPatching . Patch ( target , original , patch ) ;
218
+ patchedOctrees = TerrainPatching . Patch ( target , original , patch ) ;
219
+ }
220
+
221
+ var octreePatches = patchedBatches [ batchId ] . octreePatches ;
222
+ for ( int i = 0 ; i < Constants . OCTREES_PER_BATCH ; i ++ )
223
+ {
224
+ if ( patchedOctrees [ i ] )
225
+ {
226
+ octreePatches [ i ] ??= new List < string > ( ) ;
227
+ var patches = octreePatches [ i ] ! ;
228
+
229
+ if ( patches . Count > 0 )
230
+ {
231
+ var warning = $ "Patch '{ patchName } ' is overriding ";
232
+ warning += patches . Count == 1 ? "patch " : "patches [" ;
233
+ warning += string . Join ( "," , patches . Select ( patch => $ "'{ patch } '") ) ;
234
+ if ( patches . Count > 1 ) { warning += "]" ; }
235
+ warning += $ " in batch [{ batchId . x } , { batchId . y } , { batchId . z } ]";
236
+ warning += $ " at octree #{ i } !";
237
+
238
+ Mod . LogWarning ( warning ) ;
239
+ }
240
+
241
+ patches . Add ( patchName ) ;
242
+ }
189
243
}
190
244
}
191
245
}
@@ -206,12 +260,13 @@ private PatchesDir()
206
260
207
261
foreach ( string path in Directory . EnumerateFiles ( this . path ) )
208
262
{
209
- if ( System . IO . Path . GetExtension ( path ) == ".optoctrees" &&
210
- ! TerrainRegistry . patchedBatches . ContainsValue ( path ) )
263
+ if ( System . IO . Path . GetExtension ( path ) == ".optoctrees" )
211
264
{
212
265
File . Delete ( path ) ;
213
266
}
214
267
}
268
+
269
+ break ;
215
270
}
216
271
}
217
272
}
@@ -231,9 +286,11 @@ public static string? Path
231
286
232
287
internal static class TerrainPatching
233
288
{
234
- // Patches a target file, using an original file and a patch file.
235
- public static void Patch ( BinaryWriter target , BinaryReader original , BinaryReader patch )
289
+ // Patches a target file, using an original file and a patch file. Returns an array
290
+ // indicating which octrees were modified.
291
+ public static BitArray Patch ( BinaryWriter target , BinaryReader original , BinaryReader patch )
236
292
{
293
+ var patchedOctrees = new BitArray ( Constants . OCTREES_PER_BATCH ) ;
237
294
int patchedOctreeCount = patch . ReadByte ( ) ;
238
295
239
296
if ( patchedOctreeCount > Constants . OCTREES_PER_BATCH )
@@ -262,7 +319,9 @@ public static void Patch(BinaryWriter target, BinaryReader original, BinaryReade
262
319
{
263
320
try
264
321
{
265
- octrees [ patch . ReadByte ( ) ] = patch . ReadBytes ( patch . ReadUInt16 ( ) * 4 ) ;
322
+ int octree = patch . ReadByte ( ) ;
323
+ patchedOctrees [ octree ] = true ;
324
+ octrees [ octree ] = patch . ReadBytes ( patch . ReadUInt16 ( ) * 4 ) ;
266
325
}
267
326
catch ( EndOfStreamException )
268
327
{
@@ -293,6 +352,8 @@ public static void Patch(BinaryWriter target, BinaryReader original, BinaryReade
293
352
target . Write ( ( uint ) 0 ) ;
294
353
}
295
354
}
355
+
356
+ return patchedOctrees ;
296
357
}
297
358
}
298
359
}
0 commit comments