Example #1
0
		public override void Read(BlamLib.IO.EndianReader s)
		{
			CacheFileBase cache = s.Owner as CacheFileBase;

			#region read body
			groupTagsCount = s.ReadInt32();
			groupTagsOffset = (groupTagsAddress = s.ReadUInt32()) - cache.AddressMask;

			tagCount = s.ReadInt32();
			tagsOffset = (address = s.ReadUInt32()) - cache.AddressMask;

			dependentTagsCount = s.ReadInt32();
			dependentTagsOffset = (dependentTagsAddress = s.ReadUInt32()) - cache.AddressMask;

			s.ReadInt32();
			s.ReadUInt32(); // seems to be the same address as the dependent tags

			s.ReadUInt32(); // crc?
			s.ReadInt32(); // 'tags'
			#endregion

			ReadDependents(s);

			ReadTagInstances(s);

			ReadGroupTags(s);

			#region fixup group tag info
			for (int x = 0; x < tagCount; x++)
			{
				var item = items[x];
				if (!item.IsEmpty)
				{
					item.GroupTag = groupTags[item.Datum.Index].GroupTag1;
					item.GroupTagInt = item.GroupTag.ID;
					item.Fixup((ushort)x); // Fix the hacks Bungie did for Halo3
				}
			}
			#endregion

			#region Load tag names
			s.Seek(cache.HeaderHalo3.TagNamesBufferOffset);
			string file_name;
			foreach (var ci in items)
			{
				if (!ci.IsEmpty)
				{
					ci.TagNameOffset = s.PositionUnsigned;
					file_name = s.ReadCString();
					if (file_name == "") file_name = "NONE";
				}
				else
				{
					ci.TagNameOffset = uint.MaxValue;
					ci.ReferenceName = DatumIndex.Null;
					continue;
				}

				ci.ReferenceName = cache.References.AddOptimized(ci.GroupTag, file_name);
			}
			#endregion
		}
Example #2
0
		public override void Read(BlamLib.IO.EndianReader s)
		{
			DataCacheFile cache = s.Owner as DataCacheFile;

			type = (DataCacheType)s.ReadInt32();
			tagNamesTableOffset = s.ReadInt32();
			tagInstancesTableOffset = s.ReadInt32();
			tagCount = s.ReadInt32();
			items = new DataItem[tagCount];

			TagInterface.TagGroup tgroup = null;
			switch(type)
			{
				case DataCacheType.Bitmap: tgroup = TagGroups.bitm; break;
				case DataCacheType.Sound: tgroup = TagGroups.snd_; break;
				case DataCacheType.Loc:
					break;
			}

			s.Seek(TagNamesTableOffset, System.IO.SeekOrigin.Begin);
			DataItem item = null;
			for (int x = 0; x < TagCount; x++)
			{
				item = new DataItem();
				items[x] = item;
				item.GroupTag = tgroup;
				item.ReferenceName = cache.References.AddOptimized(item.GroupTag, s.ReadCString());
			}

			s.Seek(tagInstancesTableOffset, System.IO.SeekOrigin.Begin);
			for (int x = 0; x < TagCount; x++)
				items[x].Read(s);
		}
Example #3
0
		public override void Read(BlamLib.IO.EndianReader s)
		{
			CacheFile cache = s.Owner as CacheFile;
			tagsOffset = (uint)(cache.Header.OffsetToIndex + cache.HeaderHalo2.IndexStreamSize);
			bool is_alpha = cache.EngineVersion == BlamVersion.Halo2_Alpha;
			bool is_echo = cache.EngineVersion == BlamVersion.Halo2_Epsilon;
			bool is_pc = cache.EngineVersion == BlamVersion.Halo2_PC;
			bool is_mp = cache.HeaderHalo2.CacheType == CacheType.Multiplayer;

			Managers.BlamDefinition bdef = Program.GetManager(cache.EngineVersion);

			uint tags_addressmask;
			if(!is_pc)
			{
				cache.AddressMask = 
					bdef[cache.EngineVersion].CacheTypes.BaseAddress - (uint)cache.Header.OffsetToIndex;
				tags_addressmask =
					(uint)(cache.Header.OffsetToIndex + cache.HeaderHalo2.IndexStreamSize);
			}
			else
			{
				// pc maps use virtual addresses which are actually offsets relative to 
				// the start of the tag memory buffer. since these are offsets and not actually 
				// addresses which we would normally mask the base off of, we have to do some 
				// number magic so our subtraction operations actually end up working in reverse 
				// to get the correct file offset
				tags_addressmask = 0 - (uint)cache.Header.OffsetToIndex;

				cache.AddressMask = tags_addressmask;
			}

			#region version dependant loading
			if (is_alpha)
			{
				groupTagsAddress = address = s.ReadUInt32();
				groupTagsCount = 0;
				scenario.Read(s);
				s.ReadInt32(); // crc
				tagCount = s.ReadInt32();
				items = new CacheItem[tagCount];
				s.ReadInt32(); // 'tags'
			}
			else if(is_pc)
			{
				groupTagsAddress = s.ReadPointer(); // offset (relative to the tag index offset) 
				groupTagsCount = s.ReadInt32();
				uint offset = s.ReadPointer(); // offset (relative to the tag index offset) to the tag entries
				scenario.Read(s);
				gameGlobals.Read(s);
				s.ReadInt32(); // crc
				tagCount = s.ReadInt32();
				items = new CacheItem[tagCount];
				s.ReadInt32(); // 'tags'

				s.Seek(offset /*- 32, System.IO.SeekOrigin.Current*/); // go to the first tag entry
			}
			else
			{
				groupTagsAddress = s.ReadUInt32();
				groupTagsCount = s.ReadInt32();
				address = s.ReadUInt32();
				scenario.Read(s);
				gameGlobals.Read(s);
				s.ReadInt32(); // crc
				tagCount = s.ReadInt32();
				items = new CacheItem[tagCount];
				s.ReadInt32(); // 'tags'

				s.Seek(groupTagsCount * 12, System.IO.SeekOrigin.Current); // go to the first tag entry
			}

			this.groupTagsOffset = this.groupTagsAddress - s.BaseAddress;
			#endregion

			CacheItem item;
			uint temp_pos = 0;
			uint sbsp_offset = 0;

			DatumIndex[] ltmps = null;
			Tags.scenario_structure_bsp_reference_block bsp_block = new Tags.scenario_structure_bsp_reference_block();

			if (is_pc) // MP maps need this adjustment
				cache.AddressMask = tags_addressmask += cache.HeaderHalo2.PcFields.VirtualAddress;

			for (int x = 0; x < items.Length; x++)
			{
				item = new CacheItem();
				items[x] = item;
				if (is_alpha)	item.ReadAlpha(s);
				else			item.Read(s);

				if (item.Location == ItemLocation.Unknown) items[x] = CacheItem.Null;
				else if (is_pc && item.HasExternalData) HasExternalTags = true;
			}

			if (!is_pc)
			{
				// While the tag definitions come right after the tag header in a cache file, when 
				// finally loaded into game memory this isn't the case. The 'stream' size of the tag 
				// header is how much actual memory is used by map's generated the tag header, but the 
				// map's tag header may not utilize the entire memory space dedicated to it in game memory.
				// So, the game would read the tag header data using the offset and 'stream' size data from 
				// the cache header, then it would seek to offset+stream_size to get to the tag definitions 
				// which it would then read into game memory at the memory location defined by 'address'
				tags_addressmask =
					items[0].Address - tags_addressmask;
				cache.AddressMask = tags_addressmask;
				for (int x = 0; x < items.Length; x++)
				{
					item = items[x];
					item.Offset = (int)(item.Address - tags_addressmask);

					#region on scnr tag
					if (!is_alpha && !is_echo && TagGroups.scnr.ID == item.GroupTag.ID)
					{
						temp_pos = s.PositionUnsigned;

						//if (is_alpha || is_echo)
						//	s.Seek(item.Offset + 828);
						//else
							s.Seek(item.Offset + 528);

						bspTags = new Item[s.ReadInt32()];
						sbsp_offset = s.ReadPointer();

						ltmps = new DatumIndex[bspTags.Length];

						s.Seek(temp_pos);
					}
					#endregion
					#region on sbsp tag
					else if (!is_alpha && !is_echo && TagGroups.sbsp.ID == item.GroupTag.ID)
					{
						temp_pos = s.PositionUnsigned;

						s.Seek(sbsp_offset + (uint)(bspCount *
							Halo2.Tags.scenario_structure_bsp_reference_block.kRuntimeSizeOf));
						bspTags[bspCount] = item;
						bsp_block.Read(cache);

						if (bsp_block.RuntimeOffset != 0)
						{
							item.Offset = bsp_block.RuntimeOffset;
							item.Size = bsp_block.RuntimeSize;
							item.Address = (uint)bsp_block.RuntimeAddress.Value;
							//cache.BspAddressMasks.Add((uint)(item.Address - item.Offset));
						}

						ltmps[bspCount] = bsp_block.Lightmap.Datum;
						item.BspIndex = bspCount++;

						s.Seek(temp_pos);
					}
					#endregion
				}
			}

			#region alpha tag name code
			if (is_alpha)
			{
				// following the tag datums in alpha builds is the tag names buffer
				foreach (Halo2.CacheItem ci in items)
				{
					ci.TagNameOffset = s.PositionUnsigned;
					ci.ReferenceName = cache.References.AddOptimized(ci.GroupTag, s.ReadCString());
				}
			}
			#endregion
			#region retail tag name & bsp offset fixup code
			else
			{
				// Build the absolute tag name offsets
				s.Seek(cache.HeaderHalo2.TagNameIndicesOffset);
				int[] offsets = new int[tagCount];
				for (int x = 0; x < offsets.Length; x++)
				{
					int offset = s.ReadInt32();
					// Offset will be -1 if the tag in question is 'null'
					if (offset != -1)
						offset += cache.HeaderHalo2.TagNamesBufferOffset;

					offsets[x] = offset;
				}
				// Fixup all tag instances which are named
				for (int x = 0; x < tagCount; x++)
				{
					if (offsets[x] != -1)
						FixupTagInstanceHeaderName(cache, items[x], offsets[x], s);
				}

				// PC maps store all zones in the tag memory, they don't need to swap out and thus don't 
				// need any fix ups (durrr, PCs have loltons of RAM)
				if (!is_pc && !is_echo)
				{
					var head = new Halo2.Tags.scenario_structure_bsps_header();
					foreach (CacheItem tmp_item in bspTags)
					{
						s.Seek(tmp_item.Offset);
						head.Read(cache);

						// bsp
						uint bsp_address_mask = head.FixupBspInstanceHeader(tmp_item, s.Position);
						cache.BspAddressMasks.Add(bsp_address_mask);

						// ltmp
						DatumIndex ltmp_datum = ltmps[tmp_item.BspIndex];
						if (ltmp_datum != DatumIndex.Null)
							head.FixupLightmapInstanceHeader(this.items[ltmp_datum.Index], tmp_item);
					}
				}
			}
			#endregion
		}