public static bool ShouldPatchFrom(H2mccMap scene, string line, out SyntaxNodePatch patch)
        {
            patch = null;

            if (line.TrimStart().StartsWith("//"))
            {
                return(false);
            }

            try
            {
                patch = new SyntaxNodePatch
                {
                    Index    = ParseFrom(line, "@:", " "),
                    NodeData = new ScenarioTag.ScriptSyntaxNode
                    {
                        //Checkval = ParseFrom(line, "a:"),
                        OperationId = ParseFrom(line, "op:"),
                        DataType    = (ScriptDataType)ParseFrom(line, "dt:"),
                        NodeType    = (NodeType)ParseFrom(line, "nt:"),
                        NextIndex   = ParseFrom(line, "next:"),
                        //NextCheckval = ParseFrom(line, "f:"),
                        NodeString = ParseFrom(line, "str:"),
                        //ValueH = ParseFrom(line, "h:"),
                        NodeData_32 = ParseFrom(line, "d0:") | ((uint)ParseFrom(line, "d1:", ";")) << 16
                    }
                };

                if (patch.NodeData.NodeType == NodeType.MethodDecl)
                {
                    return(false);
                }

                var node = scene.Scenario.ScriptSyntaxNodes[patch.Index];

                if (node.OperationId != patch.NodeData.OperationId ||
                    node.DataType != patch.NodeData.DataType ||
                    node.NodeType != patch.NodeData.NodeType ||
                    node.NextIndex != patch.NodeData.NextIndex ||
                    node.NodeString != patch.NodeData.NodeString ||
                    node.NodeData_32 != patch.NodeData.NodeData_32)
                {
                    return(true);
                }

                return(false);
            }
            catch
            {
                return(false);
            }
        }
Exemple #2
0
        public async Task Run()
        {
            using var inmemMap = new MemoryStream();
            using (var map = File.Open(this.Args.MapPath, FileMode.Open))
            {
                H2mccCompression.Decompress(map, inmemMap);
                inmemMap.Position = 0;

                // Load to determine where to write patches to
                var factory = new MapFactory(this.Args.MapPath);
                this.scene = factory.LoadSingleH2mccMap(inmemMap);
            }

            var tagPatcher = new TagPatcher(scene, inmemMap);
            var settings   = new JsonSerializerOptions()
            {
                ReadCommentHandling = JsonCommentHandling.Skip
            };
            var patches = JsonSerializer.Deserialize <TagPatch[]>(File.ReadAllText(this.Args.TagPatchPath), settings);

            foreach (var patch in patches)
            {
                tagPatcher.Apply(patch);
            }

            inmemMap.Position = 0;
            var sig = H2BaseMap.CalculateSignature(inmemMap);

            inmemMap.WriteInt32At(BlamSerializer.StartsAt <H2vMapHeader>(h => h.StoredSignature), sig);
            inmemMap.Position = 0;

            using (var map = File.Open(this.Args.MapPath, FileMode.Open))
            {
                inmemMap.CopyTo(map);
            }
        }
        public static void PatchMap(H2mccMap scene, Stream map, string patchFilePath)
        {
            var scenarioStart = scene.TagIndex[scene.IndexHeader.Scenario].Offset.Value;
            var nodesStart    = BlamSerializer.StartsAt <ScenarioTag>(s => s.ScriptSyntaxNodes);
            var nodeCount     = map.ReadUInt32At(scenarioStart + nodesStart);
            var nodeOffset    = (int)map.ReadUInt32At(scenarioStart + nodesStart + 4) - scene.SecondaryMagic;

            var nodeSize = BlamSerializer.SizeOf <ScenarioTag.ScriptSyntaxNode>();

            var patchLines = File.ReadAllLines(patchFilePath);

            foreach (var line in patchLines)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                if (ShouldPatchFrom(scene, line, out var patch))
                {
                    Console.WriteLine($"\t Patching {scene.Header.Name} [{patch.Index}]");
                    var patchStart = nodeOffset + patch.Index * nodeSize;

                    // Fixup next node's check value. We never change check values, so we can
                    // re-use the 'old' nodes here to get that info
                    if (patch.NodeData.NextIndex == ushort.MaxValue)
                    {
                        patch.NodeData.NextCheckval = ushort.MaxValue;
                    }
                    else
                    {
                        var nextNode = scene.Scenario.ScriptSyntaxNodes[patch.NodeData.NextIndex];
                        patch.NodeData.NextCheckval = nextNode.Checkval;
                    }

                    // Fixup next node's check value for scope/invocation nodes
                    if ((patch.NodeData.NodeType == NodeType.BuiltinInvocation || patch.NodeData.NodeType == NodeType.ScriptInvocation))
                    {
                        if (patch.NodeData.NodeData_H16 == ushort.MaxValue)
                        {
                            patch.NodeData.NodeData_32 = patch.NodeData.NodeData_H16 | ((uint)ushort.MaxValue) << 16;
                        }
                        else
                        {
                            var nextNode = scene.Scenario.ScriptSyntaxNodes[patch.NodeData.NodeData_H16];
                            patch.NodeData.NodeData_32 = patch.NodeData.NodeData_H16 | ((uint)nextNode.Checkval) << 16;
                        }
                    }

                    //map.WriteUInt16At(patchStart + 0, patch.NodeData.Checkval);
                    map.WriteUInt16At(patchStart + 2, patch.NodeData.OperationId);
                    map.WriteUInt16At(patchStart + 4, (ushort)patch.NodeData.DataType);
                    map.WriteUInt16At(patchStart + 6, (ushort)patch.NodeData.NodeType);
                    map.WriteUInt16At(patchStart + 8, patch.NodeData.NextIndex);
                    map.WriteUInt16At(patchStart + 10, patch.NodeData.NextCheckval);
                    map.WriteUInt16At(patchStart + 12, patch.NodeData.NodeString);
                    //map.WriteUInt16At(patchStart + 14, patch.NodeData.ValueH);
                    map.WriteUInt32At(patchStart + 16, patch.NodeData.NodeData_32);
                }
            }
        }