Skip to content

Commit

Permalink
Merge pull request #637 from anatawa12/refactor-object-mapping
Browse files Browse the repository at this point in the history
refactor: ObjectMapping System
  • Loading branch information
anatawa12 authored Oct 25, 2023
2 parents 4bf2125 + 7bc727c commit 035233c
Show file tree
Hide file tree
Showing 14 changed files with 510 additions and 246 deletions.
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

0 comments on commit 035233c

Please sign in to comment.