7 Commits
17 changed files with 254 additions and 90 deletions

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);
}
}
+9 -4
View File
@@ -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);
}
+7 -2
View File
@@ -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)
{
+17 -11
View File
@@ -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)
{
}
+4 -4
View File
@@ -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++)
+22
View File
@@ -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;
}
}
+98 -15
View File
@@ -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>
+2 -2
View File
@@ -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);
}
+18 -12
View File
@@ -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;
}
}
}
+21 -11
View File
@@ -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);
}
}