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