public static void InjectMembers(this IVirtualMachine virtualMachine, GamePatch gamePatch, Type type) { if (((AvailableSinceAttribute)Attribute.GetCustomAttribute(type, typeof(AvailableSinceAttribute)))?.AvailableSince > gamePatch) { return; } foreach (var member in type.GetMembers()) { if (((AvailableSinceAttribute)Attribute.GetCustomAttribute(member, typeof(AvailableSinceAttribute)))?.AvailableSince > gamePatch) { continue; } if (member.DeclaringType == type) { if (member is FieldInfo field) { virtualMachine.InjectField(field); } else if (member is MethodInfo method) { virtualMachine.InjectMethod(method); } } } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { using var reader = new BinaryReader(stream); var mapSounds = reader.ReadMapSounds(); if (mapSounds.GetMinimumPatch() <= targetPatch.Patch) { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } try { if (mapSounds.TryDowngrade(targetPatch.Patch)) { var newMapSoundsFileStream = new MemoryStream(); using var writer = new BinaryWriter(newMapSoundsFileStream, new UTF8Encoding(false, true), true); writer.Write(mapSounds); return(new AdaptResult { Status = MapFileStatus.Adapted, AdaptedFileStream = newMapSoundsFileStream, }); } else { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } } catch { return(new AdaptResult { Status = MapFileStatus.AdapterError, }); } } catch (NotSupportedException) { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { return(new AdaptResult { Status = targetPatch.Patch >= GamePatch.v1_30_0 && targetPatch.Patch <= GamePatch.v1_30_4 ? MapFileStatus.Compatible : MapFileStatus.Unadaptable, }); }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { using var reader = new BinaryReader(stream); var mapEnvironment = reader.ReadMapEnvironment(); return(new AdaptResult { Status = MapFileStatus.Compatible, }); } catch (NotSupportedException) { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } catch (NotSupportedException) { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { return(new AdaptResult { Status = MapFileStatus.Compatible, }); }
public static IEnumerable <(string, int)> GetFrameNames(GamePatch patch) { return(patch switch { GamePatch.v1_32_0 => GetFrameNamesPatch1_32_0(), _ => Array.Empty <(string, int)>(), });
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { // TODO return(new AdaptResult { Status = MapFileStatus.Unknown, }); }
public static IEnumerable <string> GetIdentifiers(GamePatch patch) { return(patch switch { // TODO: other patches GamePatch.v1_32_0 => GetIdentifiersPatch1_32_0(), _ => Array.Empty <string>(), });
public static IEnumerable <(string name, int createContext)> GetFrameNames(GamePatch from, GamePatch to) { for (var patch = from + 1; patch <= to; patch++) { foreach (var identifier in GetFrameNames(patch)) { yield return(identifier); } } }
public static void InjectCommonApi(this IVirtualMachine virtualMachine, GamePatch gamePatch) { foreach (var type in typeof(VirtualMachineExtensions).Assembly.GetTypes()) { if (type.Name.EndsWith("Api", StringComparison.Ordinal)) { virtualMachine.InjectMembers(gamePatch, type); } } }
public static IEnumerable <string> GetIdentifiers(GamePatch from, GamePatch to) { for (var patch = from + 1; patch <= to; patch++) { foreach (var identifier in GetIdentifiers(patch)) { yield return(identifier); } } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { // TODO: War3Net.Modeling.BinaryModelParser.Parse(stream) using var reader = new BinaryReader(stream); reader.ReadInt32(); while (stream.Length - stream.Position > 8) { // Find VERS chunk. var chunkTag = new string(reader.ReadChars(4)); var chunkSize = reader.ReadInt32(); if (chunkTag == "VERS") { var version = reader.ReadUInt32(); if (version > 800 && targetPatch.Patch < GamePatch.v1_32_0) { return(new AdaptResult { Status = MapFileStatus.Unadaptable, Diagnostics = new[] { $"Model version not supported: v{version}" }, }); } else { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } } else { reader.ReadBytes(chunkSize); } } // Unable to find VERS chunk. return(new AdaptResult { // Status = MapFileStatus.ParseError, Status = MapFileStatus.Unknown, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { using var reader = new BinaryReader(stream); var campaignInfo = reader.ReadCampaignInfo(); var targetPatchEditorVersion = targetPatch.Patch.GetEditorVersion(); if (campaignInfo.EditorVersion == targetPatchEditorVersion) { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } try { campaignInfo.EditorVersion = targetPatchEditorVersion; var newCampaignInfoFileStream = new MemoryStream(); using var writer = new BinaryWriter(newCampaignInfoFileStream, new UTF8Encoding(false, true), true); writer.Write(campaignInfo); return(new AdaptResult { Status = MapFileStatus.Adapted, AdaptedFileStream = newCampaignInfoFileStream, }); } catch { return(new AdaptResult { Status = MapFileStatus.AdapterError, }); } } catch (NotSupportedException) { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public static bool TryDowngrade(this MapUnits mapUnits, GamePatch targetPatch) { try { while (mapUnits.GetMinimumPatch() > targetPatch) { mapUnits.DowngradeOnce(); } return(true); } catch (NotSupportedException) { return(false); } catch { throw; } }
public static bool TryDowngrade(this MapInfo mapInfo, GamePatch targetPatch) { try { while (mapInfo.GetMinimumPatch() > targetPatch) { mapInfo.DowngradeOnce(); } var targetGameBuild = GameBuildsProvider.GetGameBuilds(targetPatch)[0]; mapInfo.EditorVersion = targetGameBuild.EditorVersion.Value; if (mapInfo.FormatVersion >= MapInfoFormatVersion.Lua) { mapInfo.GameVersion = targetGameBuild.Version; } return(true); } catch { throw; } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { var triggerDataPath = Path.Combine(targetPatch.GameDataPath, PathConstants.TriggerDataPath); if (!File.Exists(triggerDataPath)) { return(new AdaptResult { Status = MapFileStatus.ConfigError, Diagnostics = triggerDataPath.GetFileNotFoundDiagnostics(), }); } using var reader = new BinaryReader(stream); var mapTriggers = reader.ReadMapTriggers(); try { var triggerDataText = File.ReadAllText(triggerDataPath); var triggerDataReader = new StringReader(triggerDataText); var triggerData = triggerDataReader.ReadTriggerData(); stream.Position = 0; reader.ReadMapTriggers(triggerData); } catch (KeyNotFoundException e) { return(new AdaptResult { Status = MapFileStatus.Incompatible, Diagnostics = new[] { e.Message }, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } if (mapTriggers.GetMinimumPatch() <= targetPatch.Patch) { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } try { if (mapTriggers.TryDowngrade(targetPatch.Patch)) { var newMapTriggersFileStream = new MemoryStream(); using var writer = new BinaryWriter(newMapTriggersFileStream, new UTF8Encoding(false, true), true); writer.Write(mapTriggers); return(new AdaptResult { Status = MapFileStatus.Adapted, AdaptedFileStream = newMapTriggersFileStream, }); } else { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } } catch { return(new AdaptResult { Status = MapFileStatus.AdapterError, }); } } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { var upgradeDataPath = Path.Combine(targetPatch.GameDataPath, PathConstants.UpgradeDataPath); if (!File.Exists(upgradeDataPath)) { return(new AdaptResult { Status = MapFileStatus.ConfigError, Diagnostics = upgradeDataPath.GetFileNotFoundDiagnostics(), }); } var upgradeMetaDataPath = Path.Combine(targetPatch.GameDataPath, PathConstants.UpgradeMetaDataPath); if (!File.Exists(upgradeMetaDataPath)) { return(new AdaptResult { Status = MapFileStatus.ConfigError, Diagnostics = upgradeMetaDataPath.GetFileNotFoundDiagnostics(), }); } using var reader = new BinaryReader(stream); var mapUpgradeObjectData = reader.ReadMapUpgradeObjectData(); try { var knownIds = new HashSet <int>(); knownIds.AddItemsFromSylkTable(upgradeDataPath, DataConstants.UpgradeDataKeyColumn); var knownProperties = new HashSet <int>(); knownProperties.AddItemsFromSylkTable(upgradeMetaDataPath, DataConstants.MetaDataIdColumn); var diagnostics = new List <string>(); var baseUpgrades = new List <LevelObjectModification>(); foreach (var upgrade in mapUpgradeObjectData.BaseUpgrades) { if (!knownIds.Contains(upgrade.OldId)) { diagnostics.Add($"Unknown base upgrade: '{upgrade.OldId.ToRawcode()}'"); continue; } if (upgrade.Modifications.Any(property => !knownProperties.Contains(property.Id))) { diagnostics.AddRange(upgrade.Modifications.Where(property => !knownProperties.Contains(property.Id)).Select(property => $"Unknown property: '{property.Id.ToRawcode()}'")); upgrade.Modifications.RemoveAll(property => !knownProperties.Contains(property.Id)); } baseUpgrades.Add(upgrade); } var newUpgrades = new List <LevelObjectModification>(); foreach (var upgrade in mapUpgradeObjectData.NewUpgrades) { if (!knownIds.Contains(upgrade.OldId)) { diagnostics.Add($"Unknown base upgrade: '{upgrade.OldId.ToRawcode()}'"); continue; } if (knownIds.Contains(upgrade.NewId)) { diagnostics.Add($"Conflicting upgrade: '{upgrade.NewId.ToRawcode()}'"); continue; } if (upgrade.Modifications.Any(property => !knownProperties.Contains(property.Id))) { diagnostics.AddRange(upgrade.Modifications.Where(property => !knownProperties.Contains(property.Id)).Select(property => $"Unknown property: '{property.Id.ToRawcode()}'")); upgrade.Modifications.RemoveAll(property => !knownProperties.Contains(property.Id)); } newUpgrades.Add(upgrade); } if (diagnostics.Count > 0) { var memoryStream = new MemoryStream(); using var writer = new BinaryWriter(memoryStream, new UTF8Encoding(false, true), true); writer.Write(new MapUpgradeObjectData(mapUpgradeObjectData.FormatVersion) { BaseUpgrades = baseUpgrades, NewUpgrades = newUpgrades, }); return(new AdaptResult { Status = MapFileStatus.Adapted, Diagnostics = diagnostics.ToArray(), AdaptedFileStream = memoryStream, }); } else { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } } catch { return(new AdaptResult { Status = MapFileStatus.AdapterError, }); } } catch (NotSupportedException) { return(new AdaptResult { Status = MapFileStatus.Unadaptable, }); } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public static Version ToVersion(this GamePatch gamePatch) { return(GamePatchVersionProvider.GetGameVersion(gamePatch)); }
public static int GetEditorVersion(this GamePatch gamePatch) { // https://www.hiveworkshop.com/threads/list-of-official-patches-for-warcraft-3.322919/ switch (gamePatch) { case GamePatch.v1_00: return(4448); case GamePatch.v1_01: case GamePatch.v1_01b: case GamePatch.v1_01c: return(4482); case GamePatch.v1_02: case GamePatch.v1_02a: return(4531); case GamePatch.v1_03: return(4572); case GamePatch.v1_04: case GamePatch.v1_04b: case GamePatch.v1_04c: case GamePatch.v1_05: case GamePatch.v1_06: return(4654); case GamePatch.v1_07: return(6031); case GamePatch.v1_10: return(6034); case GamePatch.v1_11: return(6035); case GamePatch.v1_12: return(6036); case GamePatch.v1_13: case GamePatch.v1_13b: return(6037); case GamePatch.v1_14: return(6039); case GamePatch.v1_14b: return(6040); case GamePatch.v1_15: return(6043); case GamePatch.v1_16: return(6046); case GamePatch.v1_17: return(6050); case GamePatch.v1_18: return(6051); case GamePatch.v1_19: case GamePatch.v1_19b: case GamePatch.v1_20a: case GamePatch.v1_20b: case GamePatch.v1_20c: case GamePatch.v1_20d: case GamePatch.v1_20e: case GamePatch.v1_21: case GamePatch.v1_21b: return(6052); case GamePatch.v1_22: return(6057); case GamePatch.v1_23: return(6058); case GamePatch.v1_24a: case GamePatch.v1_24b: case GamePatch.v1_24c: case GamePatch.v1_24d: case GamePatch.v1_24e: case GamePatch.v1_25b: case GamePatch.v1_26a: case GamePatch.v1_27a: case GamePatch.v1_27b: case GamePatch.v1_28: case GamePatch.v1_28_1: case GamePatch.v1_28_2: case GamePatch.v1_28_3: case GamePatch.v1_28_4: case GamePatch.v1_28_5: return(6059); case GamePatch.v1_29_0: case GamePatch.v1_29_1: case GamePatch.v1_29_2: return(6060); case GamePatch.v1_30_0: case GamePatch.v1_30_1: case GamePatch.v1_30_2: case GamePatch.v1_30_3: case GamePatch.v1_30_4: return(6061); case GamePatch.v1_31_0: case GamePatch.v1_31_1: return(6072); case GamePatch.v1_32_0: case GamePatch.v1_32_1: return(6105); case GamePatch.v1_32_2: return(6106); // TODO case GamePatch.v1_32_3: case GamePatch.v1_32_4: case GamePatch.v1_32_5: case GamePatch.v1_32_6: case GamePatch.v1_32_7: case GamePatch.v1_32_8: case GamePatch.v1_32_9: case GamePatch.v1_32_10: return(6106); default: throw new NotSupportedException(); } ; }
public GameNode(Node root, GamePatch patch) => (Root, GamePatch) = (root, patch);
public GamePatcher(GamePatch patch) => this.patch = patch;
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { string scriptText; using (var reader = new StreamReader(stream, null, true, -1, true)) { scriptText = reader.ReadToEnd(); } try { var diagnostics = new List <string>(); var regexDiagnostics = new List <RegexDiagnostic>(); // Find incompatible identifiers var incompatibleIdentifiers = new HashSet <string>(); incompatibleIdentifiers.UnionWith(CommonIdentifiersProvider.GetIdentifiers(targetPatch.Patch, originPatch)); incompatibleIdentifiers.UnionWith(BlizzardIdentifiersProvider.GetIdentifiers(targetPatch.Patch, originPatch)); foreach (var incompatibleIdentifier in incompatibleIdentifiers) { var regex = new Regex($"\\b{incompatibleIdentifier}\\b"); var matches = regex.Matches(scriptText); var usageCount = matches.Count; if (usageCount > 0) { diagnostics.Add($"Found incompatible identifier: '{incompatibleIdentifier}' ({usageCount}x)"); regexDiagnostics.Add(new RegexDiagnostic { DisplayText = $"Identifier: '{incompatibleIdentifier}'", Matches = usageCount, Regex = regex, }); } } // Find incompatible audio formats var incompatibleAudioFormats = new HashSet <string>(); if (targetPatch.Patch < GamePatch.v1_32_0) { incompatibleAudioFormats.Add("flac"); } if (targetPatch.Patch < GamePatch.v1_30_0 || targetPatch.Patch > GamePatch.v1_30_4) { incompatibleAudioFormats.Add("ogg"); } foreach (var incompatibleAudioFormat in incompatibleAudioFormats) { var regex = new Regex($"\"(\\w|/|\\\\)+.{incompatibleAudioFormat}\""); var matches = regex.Matches(scriptText); var usageCount = matches.Count; if (usageCount > 0) { diagnostics.Add($"Found incompatible audio formats: '{incompatibleAudioFormat}' ({usageCount}x)"); regexDiagnostics.Add(new RegexDiagnostic { DisplayText = $"Audio file format: '{incompatibleAudioFormat}'", Matches = usageCount, Regex = regex, }); } } // Find incompatible frame names var incompatibleFrameNames = new HashSet <string>(); if (targetPatch.Patch >= GamePatch.v1_31_0) { incompatibleFrameNames.UnionWith(FrameNamesProvider.GetFrameNames(targetPatch.Patch, originPatch).Select(frame => frame.name)); } foreach (var incompatibleFrameName in incompatibleFrameNames) { var regex = new Regex($"{nameof(War3Api.Common.BlzGetFrameByName)}( |\t)*\\(\"{incompatibleFrameName}\"( |\t)*,( |\t)*"); var matches = regex.Matches(scriptText); var usageCount = matches.Count; if (usageCount > 0) { diagnostics.Add($"Found incompatible frame names: '{incompatibleFrameName}' ({usageCount}x)"); regexDiagnostics.Add(new RegexDiagnostic { DisplayText = $"Frame name: '{incompatibleFrameName}'", Matches = usageCount, Regex = regex, }); } } if (diagnostics.Count == 0) { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } else { return(new AdaptResult { Status = MapFileStatus.Incompatible, Diagnostics = diagnostics.ToArray(), RegexDiagnostics = regexDiagnostics.ToArray(), }); } } catch { return(new AdaptResult { Status = MapFileStatus.AdapterError, }); } } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
public AvailableSinceAttribute(GamePatch gamePatch) { AvailableSince = gamePatch; }
public static Version GetGameVersion(GamePatch gamePatch) { return(gamePatch switch { #pragma warning disable SA1025 // Code should not contain multiple whitespace in a row GamePatch.v1_00 => new Version(1, 0, 0, 4448), GamePatch.v1_01 => new Version(1, 1, 0, 4482), GamePatch.v1_01b => new Version(1, 1, 2, 4483), GamePatch.v1_01c => new Version(1, 1, 3, 4484), GamePatch.v1_02 => new Version(1, 2, 0, 4531), GamePatch.v1_02a => new Version(1, 2, 1, 4563), GamePatch.v1_03 => new Version(1, 3, 0, 4653), GamePatch.v1_04 => new Version(1, 4, 0, 4709), GamePatch.v1_04b => new Version(1, 4, 2, 4709), GamePatch.v1_04c => new Version(1, 4, 3, 4905), GamePatch.v1_05 => new Version(1, 5, 0, 4944), GamePatch.v1_06 => new Version(1, 6, 0, 5551), GamePatch.v1_07 => new Version(1, 7, 0, 5535), GamePatch.v1_10 => new Version(1, 10, 0, 5610), GamePatch.v1_11 => new Version(1, 11, 0, 5616), GamePatch.v1_12 => new Version(1, 12, 0, 5636), GamePatch.v1_13 => new Version(1, 13, 0, 5816), GamePatch.v1_13b => new Version(1, 13, 2, 5818), GamePatch.v1_14 => new Version(1, 14, 0, 5840), GamePatch.v1_14b => new Version(1, 14, 2, 5846), GamePatch.v1_15 => new Version(1, 15, 0, 5917), GamePatch.v1_16 => new Version(1, 16, 0, 5926), GamePatch.v1_17 => new Version(1, 17, 0, 5988), GamePatch.v1_18 => new Version(1, 18, 0, 6030), GamePatch.v1_19 => new Version(1, 19, 0, 6041), GamePatch.v1_19b => new Version(1, 19, 2, 6046), GamePatch.v1_20a => new Version(1, 20, 1, 6048), GamePatch.v1_20b => new Version(1, 20, 2, 6056), GamePatch.v1_20c => new Version(1, 20, 3, 6065), GamePatch.v1_20d => new Version(1, 20, 4, 6070), GamePatch.v1_20e => new Version(1, 20, 5, 6074), GamePatch.v1_21 => new Version(1, 21, 0, 6263), GamePatch.v1_21b => new Version(1, 21, 2, 6300), GamePatch.v1_22 => new Version(1, 22, 0, 6328), GamePatch.v1_23 => new Version(1, 23, 0, 6352), GamePatch.v1_24a => new Version(1, 24, 1, 6372), GamePatch.v1_24b => new Version(1, 24, 2, 6374), GamePatch.v1_24c => new Version(1, 24, 3, 6378), GamePatch.v1_24d => new Version(1, 24, 4, 6384), GamePatch.v1_24e => new Version(1, 24, 5, 6387), GamePatch.v1_25b => new Version(1, 25, 2, 6394), GamePatch.v1_26a => new Version(1, 26, 1, 6397), GamePatch.v1_27a => new Version(1, 27, 1, 52240), GamePatch.v1_27b => new Version(1, 27, 2, 7085), GamePatch.v1_28 => new Version(1, 28, 0, 7205), GamePatch.v1_28_1 => new Version(1, 28, 1, 7365), GamePatch.v1_28_2 => new Version(1, 28, 2, 7395), GamePatch.v1_28_3 => new Version(1, 28, 3, 7205), GamePatch.v1_28_4 => new Version(1, 28, 4, 7608), GamePatch.v1_28_5 => new Version(1, 28, 5, 7680), GamePatch.v1_29_0 => new Version(1, 29, 0, 9055), GamePatch.v1_29_1 => new Version(1, 29, 1, 9160), GamePatch.v1_29_2 => new Version(1, 29, 2, 9231), GamePatch.v1_30_0 => new Version(1, 30, 0, 9922), GamePatch.v1_30_1 => new Version(1, 30, 1, 10211), GamePatch.v1_30_2 => new Version(1, 30, 2, 11113), GamePatch.v1_30_3 => new Version(1, 30, 3, 11235), GamePatch.v1_30_4 => new Version(1, 30, 4, 11274), GamePatch.v1_31_0 => new Version(1, 31, 0, 12071), GamePatch.v1_31_1 => new Version(1, 31, 1, 12164), GamePatch.v1_32_0 => new Version(1, 32, 0, 14481), GamePatch.v1_32_1 => new Version(1, 32, 1, 14604), GamePatch.v1_32_2 => new Version(1, 32, 2, 14722), GamePatch.v1_32_3 => new Version(1, 32, 3, 14883), GamePatch.v1_32_4 => new Version(1, 32, 4, 15098), GamePatch.v1_32_5 => new Version(1, 32, 5, 15129), GamePatch.v1_32_6 => new Version(1, 32, 6, 15355), GamePatch.v1_32_7 => new Version(1, 32, 7, 15572), GamePatch.v1_32_8 => new Version(1, 32, 8, 15801), // GamePatch.v1_32_9 => new Version(1, 32, 9, ?????), #pragma warning restore SA1025 // Code should not contain multiple whitespace in a row _ => throw new InvalidEnumArgumentException(nameof(gamePatch), (int)gamePatch, typeof(GamePatch)), });
public static Version GetPatchVersion(GamePatch gamePatch) { return(gamePatch switch { GamePatch.v1_00 => new Version(1, 0, 0, 4448), GamePatch.v1_01 => new Version(1, 1, 0, 4482), GamePatch.v1_01b => new Version(1, 1, 2, 4483), GamePatch.v1_01c => new Version(1, 1, 3, 0), // todo GamePatch.v1_02 => new Version(1, 2, 0, 4531), GamePatch.v1_02a => new Version(1, 2, 1, 4563), GamePatch.v1_03 => new Version(1, 3, 0, 4653), GamePatch.v1_04 => new Version(1, 4, 0, 4709), GamePatch.v1_04b => new Version(1, 4, 2, 0), // todo GamePatch.v1_04c => new Version(1, 4, 3, 4905), GamePatch.v1_05 => new Version(1, 5, 0, 4944), GamePatch.v1_06 => new Version(1, 6, 0, 5551), GamePatch.v1_07 => new Version(1, 7, 0, 5535), GamePatch.v1_10 => new Version(1, 10, 0, 5610), GamePatch.v1_11 => new Version(1, 11, 0, 5616), GamePatch.v1_12 => new Version(1, 12, 0, 5636), GamePatch.v1_13 => new Version(1, 13, 0, 5816), GamePatch.v1_13b => new Version(1, 13, 2, 5818), GamePatch.v1_14 => new Version(1, 14, 0, 5840), GamePatch.v1_14b => new Version(1, 14, 2, 5846), GamePatch.v1_15 => new Version(1, 15, 0, 5917), GamePatch.v1_16 => new Version(1, 16, 0, 5926), GamePatch.v1_17 => new Version(1, 17, 0, 5988), GamePatch.v1_18 => new Version(1, 18, 0, 6030), GamePatch.v1_19 => new Version(1, 19, 0, 6041), GamePatch.v1_19b => new Version(1, 19, 2, 6046), GamePatch.v1_20a => new Version(1, 20, 1, 6048), GamePatch.v1_20b => new Version(1, 20, 2, 6056), GamePatch.v1_20c => new Version(1, 20, 3, 6065), GamePatch.v1_20d => new Version(1, 20, 4, 6070), GamePatch.v1_20e => new Version(1, 20, 5, 6074), GamePatch.v1_21 => new Version(1, 21, 0, 6263), GamePatch.v1_21b => new Version(1, 21, 2, 6300), GamePatch.v1_22 => new Version(1, 22, 0, 6328), GamePatch.v1_23 => new Version(1, 23, 0, 6352), GamePatch.v1_24a => new Version(1, 24, 1, 6372), GamePatch.v1_24b => new Version(1, 24, 2, 6374), GamePatch.v1_24c => new Version(1, 24, 3, 6378), GamePatch.v1_24d => new Version(1, 24, 4, 6384), GamePatch.v1_24e => new Version(1, 24, 5, 6387), GamePatch.v1_25b => new Version(1, 25, 2, 6394), GamePatch.v1_26a => new Version(1, 26, 1, 6397), GamePatch.v1_27a => new Version(1, 27, 1, 52240), GamePatch.v1_27b => new Version(1, 27, 2, 7085), GamePatch.v1_28 => new Version(1, 28, 0, 7205), GamePatch.v1_28_1 => new Version(1, 28, 1, 7365), GamePatch.v1_28_2 => new Version(1, 28, 2, 7395), GamePatch.v1_28_3 => new Version(1, 28, 3, 7205), GamePatch.v1_28_4 => new Version(1, 28, 4, 7608), GamePatch.v1_28_5 => new Version(1, 28, 5, 7680), GamePatch.v1_29_0 => new Version(1, 29, 0, 9055), GamePatch.v1_29_1 => new Version(1, 29, 1, 9160), GamePatch.v1_29_2 => new Version(1, 29, 2, 9231), GamePatch.v1_30_0 => new Version(1, 30, 0, 9922), GamePatch.v1_30_1 => new Version(1, 30, 1, 10211), GamePatch.v1_30_2 => new Version(1, 30, 2, 11113), GamePatch.v1_30_3 => new Version(1, 30, 3, 11235), GamePatch.v1_30_4 => new Version(1, 30, 4, 11274), GamePatch.v1_31_0 => new Version(1, 31, 0, 12071), GamePatch.v1_31_1 => new Version(1, 31, 1, 12164), GamePatch.v1_32_0 => new Version(1, 32, 0, 14481), GamePatch.v1_32_1 => new Version(1, 32, 1, 14604), });
public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch) { try { var commonJPath = Path.Combine(targetPatch.GameDataPath, PathConstants.CommonJPath); if (!File.Exists(commonJPath)) { return(new AdaptResult { Status = MapFileStatus.ConfigError, Diagnostics = commonJPath.GetFileNotFoundDiagnostics(), }); } var blizzardJPath = Path.Combine(targetPatch.GameDataPath, PathConstants.BlizzardJPath); if (!File.Exists(blizzardJPath)) { return(new AdaptResult { Status = MapFileStatus.ConfigError, Diagnostics = blizzardJPath.GetFileNotFoundDiagnostics(), }); } var commonJText = File.ReadAllText(commonJPath); var commonJCompilationUnit = JassSyntaxFactory.ParseCompilationUnit(commonJText); var blizzardJText = File.ReadAllText(blizzardJPath); var blizzardJCompilationUnit = JassSyntaxFactory.ParseCompilationUnit(blizzardJText); string scriptText; using (var reader = new StreamReader(stream, leaveOpen: true)) { scriptText = reader.ReadToEnd(); } var compilationUnit = JassSyntaxFactory.ParseCompilationUnit(scriptText); try { var context = new JassMapScriptAdapterContext(); foreach (var declaration in commonJCompilationUnit.Declarations) { RegisterDeclaration(declaration, context); } foreach (var declaration in blizzardJCompilationUnit.Declarations) { RegisterDeclaration(declaration, context); } // Common.j and Blizzard.j should not cause any diagnostics. if (context.Diagnostics.Count > 0) { return(new AdaptResult { Status = MapFileStatus.AdapterError, Diagnostics = context.Diagnostics.ToArray(), }); } if (TryAdaptCompilationUnit(context, compilationUnit, out var adaptedCompilationUnit)) { var memoryStream = new MemoryStream(); using var writer = new StreamWriter(memoryStream, new UTF8Encoding(false, true), leaveOpen: true); var renderer = new JassRenderer(writer); renderer.Render(adaptedCompilationUnit); return(new AdaptResult { Status = MapFileStatus.Adapted, Diagnostics = context.Diagnostics.ToArray(), AdaptedFileStream = memoryStream, }); } if (context.Diagnostics.Count == 0) { return(new AdaptResult { Status = MapFileStatus.Compatible, }); } else { return(new AdaptResult { Status = MapFileStatus.Incompatible, Diagnostics = context.Diagnostics.ToArray(), }); } } catch { return(new AdaptResult { Status = MapFileStatus.AdapterError, }); } } catch (Exception e) { return(new AdaptResult { Status = MapFileStatus.ParseError, Diagnostics = new[] { e.Message }, }); } }
private static TargetPatch GetTargetPatch(GamePatch patch) { return(_appSettings.TargetPatches.First(targetPatch => targetPatch.Patch == patch)); }
static void Main(string[] args) { string jarPath; string rootPath; string backupName; string backupPath; bool doBackup = false; Console.WriteLine($" LargeShipPatcher {Assembly.GetExecutingAssembly().GetName().Version} for Space Haven"); Console.WriteLine($"--------------------------------------------------------------------------"); Console.WriteLine($" IMPORTANT !"); Console.WriteLine($"Execute this patch as admin / sudo from the same folder as spacehaven.jar"); Console.WriteLine($"--------------------------------------------------------------------------"); Console.WriteLine($" FEATURES"); Console.WriteLine($"- Allow ships of size 3x2, 2x3 and 3x3 to be build"); Console.WriteLine($"- Increase the available ship points from 8 to 14"); Console.WriteLine($"- Increase sector size from 8x8 to 10x10"); Console.WriteLine($"- Allow changing the amount of system points per ship point"); Console.WriteLine($"- Features can be tweaked by editing the \"LargeShipPatcher.xml\" file"); Console.WriteLine($"--------------------------------------------------------------------------"); if (File.Exists("spacehaven.jar")) { rootPath = Directory.GetCurrentDirectory(); jarPath = Path.Combine(rootPath, "spacehaven.jar"); } else { while (true) { Console.WriteLine("Please input the path to \"spacehaven.jar\" :"); rootPath = Console.ReadLine(); if (!Directory.Exists(rootPath)) { rootPath = Path.GetDirectoryName(rootPath); } jarPath = Path.Combine(rootPath, "spacehaven.jar"); if (File.Exists(jarPath)) { break; } Console.WriteLine($"Could not find \"{jarPath}\"..."); } } try { using (File.OpenWrite(jarPath)) { } File.WriteAllText(Path.Combine(rootPath, "LargeShipPatcher_ReadMe.txt"), Configs.ResourceManager.GetString("ReadMe", CultureInfo.InvariantCulture)); } catch (Exception) { Console.WriteLine($"Error : write permission denied, make sure the patcher has full rights to write in this folder"); Console.ReadLine(); return; } string tempFilePath = Path.Combine(Path.GetDirectoryName(jarPath), "spacehaven.jar.temp"); File.Copy(jarPath, tempFilePath, true); int entriesCount = 0; bool error = false; string versionString; string versionNameString; string buildString = string.Empty; GamePatch matchingPatch = null; using (ZipArchive jarFile = ZipFile.Open(tempFilePath, ZipArchiveMode.Update)) { ZipArchiveEntry versionFile = jarFile.GetEntry("version.txt"); Version version; using (TextReader versionReader = new StreamReader(versionFile.Open())) { try { versionString = versionReader.ReadLine(); if (versionString == null) { throw new Exception(); } } catch (Exception) { versionString = string.Empty; } try { versionNameString = versionReader.ReadLine(); if (versionNameString == null) { throw new Exception(); } } catch (Exception) { versionNameString = string.Empty; } versionString = versionString.Trim(); versionNameString = versionNameString.Trim(); try { version = new Version(versionString); } catch (Exception) { version = null; Console.WriteLine($"Can't parse \"{versionString}\", game version unknown !"); } } ZipArchiveEntry mainClass = jarFile.GetEntry("fi/bugbyte/spacehaven/MainClass.class"); using (TextReader mainClassReader = new StreamReader(mainClass.Open(), System.Text.Encoding.ASCII)) { string classText = mainClassReader.ReadToEnd(); foreach (GamePatch knownVersion in knownVersions.FindAll(p => p.version == version)) { // note : this can fail, for example if there is a build 1 and the game is build 11, it will match the build 1 if (classText.Contains(knownVersion.build, StringComparison.OrdinalIgnoreCase)) { buildString = knownVersion.build; matchingPatch = knownVersion; break; } } } List <GamePatch> matchingPatches = new List <GamePatch>(); if (version != null) { matchingPatches.AddRange(knownVersions.FindAll(p => p.version == version)); } else { version = new Version(int.MaxValue, int.MaxValue); } if (matchingPatches.Count == 0) { matchingPatches = knownVersions.FindAll(p => p.version < version).OrderByDescending(i => i.version).Take(2).ToList(); matchingPatches.AddRange(knownVersions.FindAll(p => p.version > version).OrderBy(i => i.version).Take(2)); } Console.WriteLine($"Found Space Haven {(string.IsNullOrEmpty(versionNameString) ? "RELEASE UNKNOWN" : versionNameString)}, version {versionString} - {(string.IsNullOrEmpty(buildString) ? "BUILD UNKNOWN" : buildString)}"); Console.WriteLine($"--------------------------------------------------------------------------"); if (matchingPatch == null) { startPatchSelect: Console.WriteLine($"Unable to find a matching patch for this version"); Console.WriteLine($"You can use another available patch but this can cause issues and crashes."); for (int i = 0; i < matchingPatches.Count; i++) { Console.WriteLine($"[{i}] {matchingPatches[i]}"); } Console.WriteLine($"Input a number for the patch you want to use and press enter"); if (!int.TryParse(Console.ReadLine(), out int index) || index < 0 || index > matchingPatches.Count - 1) { Console.WriteLine($"--------------------------------------------------------------------------"); Console.WriteLine("Error : bad input"); Console.WriteLine($"--------------------------------------------------------------------------"); goto startPatchSelect; } matchingPatch = matchingPatches[index]; Console.WriteLine(""); Console.WriteLine($"--------------------------------------------------------------------------"); } backupName = "spacehaven.jar_" + versionString + "_" + buildString.Replace(" ", "") + "_" + DateTime.Now.ToString("yyMMddHHmm"); backupPath = Path.Combine(Path.GetDirectoryName(jarPath), backupName); Console.WriteLine("Ready to patch - Do you want to keep a backup ? (y/n)"); if (Console.ReadKey(true).KeyChar == 'y') { doBackup = true; } using (ZipArchive patchFile = new ZipArchive(new MemoryStream(matchingPatch.Patch))) { foreach (ZipArchiveEntry patchedEntry in patchFile.Entries) { if (!patchedEntry.FullName.EndsWith(".class")) { continue; } try { jarFile.GetEntry(patchedEntry.FullName).Delete(); ZipArchiveEntry replacedEntry = jarFile.CreateEntry(patchedEntry.FullName, CompressionLevel.Fastest); patchedEntry.Open().CopyTo(replacedEntry.Open()); Console.WriteLine($"Patching {patchedEntry.FullName}"); entriesCount++; } catch (Exception) { Console.WriteLine($"Error while patching class {patchedEntry.FullName}..."); error = true; } } } } // note : file is written to here, when the ZipArchive object is being disposed of. Console.WriteLine($"--------------------------------------------------------------------------"); if (!error) { File.WriteAllText(Path.Combine(rootPath, "LargeShipPatcher.xml"), Configs.ResourceManager.GetString("LargeShipPatcher", CultureInfo.InvariantCulture)); Console.WriteLine($"Done : {entriesCount} classes patched"); if (doBackup) { File.Copy(jarPath, backupPath, true); Console.WriteLine($"Backup created : \"{backupName}\""); } File.Move(tempFilePath, jarPath, true); Console.WriteLine($"File written to {jarPath}"); } else { Console.WriteLine($"Error while patching - no change was done"); File.Delete(tempFilePath); } Console.WriteLine("Press any key to exit"); Console.ReadLine(); }