/// <returns>A <b>new</b> <see cref="Map"/> object containing <b>only</b> the decompiled map files, or <see langword="null"/> if cancelled.</returns> public static Map?DecompileMap(Map map, MapFiles filesToDecompile, BackgroundWorker?worker) { if (!filesToDecompile.IsDefined(allowNoFlags: false)) { throw new InvalidEnumArgumentException(nameof(filesToDecompile), (int)filesToDecompile, typeof(MapFiles)); } if (filesToDecompile.HasFlag(MapFiles.Environment)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.PathingMap)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.PreviewIcons)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.ShadowMap)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.ImportedFiles)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.Info)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.AbilityObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.BuffObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.DestructableObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.DoodadObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.ItemObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.UnitObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.UpgradeObjectData)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.CustomTextTriggers)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.Script)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.TriggerStrings)) { throw new NotImplementedException(); } if (filesToDecompile.HasFlag(MapFiles.Doodads)) { throw new NotImplementedException(); } var decompiler = new JassScriptDecompiler(map); var decompiledMap = new Map(); var decompiledCount = 0; var toDecompileCount = 0; var progress = 0; if (filesToDecompile.HasFlag(MapFiles.Sounds)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Cameras)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Environment)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.PathingMap)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.PreviewIcons)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Regions)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.ShadowMap)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.ImportedFiles)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Info)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.AbilityObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.BuffObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.DestructableObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.DoodadObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.ItemObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.UnitObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.UpgradeObjectData)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.CustomTextTriggers)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Script)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Triggers)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.TriggerStrings)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Doodads)) { toDecompileCount++; } if (filesToDecompile.HasFlag(MapFiles.Units)) { toDecompileCount++; } var gameVersion = map.Info?.GameVersion; var gamePatch = gameVersion is null ? GamePatch.v1_26a : GamePatchVersionProvider.GetGamePatch(gameVersion); var progressState = new ProgressState(); bool StartDecompilingFile(MapFiles mapFile) { if (filesToDecompile.HasFlag(mapFile)) { progressState.MapFile = mapFile; worker?.ReportProgress(progress, progressState); decompiledCount++; progress = (100 * decompiledCount) / toDecompileCount; return(true); } return(false); } bool WaitForCancel() { if (worker is not null) { progressState.Error = true; worker.ReportProgress(progress, progressState); while (progressState.Error) { Thread.Sleep(500); } return(worker.CancellationPending); } return(false); } if (StartDecompilingFile(MapFiles.Sounds)) { var formatVersion = gamePatch >= GamePatch.v1_32_6 ? MapSoundsFormatVersion.ReforgedV3 : gamePatch >= GamePatch.v1_32_0 ? MapSoundsFormatVersion.Reforged : MapSoundsFormatVersion.Normal; if (decompiler.TryDecompileMapSounds(formatVersion, out var decompiledMapSounds)) { decompiledMap.Sounds = decompiledMapSounds; } else if (WaitForCancel()) { return(null); } } if (StartDecompilingFile(MapFiles.Cameras)) { var formatVersion = MapCamerasFormatVersion.Normal; var useNewFormat = gamePatch >= GamePatch.v1_31_0; if (decompiler.TryDecompileMapCameras(formatVersion, useNewFormat, out var decompiledMapCameras)) { decompiledMap.Cameras = decompiledMapCameras; } else if (WaitForCancel()) { return(null); } } if (StartDecompilingFile(MapFiles.Regions)) { var formatVersion = MapRegionsFormatVersion.Normal; if (decompiler.TryDecompileMapRegions(formatVersion, out var decompiledMapRegions)) { decompiledMap.Regions = decompiledMapRegions; } else if (WaitForCancel()) { return(null); } } if (StartDecompilingFile(MapFiles.Triggers)) { var formatVersion = gamePatch >= GamePatch.v1_07 ? MapTriggersFormatVersion.Tft : MapTriggersFormatVersion.RoC; var subVersion = gamePatch >= GamePatch.v1_31_0 ? (MapTriggersSubVersion?)MapTriggersSubVersion.New : null; if (decompiler.TryDecompileMapTriggers(formatVersion, subVersion, out var decompiledMapTriggers)) { decompiledMap.Triggers = decompiledMapTriggers; } else if (WaitForCancel()) { return(null); } } if (StartDecompilingFile(MapFiles.Units)) { var formatVersion = gamePatch >= GamePatch.v1_07 ? MapWidgetsFormatVersion.TFT : MapWidgetsFormatVersion.RoC; var subVersion = gamePatch >= GamePatch.v1_07 ? MapWidgetsSubVersion.V11 : MapWidgetsSubVersion.V9; var useNewFormat = gamePatch >= GamePatch.v1_32_0; if (decompiler.TryDecompileMapUnits(formatVersion, subVersion, useNewFormat, out var decompiledMapUnits)) { decompiledMap.Units = decompiledMapUnits; } else if (WaitForCancel()) { return(null); } } progressState.MapFile = null; worker?.ReportProgress(progress, progressState); return(decompiledMap); }
public static Version ToVersion(this GamePatch gamePatch) { return(GamePatchVersionProvider.GetGameVersion(gamePatch)); }
public void TranspileAndSaveTest(string inputFile, string outputFile, ScriptLanguage targetLanguage) { var targetFileName = targetLanguage switch { ScriptLanguage.Jass => "war3map.j", ScriptLanguage.Lua => "war3map.lua", _ => throw new InvalidEnumArgumentException(nameof(targetLanguage), (int)targetLanguage, typeof(ScriptLanguage)), }; using var mapArchive = MpqArchive.Open(inputFile, true); var map = Map.Open(mapArchive); var sourceLanguage = map.Info.ScriptLanguage; var mpqArchiveBuilder = new MpqArchiveBuilder(mapArchive); using var mapInfoStream = new MemoryStream(); using var mapInfoWriter = new BinaryWriter(mapInfoStream); var mapInfo = map.Info; mapInfo.ScriptLanguage = targetLanguage; if (mapInfo.FormatVersion < MapInfoFormatVersion.Lua) { mapInfo.FormatVersion = MapInfoFormatVersion.Lua; if (mapInfo.GameVersion is null) { mapInfo.GameVersion = GamePatchVersionProvider.GetGameVersion(War3Net.Build.Common.GamePatch.v1_31_1); } } mapInfoWriter.Write(mapInfo); mapInfoStream.Position = 0; mpqArchiveBuilder.AddFile(MpqFile.New(mapInfoStream, MapInfo.FileName)); if (sourceLanguage == ScriptLanguage.Jass) { if (targetLanguage != ScriptLanguage.Lua) { throw new NotSupportedException($"Unable to transpile from {sourceLanguage} to {targetLanguage}."); } mpqArchiveBuilder.RemoveFile("war3map.j"); mpqArchiveBuilder.RemoveFile(@"Scripts\war3map.j"); using var reader = new StreamReader(@"C:\Users\Stan\Google Drive\PHP Projects\Files\common.j"); var commonJ = JassSyntaxFactory.ParseCompilationUnit(reader.ReadToEnd()); using var reader2 = new StreamReader(@"C:\Users\Stan\Google Drive\PHP Projects\Files\blizzard.j"); var blizzardJ = JassSyntaxFactory.ParseCompilationUnit(reader2.ReadToEnd()); var transpiler = new JassToLuaTranspiler(); transpiler.RegisterJassFile(commonJ); transpiler.RegisterJassFile(blizzardJ); var script = mapArchive.OpenFile("war3map.j"); using var reader3 = new StreamReader(script); var luaCompilationUnit = transpiler.Transpile(JassSyntaxFactory.ParseCompilationUnit(reader3.ReadToEnd())); script.Close(); var tempFileName = Path.GetTempFileName(); try { using (var writer = new StreamWriter(tempFileName)) { var luaRenderOptions = new LuaSyntaxGenerator.SettingInfo { // Indent = 4, // IsCommentsDisabled = true, }; var luaRenderer = new LuaRenderer(luaRenderOptions, writer); luaRenderer.RenderCompilationUnit(luaCompilationUnit); } using var fileStream = File.OpenRead(tempFileName); mpqArchiveBuilder.AddFile(MpqFile.New(fileStream, targetFileName)); var mpqArchiveCreateOptions = new MpqArchiveCreateOptions { AttributesCreateMode = MpqFileCreateMode.Prune, }; mpqArchiveBuilder.SaveTo(outputFile, mpqArchiveCreateOptions); } finally { File.Delete(tempFileName); } } else if (sourceLanguage == ScriptLanguage.Lua) { throw new NotSupportedException($"Unable to transpile from {sourceLanguage} to {targetLanguage}."); } else { throw new NotSupportedException($"Unable to transpile from {sourceLanguage} to {targetLanguage}."); } }
public static void TranspileAndSave(string inputFile, string outputFile, string?commonJPath, string?blizzardJPath, ScriptLanguage targetLanguage, BackgroundWorker?worker) { var targetFileName = targetLanguage switch { ScriptLanguage.Jass => "war3map.j", ScriptLanguage.Lua => "war3map.lua", _ => throw new InvalidEnumArgumentException(nameof(targetLanguage), (int)targetLanguage, typeof(ScriptLanguage)), }; using var mapArchive = MpqArchive.Open(inputFile, true); var map = Map.Open(mapArchive); var sourceLanguage = map.Info.ScriptLanguage; var mpqArchiveBuilder = new MpqArchiveBuilder(mapArchive); using var mapInfoStream = new MemoryStream(); using var mapInfoWriter = new BinaryWriter(mapInfoStream); var mapInfo = map.Info; mapInfo.ScriptLanguage = targetLanguage; if (mapInfo.FormatVersion < MapInfoFormatVersion.Lua) { mapInfo.FormatVersion = MapInfoFormatVersion.Lua; if (mapInfo.GameVersion is null) { mapInfo.GameVersion = GamePatchVersionProvider.GetGameVersion(GamePatch.v1_31_1); } } mapInfoWriter.Write(mapInfo); mapInfoStream.Position = 0; mpqArchiveBuilder.AddFile(MpqFile.New(mapInfoStream, MapInfo.FileName)); if (sourceLanguage == ScriptLanguage.Jass) { if (targetLanguage != ScriptLanguage.Lua) { throw new NotSupportedException($"Unable to transpile from {sourceLanguage} to {targetLanguage}."); } mpqArchiveBuilder.RemoveFile("war3map.j"); mpqArchiveBuilder.RemoveFile(@"Scripts\war3map.j"); var jassHelperFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Warcraft III", "JassHelper"); if (string.IsNullOrEmpty(commonJPath)) { if (Directory.Exists(jassHelperFolder)) { commonJPath = Path.Combine(jassHelperFolder, "common.j"); if (string.IsNullOrEmpty(blizzardJPath)) { blizzardJPath = Path.Combine(jassHelperFolder, "Blizzard.j"); } } else { throw new DirectoryNotFoundException("Unable to automatically find common.j and Blizzard.j folder."); } } var mapHasCustomBlizzardJ = mapArchive.FileExists(@"Scripts\Blizzard.j"); if (string.IsNullOrEmpty(blizzardJPath) && !mapHasCustomBlizzardJ) { if (Directory.Exists(jassHelperFolder)) { blizzardJPath = Path.Combine(jassHelperFolder, "Blizzard.j"); } else { throw new DirectoryNotFoundException("Unable to automatically find common.j and Blizzard.j folder."); } } var estimatedWorkToTranspile = map.Script.Length + 700000; var estimatedWorkToRegisterCommonAndBlizzard = 35000000 / estimatedWorkToTranspile; if (estimatedWorkToRegisterCommonAndBlizzard == 0) { estimatedWorkToRegisterCommonAndBlizzard = 1; } var transpiler = new JassToLuaTranspiler(); transpiler.RegisterJassFile(JassSyntaxFactory.ParseCompilationUnit(File.ReadAllText(commonJPath))); worker?.ReportProgress(estimatedWorkToRegisterCommonAndBlizzard); if (mapHasCustomBlizzardJ) { throw new NotImplementedException("Custom Blizzard.j files are currently not supported."); } else { transpiler.RegisterJassFile(JassSyntaxFactory.ParseCompilationUnit(File.ReadAllText(blizzardJPath))); worker?.ReportProgress(estimatedWorkToRegisterCommonAndBlizzard * 2); } var luaCompilationUnit = transpiler.Transpile(JassSyntaxFactory.ParseCompilationUnit(map.Script)); using var stream = new MemoryStream(); using (var writer = new StreamWriter(stream, leaveOpen: true)) { var luaRenderOptions = new LuaSyntaxGenerator.SettingInfo { // Indent = 4, // IsCommentsDisabled = true, }; var luaRenderer = new LuaRenderer(luaRenderOptions, writer); luaRenderer.RenderCompilationUnit(luaCompilationUnit); writer.Flush(); } stream.Position = 0; mpqArchiveBuilder.AddFile(MpqFile.New(stream, targetFileName)); worker?.ReportProgress(100); var mpqArchiveCreateOptions = new MpqArchiveCreateOptions { }; mpqArchiveBuilder.SaveTo(outputFile, mpqArchiveCreateOptions); } else if (sourceLanguage == ScriptLanguage.Lua) { mpqArchiveBuilder.RemoveFile("war3map.lua"); mpqArchiveBuilder.RemoveFile(@"Scripts\war3map.lua"); throw new NotSupportedException($"Unable to transpile from {sourceLanguage} to {targetLanguage}."); } else { throw new NotSupportedException($"Unable to transpile from {sourceLanguage} to {targetLanguage}."); } }