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);
                    }
                }
            }
        }
Exemple #2
0
        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 },
                });
            }
        }
Exemple #3
0
 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,
     });
 }
Exemple #4
0
 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 },
         });
     }
 }
Exemple #5
0
 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 },
         });
     }
 }
Exemple #6
0
 public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch)
 {
     return(new AdaptResult
     {
         Status = MapFileStatus.Compatible,
     });
 }
Exemple #7
0
        public static IEnumerable <(string, int)> GetFrameNames(GamePatch patch)
        {
            return(patch switch
            {
                GamePatch.v1_32_0 => GetFrameNamesPatch1_32_0(),

                _ => Array.Empty <(string, int)>(),
            });
Exemple #8
0
 public AdaptResult AdaptFile(Stream stream, TargetPatch targetPatch, GamePatch originPatch)
 {
     // TODO
     return(new AdaptResult
     {
         Status = MapFileStatus.Unknown,
     });
 }
Exemple #9
0
        public static IEnumerable <string> GetIdentifiers(GamePatch patch)
        {
            return(patch switch
            {
                // TODO: other patches
                GamePatch.v1_32_0 => GetIdentifiersPatch1_32_0(),

                _ => Array.Empty <string>(),
            });
Exemple #10
0
 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);
         }
     }
 }
Exemple #12
0
 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);
         }
     }
 }
Exemple #13
0
        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 },
                });
            }
        }
Exemple #14
0
        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 },
                });
            }
        }
Exemple #15
0
        public static bool TryDowngrade(this MapUnits mapUnits, GamePatch targetPatch)
        {
            try
            {
                while (mapUnits.GetMinimumPatch() > targetPatch)
                {
                    mapUnits.DowngradeOnce();
                }

                return(true);
            }
            catch (NotSupportedException)
            {
                return(false);
            }
            catch
            {
                throw;
            }
        }
Exemple #16
0
        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;
            }
        }
Exemple #17
0
        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 },
                });
            }
        }
Exemple #18
0
        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 },
                });
            }
        }
Exemple #19
0
 public static Version ToVersion(this GamePatch gamePatch)
 {
     return(GamePatchVersionProvider.GetGameVersion(gamePatch));
 }
Exemple #20
0
        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();
            }
            ;
        }
Exemple #21
0
 public GameNode(Node root, GamePatch patch) =>
 (Root, GamePatch) = (root, patch);
Exemple #22
0
 public GamePatcher(GamePatch patch) => this.patch = patch;
Exemple #23
0
        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;
 }
Exemple #25
0
        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),
     });
Exemple #27
0
        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 },
                });
            }
        }
Exemple #28
0
 private static TargetPatch GetTargetPatch(GamePatch patch)
 {
     return(_appSettings.TargetPatches.First(targetPatch => targetPatch.Patch == patch));
 }
Exemple #29
0
        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();
        }