mirror of
https://github.com/AssetRipper/TypeTreeConversion.git
synced 2026-11-13 18:07:53 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4435d8d40 | ||
|
|
56d3c67f1c | ||
|
|
961bb55c22 | ||
|
|
a8e7340d0a | ||
|
|
e47d747b93 | ||
|
|
bdabaa6879 | ||
|
|
cec86c9611 |
No files matched your search
@@ -2,13 +2,16 @@
|
||||
|
||||
namespace TypeTreeConversion.TextAssetExample;
|
||||
|
||||
/// <summary>
|
||||
/// Replaces all fields with the fields of TextAsset.
|
||||
/// </summary>
|
||||
public class TextAssetFieldConverter : DefaultFieldConverter
|
||||
{
|
||||
public TextAssetFieldConverter(ClassDatabaseFile classDatabase) : base(classDatabase)
|
||||
public TextAssetFieldConverter(FieldConverterRegistry registry) : base(registry)
|
||||
{
|
||||
}
|
||||
|
||||
protected override AssetTypeValueField CreateNewBaseField(int originalTypeID)
|
||||
protected override AssetTypeValueField? CreateNewBaseField(int originalTypeID)
|
||||
{
|
||||
return base.CreateNewBaseField(49);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace TypeTreeConversion.TextAssetExample;
|
||||
|
||||
/// <summary>
|
||||
/// This example plugin replaces all assets with TextAssets.
|
||||
/// </summary>
|
||||
public class TextAssetPlugin : ConversionPlugin
|
||||
{
|
||||
public TextAssetPlugin()
|
||||
@@ -10,15 +13,25 @@ public class TextAssetPlugin : ConversionPlugin
|
||||
|
||||
private static void RegisterFieldConverters(FieldConverterRegistry registry)
|
||||
{
|
||||
TextAssetFieldConverter converter = new(registry.ClassDatabase);
|
||||
//We want to convert all assets to TextAssets,
|
||||
//so we assign an alternative default field converter.
|
||||
registry.DefaultConverter = new TextAssetFieldConverter(registry);
|
||||
|
||||
//This is cleared to ensure prior MonoBehaviours get TextAsset fields.
|
||||
//If it was not cleared, MonoBehaviourFieldConverter would be used instead.
|
||||
//There's generally no need to clear unless you're defining a custom default converter.
|
||||
registry.Converters.Clear();
|
||||
registry.DefaultConverter = converter;
|
||||
}
|
||||
|
||||
private static void RegisterTypeTreeReplacers(TypeTreeReplacerRegistry registry)
|
||||
{
|
||||
TextAssetTypeTreeConverter converter = new(registry.ClassDatabase);
|
||||
//We want to replace all type trees with the type tree of TextAsset,
|
||||
//so we assign an alternative default replacer.
|
||||
registry.DefaultReplacer = new TextAssetTypeTreeReplacer(registry);
|
||||
|
||||
//This is cleared to ensure prior MonoBehaviours get new TextAsset type trees.
|
||||
//If it was not cleared, MonoBehaviourTypeTreeReplacer would be used instead.
|
||||
//There's generally no need to clear unless you're defining a custom default replacer.
|
||||
registry.Replacers.Clear();
|
||||
registry.DefaultReplacer = converter;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using AssetsTools.NET;
|
||||
|
||||
namespace TypeTreeConversion.TextAssetExample;
|
||||
|
||||
public class TextAssetTypeTreeConverter : DefaultTypeTreeReplacer
|
||||
{
|
||||
public TextAssetTypeTreeConverter(ClassDatabaseFile classDatabase) : base(classDatabase)
|
||||
{
|
||||
}
|
||||
|
||||
protected override TypeTreeType CreateReplacement(int originalTypeID)
|
||||
{
|
||||
return base.CreateReplacement(49);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using AssetsTools.NET;
|
||||
|
||||
namespace TypeTreeConversion.TextAssetExample;
|
||||
|
||||
/// <summary>
|
||||
/// Replaces all type trees with the type tree of TextAsset.
|
||||
/// </summary>
|
||||
public class TextAssetTypeTreeReplacer : DefaultTypeTreeReplacer
|
||||
{
|
||||
public TextAssetTypeTreeReplacer(TypeTreeReplacerRegistry registry) : base(registry)
|
||||
{
|
||||
}
|
||||
|
||||
protected override TypeTreeType? CreateReplacement(int originalTypeID)
|
||||
{
|
||||
return base.CreateReplacement(49);
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,20 @@ public class DefaultFieldConverter : FieldConverter
|
||||
{
|
||||
private readonly ClassDatabaseFile classDatabase;
|
||||
|
||||
public DefaultFieldConverter(ClassDatabaseFile classDatabase)
|
||||
public DefaultFieldConverter(FieldConverterRegistry registry)
|
||||
{
|
||||
this.classDatabase = classDatabase;
|
||||
classDatabase = registry.DestinationClassDatabase;
|
||||
}
|
||||
|
||||
protected override AssetTypeValueField CreateNewBaseField(int originalTypeID)
|
||||
protected override AssetTypeValueField? CreateNewBaseField(int originalTypeID)
|
||||
{
|
||||
AssetTypeTemplateField templateField = new();
|
||||
templateField.FromClassDatabase(classDatabase, classDatabase.FindAssetClassByID(originalTypeID));
|
||||
ClassDatabaseType? cldbType = classDatabase.FindAssetClassByID(originalTypeID);
|
||||
if (cldbType is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
templateField.FromClassDatabase(classDatabase, cldbType);
|
||||
return ValueBuilder.DefaultValueFieldFromTemplate(templateField);
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,12 @@ public class DefaultTypeTreeReplacer : TypeTreeReplacer
|
||||
{
|
||||
private readonly ClassDatabaseFile classDatabase;
|
||||
|
||||
public DefaultTypeTreeReplacer(ClassDatabaseFile classDatabase)
|
||||
public DefaultTypeTreeReplacer(TypeTreeReplacerRegistry registry)
|
||||
{
|
||||
this.classDatabase = classDatabase;
|
||||
classDatabase = registry.DestinationClassDatabase;
|
||||
}
|
||||
|
||||
protected override TypeTreeType CreateReplacement(int originalTypeID)
|
||||
protected override TypeTreeType? CreateReplacement(int originalTypeID)
|
||||
{
|
||||
return ClassDatabaseToTypeTree.Convert(classDatabase, originalTypeID);
|
||||
}
|
||||
|
||||
@@ -15,14 +15,19 @@ public abstract class FieldConverter
|
||||
return;
|
||||
}
|
||||
|
||||
AssetTypeValueField baseField = CreateNewBaseField(asset.TypeID);
|
||||
AssetTypeValueField? baseField = CreateNewBaseField(asset.TypeID);
|
||||
|
||||
if (baseField is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CopyFields(asset, asset.BaseField, baseField);
|
||||
|
||||
asset.BaseField = baseField;
|
||||
}
|
||||
|
||||
protected abstract AssetTypeValueField CreateNewBaseField(int originalTypeID);
|
||||
protected abstract AssetTypeValueField? CreateNewBaseField(int originalTypeID);
|
||||
|
||||
protected virtual void CopyFields(UnityAsset asset, AssetTypeValueField source, AssetTypeValueField destination)
|
||||
{
|
||||
|
||||
@@ -2,22 +2,28 @@
|
||||
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
public sealed class FieldConverterRegistry
|
||||
public sealed class FieldConverterRegistry : Registry
|
||||
{
|
||||
public Dictionary<int, FieldConverter> Converters { get; }
|
||||
/// <summary>
|
||||
/// The converters to use for each type ID.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This initially contains a <see cref="MonoBehaviourFieldConverter"/> instance for type ID 114.
|
||||
/// </remarks>
|
||||
public Dictionary<int, FieldConverter> Converters { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The default converter to use when no converter is found for a type ID.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is initially set to a <see cref="DefaultFieldConverter"/> instance.
|
||||
/// </remarks>
|
||||
public FieldConverter DefaultConverter { get; set; }
|
||||
|
||||
public ClassDatabaseFile ClassDatabase { get; }
|
||||
|
||||
internal FieldConverterRegistry(ClassDatabaseFile classDatabase)
|
||||
internal FieldConverterRegistry(ClassDatabaseFile sourceClassDatabase, ClassDatabaseFile destinationClassDatabase) : base(sourceClassDatabase, destinationClassDatabase)
|
||||
{
|
||||
ClassDatabase = classDatabase;
|
||||
DefaultConverter = new DefaultFieldConverter(classDatabase);
|
||||
Converters = new()
|
||||
{
|
||||
{ 114, new MonoBehaviourFieldConverter(classDatabase) }
|
||||
};
|
||||
DefaultConverter = new DefaultFieldConverter(this);
|
||||
Converters.Add(114, new MonoBehaviourFieldConverter(this));
|
||||
}
|
||||
|
||||
public FieldConverter GetConverter(int typeID)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using AssetsTools.NET;
|
||||
|
||||
namespace TypeTreeConversion;
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
/// <summary>
|
||||
/// This replacer ensures that MonoBehaviours are correctly converted.
|
||||
/// Currently, this is done by doing nothing.
|
||||
/// </summary>
|
||||
public class MonoBehaviourFieldConverter : DefaultFieldConverter
|
||||
{
|
||||
public MonoBehaviourFieldConverter(ClassDatabaseFile classDatabase) : base(classDatabase)
|
||||
public MonoBehaviourFieldConverter(FieldConverterRegistry registry) : base(registry)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
/// <summary>
|
||||
/// This replacer ensures that MonoBehaviours are correctly converted.
|
||||
/// Currently, this is done by doing nothing.
|
||||
/// </summary>
|
||||
public class MonoBehaviourTypeTreeReplacer : DefaultTypeTreeReplacer
|
||||
{
|
||||
public MonoBehaviourTypeTreeReplacer(ClassDatabaseFile classDatabase) : base(classDatabase)
|
||||
public MonoBehaviourTypeTreeReplacer(TypeTreeReplacerRegistry registry) : base(registry)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -78,14 +78,14 @@ public static class Program
|
||||
AssetsManager manager = new();
|
||||
manager.LoadClassPackage(new MemoryStream(TpkCreator.ConvertJsonToTpk(typeTreePath)));
|
||||
AssetsFileInstance file = manager.LoadAssetsFile(inputPath, false);
|
||||
manager.LoadClassDatabaseFromPackage(file.file.Metadata.UnityVersion);
|
||||
ClassDatabaseFile sourceClassDatabase = manager.LoadClassDatabaseFromPackage(file.file.Metadata.UnityVersion);
|
||||
SerializeFile serializeFile = new(file, manager);
|
||||
|
||||
ClassPackageFile tpk = new();
|
||||
tpk.Read(tpkPath);
|
||||
ClassDatabaseFile unityClassDatabase = tpk.GetClassDatabase(file.file.Metadata.UnityVersion);
|
||||
ClassDatabaseFile destinationClassDatabase = tpk.GetClassDatabase(file.file.Metadata.UnityVersion);
|
||||
|
||||
FieldConverterRegistry registry = new(unityClassDatabase);
|
||||
FieldConverterRegistry registry = new(sourceClassDatabase, destinationClassDatabase);
|
||||
RegisterFieldConverters?.Invoke(registry);
|
||||
|
||||
foreach (UnityAsset asset in serializeFile.Assets)
|
||||
@@ -94,7 +94,7 @@ public static class Program
|
||||
converter.Convert(asset);
|
||||
}
|
||||
|
||||
TypeTreeReplacerRegistry replacerRegistry = new(unityClassDatabase);
|
||||
TypeTreeReplacerRegistry replacerRegistry = new(sourceClassDatabase, destinationClassDatabase);
|
||||
RegisterTypeTreeReplacers?.Invoke(replacerRegistry);
|
||||
|
||||
for (int i = 0; i < file.file.Metadata.TypeTreeTypes.Count; i++)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using AssetsTools.NET;
|
||||
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
public abstract class Registry
|
||||
{
|
||||
/// <summary>
|
||||
/// The class database of the source file, loaded from json.
|
||||
/// </summary>
|
||||
public ClassDatabaseFile SourceClassDatabase { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The class database of the destination file, loaded from a tpk.
|
||||
/// </summary>
|
||||
public ClassDatabaseFile DestinationClassDatabase { get; }
|
||||
|
||||
internal Registry(ClassDatabaseFile sourceClassDatabase, ClassDatabaseFile destinationClassDatabase)
|
||||
{
|
||||
SourceClassDatabase = sourceClassDatabase;
|
||||
DestinationClassDatabase = destinationClassDatabase;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,22 @@
|
||||
using AssetsTools.NET;
|
||||
using AssetsTools.NET.Extra;
|
||||
using System.Collections;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
public readonly struct SerializeFile
|
||||
public readonly record struct SerializeFile
|
||||
{
|
||||
private readonly AssetsFileInstance file;
|
||||
private readonly AssetsManager manager;
|
||||
public AssetsFileInstance FileInstance { get; }
|
||||
public AssetsManager Manager { get; }
|
||||
|
||||
public SerializeFile(AssetsFileInstance file, AssetsManager manager)
|
||||
{
|
||||
this.file = file;
|
||||
this.manager = manager;
|
||||
FileInstance = file;
|
||||
Manager = manager;
|
||||
}
|
||||
|
||||
public IEnumerable<UnityAsset> Assets
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (AssetFileInfo info in file.file.AssetInfos)
|
||||
{
|
||||
yield return new UnityAsset(manager, file, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
public AssetList Assets => new(this);
|
||||
|
||||
public static SerializeFile Load(string path)
|
||||
{
|
||||
@@ -31,4 +24,94 @@ public readonly struct SerializeFile
|
||||
AssetsFileInstance file = manager.LoadAssetsFile(path, false);
|
||||
return new SerializeFile(file, manager);
|
||||
}
|
||||
|
||||
public readonly struct AssetList : IList<UnityAsset>
|
||||
{
|
||||
private readonly SerializeFile _file;
|
||||
|
||||
public AssetList(SerializeFile file)
|
||||
{
|
||||
_file = file;
|
||||
}
|
||||
|
||||
private IList<AssetFileInfo> InternalList => _file.FileInstance.file.AssetInfos;
|
||||
|
||||
private UnityAsset GetAsset(AssetFileInfo info)
|
||||
{
|
||||
return new UnityAsset(_file.Manager, _file.FileInstance, info);
|
||||
}
|
||||
|
||||
public UnityAsset this[int index] { get => GetAsset(InternalList[index]); set => InternalList[index] = value.FileInfo; }
|
||||
|
||||
public int Count => InternalList.Count;
|
||||
|
||||
public bool IsReadOnly => InternalList.IsReadOnly;
|
||||
|
||||
public void Add(UnityAsset item)
|
||||
{
|
||||
ThrowIfFromDifferentFile(item);
|
||||
InternalList.Add(item.FileInfo);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
InternalList.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(UnityAsset item)
|
||||
{
|
||||
return item.File == _file && InternalList.Contains(item.FileInfo);
|
||||
}
|
||||
|
||||
public void CopyTo(UnityAsset[] array, int arrayIndex)
|
||||
{
|
||||
for (int i = 0; i < InternalList.Count; i++)
|
||||
{
|
||||
array[arrayIndex + i] = GetAsset(InternalList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<UnityAsset> GetEnumerator()
|
||||
{
|
||||
foreach (AssetFileInfo info in InternalList)
|
||||
{
|
||||
yield return GetAsset(info);
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(UnityAsset item)
|
||||
{
|
||||
if (item.File != _file)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return InternalList.IndexOf(item.FileInfo);
|
||||
}
|
||||
|
||||
public void Insert(int index, UnityAsset item)
|
||||
{
|
||||
ThrowIfFromDifferentFile(item);
|
||||
InternalList.Insert(index, item.FileInfo);
|
||||
}
|
||||
|
||||
public bool Remove(UnityAsset item)
|
||||
{
|
||||
return InternalList.Remove(item.FileInfo);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
InternalList.RemoveAt(index);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
private void ThrowIfFromDifferentFile(UnityAsset asset, [CallerArgumentExpression(nameof(asset))] string? paramName = null)
|
||||
{
|
||||
if (asset.File != _file)
|
||||
{
|
||||
throw new ArgumentException("Asset is from a different file.", paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>1.0.1</Version>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -11,10 +11,10 @@ public abstract class TypeTreeReplacer
|
||||
return original;
|
||||
}
|
||||
|
||||
return CreateReplacement(original.TypeId);
|
||||
return CreateReplacement(original.TypeId) ?? original;
|
||||
}
|
||||
|
||||
protected virtual bool ShouldReplace(TypeTreeType original) => true;
|
||||
|
||||
protected abstract TypeTreeType CreateReplacement(int originalTypeID);
|
||||
protected abstract TypeTreeType? CreateReplacement(int originalTypeID);
|
||||
}
|
||||
@@ -2,26 +2,32 @@
|
||||
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
public sealed class TypeTreeReplacerRegistry
|
||||
public sealed class TypeTreeReplacerRegistry : Registry
|
||||
{
|
||||
public Dictionary<int, TypeTreeReplacer> Replacers { get; }
|
||||
/// <summary>
|
||||
/// The replacers to use for each type ID.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This initially contains a <see cref="MonoBehaviourTypeTreeReplacer"/> instance for type ID 114.
|
||||
/// </remarks>
|
||||
public Dictionary<int, TypeTreeReplacer> Replacers { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The default replacer to use when no replacer is found for a type ID.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is initially set to a <see cref="DefaultTypeTreeReplacer"/> instance.
|
||||
/// </remarks>
|
||||
public TypeTreeReplacer DefaultReplacer { get; set; }
|
||||
|
||||
public ClassDatabaseFile ClassDatabase { get; }
|
||||
|
||||
internal TypeTreeReplacerRegistry(ClassDatabaseFile classDatabase)
|
||||
internal TypeTreeReplacerRegistry(ClassDatabaseFile sourceClassDatabase, ClassDatabaseFile destinationClassDatabase) : base(sourceClassDatabase, destinationClassDatabase)
|
||||
{
|
||||
ClassDatabase = classDatabase;
|
||||
DefaultReplacer = new DefaultTypeTreeReplacer(classDatabase);
|
||||
Replacers = new()
|
||||
{
|
||||
{ 114, new MonoBehaviourTypeTreeReplacer(classDatabase) }
|
||||
};
|
||||
DefaultReplacer = new DefaultTypeTreeReplacer(this);
|
||||
Replacers.Add(114, new MonoBehaviourTypeTreeReplacer(this));
|
||||
}
|
||||
|
||||
public TypeTreeReplacer GetReplacer(int typeID)
|
||||
{
|
||||
return Replacers.TryGetValue(typeID, out TypeTreeReplacer? converter) ? converter : DefaultReplacer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,28 @@ using System.Diagnostics;
|
||||
namespace TypeTreeConversion;
|
||||
|
||||
[DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")]
|
||||
public readonly struct UnityAsset
|
||||
public readonly record struct UnityAsset
|
||||
{
|
||||
public AssetsManager Manager { get; }
|
||||
public AssetsFileInstance File { get; }
|
||||
public AssetFileInfo Info { get; }
|
||||
public AssetsFileInstance FileInstance { get; }
|
||||
public AssetFileInfo FileInfo { get; }
|
||||
|
||||
public UnityAsset(AssetsManager manager, AssetsFileInstance file, AssetFileInfo info)
|
||||
{
|
||||
this.Manager = manager;
|
||||
this.File = file;
|
||||
this.Info = info;
|
||||
Manager = manager;
|
||||
FileInstance = file;
|
||||
FileInfo = info;
|
||||
}
|
||||
|
||||
public SerializeFile File => new SerializeFile(FileInstance, Manager);
|
||||
|
||||
public int TypeID
|
||||
{
|
||||
get => Info.TypeId;
|
||||
set => Info.TypeId = value;
|
||||
get => FileInfo.TypeId;
|
||||
set => FileInfo.TypeId = value;
|
||||
}
|
||||
|
||||
public long PathID => Info.PathId;
|
||||
public long PathID => FileInfo.PathId;
|
||||
|
||||
public string Name
|
||||
{
|
||||
@@ -45,11 +47,11 @@ public readonly struct UnityAsset
|
||||
{
|
||||
get
|
||||
{
|
||||
return Manager.GetBaseField(File, Info);
|
||||
return Manager.GetBaseField(FileInstance, FileInfo);
|
||||
}
|
||||
set
|
||||
{
|
||||
Info.SetNewData(value);
|
||||
FileInfo.SetNewData(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +59,12 @@ public readonly struct UnityAsset
|
||||
{
|
||||
return $"{TypeID} : {Name}";
|
||||
}
|
||||
|
||||
public UnityAsset? ResolveAsset(AssetTypeValueField pptrField)
|
||||
{
|
||||
AssetExternal assetExternal = Manager.GetExtAsset(FileInstance, pptrField);
|
||||
return assetExternal.file is null || assetExternal.info is null
|
||||
? null
|
||||
: new UnityAsset(Manager, assetExternal.file, assetExternal.info);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user