Skip to content

Instantly share code, notes, and snippets.

@twist84
Forked from camden-smallwood-zz/NullTagCommand.cs
Created January 4, 2017 18:27
Show Gist options
  • Save twist84/5becb8df929cc63196ca23ec2a01fb9a to your computer and use it in GitHub Desktop.
Save twist84/5becb8df929cc63196ca23ec2a01fb9a to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TagTool.Cache;
using TagTool.Serialization;
using TagTool.TagDefinitions;
using TagTool.TagGroups;
using static TagTool.Commands.ArgumentParser;
namespace TagTool.Commands.Tags
{
class NullTagCommand : Command
{
public OpenTagCache Info { get; }
public NullTagCommand(OpenTagCache info)
: base(CommandFlags.None,
"nulltag",
"Nulls a tag in the current tag cache.",
"nulltag <tag index>",
"Nulls a tag in the current tag index. The tag's data will be removed from cache.")
{
Info = info;
}
private void LoadTagDependencies(int index, ref HashSet<int> tags)
{
var queue = new List<int> { index };
while (queue.Count != 0)
{
var nextQueue = new List<int>();
foreach (var entry in queue)
{
if (!tags.Contains(entry))
{
if (Info.Cache.Tags[entry] == null)
continue;
tags.Add(entry);
foreach (var dependency in Info.Cache.Tags[entry].Dependencies)
if (!nextQueue.Contains(dependency))
nextQueue.Add(dependency);
}
}
queue = nextQueue;
}
}
public override bool Execute(List<string> args)
{
var globalTags = new HashSet<int>();
LoadTagDependencies(0x0000, ref globalTags);
LoadTagDependencies(0x27C3, ref globalTags);
var tagCount = Info.Cache.Tags.Count;
var currentTag = 0;
var resources = new ResourceDataManager();
resources.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
var tagQueue = new List<int>();
var resourceQueue = new List<int>();
Info.Cache.Tags.FindAllInGroup("bink").ToList().ForEach(tag => { if (tag != null && !resourceQueue.Contains(tag.Index)) resourceQueue.Add(tag.Index); });
Info.Cache.Tags.FindAllInGroup("bitm").ToList().ForEach(tag => { if (tag != null && !resourceQueue.Contains(tag.Index)) resourceQueue.Add(tag.Index); });
Info.Cache.Tags.FindAllInGroup("mode").ToList().ForEach(tag => { if (tag != null && !resourceQueue.Contains(tag.Index)) resourceQueue.Add(tag.Index); });
Info.Cache.Tags.FindAllInGroup("jmad").ToList().ForEach(tag => { if (tag != null && !resourceQueue.Contains(tag.Index)) resourceQueue.Add(tag.Index); });
Info.Cache.Tags.FindAllInGroup("snd!").ToList().ForEach(tag => { if (tag != null && !resourceQueue.Contains(tag.Index)) resourceQueue.Add(tag.Index); });
Info.Cache.Tags.FindAllInGroup("sbsp").ToList().ForEach(tag => { if (tag != null && !resourceQueue.Contains(tag.Index)) resourceQueue.Add(tag.Index); });
Info.Cache.Tags.ForEach(tag => { if (tag != null && (!globalTags.Contains(tag.Index)) && (!resourceQueue.Contains(tag.Index)) && (!tagQueue.Contains(tag.Index))) tagQueue.Add(tag.Index); });
tagQueue.AddRange(resourceQueue);
resourceQueue.Clear();
resourceQueue = null;
foreach (var tagIndex in tagQueue)
{
var tag = Info.Cache.Tags[tagIndex];
if (tag == null)
continue;
if (globalTags.Contains(tag.Index))
continue;
using (var stream = Info.OpenCacheReadWrite())
{
var tagName = $"{Info.TagNames[tag.Index]}.{Info.StringIDs.GetString(tag.Group.Name)}";
Console.Write($"[{currentTag++}/{tagCount - globalTags.Count}] {tagName} (tag 0x{tag.Index:X4}): ");
var context = new TagSerializationContext(stream, Info.Cache, Info.StringIDs, tag);
if (tag.IsInGroup("bitm"))
{
Console.Write("nulling bitmap resources...");
var bitm = Info.Deserializer.Deserialize<Bitmap>(context);
foreach (var resource in bitm.Resources)
{
var location = resource.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(resource.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
}
else if (tag.IsInGroup("bink"))
{
Console.Write("nulling bink resource...");
var bink = Info.Deserializer.Deserialize<Bink>(context);
var location = bink.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(bink.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
else if (tag.IsInGroup("mode"))
{
Console.Write("nulling render model resource...");
var mode = Info.Deserializer.Deserialize<RenderModel>(context);
var location = mode.Geometry.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(mode.Geometry.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
else if (tag.IsInGroup("jmad"))
{
Console.Write("nulling model animation graph resources...");
var jmad = Info.Deserializer.Deserialize<ModelAnimationGraph>(context);
foreach (var resourceGroup in jmad.ResourceGroups)
{
var location = resourceGroup.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(resourceGroup.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
}
else if (tag.IsInGroup("snd!"))
{
Console.Write("nulling sound resource...");
var snd_ = Info.Deserializer.Deserialize<Sound>(context);
var location = snd_.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(snd_.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
else if (tag.IsInGroup("sbsp"))
{
Console.Write("null scenario structure bsp resources...");
var sbsp = Info.Deserializer.Deserialize<ScenarioStructureBsp>(context);
{
var location = sbsp.Geometry.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(sbsp.Geometry.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
{
var location = sbsp.Geometry2.Resource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(sbsp.Geometry2.Resource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
{
var location = sbsp.CollisionBSPResource.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(sbsp.CollisionBSPResource, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
{
var location = sbsp.Resource4.GetLocation();
var cache = resources.GetCache(location);
resources.ReplaceRaw(sbsp.Resource4, new byte[] { });
using (var resourceStream = resources.OpenCacheReadWrite(location))
using (var writer = new BinaryWriter(resourceStream))
{
cache.UpdateResourceTable(writer);
}
}
}
Console.Write("nulling tag data...");
Info.Cache.SetTagDataRaw(stream, tag, new byte[] { });
Info.Cache.Tags[tag.Index] = null;
using (var writer = new BinaryWriter(stream))
Info.Cache.UpdateTagOffsets(writer);
Console.WriteLine("done.");
}
}
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment