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.Assemblies;
|
||||||
using AssetRipper.Processing.AudioMixers;
|
using AssetRipper.Processing.AudioMixers;
|
||||||
using AssetRipper.Processing.Editor;
|
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.Prefabs;
|
||||||
|
using AssetRipper.Processing.Scenes;
|
||||||
|
using AssetRipper.Processing.ScriptableObject;
|
||||||
|
using AssetRipper.Processing.Textures;
|
||||||
|
|
||||||
namespace AssetRipper.Export.UnityProjects;
|
namespace AssetRipper.Export.UnityProjects;
|
||||||
|
|
||||||
@ -68,10 +67,6 @@ public class ExportHandler
|
|||||||
yield return new AudioMixerProcessor();
|
yield return new AudioMixerProcessor();
|
||||||
yield return new EditorFormatProcessor(Settings.ProcessingSettings.BundledAssetsExportMode);
|
yield return new EditorFormatProcessor(Settings.ProcessingSettings.BundledAssetsExportMode);
|
||||||
//Static mesh separation goes here
|
//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 LightingDataProcessor();//Needs to be after static mesh separation
|
||||||
yield return new PrefabProcessor();
|
yield return new PrefabProcessor();
|
||||||
yield return new SpriteProcessor();
|
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