@@ -6,7 +6,7 @@ public abstract partial class GameRepositoryTests
66{
77 private const string TextEntry = "Data/Text/text.txt" ;
88
9- // ----------------------- intra- origin: several MEGs in the same game -----------------------
9+ #region Intra- origin: several MEGs in the same game
1010
1111 [ Fact ]
1212 public void MegaFilesXml_ThreeListedMegs_LastListedWins ( )
@@ -58,7 +58,9 @@ public void MasterMeg_PatchSlotsOverrideMegaFilesXml_64PatchWinsOverall()
5858 Assert . Equal ( "64Patch" , ReadAll ( gameRepo . OpenFile ( TextEntry , megFileOnly : true ) ) ) ;
5959 }
6060
61- // ----------------------- inter-origin: mod MEGs shadow game MEGs -----------------------
61+ #endregion
62+
63+ #region Inter-origin: mod MEGs shadow game MEGs
6264
6365 [ Fact ]
6466 public void ModPatchMeg_ShadowsGamePatchMeg ( )
@@ -133,32 +135,37 @@ public void MegaFilesXml_MixesModAndGameMegs_LaterListedWins()
133135 Assert . Equal ( "game" , ReadAll ( gameRepo . OpenFile ( TextEntry , megFileOnly : true ) ) ) ;
134136 }
135137
136- // ----------------------- RegisterAndWriteMeg convenience -----------------------
137-
138- [ Fact ]
139- public void RegisterAndWriteMeg_LoadsMegViaGeneratedMegaFilesXml ( )
140- {
141- using var repo = CreateBuilder ( )
142- . ConfigureGame ( g => g . RegisterAndWriteMeg ( "Data/Custom.meg" ,
143- m => m . Add ( TextEntry , "registered" ) ) )
144- . Build ( ) ;
145- var gameRepo = CreateRepository ( repo ) ;
138+ #endregion
146139
147- Assert . Equal ( "registered" , ReadAll ( gameRepo . OpenFile ( TextEntry , megFileOnly : true ) ) ) ;
148- }
140+ // Both of these normalized paths hash to CRC32 0x2AAF63A4:
141+ // model : DATA\ART\MODELS\MOV_EMPIRE_INTRO_SHUTTLE_FIRE_DIE_00.ALA
142+ // WAV entry : U000_EMP0212_ENG.WAV
143+ // The model request collides with the bare WAV entry once the engine has prefixed the model directory,
144+ // which is why the lookup is driven through DATA\ART\MODELS below.
145+ private const string ModelLookup = @"Data\Art\Models\MOV_EMPIRE_INTRO_SHUTTLE_FIRE_DIE_00.ALA" ;
146+ private const string CollidingWav = "U000_EMP0212_ENG.WAV" ;
149147
150148 [ Fact ]
151- public void RegisterAndWriteMeg_RegistrationOrderIsLoadOrder ( )
149+ public void Crc32Collision_ModelLoadedFirst_ShadowedByLaterWav ( )
152150 {
151+ // Both files genuinely exist in the master MEG. The model's MEG (First.meg) is loaded before the
152+ // WAV's MEG (Second.meg), so the later WAV takes over the shared CRC32 slot.
153153 using var repo = CreateBuilder ( )
154154 . ConfigureGame ( g =>
155155 {
156- g . RegisterAndWriteMeg ( "Data/First.meg" , m => m . Add ( TextEntry , "first " ) ) ;
157- g . RegisterAndWriteMeg ( "Data/Second.meg" , m => m . Add ( TextEntry , "second " ) ) ;
156+ g . RegisterAndWriteMeg ( "Data/First.meg" , meg => meg . Add ( ModelLookup , "model-bytes " ) ) ;
157+ g . RegisterAndWriteMeg ( "Data/Second.meg" , meg => meg . Add ( CollidingWav , "wav-bytes " ) ) ;
158158 } )
159159 . Build ( ) ;
160- var gameRepo = CreateRepository ( repo ) ;
160+ var modelRepo = CreateRepository ( repo ) . ModelRepository ;
161+
162+ var found = modelRepo . FileExists ( ModelLookup , megFileOnly : false , out var inMeg , out var actualFilePath ) ;
161163
162- Assert . Equal ( "second" , ReadAll ( gameRepo . OpenFile ( TextEntry , megFileOnly : true ) ) ) ;
164+ // The model exists, yet requesting it resolves to the colliding WAV that was loaded later: the
165+ // engine reports the WAV's path and hands back the WAV's bytes instead of the model.
166+ Assert . True ( found ) ;
167+ Assert . True ( inMeg ) ;
168+ Assert . Equal ( CollidingWav , actualFilePath ) ;
169+ Assert . Equal ( "wav-bytes" , ReadAll ( modelRepo . OpenFile ( ModelLookup ) ) ) ;
163170 }
164171}
0 commit comments