using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; namespace Dirt { public class ModificationReference { GameObject owner; Object target; public string targetPath { get; private set; } public List targetIndexedPath { get; private set; } public string targetPropertyValue { get; private set; } public bool hasTargetPropertyObjectValue { get; private set; } public Object targetPropertyObjectValue { get; private set; } public bool isNothing { get; private set; } public bool hasValue { get; private set; } public ModificationReference(GameObject owner, Object target) { SetOwner(owner); SetTarget(target); } public void SetOwner(GameObject owner) { this.owner = owner; } public GameObject GetOwner() { if (!owner) { Debug.LogWarning("Reference has no owner"); } return owner; } public List GetOwnerHierarchy() { var scenes = AssetDatabase.FindAssets("t:scene") .Select(AssetDatabase.GUIDToAssetPath) .Select(AssetDatabase.LoadAssetAtPath) .ToList(); var hierarchy = new List(); var current = GetOwner(); if (current) { var scene = current.scene; hierarchy.Add(current); while (current) { var parent = current.transform.parent; if (parent) { current = parent.gameObject; hierarchy.Add(current); } break; } if (scene.IsValid()) { hierarchy.Add(scenes.FirstOrDefault(x => x.name == scene.name)); } } hierarchy.Reverse(); return hierarchy; } public void SetTarget(Object target) { this.target = target; } public Object GetTarget() { if (!target) { Debug.LogWarning($"{(owner ? $"{owner.name}: " : "")}Reference has no target"); } return target; } public SerializedProperty GetTargetProperty(Modification modification) { var target = GetTarget(); if (!target) { return null; } var prefabObject = new SerializedObject(target); return prefabObject.FindProperty(modification.propertyPath); } public int Setup(Modification modification) { var componentIndex = -1; var owner = GetOwner(); var target = GetTarget(); if (owner && target) { var parent = target is Transform transform ? transform : target is GameObject gameObject ? gameObject.transform : (target as Component).transform; var components = parent.GetComponents(); componentIndex = ArrayUtility.IndexOf(components, target); var path = new List(); targetIndexedPath = new List(); while (parent && parent != owner.transform) { path.Insert(0, parent.name); targetIndexedPath.Insert(0, parent.GetSiblingIndex()); parent = parent.parent; } targetPath = string.Join("/", path); } else { targetPath = string.Empty; } var p = GetTargetProperty(modification); string v; if (p is null) { isNothing = true; v = "(nothing)"; } else { hasValue = true; switch (p.type) { case "bool": v = $"{p.boolValue}"; break; case "short": case "int": case "uint": v = $"{p.intValue}"; break; case "float": v = $"{p.floatValue:0.00}"; break; case "string": v = p.stringValue == string.Empty ? $"(empty)" : $"{p.stringValue}"; break; case "Enum": if (0 <= p.enumValueIndex && p.enumValueIndex < p.enumNames.Length) v = $"{p.enumNames[p.enumValueIndex]}"; else v = $"[type Enum] {p.enumValueIndex}"; break; case "ArraySize": v = p.intValue.ToString(); break; default: if (Regex.IsMatch(p.type, @"^PPtr\<.+\>$")) { hasTargetPropertyObjectValue = true; targetPropertyObjectValue = p.objectReferenceValue; v = string.Empty; break; } v = $"[type {p.type}]"; v = $"{v}"; hasValue = false; break; } } targetPropertyValue = v; return componentIndex; } } }