// Window constructor. public Vidmot() : base("Dagateljari") { total = new VBox(); tns = new TNS(); sna = new SNA(); hbButtons = new HBox(); btnL = new Button("New Sticky Note"); btnR = new Button("Close Application"); // Bound to 100 SNotes. snote = new SNote[100]; // Initially 0 SNotes stored in each run. snCount = 0; messagePass = new SNote(this); // Delete function widgets. extraR = new Button("Delete this note"); extraL = new Label(""); extraBox = new HBox(); // Load stored SNotes from previous run. Loader.readSNotes(this); snote = Loader.getSNotes(); snCount = Loader.getSnCount(); int n=0; while(snote[n] is SNote) { tns.addSNote(snote[n], snote[n].getStatus()); n++; } hbButtons.Homogeneous = true; hbButtons.Add(btnL); hbButtons.Add(btnR); extraBox.Homogeneous = true; extraBox.Add(extraL); extraBox.Add(extraR); // Set functions. btnL.Clicked += onBtnTnsLClicked; btnR.Clicked += onBtnTnsRClicked; extraR.Clicked += onBtnExtraRClicked; DeleteEvent += delegate { Loader.writeSNotes(snote, snCount); Application.Quit(); }; total.PackStart(tns, true, true, 0); total.PackStart(hbButtons, false, false, 10); Add(total); // Set initial window size. SetDefaultSize(400,500); ShowAll(); }
async UniTask LoadLVLSNA() { loadingState = "Loading level memory"; await WaitIfNecessary(); Reader reader = files_array[Mem.Lvl].reader; Pointer off_current; SNA sna = (SNA)files_array[Mem.Lvl]; // First read GPT files_array[Mem.Lvl].GotoHeader(); reader = files_array[Mem.Lvl].reader; print("LVL GPT offset: " + Pointer.Current(reader)); if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { // SDA /*sna.GotoSDA(); * print(Pointer.Current(reader)); * reader.ReadUInt32(); * reader.ReadUInt32(); // same as next * uint num_strings = reader.ReadUInt32(); * uint indexOfTextGlobal = reader.ReadUInt32(); // dword_6EEE78 * uint dword_83EC58 = reader.ReadUInt32(); * print(num_strings + " - " + Pointer.Current(reader)); * * // DLG * sna.GotoDLG(); * Pointer off_strings = Pointer.Read(reader); * for (int i = 0; i < num_strings; i++) { * Pointer.Read(reader); * } * reader.ReadUInt32();*/ // GPT sna.GotoHeader(); if (Settings.s.game != Settings.Game.PlaymobilLaura) { Pointer.Read(reader); // sound related } Pointer.Read(reader); Pointer.Read(reader); reader.ReadUInt32(); } if (Settings.s.engineVersion != Settings.EngineVersion.Montreal) { loadingState = "Reading settings for persos in fix"; await WaitIfNecessary(); // Fill in fix -> lvl pointers for perso's in fix uint num_persoInFixPointers = reader.ReadUInt32(); Pointer[] persoInFixPointers = new Pointer[num_persoInFixPointers]; for (int i = 0; i < num_persoInFixPointers; i++) { Pointer off_perso = Pointer.Read(reader); if (off_perso != null) { off_current = Pointer.Goto(ref reader, off_perso); reader.ReadUInt32(); Pointer off_stdGame = Pointer.Read(reader); if (off_stdGame != null) { if (Settings.s.engineVersion > Settings.EngineVersion.TT) { Pointer.Goto(ref reader, off_stdGame); reader.ReadUInt32(); // type 0 reader.ReadUInt32(); // type 1 reader.ReadUInt32(); // type 2 Pointer off_superObject = Pointer.Read(reader); Pointer.Goto(ref reader, off_current); if (off_superObject == null) { continue; } } else { Pointer.Goto(ref reader, off_current); } // First read everything from the GPT Pointer off_newSuperObject = null, off_nextBrother = null, off_prevBrother = null, off_father = null; byte[] matrixData = null, floatData = null, renderBits = null; if (Settings.s.engineVersion > Settings.EngineVersion.TT) { off_newSuperObject = Pointer.Read(reader); matrixData = reader.ReadBytes(0x58); renderBits = reader.ReadBytes(4); floatData = reader.ReadBytes(4); off_nextBrother = Pointer.Read(reader); off_prevBrother = Pointer.Read(reader); off_father = Pointer.Read(reader); } else { matrixData = reader.ReadBytes(0x58); off_newSuperObject = Pointer.Read(reader); Pointer.DoAt(ref reader, off_stdGame + 0xC, () => { ((SNA)off_stdGame.file).AddPointer(off_stdGame.offset + 0xC, off_newSuperObject); }); } // Then fill everything in off_current = Pointer.Goto(ref reader, off_newSuperObject); uint newSOtype = reader.ReadUInt32(); Pointer off_newSOengineObject = Pointer.Read(reader); if (SuperObject.GetSOType(newSOtype) == SuperObject.Type.Perso) { persoInFixPointers[i] = off_newSOengineObject; Pointer.Goto(ref reader, off_newSOengineObject); Pointer off_p3dData = Pointer.Read(reader); if (Settings.s.game == Settings.Game.R2Demo) { ((SNA)off_p3dData.file).OverwriteData(off_p3dData.FileOffset + 0x1C, matrixData); } else { ((SNA)off_p3dData.file).OverwriteData(off_p3dData.FileOffset + 0x18, matrixData); } if (Settings.s.engineVersion > Settings.EngineVersion.TT) { FileWithPointers file = off_newSuperObject.file; file.AddPointer(off_newSuperObject.FileOffset + 0x14, off_nextBrother); file.AddPointer(off_newSuperObject.FileOffset + 0x18, off_prevBrother); file.AddPointer(off_newSuperObject.FileOffset + 0x1C, off_father); ((SNA)file).OverwriteData(off_newSuperObject.FileOffset + 0x30, renderBits); ((SNA)file).OverwriteData(off_newSuperObject.FileOffset + 0x38, floatData); } } else { persoInFixPointers[i] = null; } } Pointer.Goto(ref reader, off_current); } } } loadingState = "Loading globals"; await WaitIfNecessary(); if (Settings.s.engineVersion > Settings.EngineVersion.Montreal) { globals.off_actualWorld = Pointer.Read(reader); globals.off_dynamicWorld = Pointer.Read(reader); globals.off_inactiveDynamicWorld = Pointer.Read(reader); globals.off_fatherSector = Pointer.Read(reader); globals.off_firstSubMapPosition = Pointer.Read(reader); } else { globals.off_actualWorld = Pointer.Read(reader); globals.off_dynamicWorld = Pointer.Read(reader); globals.off_fatherSector = Pointer.Read(reader); uint soundEventIndex = reader.ReadUInt32(); // In Montreal version this is a pointer, also sound event related if (Settings.s.game == Settings.Game.PlaymobilLaura) { Pointer.Read(reader); } } globals.num_always = reader.ReadUInt32(); globals.spawnablePersos = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), LinkedList.Type.Double); globals.off_always_reusableSO = Pointer.Read(reader); // There are (num_always) empty SuperObjects starting with this one. if (Settings.s.engineVersion > Settings.EngineVersion.Montreal) { globals.off_always_reusableUnknown1 = Pointer.Read(reader); // (num_always) * 0x2c blocks globals.off_always_reusableUnknown2 = Pointer.Read(reader); // (num_always) * 0x4 blocks } else { reader.ReadUInt32(); // 0x6F. In Montreal version this is a pointer to a pointer table for always globals.spawnablePersos.FillPointers(reader, globals.spawnablePersos.off_tail, globals.spawnablePersos.offset); } if (Settings.s.game == Settings.Game.DD) { reader.ReadUInt32(); } if (Settings.s.engineVersion > Settings.EngineVersion.Montreal) { Pointer dword_4A6B1C_always_header = Pointer.Read(reader); Pointer dword_4A6B20_always_last = Pointer.Read(reader); Pointer v28 = Pointer.Read(reader); Pointer v31 = Pointer.Read(reader); Pointer v32 = Pointer.Read(reader); Pointer v33 = Pointer.Read(reader); // These things aren't parsed, but in raycap they're null. This way we'll notice when they aren't. if (v28 != null) { print("v28 is not null, it's " + v28); } if (v31 != null) { print("v31 is not null, it's " + v31); } if (v32 != null) { print("v32 is not null, it's " + v32); } if (v33 != null) { print("v33 is not null, it's " + v33); } // Fill in pointers for the unknown table related to "always". FillLinkedListPointers(reader, dword_4A6B20_always_last, dword_4A6B1C_always_header); } // Fill in pointers for the object type tables and read them objectTypes = new ObjectType[3][]; for (uint i = 0; i < 3; i++) { Pointer off_names_header = Pointer.Current(reader); Pointer off_names_first = Pointer.Read(reader); Pointer off_names_last = Pointer.Read(reader); uint num_names = reader.ReadUInt32(); FillLinkedListPointers(reader, off_names_last, off_names_header); ReadObjectNamesTable(reader, off_names_first, num_names, i); } // Begin of engineStructure loadingState = "Loading engine structure"; await WaitIfNecessary(); print("Start of EngineStructure: " + Pointer.Current(reader)); if (Settings.s.engineVersion > Settings.EngineVersion.Montreal) { reader.ReadByte(); string mapName = reader.ReadString(0x1E); reader.ReadChars(0x1E); string mapName2 = reader.ReadString(0x1E); reader.ReadByte(); reader.ReadBytes(0x178); // don't know what this data is } else { reader.ReadByte(); string mapName = reader.ReadString(0x104); reader.ReadChars(0x104); string mapName2 = reader.ReadString(0x104); if (Settings.s.game == Settings.Game.PlaymobilLaura) { reader.ReadChars(0x104); reader.ReadChars(0x104); } string mapName3 = reader.ReadString(0x104); if (Settings.s.game == Settings.Game.TT) { reader.ReadBytes(0x47F7); // don't know what this data is } else if (Settings.s.game == Settings.Game.TTSE) { reader.ReadBytes(0x240F); } else if (Settings.s.game == Settings.Game.PlaymobilLaura) { reader.ReadBytes(0x240F); // don't know what this data is } else // Hype & Alex { reader.ReadBytes(0x2627); // don't know what this data is } } Pointer off_unknown_first = Pointer.Read(reader); Pointer off_unknown_last = Pointer.Read(reader); uint num_unknown = reader.ReadUInt32(); families = LinkedList <Family> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double); families.FillPointers(reader, families.off_tail, families.off_head); if (Settings.s.game == Settings.Game.PlaymobilLaura) { LinkedList <int> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double); } LinkedList <SuperObject> alwaysActiveCharacters = LinkedList <SuperObject> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double); if (Settings.s.engineVersion > Settings.EngineVersion.Montreal) { reader.ReadUInt32(); reader.ReadUInt32(); reader.ReadUInt32(); if (Settings.s.game == Settings.Game.RedPlanet || Settings.s.game == Settings.Game.R2Demo) { reader.ReadUInt32(); } Pointer off_languages = Pointer.Read(reader); reader.ReadUInt32(); Pointer.DoAt(ref reader, off_languages, () => { ReadLanguages(reader, off_languages, localization.num_languages); }); for (uint i = 0; i < 2; i++) { Pointer off_matrix = Pointer.Current(reader); Matrix mat = Matrix.Read(reader, off_matrix); } reader.ReadUInt32(); reader.ReadUInt16(); ReadLevelNames(reader, Pointer.Current(reader), 80); uint num_mapNames = reader.ReadUInt32(); Array.Resize(ref levels, (int)num_mapNames); reader.ReadUInt16(); reader.ReadUInt32(); reader.ReadUInt32(); if (Settings.s.game == Settings.Game.DD) { reader.ReadUInt32(); } // End of engineStructure Pointer off_light = Pointer.Read(reader); // the offset of a light. It's just an ordinary light. Pointer off_mainChar = Pointer.Read(reader); // superobject Pointer off_characterLaunchingSoundEvents = Pointer.Read(reader); if (Settings.s.game == Settings.Game.DD) { globals.off_backgroundGameMaterial = Pointer.Read(reader); } Pointer off_shadowPolygonVisualMaterial = Pointer.Read(reader); Pointer off_shadowPolygonGameMaterialInit = Pointer.Read(reader); Pointer off_shadowPolygonGameMaterial = Pointer.Read(reader); Pointer off_textureOfTextureShadow = Pointer.Read(reader); Pointer off_col_taggedFacesTable = Pointer.Read(reader); for (int i = 0; i < 10; i++) { Pointer off_elementForShadow = Pointer.Read(reader); Pointer off_geometricShadowObject = Pointer.Read(reader); } Pointer.Read(reader); // DemoSOList if (Settings.s.game == Settings.Game.R2Demo || Settings.s.game == Settings.Game.RedPlanet || Settings.s.mode == Settings.Mode.DonaldDuckPCDemo) { Pointer.Read(reader); } if (Settings.s.mode == Settings.Mode.DonaldDuckPCDemo) { reader.ReadUInt32(); reader.ReadUInt32(); } loadingState = "Loading level animation bank"; //print("Animation bank: " + Pointer.Current(reader)); await WaitIfNecessary(); AnimationBank.Read(reader, Pointer.Current(reader), 0, 1, files_array[Mem.LvlKeyFrames], append: true); animationBanks[1] = animationBanks[0]; } if (FileSystem.mode != FileSystem.Mode.Web) { string levelsFolder = gameDataBinFolder + ConvertPath(gameDsb.levelsDataPath) + "/"; ((SNA)files_array[0]).CreateMemoryDump(levelsFolder + "fix.dmp", true); ((SNA)files_array[1]).CreateMemoryDump(levelsFolder + lvlName + "/" + lvlName + ".dmp", true); } // Read PTX loadingState = "Loading level textures"; await WaitIfNecessary(); // Can't yield inside a lambda, so we must do it the old fashioned way, with off_current if (sna.PTX != null) { off_current = Pointer.Goto(ref reader, sna.PTX); await ReadTexturesLvl(reader, Pointer.Current(reader)); Pointer.Goto(ref reader, off_current); } /*Pointer.DoAt(ref reader, sna.PTX, () => { * ReadTexturesLvl(reader, Pointer.Current(reader)); * });*/ // Read background game material (DD only) globals.backgroundGameMaterial = GameMaterial.FromOffsetOrRead(globals.off_backgroundGameMaterial, reader); // Parse actual world & always structure loadingState = "Loading families"; await WaitIfNecessary(); ReadFamilies(reader); loadingState = "Creating animation bank"; await WaitIfNecessary(); if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { animationBanks = new AnimationBank[2]; animationBanks[0] = new AnimationBank(null) { animations = new Animation.Component.AnimA3DGeneral[0] }; animationBanks[1] = animationBanks[0]; } else if (Settings.s.engineVersion <= Settings.EngineVersion.TT) { uint maxAnimIndex = 0; foreach (State s in states) { if (s.anim_ref != null && s.anim_ref.anim_index > maxAnimIndex) { maxAnimIndex = s.anim_ref.anim_index; } } animationBanks = new AnimationBank[2]; animationBanks[0] = new AnimationBank(null) { animations = new Animation.Component.AnimA3DGeneral[maxAnimIndex + 1] }; foreach (State s in states) { if (s.anim_ref != null) { animationBanks[0].animations[s.anim_ref.anim_index] = s.anim_ref.a3d; } } animationBanks[1] = animationBanks[0]; } loadingState = "Loading superobject hierarchy"; await WaitIfNecessary(); await ReadSuperObjects(reader); loadingState = "Loading always structure"; await WaitIfNecessary(); ReadAlways(reader); loadingState = "Filling in cross-references"; await WaitIfNecessary(); ReadCrossReferences(reader); // TODO: Make more generic if (Settings.s.game == Settings.Game.R2) { loadingState = "Filling in comport names"; await WaitIfNecessary(); string path = gameDataBinFolder + "R2DC_Comports.json"; if (!FileSystem.FileExists(path)) { path = "Assets/StreamingAssets/R2DC_Comports.json"; // Offline, the json doesn't exist, so grab it from StreamingAssets } Stream stream = FileSystem.GetFileReadStream(path); if (stream != null) { ReadAndFillComportNames(stream); } } }
async UniTask LoadFIXSNA() { loadingState = "Loading fixed memory"; await WaitIfNecessary(); files_array[Mem.Fix].GotoHeader(); Reader reader = files_array[Mem.Fix].reader; print("FIX GPT offset: " + Pointer.Current(reader)); SNA sna = (SNA)files_array[Mem.Fix]; if (Settings.s.engineVersion <= Settings.EngineVersion.TT) { // Tonic Trouble inputStruct = new InputStructure(null); uint stringCount = Settings.s.game == Settings.Game.TTSE ? 351 : (uint)gameDsb.textFiles.Sum(t => t.strings.Count); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); if (Settings.s.game == Settings.Game.TTSE) { for (int i = 0; i < 50; i++) { Pointer.Read(reader); } } else { for (int i = 0; i < 100; i++) { Pointer.Read(reader); } } reader.ReadUInt32(); // 0x35 if (Settings.s.game != Settings.Game.TTSE) { reader.ReadBytes(0x80); // contains strings like MouseXPos, input related. first dword of this is a pointer to inputstructure probably } reader.ReadBytes(0x90); Pointer.Read(reader); reader.ReadUInt32(); // 0x28 reader.ReadUInt32(); // 0x1 if (Settings.s.game == Settings.Game.TTSE) { Pointer.Read(reader); } for (int i = 0; i < 100; i++) { Pointer.Read(reader); } for (int i = 0; i < 100; i++) { Pointer.Read(reader); } reader.ReadUInt32(); // 0x1 if (Settings.s.game == Settings.Game.TTSE) { reader.ReadBytes(0xB4); } else { if (stringCount != 598) // English version and probably other versions have 603 strings. It's a hacky way to check which version. { reader.ReadBytes(0x2CC); } else // French version: 598 { reader.ReadBytes(0x2C0); } } reader.ReadBytes(0x1C); // Init strings reader.ReadUInt32(); // 0 reader.ReadUInt32(); // 1 reader.ReadUInt32(); // ??? Pointer.Read(reader); for (int i = 0; i < stringCount; i++) { Pointer.Read(reader); // read num_loaded_strings pointers here } reader.ReadBytes(0xC); // dword_51A728. probably a table of some sort: 2 ptrs and a number if (Settings.s.game != Settings.Game.TTSE) // There's more but what is even the point in reading all this { reader.ReadUInt32(); Pointer.Read(reader); reader.ReadBytes(0x14); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadUInt32(); // 0, so can be pointer too reader.ReadBytes(0x30); reader.ReadBytes(0x960); } } else if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { uint num_strings = 0; inputStruct = new InputStructure(null); // SDA Pointer.DoAt(ref reader, sna.SDA, () => { print(Pointer.Current(reader)); reader.ReadUInt32(); reader.ReadUInt32(); // same as next num_strings = reader.ReadUInt32(); uint indexOfTextGlobal = reader.ReadUInt32(); // dword_6EEE78 uint dword_83EC58 = reader.ReadUInt32(); print(num_strings + " - " + Pointer.Current(reader)); }); // DLG Pointer.DoAt(ref reader, sna.DLG, () => { Pointer off_strings = Pointer.Read(reader); for (int i = 0; i < num_strings; i++) { Pointer.Read(reader); } reader.ReadUInt32(); }); // GPT sna.GotoHeader(); Pointer.Read(reader); Pointer off_mainLight = Pointer.Read(reader); uint lpPerformanceCount = reader.ReadUInt32(); Pointer.Read(reader); Pointer off_defaultMaterial = Pointer.Read(reader); Pointer off_geometricObject1 = Pointer.Read(reader); Pointer off_geometricObject2 = Pointer.Read(reader); Pointer off_geometricObject3 = Pointer.Read(reader); reader.ReadBytes(0x90); // FON_ related reader.ReadBytes(0x3D54); // FON_ related for (int i = 0; i < 100; i++) { Pointer.Read(reader); // matrix in stack } uint matrixInStack = reader.ReadUInt32(); // number of matrix in stack reader.ReadBytes(0xC); reader.ReadBytes(0x20); reader.ReadUInt32(); reader.ReadUInt32(); Pointer.Read(reader); Pointer.Read(reader); for (int i = 0; i < num_strings; i++) { Pointer.Read(reader); } LinkedList <int> fontDefinitions = LinkedList <int> .ReadHeader(reader, Pointer.Current(reader)); Pointer.Read(reader); reader.ReadUInt32(); reader.ReadUInt32(); reader.ReadUInt32(); Pointer off_geometricObject4 = Pointer.Read(reader); Pointer off_geometricObject5 = Pointer.Read(reader); Pointer off_geometricObject6 = Pointer.Read(reader); Pointer off_visualmaterial1 = Pointer.Read(reader); Pointer off_visualmaterial2 = Pointer.Read(reader); for (int i = 0; i < 10; i++) { Pointer off_texture = Pointer.Read(reader); } Pointer off_visualmaterial3 = Pointer.Read(reader); Pointer off_gamematerial = Pointer.Read(reader); uint geometricElementIndexGlobal = reader.ReadUInt32(); Pointer off_texture2 = Pointer.Read(reader); Pointer off_geometricObject7 = Pointer.Read(reader); for (uint i = 0; i < 7; i++) { Pointer.Read(reader); // Material for stencils. Order: corner, border, center, side, redarrow, bullet, and another one } Pointer dword_5DCB9C = Pointer.Read(reader); // Now comes INV_fn_vSnaMultilanguageLoading print(Pointer.Current(reader)); } else { Pointer off_identityMatrix = Pointer.Read(reader); reader.ReadBytes(50 * 4); uint matrixInStack = reader.ReadUInt32(); Pointer off_collisionGeoObj = Pointer.Read(reader); Pointer off_staticCollisionGeoObj = Pointer.Read(reader); loadingState = "Loading input structure"; await WaitIfNecessary(); for (int i = 0; i < Settings.s.numEntryActions; i++) { Pointer.Read(reader); // 3DOS_EntryActions } Pointer off_IPT_keyAndPadDefine = Pointer.Read(reader); ReadKeypadDefine(reader, off_IPT_keyAndPadDefine); inputStruct = InputStructure.Read(reader, Pointer.Current(reader)); foreach (EntryAction ea in inputStruct.entryActions) { print(ea.ToString()); } print("Num entractions: " + inputStruct.num_entryActions); print("Off entryactions: " + inputStruct.off_entryActions); Pointer off_IPT_entryElementList = Pointer.Read(reader); print("Off entryelements: " + off_IPT_entryElementList); loadingState = "Loading text"; await WaitIfNecessary(); localization = FromOffsetOrRead <LocalizationStructure>(reader, Pointer.Current(reader), inline: true); // FON_g_stGeneral loadingState = "Loading fixed animation bank"; await WaitIfNecessary(); animationBanks = new AnimationBank[2]; // 1 in fix, 1 in lvl animationBanks[0] = AnimationBank.Read(reader, Pointer.Current(reader), 0, 1, files_array[Mem.FixKeyFrames])[0]; print("Fix animation bank: " + animationBanks[0].off_header); Pointer off_fixInfo = Pointer.Read(reader); } // Read PTX loadingState = "Loading fixed textures"; await WaitIfNecessary(); // Can't yield inside a lambda, so we must do it the old fashioned way, with off_current if (sna.PTX != null) { Pointer off_current = Pointer.Goto(ref reader, sna.PTX); await ReadTexturesFix(reader, Pointer.Current(reader)); Pointer.Goto(ref reader, off_current); } /*Pointer.DoAt(ref reader, sna.PTX, () => { * ReadTexturesFix(reader, Pointer.Current(reader)); * });*/ }
protected override async UniTask Load() { try { if (gameDataBinFolder == null || gameDataBinFolder.Trim().Equals("")) { throw new Exception("GAMEDATABIN folder doesn't exist"); } if (lvlName == null || lvlName.Trim() == "") { throw new Exception("No level name specified!"); } globals = new Globals(); gameDataBinFolder += "/"; await FileSystem.CheckDirectory(gameDataBinFolder); if (!FileSystem.DirectoryExists(gameDataBinFolder)) { throw new Exception("GAMEDATABIN folder doesn't exist"); } loadingState = "Initializing files"; await WaitIfNecessary(); string gameDsbPath = gameDataBinFolder + ConvertCase("Game.dsb", Settings.CapsType.DSB); if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { gameDsbPath = gameDataBinFolder + ConvertCase("gamedsc.bin", Settings.CapsType.DSB); } else if (Settings.s.game == Settings.Game.TTSE) { gameDsbPath = gameDataBinFolder + ConvertCase("GAME.DSC", Settings.CapsType.DSB); } await PrepareFile(gameDsbPath); gameDsb = new DSB("Game", gameDsbPath); if (FileSystem.mode != FileSystem.Mode.Web) { gameDsb.Save(gameDataBinFolder + ConvertCase("Game_dsb.dmp", Settings.CapsType.DSB)); } gameDsb.ReadAllSections(); gameDsb.Dispose(); await CreateCNT(); if (Settings.s.game == Settings.Game.R2) { string comportsPath = gameDataBinFolder + "R2DC_Comports.json"; await PrepareFile(comportsPath); } if (lvlName.EndsWith(".exe")) { if (!Settings.s.hasMemorySupport) { throw new Exception("This game does not have memory support."); } Settings.s.loadFromMemory = true; MemoryFile mem = new MemoryFile(lvlName); files_array[0] = mem; await WaitIfNecessary(); await LoadMemory(); } else { hasTransit = false; DAT dat = null; string levelsSubFolder = ConvertCase(ConvertPath(gameDsb.levelsDataPath), Settings.CapsType.All) + "/"; string levelsFolder = gameDataBinFolder + levelsSubFolder; string langDataPath = gameDataBinFolder + ConvertCase("../LangData/English/", Settings.CapsType.All) + levelsSubFolder; if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { await FileSystem.CheckDirectory(langDataPath); if (FileSystem.mode != FileSystem.Mode.Web && !FileSystem.DirectoryExists(langDataPath)) { string langPath = gameDataBinFolder + ConvertCase("../LangData/", Settings.CapsType.All); await FileSystem.CheckDirectory(langPath); if (FileSystem.DirectoryExists(langPath)) { DirectoryInfo dirInfo = new DirectoryInfo(langPath); DirectoryInfo firstLang = dirInfo.GetDirectories().FirstOrDefault(); if (firstLang != null) { langDataPath = firstLang.FullName + "/" + levelsSubFolder; await FileSystem.CheckDirectory(langDataPath); } } } } await WaitIfNecessary(); bool hasRelocationFiles = true; if (Settings.s.mode == Settings.Mode.Rayman2PC || Settings.s.mode == Settings.Mode.DonaldDuckPC) { string dataPath = levelsFolder + "LEVELS0.DAT"; await PrepareBigFile(dataPath, 512 *1024); if (FileSystem.FileExists(dataPath)) { dat = new DAT("LEVELS0", gameDsb, dataPath); hasRelocationFiles = false; } } // Prepare folder names string lvlFolder = ConvertCase(lvlName + "/", Settings.CapsType.LevelFolder); string langLvlFolder = ConvertCase(lvlName + "/", Settings.CapsType.LangLevelFolder); // Prepare paths paths["fix.sna"] = levelsFolder + ConvertCase("Fix.sna", Settings.CapsType.Fix); paths["fix.rtb"] = levelsFolder + ConvertCase("Fix.rtb", Settings.CapsType.FixRelocation); paths["fix.gpt"] = levelsFolder + ConvertCase("Fix.gpt", Settings.CapsType.Fix); paths["fix.rtp"] = levelsFolder + ConvertCase("Fix.rtp", Settings.CapsType.FixRelocation); paths["fix.ptx"] = levelsFolder + ConvertCase("Fix.ptx", Settings.CapsType.Fix); paths["fix.rtt"] = levelsFolder + ConvertCase("Fix.rtt", Settings.CapsType.FixRelocation); if (Settings.s.engineVersion < Settings.EngineVersion.R2) { paths["fixlvl.rtb"] = levelsFolder + lvlFolder + ConvertCase("FixLvl.rtb", Settings.CapsType.FixLvl); } else { paths["fixlvl.rtb"] = null; } if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { paths["fix.sda"] = levelsFolder + ConvertCase("Fix.sda", Settings.CapsType.Fix); paths["fix.lng"] = langDataPath + ConvertCase("Fix.lng", Settings.CapsType.LangFix); paths["fix.rtg"] = langDataPath + ConvertCase("Fix.rtg", Settings.CapsType.FixRelocation); paths["fix.dlg"] = langDataPath + ConvertCase("Fix.dlg", Settings.CapsType.LangFix); paths["fix.rtd"] = langDataPath + ConvertCase("Fix.rtd", Settings.CapsType.FixRelocation); paths["fixlvl.rtg"] = langDataPath + langLvlFolder + ConvertCase("FixLvl.rtg", Settings.CapsType.FixLvl); } else { paths["fix.sda"] = null; paths["fix.lng"] = null; paths["fix.rtg"] = null; paths["fix.dlg"] = null; paths["fix.rtd"] = null; paths["fixlvl.rtg"] = null; } paths["lvl.sna"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".sna", Settings.CapsType.LevelFile); paths["lvl.gpt"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".gpt", Settings.CapsType.LevelFile); paths["lvl.ptx"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".ptx", Settings.CapsType.LevelFile); if (hasRelocationFiles) { paths["lvl.rtb"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".rtb", Settings.CapsType.LevelRelocation); paths["lvl.rtp"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".rtp", Settings.CapsType.LevelRelocation); paths["lvl.rtt"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".rtt", Settings.CapsType.LevelRelocation); } else { paths["lvl.rtb"] = null; paths["lvl.rtp"] = null; paths["lvl.rtt"] = null; } if (Settings.s.engineVersion == Settings.EngineVersion.Montreal) { paths["lvl.sda"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".sda", Settings.CapsType.LevelFile); paths["lvl.lng"] = langDataPath + langLvlFolder + ConvertCase(lvlName + ".lng", Settings.CapsType.LangLevelFile); paths["lvl.rtg"] = langDataPath + langLvlFolder + ConvertCase(lvlName + ".rtg", Settings.CapsType.LangLevelFile); paths["lvl.dlg"] = langDataPath + langLvlFolder + ConvertCase(lvlName + ".dlg", Settings.CapsType.LangLevelFile); paths["lvl.rtd"] = langDataPath + langLvlFolder + ConvertCase(lvlName + ".rtd", Settings.CapsType.LangLevelRelocation); } else { paths["lvl.sda"] = null; paths["lvl.lng"] = null; paths["lvl.rtg"] = null; paths["lvl.dlg"] = null; paths["lvl.rtd"] = null; } paths["lvl.dsb"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".dsb", Settings.CapsType.DSB); if (Settings.s.engineVersion < Settings.EngineVersion.R2) { paths["lvl.dsb"] = levelsFolder + lvlFolder + ConvertCase(lvlName + ".dsc", Settings.CapsType.DSB); } // Download files foreach (KeyValuePair <string, string> path in paths) { if (path.Value != null) { await PrepareFile(path.Value); } } // LEVEL DSB await WaitIfNecessary(); if (FileSystem.FileExists(paths["lvl.dsb"])) { lvlDsb = new DSB(lvlName + ".dsc", paths["lvl.dsb"]); if (FileSystem.mode != FileSystem.Mode.Web) { lvlDsb.Save(levelsFolder + lvlFolder + lvlName + "_dsb.dmp"); } //lvlDsb.ReadAllSections(); lvlDsb.Dispose(); } // FIX RelocationTable fixRtb = new RelocationTable(paths["fix.rtb"], dat, "Fix", RelocationType.RTB); await fixRtb.Init(); if (FileSystem.FileExists(paths["fixlvl.rtb"])) { // Fix -> Lvl pointers for Tonic Trouble RelocationTable fixLvlRtb = new RelocationTable(paths["fixlvl.rtb"], dat, lvlName + "Fix", RelocationType.RTB); await fixLvlRtb.Init(); fixRtb.Add(fixLvlRtb); } SNA fixSna = new SNA("Fix", paths["fix.sna"], fixRtb); if (Settings.s.engineVersion == Settings.EngineVersion.Montreal && FileSystem.DirectoryExists(langDataPath)) { RelocationTable fixLangRTG = new RelocationTable(paths["fix.rtg"], dat, "fixLang", RelocationType.RTG); await fixLangRTG.Init(); if (FileSystem.FileExists(paths["fixlvl.rtg"])) { RelocationTable fixLvlRTG = new RelocationTable(paths["fixlvl.rtg"], dat, lvlName + "FixLang", RelocationType.RTG); await fixLvlRTG.Init(); fixLangRTG.Add(fixLvlRTG); } SNA fixLangSna = new SNA("fixLang", paths["fix.lng"], fixLangRTG); await WaitIfNecessary(); fixSna.AddSNA(fixLangSna); await WaitIfNecessary(); RelocationTable fixRtd = new RelocationTable(paths["fix.rtd"], dat, "fixLang", RelocationType.RTD); await fixRtd.Init(); fixSna.ReadDLG(paths["fix.dlg"], fixRtd); } RelocationTable fixRtp = new RelocationTable(paths["fix.rtp"], dat, "fix", RelocationType.RTP); await fixRtp.Init(); fixSna.ReadGPT(paths["fix.gpt"], fixRtp); RelocationTable fixRtt = new RelocationTable(paths["fix.rtt"], dat, "fix", RelocationType.RTT); await fixRtt.Init(); fixSna.ReadPTX(paths["fix.ptx"], fixRtt); if (FileSystem.FileExists(paths["fix.sda"])) { fixSna.ReadSDA(paths["fix.sda"]); } // LEVEL RelocationTable lvlRtb = new RelocationTable(paths["lvl.rtb"], dat, lvlName, RelocationType.RTB); await lvlRtb.Init(); SNA lvlSna = new SNA(lvlName, paths["lvl.sna"], lvlRtb); if (Settings.s.engineVersion == Settings.EngineVersion.Montreal && FileSystem.DirectoryExists(langDataPath)) { RelocationTable lvlLangRTG = new RelocationTable(paths["lvl.rtg"], dat, lvlName + "Lang", RelocationType.RTG); await lvlLangRTG.Init(); SNA lvlLangSna = new SNA(lvlName + "Lang", paths["lvl.lng"], lvlLangRTG); await WaitIfNecessary(); lvlSna.AddSNA(lvlLangSna); await WaitIfNecessary(); RelocationTable lvlRtd = new RelocationTable(paths["lvl.rtd"], dat, lvlName + "Lang", RelocationType.RTD); await lvlRtd.Init(); lvlSna.ReadDLG(paths["lvl.dlg"], lvlRtd); } if (Settings.s.engineVersion > Settings.EngineVersion.TT) { RelocationTable lvlRtp = new RelocationTable(paths["lvl.rtp"], dat, lvlName, RelocationType.RTP); await lvlRtp.Init(); lvlSna.ReadGPT(paths["lvl.gpt"], lvlRtp); RelocationTable lvlRtt = new RelocationTable(paths["lvl.rtt"], dat, lvlName, RelocationType.RTT); await lvlRtt.Init(); lvlSna.ReadPTX(paths["lvl.ptx"], lvlRtt); } else { lvlSna.ReadGPT(paths["lvl.gpt"], null); lvlSna.ReadPTX(paths["lvl.ptx"], null); } if (FileSystem.FileExists(paths["lvl.sda"])) { await WaitIfNecessary(); lvlSna.ReadSDA(paths["lvl.sda"]); } await WaitIfNecessary(); fixSna.CreatePointers(); await WaitIfNecessary(); lvlSna.CreatePointers(); files_array[0] = fixSna; files_array[1] = lvlSna; files_array[2] = dat; if (FileSystem.mode != FileSystem.Mode.Web) { await WaitIfNecessary(); fixSna.CreateMemoryDump(levelsFolder + "fix.dmp", true); await WaitIfNecessary(); lvlSna.CreateMemoryDump(levelsFolder + lvlFolder + lvlName + ".dmp", true); } await LoadFIXSNA(); await LoadLVLSNA(); await WaitIfNecessary(); fixSna.Dispose(); lvlSna.Dispose(); if (dat != null) { dat.Dispose(); } } } finally { for (int i = 0; i < files_array.Length; i++) { if (files_array[i] != null) { if (!(files_array[i] is MemoryFile)) { files_array[i].Dispose(); } } } if (cnt != null) { cnt.Dispose(); } } await WaitIfNecessary(); InitModdables(); }