2 // GenericComponentStateCaptor.cs
5 // Created by Benjamin Sherratt on 04/05/2021.
6 // Copyright © 2021 SKFX Ltd. All rights reserved.
10 using System.Collections.Generic;
11 using System.Reflection;
14 namespace JurassicTween.Internal {
15 public class GenericComponentStateCaptor : IComponentStateCaptor {
16 struct FieldCaptureInfo {
17 public string animationKeyPath;
18 public MemberInfo[] memberInfoHierarchy;
20 public FieldCaptureInfo(string animationKeyPath, MemberInfo[] memberInfoHierarchy) {
21 this.animationKeyPath = animationKeyPath;
22 this.memberInfoHierarchy = memberInfoHierarchy;
26 static FieldCaptureInfo[] QueryCaptureFields(Type type) {
27 List<FieldCaptureInfo> fieldCaptureInfo = new List<FieldCaptureInfo>();
28 List<string> keyComponents = new List<string>();
29 List<MemberInfo> memberInfoHierarchy = new List<MemberInfo>();
30 QueryCaptureFields(fieldCaptureInfo, type, keyComponents, memberInfoHierarchy);
31 return fieldCaptureInfo.ToArray();
34 static void QueryCaptureFields(List<FieldCaptureInfo> fieldCaptureInfo, Type type, List<string> keyComponents, List<MemberInfo> memberInfoHierarchy) {
35 FieldInfo[] allFieldInfo = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
36 foreach (FieldInfo fieldInfo in allFieldInfo) {
37 if (fieldInfo.IsPublic || fieldInfo.GetCustomAttribute<SerializeField>() != null) {
38 keyComponents.Add(fieldInfo.Name);
39 memberInfoHierarchy.Add(fieldInfo);
41 Type fieldType = fieldInfo.FieldType;
42 if (fieldType.IsAssignableFrom(typeof(float))) {
43 string animationKey = string.Join(".", keyComponents);
44 FieldCaptureInfo info = new FieldCaptureInfo(animationKey, memberInfoHierarchy.ToArray());
45 fieldCaptureInfo.Add(info);
47 QueryCaptureFields(fieldCaptureInfo, fieldType, keyComponents, memberInfoHierarchy);
50 memberInfoHierarchy.RemoveAt(memberInfoHierarchy.Count - 1);
51 keyComponents.RemoveAt(keyComponents.Count - 1);
57 FieldCaptureInfo[] fieldCaptureInformation;
59 public GenericComponentStateCaptor(Type componentType) {
60 this.componentType = componentType;
61 fieldCaptureInformation = QueryCaptureFields(componentType);
64 public ComponentState GetComponentState(Component component) {
65 float[] stateValues = new float[fieldCaptureInformation.Length];
67 for (uint i = 0; i < fieldCaptureInformation.Length; ++i) {
68 ref FieldCaptureInfo fieldCaptureInfo = ref fieldCaptureInformation[i];
69 object instanceScope = component;
70 foreach (MemberInfo memberInfo in fieldCaptureInfo.memberInfoHierarchy) {
71 if ((memberInfo.MemberType & MemberTypes.Field) > 0) {
72 instanceScope = ((FieldInfo)memberInfo).GetValue(instanceScope);
73 } else if ((memberInfo.MemberType & MemberTypes.Property) > 0) {
74 instanceScope = ((PropertyInfo)memberInfo).GetValue(instanceScope);
76 throw new Exception("We shouldn't be here...");
80 float value = (float)instanceScope;
81 stateValues[i] = value;
84 ComponentState state = new ComponentState(stateValues);
88 public ComponentStateDelta GenerateComponentStateDelta(ComponentState startState, ComponentState endState) {
89 Dictionary<string, ComponentStateDelta.Range> rangeByAnimationKey = new Dictionary<string, ComponentStateDelta.Range>();
90 for (uint i = 0; i < fieldCaptureInformation.Length; ++i) {
91 float startValue = startState.values[i];
92 float endValue = endState.values[i];
93 if (startValue != endValue) {
94 ref FieldCaptureInfo fieldCaptureInfo = ref fieldCaptureInformation[i];
95 rangeByAnimationKey[fieldCaptureInfo.animationKeyPath] = new ComponentStateDelta.Range(startValue, endValue);
99 ComponentStateDelta delta = new ComponentStateDelta(rangeByAnimationKey);