Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: ObjectMapping System #636

Closed
wants to merge 9 commits into from
3 changes: 0 additions & 3 deletions Editor/AutomaticConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ internal class TraceAndOptimizeEditor : AvatarGlobalComponentEditorBase
private SerializedProperty _removeUnusedObjects;
private SerializedProperty _preserveEndBone;
private SerializedProperty _mmdWorldCompatibility;
private SerializedProperty _advancedAnimatorParser;
private SerializedProperty _advancedSettings;
private GUIContent _advancedSettingsLabel = new GUIContent();

Expand All @@ -21,7 +20,6 @@ private void OnEnable()
_removeUnusedObjects = serializedObject.FindProperty(nameof(TraceAndOptimize.removeUnusedObjects));
_preserveEndBone = serializedObject.FindProperty(nameof(TraceAndOptimize.preserveEndBone));
_mmdWorldCompatibility = serializedObject.FindProperty(nameof(TraceAndOptimize.mmdWorldCompatibility));
_advancedAnimatorParser = serializedObject.FindProperty(nameof(TraceAndOptimize.advancedAnimatorParser));
_advancedSettings = serializedObject.FindProperty(nameof(TraceAndOptimize.advancedSettings));
}

Expand All @@ -47,7 +45,6 @@ protected override void OnInspectorGUIInner()
{
EditorGUI.indentLevel++;
EditorGUILayout.HelpBox(CL4EE.Tr("TraceAndOptimize:warn:advancedSettings"), MessageType.Warning);
EditorGUILayout.PropertyField(_advancedAnimatorParser);
var iterator = _advancedSettings.Copy();
var enterChildren = true;
while (iterator.NextVisible(enterChildren))
Expand Down
79 changes: 53 additions & 26 deletions Editor/ObjectMapping/AnimationObjectMapper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Anatawa12.AvatarOptimizer.Processors.TraceAndOptimizes;
using JetBrains.Annotations;
using UnityEditor;
using UnityEngine;
Expand Down Expand Up @@ -93,7 +94,7 @@ public string MapPath(string srcPath, Type type)

if (componentInfo != null)
{
var component = EditorUtility.InstanceIDToObject(componentInfo.MergedInto) as Component;
var component = new ComponentOrGameObject(EditorUtility.InstanceIDToObject(componentInfo.MergedInto));
// there's mapping about component.
// this means the component is merged or some prop has mapping
if (!component) return null; // this means removed.
Expand All @@ -106,57 +107,83 @@ public string MapPath(string srcPath, Type type)
else
{
// The component is not merged & no prop mapping so process GameObject mapping

if (type != typeof(GameObject))
{
var component = EditorUtility.InstanceIDToObject(instanceId) as Component;
if (!component) return null; // this means removed
}
var component = EditorUtility.InstanceIDToObject(instanceId);
if (!component) return null; // this means removed

if (gameObjectInfo.NewPath == null) return null;
return gameObjectInfo.NewPath;
}
}

public EditorCurveBinding MapBinding(EditorCurveBinding binding)
[CanBeNull]
public EditorCurveBinding[] MapBinding(EditorCurveBinding binding)
{
var gameObjectInfo = GetGameObjectInfo(binding.path);
if (gameObjectInfo == null) return binding;
if (gameObjectInfo == null)
return null;
var (instanceId, componentInfo) = gameObjectInfo.GetComponentByType(binding.type);

if (componentInfo != null)
{
var component = EditorUtility.InstanceIDToObject(componentInfo.MergedInto) as Component;
// there's mapping about component.
// this means the component is merged or some prop has mapping
if (!component) return default; // this means removed.

var newPath = Utils.RelativePath(_rootGameObject.transform, component.transform);
if (newPath == null) return default; // this means moved to out of the animator scope

binding.path = newPath;

if (componentInfo.PropertyMapping.TryGetValue(binding.propertyName, out var newProp))
{
if (newProp == null) return default;
binding.propertyName = newProp;
// there are mapping for property
var curveBindings = new EditorCurveBinding[newProp.AllCopiedTo.Length];
var copiedToIndex = 0;
for (var i = 0; i < newProp.AllCopiedTo.Length; i++)
{
var descriptor = newProp.AllCopiedTo[copiedToIndex++];
var component = new ComponentOrGameObject(EditorUtility.InstanceIDToObject(descriptor.InstanceId));
// this means removed.
if (!component)
{
copiedToIndex -= 1;
continue;
}

var newPath = Utils.RelativePath(_rootGameObject.transform, component.transform);

// this means moved to out of the animator scope
// TODO: add warning
if (newPath == null) return Array.Empty<EditorCurveBinding>();

binding.path = newPath;
binding.type = descriptor.Type;
binding.propertyName = descriptor.Name;
curveBindings[i] = binding; // copy
}

if (copiedToIndex != curveBindings.Length)
return curveBindings.AsSpan().Slice(0, copiedToIndex).ToArray();
return curveBindings;
}
else
{
var component = new ComponentOrGameObject(EditorUtility.InstanceIDToObject(componentInfo.MergedInto));
if (!component) return Array.Empty<EditorCurveBinding>(); // this means removed.

var newPath = Utils.RelativePath(_rootGameObject.transform, component.transform);
if (newPath == null) return Array.Empty<EditorCurveBinding>(); // this means moved to out of the animator scope
if (binding.path == newPath) return null;
binding.path = newPath;
return new []{ binding };
}
}
else
{
// The component is not merged & no prop mapping so process GameObject mapping

if (binding.type != typeof(GameObject))
{
var component = EditorUtility.InstanceIDToObject(instanceId) as Component;
if (!component) return default; // this means removed
}
var component = EditorUtility.InstanceIDToObject(instanceId);
if (!component) return Array.Empty<EditorCurveBinding>(); // this means removed

if (gameObjectInfo.NewPath == null) return default;
if (gameObjectInfo.NewPath == null) return Array.Empty<EditorCurveBinding>();
if (binding.path == gameObjectInfo.NewPath) return null;
binding.path = gameObjectInfo.NewPath;
return new[] { binding };
}

return binding;
}
}
}
65 changes: 63 additions & 2 deletions Editor/ObjectMapping/ObjectMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ public BeforeGameObjectTree(GameObject gameObject)
}
}

componentByType[typeof(GameObject)] = InstanceId;

ComponentInstanceIdByType = componentByType;
}
}
Expand All @@ -103,9 +105,10 @@ class ComponentInfo
public readonly int InstanceId;
public readonly int MergedInto;
public readonly Type Type;
public readonly IReadOnlyDictionary<string, string> PropertyMapping;
public readonly IReadOnlyDictionary<string, MappedPropertyInfo> PropertyMapping;

public ComponentInfo(int instanceId, int mergedInto, Type type, IReadOnlyDictionary<string, string> propertyMapping)
public ComponentInfo(int instanceId, int mergedInto, Type type,
IReadOnlyDictionary<string, MappedPropertyInfo> propertyMapping)
{
InstanceId = instanceId;
MergedInto = mergedInto;
Expand All @@ -114,6 +117,64 @@ public ComponentInfo(int instanceId, int mergedInto, Type type, IReadOnlyDiction
}
}

readonly struct PropertyDescriptor : IEquatable<PropertyDescriptor>
{
public static readonly PropertyDescriptor Removed = default;
public readonly int InstanceId;
[NotNull] public readonly Type Type;
[NotNull] public readonly string Name;

public PropertyDescriptor(int instanceId, Type type, string name)
{
InstanceId = instanceId;
Type = type;
Name = name;
}

public override int GetHashCode()
{
unchecked
{
var hashCode = InstanceId;
hashCode = (hashCode * 397) ^ Type.GetHashCode();
hashCode = (hashCode * 397) ^ Name.GetHashCode();
return hashCode;
}
}

public bool Equals(PropertyDescriptor other) =>
InstanceId == other.InstanceId && Type == other.Type && Name == other.Name;
public override bool Equals(object obj) => obj is PropertyDescriptor other && Equals(other);
public static bool operator ==(PropertyDescriptor left, PropertyDescriptor right) => left.Equals(right);
public static bool operator !=(PropertyDescriptor left, PropertyDescriptor right) => !left.Equals(right);
}

readonly struct MappedPropertyInfo
{
public static readonly MappedPropertyInfo Removed = default;
public readonly PropertyDescriptor MappedProperty;
private readonly PropertyDescriptor[] _copiedTo;

public PropertyDescriptor[] AllCopiedTo => _copiedTo ?? Array.Empty<PropertyDescriptor>();

public MappedPropertyInfo(PropertyDescriptor property, PropertyDescriptor[] copiedTo)
{
MappedProperty = property;
_copiedTo = copiedTo;
}

public MappedPropertyInfo(int mappedInstanceId, Type mappedType, string mappedName) : this(
new PropertyDescriptor(mappedInstanceId, mappedType, mappedName))
{
}

public MappedPropertyInfo(PropertyDescriptor property)
{
MappedProperty = property;
_copiedTo = new[] { property };
}
}

static class VProp
{
private const string ExtraProps = "AvatarOptimizerExtraProps";
Expand Down
Loading
Loading