/// <summary> /// Figures out if the tag defined by <paramref name="tag_datum"/> is loaded in the tag index /// </summary> /// <param name="tag_datum">tag item defined in this cache's tag index</param> /// <returns><see cref="Blam.DatumIndex.Null"/> if not loaded</returns> public Blam.DatumIndex IsLoaded(Blam.CacheIndex.Item tag_datum) { if (tag_datum.IsEmpty) { return(Blam.DatumIndex.Null); } return(IsLoaded(References[tag_datum.ReferenceName], tag_datum.GroupTag)); }
public override int AddDependent(Blam.CacheIndex.Item tag, Blam.CacheIndex.Item dependent_tag) { int index = Add(dependent_tag); // add and\or get the index of the child id entry tag_database_entry_reference_block eref; lookup[tag.Datum].ChildIds.Add(out eref); // add a new entry reference return(eref.EntryReference.Value = index); }
public override int AddDependent(Blam.CacheIndex.Item tag, Blam.CacheIndex.Item dependent_tag) { int index = Add(dependent_tag); // add and\or get the index of the child id entry var tag_entry = lookup[tag.Datum]; var dtag_entry = lookup[dependent_tag.Datum]; Halo1.Tags.tag_database_entry_reference_block eref; dtag_entry.ReferenceIds.Add(out eref); // add a new entry reference to the dependent tag which points to this tag eref.EntryReference.Value = tag_entry.Flags.Value; tag_entry.ChildIds.Add(out eref); // add a new entry reference to this tag which points to the dependent tag return(eref.EntryReference.Value = index); }
/// <summary> /// Little hack for <see cref="CacheTagIndex"/> /// </summary> /// <param name="item"></param> /// <param name="cache"></param> /// <param name="ignore_group_hack">Hack used for Halo 2/3 where the sound definitions use different group tags</param> internal void Read(Blam.CacheIndex.Item item, Blam.CacheFile cache, bool ignore_group_hack) { Debug.Assert.If(InCache, "Tried to read a cache tag while we were NOT in a cache. {0}:{1}.{2}", engine, Name, tagGroup.Name); // HACK: for Halo 2/3 sound groups if (!ignore_group_hack && tagGroup.ID != item.GroupTag.ID) { Debug.Assert.If(false, "Tried to read a cache tag with a non-matching cache tag datum. {0}:{1} [{2} !{3}", engine, Name, tagGroup.TagToString(), item.GroupTag.TagToString()); } cache.InputStream.Seek(item.Offset); VersionCtorAttribute upgrade_parameters; bool needs_upgrading = false; if (cache.EngineVersion.SupportsTagVersioning()) { if ((upgrade_parameters = tagDefinition.VersionForEngine(cache.EngineVersion)) != null) { needs_upgrading = true; // It is ASSUMED that the group tag won't ever be needed for version construction tagDefinition = tagDefinition.NewInstance((tagDefinition as IStructureOwner).OwnerObject, upgrade_parameters.Major, upgrade_parameters.Minor); flags.Add(IO.ITagStreamFlags.DefinitionWasUpgraded); } else { needs_upgrading = false; } } tagDefinition.Read(cache); if (needs_upgrading) #if DEBUG { if (!tagDefinition.Upgrade()) { Debug.Assert.If(false, "Failed to upgrade tag group. {0} {1}", tagDefinition.GetType().Name, tagDefinition.ToVersionString()); } } #else { tagDefinition.Upgrade(); } #endif }
public override int Add(Blam.CacheIndex.Item tag) { int index = -1; tag_database_entry_block entry; if (!lookup.TryGetValue(tag.Datum, out entry)) // hey, not in the database { index = db.Entries.Count; // count will be the index of our new entry db.Entries.Add(out entry); // add a new entry entry.Name.Value = // set the name cacheFile.GetReferenceName(tag); entry.GroupTag.Value = tag.GroupTag.Tag; // set the group tag lookup.Add(tag.Datum, entry); // add entry to the dictionary return(entry.Flags.Value = index); } return(entry.Flags.Value); }
public override int Add(Blam.CacheIndex.Item tag) { int index = -1; Halo1.Tags.tag_database_entry_block entry; if (!lookup.TryGetValue(tag.Datum, out entry)) // hey, not in the database { string name = cacheFile.GetReferenceName(tag); index = db.Entries.Count; // count will be the index of our new entry db.Entries.Add(out entry); // add a new entry entry.Name.Value = // set the name System.Text.Encoding.ASCII.GetBytes(name); entry.GroupTag.Value = tag.GroupTag.Tag; // set the group tag entry.HandleDataHigh.Value = name.GetHashCode(); lookup.Add(tag.Datum, entry); // add entry to the dictionary return(entry.Flags.Value = index); } return(entry.Flags.Value); }
bool Extract(Blam.CacheExtractionInfo cei, Blam.DatumIndex tag_datum, bool remove_from_state) { if (remove_from_state) { // don't process it if it's already been done if (cacheFile.ExtractionState.Processed(tag_datum)) { return(true); } cacheFile.ExtractionState.Dequeue(tag_datum); } cacheFile.ExtractionState.CurrentTag = tag_datum; Blam.CacheIndex.Item ci = cacheFile.Index.Tags[tag_datum.Index]; bool error = false; Blam.DatumIndex handle = Open(tag_datum); if (handle != Blam.DatumIndex.Null) { // we're about to extract, update our depth level cei.ExtractionDepth++; TagManager tm = Array[handle]; #region read the tag from the cache try { tm.OpenForExtract(cei.Arguments.OutputDirectory, null); } catch (Exception ex) { extractionTrace.WriteLine("Failed to read tag, aborting extraction...'{0}.{1}'{2}{3}", tm.Name, tm.GroupTag.Name, Program.NewLine, ex); error = true; } #endregion #region if no errors if (!error) { try { tm.Extract(); } catch (Exception ex) { extractionTrace.WriteLine("Failed to write tag, aborting extraction...'{0}.{1}'{2}{3}", tm.Name, tm.GroupTag.Name, Program.NewLine, ex); error = true; } tm.Close(); } // something bad happened, so make sure we don't keep any bad tags if (error) { System.IO.File.Delete(Path.Combine(cei.Arguments.OutputDirectory, tm.Name)); } // process dependents if we want to if (!error && cei.Arguments.WithDependents) { error = !ExtractWithDependents(cei, tm); } #endregion // we're done with the extraction process, update depth level cei.ExtractionDepth--; // create and write database if (cei.Arguments.OutputDatabase && cei.ExtractionDepth == 0) { ExtractWriteTagDatabases(cei, tm); } Unload(handle); } else { error = true; } return(!error); }
public CacheTagDatabase(CacheFile cf, Blam.CacheIndex.Item root_tag) : base(root_tag) { cacheFile = cf; }
/// <summary> /// Open a tag in the cache file /// </summary> /// <param name="tag_datum">index of tag</param> /// <returns> /// The tag_index handle associated to the <see cref="TagManager"/> object used to open the tag, /// or <see cref="Blam.DatumIndex.Null"/> if this operations fails /// </returns> public Blam.DatumIndex Open(Blam.DatumIndex tag_datum) { if (tag_datum == Blam.DatumIndex.Null) { return(Blam.DatumIndex.Null); } Blam.CacheIndex.Item i = cacheFile.Index.Tags[tag_datum.Index]; if (i.IsEmpty) { throw new ArgumentNullException("tag_datum", string.Format("The tag handle {0} references an empty tag. We can't open this!", tag_datum.ToString())); } // How can we open it if we don't know where it F*****G IS YOU C**T?? if (i.Location != Blam.CacheIndex.ItemLocation.Internal && !i.IsFeignItem) { return(Blam.DatumIndex.Null); } // Is this tag already loaded? if so, reuse handle Blam.DatumIndex di = IsLoaded(i); if (di != Blam.DatumIndex.Null) { Array.IncrementReference(di); return(di); } TagManager tm = new TagManager(this); tm.ReferenceName = i.ReferenceName; // sync the tag manager's name with the cache item's bool group_tag_hack = false; BlamBuild build = Engine.ToBuild(); // HACK: Halo1 PC uses gbx's variant of the model tag if (Engine == BlamVersion.Halo1_CE && i.GroupTag == Blam.Halo1.TagGroups.mode) { tm.Manage(Blam.Halo1.TagGroups.mod2); group_tag_hack = true; } else // HACK: Halo 2/3 use a the 'sound' group tag for their 'cache_file_sound' definitions #if !NO_HALO2 if (build == BlamBuild.Halo2 && i.GroupTag == Blam.Halo2.TagGroups.snd_) { tm.Manage(Blam.Halo2.TagGroups.shit); group_tag_hack = true; } else #endif #if !NO_HALO3 if (build == BlamBuild.Halo3 && i.GroupTag == Blam.Halo3.TagGroups.snd_) { tm.Manage(Blam.Halo3.TagGroups.shit); group_tag_hack = true; } else #endif #if !NO_HALO_ODST if (build == BlamBuild.HaloOdst && i.GroupTag == Blam.Halo3.TagGroups.snd_) { tm.Manage(Blam.Halo3.TagGroups.shit); group_tag_hack = true; } else #endif #if !NO_HALO_REACH if (build == BlamBuild.HaloReach && i.GroupTag == Blam.HaloReach.TagGroups.snd_) { tm.Manage(Blam.HaloReach.TagGroups.shit); group_tag_hack = true; } else #endif #if !NO_HALO4 if (build == BlamBuild.Halo4 && i.GroupTag == Blam.Halo4.TagGroups.snd_) { tm.Manage(Blam.Halo4.TagGroups.shit); group_tag_hack = true; } else #endif { tm.Manage(i.GroupTag); } if (!i.IsFeignItem) { // We don't care about this shit when extracting or opening from a cache file const uint k_open_flags = IO.ITagStreamFlags.DontTrackTagManagerReferences | IO.ITagStreamFlags.DontTrackTagReferencers; tm.Flags.Add(k_open_flags); try { tm.Read(i, cacheFile, group_tag_hack); } catch (Exception ex) { indexTrace.WriteLine("Cache Index: Failed to open tag from cache: {0}{1}'{2}.{3}'{4}{5}", cacheFile.InputStream.FileName, Program.NewLine, cacheFile.GetReferenceName(i), i.GroupTag.Name, Program.NewLine, ex); return(Blam.DatumIndex.Null); } // Remove the flag we set before reading tm.Flags.Remove(k_open_flags); } tm.TagIndex = Array.Add(tm); base.OnEventOpen(new TagIndexEventArgs(this, tm)); return(tm.TagIndex); }
/// <summary> /// Add a tag to the database using <paramref name="tag"/> as the root tag /// </summary> /// <param name="tag">Tag to use as the root tag when adding <paramref name="dependent_tag"/> to the database</param> /// <param name="dependent_tag">Tag which is directly referenced by <paramref name="tag"/></param> /// <returns>Hash value for tag's database entry</returns> /// <remarks> /// Does not modify the current root tag. /// <paramref name="tag"/> must already already exist in the database /// </remarks> public abstract int AddDependent(Blam.CacheIndex.Item tag, Blam.CacheIndex.Item dependent_tag);
/// <summary> /// Add a tag to the database using the current root tag. /// </summary> /// <param name="dependent_tag">Tag which is directly referenced by the current root tag</param> /// <returns>Hash value for tag's database entry</returns> public int AddDependent(Blam.CacheIndex.Item dependent_tag) { return(AddDependent(root, dependent_tag)); }
/// <summary> /// Add a tag to the database /// </summary> /// <param name="tag"></param> /// <returns>Hash value for tag's database entry</returns> public abstract int Add(Blam.CacheIndex.Item tag);
/// <summary> /// Initialize the tag database with a root tag /// </summary> /// <param name="root_tag"></param> protected CacheTagDatabase(Blam.CacheIndex.Item root_tag) { SetRoot(root_tag); }
/// <summary> /// Set the current "root" tag of the database /// </summary> /// <param name="root_tag"></param> public void SetRoot(Blam.CacheIndex.Item root_tag) { Add(root = root_tag); }