mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
Remove legacy prefab outlining
This commit is contained in:
parent
2fe9ac59ec
commit
de5ce5b031
@ -12,11 +12,10 @@ using AssetRipper.Processing.AnimatorControllers;
|
||||
using AssetRipper.Processing.Assemblies;
|
||||
using AssetRipper.Processing.AudioMixers;
|
||||
using AssetRipper.Processing.Editor;
|
||||
using AssetRipper.Processing.ScriptableObject;
|
||||
using AssetRipper.Processing.PrefabOutlining;
|
||||
using AssetRipper.Processing.Scenes;
|
||||
using AssetRipper.Processing.Textures;
|
||||
using AssetRipper.Processing.Prefabs;
|
||||
using AssetRipper.Processing.Scenes;
|
||||
using AssetRipper.Processing.ScriptableObject;
|
||||
using AssetRipper.Processing.Textures;
|
||||
|
||||
namespace AssetRipper.Export.UnityProjects;
|
||||
|
||||
@ -68,10 +67,6 @@ public class ExportHandler
|
||||
yield return new AudioMixerProcessor();
|
||||
yield return new EditorFormatProcessor(Settings.ProcessingSettings.BundledAssetsExportMode);
|
||||
//Static mesh separation goes here
|
||||
if (Settings.ProcessingSettings.EnablePrefabOutlining)
|
||||
{
|
||||
yield return new PrefabOutliningProcessor();
|
||||
}
|
||||
yield return new LightingDataProcessor();//Needs to be after static mesh separation
|
||||
yield return new PrefabProcessor();
|
||||
yield return new SpriteProcessor();
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
using AssetRipper.Assets;
|
||||
using AssetRipper.Assets.Cloning;
|
||||
using AssetRipper.Assets.Collections;
|
||||
using AssetRipper.SourceGenerated;
|
||||
using AssetRipper.SourceGenerated.Classes.ClassID_1;
|
||||
using AssetRipper.SourceGenerated.Extensions;
|
||||
|
||||
namespace AssetRipper.Processing.PrefabOutlining;
|
||||
|
||||
public static class GameObjectCloner
|
||||
{
|
||||
public static IGameObject Clone(IGameObject source, ProcessedAssetCollection processedCollection)
|
||||
{
|
||||
Dictionary<IUnityObjectBase, IUnityObjectBase> clonedAssetDictionary = [];
|
||||
foreach (IUnityObjectBase asset in source.FetchHierarchy())
|
||||
{
|
||||
IUnityObjectBase clonedAsset = processedCollection.CreateAsset(asset.ClassID, AssetFactory.Create);
|
||||
clonedAssetDictionary.Add(asset, clonedAsset);
|
||||
}
|
||||
ClonedAssetResolver resolver = new ClonedAssetResolver(clonedAssetDictionary);
|
||||
foreach ((IUnityObjectBase asset, IUnityObjectBase clonedAsset) in clonedAssetDictionary)
|
||||
{
|
||||
PPtrConverter converter = new PPtrConverter(asset.Collection, clonedAsset.Collection, resolver);
|
||||
clonedAsset.CopyValues(asset, converter);
|
||||
}
|
||||
return (IGameObject)clonedAssetDictionary[source];
|
||||
}
|
||||
|
||||
private sealed class ClonedAssetResolver : IAssetResolver
|
||||
{
|
||||
private readonly Dictionary<IUnityObjectBase, IUnityObjectBase> cache;
|
||||
|
||||
public ClonedAssetResolver(Dictionary<IUnityObjectBase, IUnityObjectBase> cache)
|
||||
{
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public T? Resolve<T>(IUnityObjectBase? asset) where T : IUnityObjectBase
|
||||
{
|
||||
if (asset is null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else if (cache.TryGetValue(asset, out IUnityObjectBase? clonedAsset))
|
||||
{
|
||||
return TryCast<T>(clonedAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return TryCast<T>(asset);
|
||||
}
|
||||
}
|
||||
|
||||
private static T? TryCast<T>(IUnityObjectBase asset) where T : IUnityObjectBase
|
||||
{
|
||||
return asset is T t ? t : default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,172 +0,0 @@
|
||||
using AssetRipper.Assets.Collections;
|
||||
using AssetRipper.Assets.Generics;
|
||||
using AssetRipper.SourceGenerated.Classes.ClassID_1;
|
||||
using AssetRipper.SourceGenerated.Classes.ClassID_2;
|
||||
using AssetRipper.SourceGenerated.Classes.ClassID_4;
|
||||
using AssetRipper.SourceGenerated.Extensions;
|
||||
using AssetRipper.SourceGenerated.Subclasses.PPtr_Component;
|
||||
using AssetRipper.SourceGenerated.Subclasses.PPtr_Transform;
|
||||
|
||||
namespace AssetRipper.Processing.PrefabOutlining;
|
||||
|
||||
internal readonly struct GameObjectInfo : IEquatable<GameObjectInfo>
|
||||
{
|
||||
public GameObjectInfo(GameObjectInfo?[] children, int[] components)
|
||||
{
|
||||
Children = children;
|
||||
Components = components;
|
||||
Hash = CalculateHash(children, components);
|
||||
}
|
||||
|
||||
private GameObjectInfo?[] Children { get; }
|
||||
private int[] Components { get; }
|
||||
private int Hash { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Children: {Children.Length} Components: {Components.Length}";
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is GameObjectInfo info && Equals(info);
|
||||
}
|
||||
|
||||
public bool Equals(GameObjectInfo other)
|
||||
{
|
||||
return Hash == other.Hash
|
||||
&& Components.AsSpan().SequenceEqual(other.Components.AsSpan())
|
||||
&& Children.AsSpan().SequenceEqual(other.Children.AsSpan());
|
||||
}
|
||||
|
||||
public override int GetHashCode() => Hash;
|
||||
|
||||
public static bool operator ==(GameObjectInfo left, GameObjectInfo right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(GameObjectInfo left, GameObjectInfo right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
private static int CalculateHash(GameObjectInfo?[] children, int[] components)
|
||||
{
|
||||
HashCode hashCode = new();
|
||||
for (int i = 0; i < components.Length; i++)
|
||||
{
|
||||
hashCode.Add(components[i]);
|
||||
}
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
hashCode.Add(children[i]);
|
||||
}
|
||||
return hashCode.ToHashCode();
|
||||
}
|
||||
|
||||
public static GameObjectInfo FromGameObject(IGameObject root)
|
||||
{
|
||||
GetTransformAndComponentArray(root, out ITransform? transform, out int[] components);
|
||||
|
||||
GameObjectInfo?[] children;
|
||||
if (transform is null)
|
||||
{
|
||||
children = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
PPtrAccessList<IPPtr_Transform, ITransform> childList = transform.Children_C4P;
|
||||
if (childList.Count == 0)
|
||||
{
|
||||
children = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
children = new GameObjectInfo?[childList.Count];
|
||||
for (int i = 0; i < childList.Count; i++)
|
||||
{
|
||||
IGameObject? child = childList[i]?.GameObject_C4P;
|
||||
children[i] = child is null ? null : FromGameObject(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new GameObjectInfo(children, components);
|
||||
}
|
||||
|
||||
public static void AddCollectionToDictionary(AssetCollection collection, Dictionary<IGameObject, GameObjectInfo> dictionary)
|
||||
{
|
||||
foreach (IGameObject gameObject in collection.OfType<IGameObject>())
|
||||
{
|
||||
AddHierarchyToDictionary(gameObject, dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObjectInfo AddHierarchyToDictionary(IGameObject root, Dictionary<IGameObject, GameObjectInfo> dictionary)
|
||||
{
|
||||
if (dictionary.TryGetValue(root, out GameObjectInfo info))
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
GetTransformAndComponentArray(root, out ITransform? transform, out int[] components);
|
||||
|
||||
GameObjectInfo?[] children;
|
||||
if (transform is null)
|
||||
{
|
||||
children = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
PPtrAccessList<IPPtr_Transform, ITransform> childList = transform.Children_C4P;
|
||||
if (childList.Count == 0)
|
||||
{
|
||||
children = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
children = new GameObjectInfo?[childList.Count];
|
||||
for (int i = 0; i < childList.Count; i++)
|
||||
{
|
||||
IGameObject? child = childList[i]?.GameObject_C4P;
|
||||
children[i] = child is null ? null : AddHierarchyToDictionary(child, dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info = new GameObjectInfo(children, components);
|
||||
dictionary.Add(root, info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private static void GetTransformAndComponentArray(IGameObject root, out ITransform? transform, out int[] components)
|
||||
{
|
||||
transform = null;
|
||||
PPtrAccessList<IPPtr_Component, IComponent> componentList = root.GetComponentAccessList();
|
||||
if (componentList.Count == 0)
|
||||
{
|
||||
components = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
components = new int[componentList.Count];
|
||||
for (int i = 0; i < componentList.Count; i++)
|
||||
{
|
||||
IComponent? component = componentList[i];
|
||||
if (component is not null)
|
||||
{
|
||||
components[i] = component.ClassID;
|
||||
if (component is ITransform t)
|
||||
{
|
||||
transform = t;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
components[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,138 +0,0 @@
|
||||
using AssetRipper.Assets.Bundles;
|
||||
using AssetRipper.Assets.Collections;
|
||||
using AssetRipper.Import.Logging;
|
||||
using AssetRipper.SourceGenerated;
|
||||
using AssetRipper.SourceGenerated.Classes.ClassID_1;
|
||||
using AssetRipper.SourceGenerated.Classes.ClassID_4;
|
||||
using AssetRipper.SourceGenerated.Extensions;
|
||||
|
||||
namespace AssetRipper.Processing.PrefabOutlining;
|
||||
|
||||
public sealed class PrefabOutliningProcessor : IAssetProcessor
|
||||
{
|
||||
//Documentation note: prefab variants were introduced in 2018.3.
|
||||
//That does not affect this processor currently, but it may have an impact on future improvements.
|
||||
//https://blog.unity.com/technology/introducing-unity-2018-3
|
||||
|
||||
public void Process(GameData gameData)
|
||||
{
|
||||
Logger.Info(LogCategory.Processing, "Prefab Outlining");
|
||||
ProcessedAssetCollection processedCollection = gameData.AddNewProcessedCollection("Outlined Prefabs");
|
||||
MakeDictionaries(
|
||||
gameData.GameBundle,
|
||||
out Dictionary<IGameObject, GameObjectInfo> infoDictionary,
|
||||
out Dictionary<AssetCollection, bool> sceneInfo);
|
||||
MakeBoxes(
|
||||
infoDictionary,
|
||||
sceneInfo,
|
||||
out Dictionary<string, Dictionary<GameObjectInfo, List<IGameObject>>> boxes,
|
||||
out HashSet<IGameObject> prefabRoots);
|
||||
foreach ((string name, Dictionary<GameObjectInfo, List<IGameObject>> variants) in boxes)
|
||||
{
|
||||
if (variants.Count != 1)
|
||||
{
|
||||
continue;//We want the simplest implementation to start out
|
||||
}
|
||||
|
||||
(_, List<IGameObject> box) = variants.First();
|
||||
|
||||
if (box.Any(g => prefabRoots.Contains(g)))
|
||||
{
|
||||
continue;//Prefab already exists
|
||||
}
|
||||
|
||||
Logger.Info(LogCategory.Processing, $"Recreating prefab for {name}");
|
||||
|
||||
AddCopyToCollection(name, box[0], processedCollection);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddCopyToCollection(string name, IGameObject source, ProcessedAssetCollection collection)
|
||||
{
|
||||
//AddPrefabPlaceHolder(name, collection);
|
||||
AddNewPrefab(name, source, collection);
|
||||
}
|
||||
|
||||
private static void AddNewPrefab(string name, IGameObject source, ProcessedAssetCollection collection)
|
||||
{
|
||||
IGameObject root = GameObjectCloner.Clone(source, collection);
|
||||
root.Name = name;
|
||||
root.SetIsActive(true);
|
||||
|
||||
ITransform transform = root.GetTransform();
|
||||
transform.LocalPosition_C4.Reset();
|
||||
transform.LocalRotation_C4.Reset();
|
||||
transform.LocalScale_C4.SetValues(1, 1, 1);
|
||||
transform.LocalEulerAnglesHint_C4?.Reset();
|
||||
transform.RootOrder_C4 = 0;
|
||||
transform.Father_C4.Reset();
|
||||
}
|
||||
|
||||
private static void AddPrefabPlaceHolder(string name, ProcessedAssetCollection collection)
|
||||
{
|
||||
//Place holder code until source gen improves
|
||||
|
||||
IGameObject root = CreateNewGameObject(collection);
|
||||
root.Name = name;
|
||||
root.SetIsActive(true);
|
||||
root.TagString = TagManagerConstants.UntaggedTag;
|
||||
|
||||
ITransform rootTransform = CreateNewTransform(collection);
|
||||
rootTransform.GameObject_C4P = root;
|
||||
rootTransform.RootOrder_C4 = 0;
|
||||
//Since this Transform has no Father, its RootOrder is zero.
|
||||
|
||||
root.AddComponent(ClassIDType.Transform, rootTransform);
|
||||
|
||||
IGameObject child = CreateNewGameObject(collection);
|
||||
child.Name = "This prefab is a placeholder until AssetRipper improves.";
|
||||
child.SetIsActive(true);
|
||||
child.TagString = TagManagerConstants.UntaggedTag;
|
||||
|
||||
ITransform childTransform = CreateNewTransform(collection);
|
||||
childTransform.GameObject_C4P = child;
|
||||
childTransform.RootOrder_C4 = 0;
|
||||
//Since this Transform is the only child, its RootOrder is zero.
|
||||
|
||||
childTransform.Father_C4P = rootTransform;
|
||||
rootTransform.Children_C4P.Add(childTransform);
|
||||
|
||||
child.AddComponent(ClassIDType.Transform, childTransform);
|
||||
}
|
||||
|
||||
private static IGameObject CreateNewGameObject(ProcessedAssetCollection collection)
|
||||
{
|
||||
return collection.CreateAsset((int)ClassIDType.GameObject, GameObject.Create);
|
||||
}
|
||||
|
||||
private static ITransform CreateNewTransform(ProcessedAssetCollection collection)
|
||||
{
|
||||
return collection.CreateAsset((int)ClassIDType.Transform, Transform.Create);
|
||||
}
|
||||
|
||||
private static void MakeBoxes(Dictionary<IGameObject, GameObjectInfo> infoDictionary, Dictionary<AssetCollection, bool> sceneInfo, out Dictionary<string, Dictionary<GameObjectInfo, List<IGameObject>>> boxes, out HashSet<IGameObject> prefabRoots)
|
||||
{
|
||||
boxes = [];
|
||||
prefabRoots = [];
|
||||
foreach ((IGameObject gameObject, GameObjectInfo info) in infoDictionary)
|
||||
{
|
||||
string name = GameObjectNameCleaner.CleanName(gameObject.Name);
|
||||
boxes.GetOrAdd(name).GetOrAdd(info).Add(gameObject);
|
||||
if (!sceneInfo[gameObject.Collection] && gameObject.IsRoot())
|
||||
{
|
||||
prefabRoots.Add(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void MakeDictionaries(GameBundle gameBundle, out Dictionary<IGameObject, GameObjectInfo> infoDictionary, out Dictionary<AssetCollection, bool> sceneInfo)
|
||||
{
|
||||
infoDictionary = [];
|
||||
sceneInfo = [];
|
||||
foreach (AssetCollection collection in gameBundle.FetchAssetCollections())
|
||||
{
|
||||
sceneInfo.Add(collection, collection.IsScene);
|
||||
GameObjectInfo.AddCollectionToDictionary(collection, infoDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user