public void Load(string file) { filename = file; string directory = Path.GetDirectoryName(file) + '\\'; #region open maps shared = new SharedMaps(new FileStream(directory + MainMenu, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), new FileStream(directory + Shared, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), new FileStream(directory + SinglePlayerShared, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); map = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); reader = new BinaryReader(map); writer = new BinaryWriter(map); #endregion #region header and index header = Reinterpret.Memory <MapHeader>(reader.ReadBytes(Marshal.SizeOf(typeof(MapHeader)))); map.Position = header.IndexOffset; index = Reinterpret.Memory <IndexHeader>(reader.ReadBytes(Marshal.SizeOf(typeof(IndexHeader)))); magic = (index.MagicConstant - header.IndexOffset - Marshal.SizeOf(typeof(IndexHeader))) + (header.AllExceptRawLength - header.IndexAndMetaLength - header.IndexLength); // each "TagType" is three dwords map.Position += 12 * index.TagTypeCount; tags = new List <IndexElement>(index.TagCount); for (int i = 0; i < index.TagCount; i++) { tags.Add(Reinterpret.Memory <IndexElement>(reader.ReadBytes(Marshal.SizeOf(typeof(IndexElement))))); } #endregion #region bsps int bspCount = 0; int bspOffset = 0; if (header.HeadSignature == HeadSignature) { map.Position = 528 + unchecked (tags[LocateTagByID(index.ScenarioIdentifier)].Offset - magic); bspCount = reader.ReadInt32(); bspOffset = unchecked (reader.ReadInt32() - magic); bsps = new Bsp[bspCount]; for (int i = 0; i < bspCount; i++) { bsps[i] = new Bsp(); map.Position = bsps[i].LocationInScenario = bspOffset + 68 * i; bsps[i].BspHeaderOffset = reader.ReadInt32(); int totalBspSize = reader.ReadInt32(); bsps[i].Magic = reader.ReadInt32(); map.Position += 8; bsps[i].BspID = reader.ReadInt32(); map.Position += 4; bsps[i].LightmapID = reader.ReadInt32(); /* * HEADER FORMAT * total size * pointer to bsp location * pointer to lightmap location * 'sbsp' */ map.Position = bsps[i].BspHeaderOffset; int inHeaderBspSize = reader.ReadInt32(); int inHeaderBspOffset = reader.ReadInt32(); int lightmapOffset = reader.ReadInt32(); bsps[i].BspOffset = (inHeaderBspOffset - bsps[i].Magic) + bsps[i].BspHeaderOffset; if (bsps[i].LightmapID == -1) { bsps[i].BspSize = inHeaderBspSize; } else { bsps[i].LightmapOffset = unchecked (lightmapOffset - bsps[i].Magic) + bsps[i].BspHeaderOffset; bsps[i].BspSize = bsps[i].LightmapOffset - bsps[i].BspOffset; bsps[i].LightmapSize = totalBspSize - bsps[i].BspSize; } } } #endregion #region strings strings = new List <string>(header.StringIdCount); map.Position = header.StringIdTableOffset; for (int i = 0; i < header.StringIdCount; i++) { strings.Add(String.Empty); while (true) { byte character = reader.ReadByte(); if (character == 0) { break; } else { strings[i] += Convert.ToChar(character); } } } string[] stringArray = strings.ToArray(); #endregion #region names map.Position = header.NameTableOffset; names = new List <string>(header.NameTableCount); dictionary = new Dictionary <int, string>(header.NameTableCount); inverseDictionary = new Dictionary <string, int>(header.NameTableCount); for (int i = 0; i < header.NameTableCount; i++) { names.Add(String.Empty); while (true) { byte character = reader.ReadByte(); if (character == 0) { break; } else { names[i] += Convert.ToChar(character); } } string dictionaryName = names[i] + '.' + Singleton <ClassManager> .Instance.GetClassByID(tags[i].Type).Name; dictionary.Add(tags[i].Identifier, dictionaryName); inverseDictionary.Add(dictionaryName, tags[i].Identifier); } #endregion #region globals and coconuts if (header.HeadSignature == HeadSignature) { map.Position = unchecked (tags[LocateTagByID(index.GlobalsIdentifier)].Offset - magic); globals = new Globals(reader); map.Position = unchecked (tags[index.TagCount - 1].Offset - magic); coconuts = new Coconuts(reader, shared, magic, stringArray); } #endregion #region composition if (header.HeadSignature == HeadSignature) { for (int i = 0; i < index.TagCount; i++) { int result; switch (tags[i].Type) { case Animation: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, Animation, magic); if (result != -1) { if (result < animationStart || animationStart == -1) { animationStart = result; } } break; case Decorators: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, Decorators, magic); if (result != -1) { if (result < decoratorStart || decoratorStart == -1) { decoratorStart = result; } } break; case ParticleModel: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, ParticleModel, magic); if (result != -1) { if (result < particleModelStart || particleModelStart == -1) { particleModelStart = result; } } break; case WeatherSystem: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, WeatherSystem, magic); if (result != -1) { if (result < weatherStart || weatherStart == -1) { weatherStart = result; } } break; case RenderModel: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, RenderModel, magic); if (result != -1) { if (result < modelStart || modelStart == -1) { modelStart = result; } } break; } } // this is (should be anyways) constant soundStart = Marshal.SizeOf(typeof(MapHeader)); // this is a calculated value bitmapStart = header.CrazyDataOffset + header.CrazyDataSize; for (int i = 0; i < bspCount; i++) { Bsp bsp = bsps[i]; if (bsp.BspOffset < bspMetaStart || bspMetaStart == -1) { bspMetaStart = bsp.BspHeaderOffset; } else if (bsp.LightmapOffset < bspMetaStart || bspMetaStart == -1) { bspMetaStart = bsp.BspHeaderOffset; } int result; if (bsp.BspID != -1) { reader.BaseStream.Position = bsp.BspOffset; result = Tag.GetFirstInternalResourceOffset(reader, StructureBsp, bsp.Magic - bsp.BspHeaderOffset); if (result != -1) { if (result < bspRawStart || bspRawStart == -1 && result != -1) { bspRawStart = result; } } } if (bsp.LightmapID != -1) { reader.BaseStream.Position = bsp.LightmapOffset; result = Tag.GetFirstInternalResourceOffset(reader, StructureLightmap, bsp.Magic - bsp.BspHeaderOffset); if (result != -1) { if (result < bspRawStart || bspRawStart == -1) { bspRawStart = result; } } } } foreach (Coconuts.ExtraInfo extraInfo in coconuts.ExtraInfos) { if (extraInfo.ResourceBlock.RawSize > 0) { uint encoded = Conversion.ToUInt(extraInfo.ResourceBlock.RawOffset); if ((encoded & 0xc0000000) == 0) { if (extraInfo.ResourceBlock.RawOffset < coconutsModelStart || coconutsModelStart == -1) { coconutsModelStart = extraInfo.ResourceBlock.RawOffset; } } } } if (bspMetaStart < 0) { bspMetaStart = header.StringIdPaddedOffset; } if (animationStart < 0) { animationStart = bspMetaStart; } if (coconutsModelStart < 0) { coconutsModelStart = animationStart; } if (particleModelStart < 0) { particleModelStart = coconutsModelStart; } if (decoratorStart < 0) { decoratorStart = particleModelStart; } if (weatherStart < 0) { weatherStart = decoratorStart; } if (bspRawStart < 0) { bspRawStart = weatherStart; } if (modelStart < 0) { modelStart = bspRawStart; } // these are all duplicates stringPaddedStart = header.StringIdPaddedOffset; stringIndexStart = header.StringIdIndexOffset; stringTableStart = header.StringIdTableOffset; nameTableStart = header.NameTableOffset; nameIndexStart = header.NameIndexOffset; crazyStart = header.CrazyDataOffset; // this can be calculated a multitude of ways unicodeStart = header.NameIndexOffset + header.NameTableCount * sizeof(int); } #endregion valid = true; }
/// <summary> /// Creates a new instance of the Coconuts class and reads its values from a coconuts tag. /// </summary> public Coconuts(BinaryReader reader, SharedMaps maps, int magic, string[] strings) { #region header int playbackCount = reader.ReadInt32(); int playbackOffset = unchecked (reader.ReadInt32() - magic); int scaleCount = reader.ReadInt32(); int scaleOffset = unchecked (reader.ReadInt32() - magic); int nameCount = reader.ReadInt32(); int nameOffset = unchecked (reader.ReadInt32() - magic); int pitchRangeParameterCount = reader.ReadInt32(); int pitchRangeParameterOffset = unchecked (reader.ReadInt32() - magic); int pitchRangeCount = reader.ReadInt32(); int pitchRangeOffset = unchecked (reader.ReadInt32() - magic); int permutationCount = reader.ReadInt32(); int permutationOffset = unchecked (reader.ReadInt32() - magic); int customPlaybackCount = reader.ReadInt32(); int customPlaybackOffset = unchecked (reader.ReadInt32() - magic); int runtimeFlagsCount = reader.ReadInt32(); int runtimeFlagsOffset = unchecked (reader.ReadInt32() - magic); int chunkCount = reader.ReadInt32(); int chunkOffset = unchecked (reader.ReadInt32() - magic); int promotionCount = reader.ReadInt32(); int promotionOffset = unchecked (reader.ReadInt32() - magic); int extraInfoCount = reader.ReadInt32(); int extraInfoOffset = unchecked (reader.ReadInt32() - magic); if (playbackCount > 0) { reader.BaseStream.Position = playbackOffset; } playbackParameters = new List <Playback>(playbackCount); for (int i = 0; i < playbackCount; i++) { playbackParameters.Add(Reinterpret.Memory <Playback>(reader.ReadBytes(Marshal.SizeOf(typeof(Playback))))); } if (scaleCount > 0) { reader.BaseStream.Position = scaleOffset; } scales = new List <Scale>(scaleCount); for (int i = 0; i < scaleCount; i++) { scales.Add(Reinterpret.Memory <Scale>(reader.ReadBytes(Marshal.SizeOf(typeof(Scale))))); } if (nameCount > 0) { reader.BaseStream.Position = nameOffset; } importNames = new List <string>(nameCount); for (int i = 0; i < nameCount; i++) { importNames.Add(strings[reader.ReadInt16()]); reader.BaseStream.Position += 2; } if (pitchRangeParameterCount > 0) { reader.BaseStream.Position = pitchRangeParameterOffset; } pitchRangeParameters = new List <PitchRangeParametersBlock>(pitchRangeParameterCount); for (int i = 0; i < pitchRangeParameterCount; i++) { pitchRangeParameters.Add(Reinterpret.Memory <PitchRangeParametersBlock>(reader.ReadBytes(Marshal.SizeOf(typeof(PitchRangeParametersBlock))))); } if (pitchRangeCount > 0) { reader.BaseStream.Position = pitchRangeOffset; } pitchRanges = new List <PitchRange>(pitchRangeCount); for (int i = 0; i < pitchRangeCount; i++) { pitchRanges.Add(Reinterpret.Memory <PitchRange>(reader.ReadBytes(Marshal.SizeOf(typeof(PitchRange))))); } if (permutationCount > 0) { reader.BaseStream.Position = permutationOffset; } permutations = new List <Permutation>(permutationCount); for (int i = 0; i < permutationCount; i++) { permutations.Add(Reinterpret.Memory <Permutation>(reader.ReadBytes(Marshal.SizeOf(typeof(Permutation))))); } if (customPlaybackCount > 0) { reader.BaseStream.Position = customPlaybackOffset; } customPlaybacks = new List <CustomPlayback>(customPlaybackCount); for (int i = 0; i < customPlaybackCount; i++) { CustomPlayback customPlayback = Reinterpret.Memory <CustomPlayback>(reader.ReadBytes(Marshal.SizeOf(typeof(CustomPlayback)))); unchecked { customPlayback.FilterOffset -= magic; customPlayback.FilterPlaybackParametersOffset -= magic; customPlayback.MixFlagsOffset -= magic; customPlayback.PitchPlaybackParametersOffset -= magic; customPlayback.SoundEffectOffset -= magic; } customPlaybacks.Add(customPlayback); } if (runtimeFlagsCount > 0) { reader.BaseStream.Position = runtimeFlagsOffset; } runtimeFlags = new List <RuntimePermutationFlags>(runtimeFlagsCount); for (int i = 0; i < runtimeFlagsCount; i++) { runtimeFlags.Add(Reinterpret.Memory <RuntimePermutationFlags>(reader.ReadBytes(Marshal.SizeOf(typeof(RuntimePermutationFlags))))); } if (chunkCount > 0) { reader.BaseStream.Position = chunkOffset; } chunks = new List <Chunk>(chunkCount); for (int i = 0; i < chunkCount; i++) { chunks.Add(Reinterpret.Memory <Chunk>(reader.ReadBytes(Marshal.SizeOf(typeof(Chunk))))); } if (promotionCount > 0) { reader.BaseStream.Position = promotionOffset; } promotions = new List <Promotion>(promotionCount); for (int i = 0; i < promotionCount; i++) { Promotion promotion = Reinterpret.Memory <Promotion>(reader.ReadBytes(Marshal.SizeOf(typeof(Promotion)))); unchecked { promotion.RuleOffset -= magic; promotion.TimerOffset -= magic; } promotions.Add(promotion); } if (extraInfoCount > 0) { reader.BaseStream.Position = extraInfoOffset; } extraInfos = new List <ExtraInfo>(extraInfoCount); for (int i = 0; i < extraInfoCount; i++) { ExtraInfo extraInfo = Reinterpret.Memory <ExtraInfo>(reader.ReadBytes(Marshal.SizeOf(typeof(ExtraInfo)))); extraInfo.ResourceBlock.ResourceOffset = unchecked (extraInfo.ResourceBlock.ResourceOffset - magic); extraInfos.Add(extraInfo); } #endregion #region custom playbacks customFilters = new List <List <CustomPlayback.Filter> >(customPlaybackCount); customPitchParameters = new List <List <CustomPlayback.PitchPlaybackParameters> >(customPlaybackCount); for (int i = 0; i < customPlaybackCount; i++) { customFilters.Add(new List <CustomPlayback.Filter>(customPlaybacks[i].FilterCount)); if (customPlaybacks[i].FilterCount > 0) { reader.BaseStream.Position = customPlaybacks[i].FilterOffset; } for (int j = 0; j < customPlaybacks[i].FilterCount; j++) { customFilters[i].Add(Reinterpret.Memory <CustomPlayback.Filter>(reader.ReadBytes(Marshal.SizeOf(typeof(CustomPlayback.Filter))))); } customPitchParameters.Add(new List <CustomPlayback.PitchPlaybackParameters>(customPlaybacks[i].PitchPlaybackParametersCount)); if (customPlaybacks[i].PitchPlaybackParametersCount > 0) { reader.BaseStream.Position = customPlaybacks[i].PitchPlaybackParametersOffset; } for (int j = 0; j < customPlaybacks[i].PitchPlaybackParametersCount; j++) { customPitchParameters[i].Add(Reinterpret.Memory <CustomPlayback.PitchPlaybackParameters>(reader.ReadBytes(Marshal.SizeOf(typeof(CustomPlayback.PitchPlaybackParameters))))); } } #endregion #region promotions promotionRules = new List <List <Promotion.Rule> >(promotionCount); promotionTimers = new List <List <Promotion.Timer> >(promotionCount); for (int i = 0; i < promotionCount; i++) { promotionRules.Add(new List <Promotion.Rule>(promotions[i].RuleCount)); if (promotions[i].RuleCount > 0) { reader.BaseStream.Position = promotions[i].RuleOffset; } for (int j = 0; j < promotions[i].RuleCount; j++) { promotionRules[i].Add(Reinterpret.Memory <Promotion.Rule>(reader.ReadBytes(Marshal.SizeOf(typeof(Promotion.Rule))))); } promotionTimers.Add(new List <Promotion.Timer>(promotions[i].TimerCount)); if (promotions[i].TimerCount > 0) { reader.BaseStream.Position = promotions[i].TimerOffset; } for (int j = 0; j < promotions[i].TimerCount; j++) { promotionTimers[i].Add(Reinterpret.Memory <Promotion.Timer>(reader.ReadBytes(Marshal.SizeOf(typeof(Promotion.Timer))))); } } #endregion #region extra infos extraInfoData = new List <byte[]>(extraInfoCount); extraInfoResources = new List <List <ResourceBlock.Resource> >(extraInfoCount); for (int i = 0; i < extraInfoCount; i++) { extraInfoData.Add(new byte[extraInfos[i].ResourceBlock.RawSize]); if (extraInfos[i].ResourceBlock.RawSize > 0) { BinaryReader rawReader = maps.GetMap(extraInfos[i].ResourceBlock.RawOffset, reader); if (rawReader != null) { for (int j = 0; j < extraInfos[i].ResourceBlock.RawSize; j++) { extraInfoData[i][j] = rawReader.ReadByte(); } } extraInfoResources.Add(new List <ResourceBlock.Resource>(extraInfos[i].ResourceBlock.ResourceCount)); if (extraInfos[i].ResourceBlock.ResourceCount > 0) { reader.BaseStream.Position = extraInfos[i].ResourceBlock.ResourceOffset; } for (int j = 0; j < extraInfos[i].ResourceBlock.ResourceCount; j++) { extraInfoResources[i].Add(Reinterpret.Memory <ResourceBlock.Resource>(reader.ReadBytes(Marshal.SizeOf(typeof(ResourceBlock.Resource))))); } } } #endregion }