private bool CompareScripts(Script orig, Script mod) { bool index = orig.RootExpressionIndex.IsValid && mod.RootExpressionIndex.IsValid; int origHash = SequenceHash.GetSequenceHashCode(orig.Parameters); int modHash = SequenceHash.GetSequenceHashCode(mod.Parameters); return(index && (orig.Name == mod.Name) && (orig.ExecutionType == mod.ExecutionType) && (orig.ReturnType == mod.ReturnType) && (origHash == modHash)); }
private void WriteScripts(ScriptData data, IStream stream, StructureValueCollection scnr) { ScriptLayout layout; if (_buildInfo.Name.Contains("Halo: Reach")) { layout = ScriptLayout.HaloReach; } else if (_buildInfo.Name.Contains("Halo 3") || _buildInfo.Name.Contains("Halo ODST")) { layout = ScriptLayout.Halo3; } else { throw new NotImplementedException("Saving this game's scripts is not supported yet."); } Dictionary <int, uint> newParamAddresses = WriteParams(data, stream, scnr); StructureLayout scrlayout = _buildInfo.Layouts.GetLayout("script element"); int oldScriptCount = (int)scnr.GetInteger("number of scripts"); int newScriptCount = data.Scripts.Count; uint oldScriptAddress = (uint)scnr.GetInteger("script table address"); long expOldScriptAddress = _expander.Expand(oldScriptAddress); long newScriptAddress = 0; int oldScriptSize = oldScriptCount * scrlayout.Size; int newScriptSize = newScriptCount * scrlayout.Size; // get new Script Address if (newScriptCount > 0) { if (oldScriptCount > 0) { newScriptAddress = _allocator.Reallocate(expOldScriptAddress, oldScriptSize, newScriptSize, stream); } else { newScriptAddress = _allocator.Allocate(newScriptSize, stream); } stream.SeekTo(_metaArea.PointerToOffset(newScriptAddress)); // write scripts foreach (var scr in data.Scripts) { int paramCount = scr.Parameters.Count; if (paramCount > 0) { int hash = SequenceHash.GetSequenceHashCode(scr.Parameters); if (newParamAddresses.TryGetValue(hash, out uint addr)) { scr.Write(stream, _stringIDs, paramCount, addr, layout); } else { throw new KeyNotFoundException("Failed to retrieve the address for a new parameter block."); } } else { scr.Write(stream, _stringIDs, 0, 0, layout); } } } else { if (oldScriptCount > 0) { _allocator.Free(expOldScriptAddress, oldScriptSize); } } scnr.SetInteger("number of scripts", (uint)data.Scripts.Count); scnr.SetInteger("script table address", _expander.Contract(newScriptAddress)); }
/// <summary> /// Frees the old Script Parameters and writes new ones to the stream. /// </summary> /// <param name="data">The new script data</param> /// <param name="stream">The stream to write to</param> /// <param name="scnr">scnr Meta Data</param> /// <returns>A dictionary containing the hashes of parameter groups an their new addresses.</returns> private Dictionary <int, uint> WriteParams(ScriptData data, IStream stream, StructureValueCollection scnr) { StructureLayout scrlayout = _buildInfo.Layouts.GetLayout("script element"); StructureLayout paramlayout = _buildInfo.Layouts.GetLayout("script parameter element"); int oldScriptCount = (int)scnr.GetInteger("number of scripts"); uint oldScriptAddress = (uint)scnr.GetInteger("script table address"); long expOldScriptAddress = _expander.Expand(oldScriptAddress); int oldParamSize = 0; StructureValueCollection[] oldScripts = TagBlockReader.ReadTagBlock(stream, oldScriptCount, expOldScriptAddress, scrlayout, _metaArea); HashSet <uint> freedParamAddresses = new HashSet <uint>(); int oldTotalParamCount = 0; // loop through old scripts for (int i = 0; i < oldScripts.Length; i++) { int paramCount = (int)oldScripts[i].GetInteger("number of parameters"); uint addr = (uint)oldScripts[i].GetInteger("address of parameter list"); oldTotalParamCount += paramCount; // free params if (addr != 0 && !freedParamAddresses.Contains(addr)) { long exp = _expander.Expand(addr); int blockSize = paramCount * paramlayout.Size; _allocator.Free(exp, blockSize); oldParamSize += blockSize; freedParamAddresses.Add(addr); } } int newTotalParamCount = 0; int newParamSize = 0; Dictionary <int, uint> newParamAddresses = new Dictionary <int, uint>(); // loop through new scripts foreach (var scr in data.Scripts) { int count = scr.Parameters.Count; if (count > 0) { int paramHash = SequenceHash.GetSequenceHashCode(scr.Parameters); if (!newParamAddresses.ContainsKey(paramHash)) { long newAddr = _allocator.Allocate(paramlayout.Size * count, stream); uint conNewAddr = _expander.Contract(newAddr); stream.SeekTo(_metaArea.PointerToOffset(newAddr)); // write params to stream foreach (var par in scr.Parameters) { par.Write(stream); } newParamAddresses.Add(paramHash, conNewAddr); newParamSize += scr.Parameters.Count * 36; } } newTotalParamCount += scr.Parameters.Count; } return(newParamAddresses); }