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); } }
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); } } }