]> git.bts.cx Git - jurassic-tween.git/blob - Scripts/Runtime/Internal/GenericComponentStateCaptor.cs
Updated licence and some notes on the readme
[jurassic-tween.git] / Scripts / Runtime / Internal / GenericComponentStateCaptor.cs
1 //
2 // GenericComponentStateCaptor.cs
3 // JurassicTween
4 //
5 // Created by Benjamin Sherratt on 04/05/2021.
6 // Copyright © 2021 SKFX Ltd. All rights reserved.
7 //
8
9 using System;
10 using System.Collections.Generic;
11 using System.Reflection;
12 using UnityEngine;
13
14 namespace JurassicTween.Internal {
15     public class GenericComponentStateCaptor : IComponentStateCaptor {
16         struct FieldCaptureInfo {
17             public string animationKeyPath;
18             public MemberInfo[] memberInfoHierarchy;
19
20             public FieldCaptureInfo(string animationKeyPath, MemberInfo[] memberInfoHierarchy) {
21                 this.animationKeyPath = animationKeyPath;
22                 this.memberInfoHierarchy = memberInfoHierarchy;
23             }
24         }
25
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();
32         }
33
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);
40
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);
46                     } else {
47                         QueryCaptureFields(fieldCaptureInfo, fieldType, keyComponents, memberInfoHierarchy);
48                     }
49
50                     memberInfoHierarchy.RemoveAt(memberInfoHierarchy.Count - 1);
51                     keyComponents.RemoveAt(keyComponents.Count - 1);
52                 }
53             }
54         }
55
56         Type componentType;
57         FieldCaptureInfo[] fieldCaptureInformation;
58
59         public GenericComponentStateCaptor(Type componentType) {
60             this.componentType = componentType;
61             fieldCaptureInformation = QueryCaptureFields(componentType);
62         }
63
64         public ComponentState GetComponentState(Component component) {
65             float[] stateValues = new float[fieldCaptureInformation.Length];
66
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);
75                     } else {
76                         throw new Exception("We shouldn't be here...");
77                     }
78                 }
79
80                 float value = (float)instanceScope;
81                 stateValues[i] = value;
82             }
83
84             ComponentState state = new ComponentState(stateValues);
85             return state;
86         }
87
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);
96                 }
97             }
98
99             ComponentStateDelta delta = new ComponentStateDelta(rangeByAnimationKey);
100             return delta;
101         }
102     }
103 }