Elin Decompiled Documentation EA 23.343.5 Nightly
Loading...
Searching...
No Matches
ElinGameIOPropertyAttribute.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Linq.Expressions;
5using System.Reflection;
6using Newtonsoft.Json.Linq;
7using UnityEngine;
8
9[AttributeUsage(AttributeTargets.Property)]
11{
12 private static bool _registered;
13
14 private static readonly Dictionary<string, (PropertyInfo property, Func<object> getter, Action<object> setter)> _contextVars = new Dictionary<string, (PropertyInfo, Func<object>, Action<object>)>();
15
16 public string ChunkName { get; }
17
18 public ElinGameIOPropertyAttribute(string chunkName)
19 {
20 ChunkName = chunkName;
21 }
22
23 public override void Register(PropertyInfo property)
24 {
25 if (!_registered)
26 {
27 BaseModManager.SubscribeEvent<GameIOContext>("elin.game.post_load", LoadGameIOProperty);
28 BaseModManager.SubscribeEvent<GameIOContext>("elin.game.post_save", SaveGameIOProperty);
29 _registered = true;
30 }
31 MethodInfo getMethod = property.GetMethod;
32 MethodInfo setMethod = property.SetMethod;
33 if (!(getMethod == null) && !(setMethod == null) && getMethod.IsStatic && setMethod.IsStatic)
34 {
35 Func<object> item = CreateGetterDelegate(getMethod);
36 Action<object> item2 = CreateSetterDelegate(setMethod);
37 Type declaringType = property.DeclaringType;
38 _contextVars[declaringType.FullName + ":" + ChunkName] = (property, item, item2);
39 }
40 }
41
42 private static Func<object> CreateGetterDelegate(MethodInfo method)
43 {
44 return Expression.Lambda<Func<object>>(Expression.Convert(Expression.Call(method), typeof(object)), Array.Empty<ParameterExpression>()).Compile();
45 }
46
47 private static Action<object> CreateSetterDelegate(MethodInfo method)
48 {
49 Type parameterType = method.GetParameters()[0].ParameterType;
50 ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "obj");
51 UnaryExpression arg = Expression.Convert(parameterExpression, parameterType);
52 return Expression.Lambda<Action<object>>(Expression.Call(method, arg), new ParameterExpression[1] { parameterExpression }).Compile();
53 }
54
55 private static void LoadGameIOProperty(GameIOContext context)
56 {
57 if (!context.Load<Dictionary<string, object>>("context_vars", out var data))
58 {
59 data = new Dictionary<string, object>();
60 }
61 KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)>[] array = _contextVars.ToArray();
62 foreach (KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)> keyValuePair in array)
63 {
64 keyValuePair.Deconstruct(out var key, out var value);
65 (PropertyInfo, Func<object>, Action<object>) tuple = value;
66 string text = key;
67 var (propertyInfo, _, action) = tuple;
68 try
69 {
70 string key2 = propertyInfo.DeclaringType.FullName + ":" + text;
71 object valueOrDefault = data.GetValueOrDefault(key2);
72 action(CoerceValue(valueOrDefault, propertyInfo.PropertyType));
73 }
74 catch (Exception arg)
75 {
76 Debug.LogError($"#io failed to populate context var {text}\n{arg}");
77 }
78 }
79 static object CoerceValue(object obj, Type type)
80 {
81 if (obj is JToken jToken)
82 {
83 return jToken.ToObject(type);
84 }
85 if (obj == null)
86 {
87 return type.IsValueType ? Activator.CreateInstance(type) : null;
88 }
89 object result;
90 return DynamicReflection.TryCoerce(obj, type, out result) ? result : obj;
91 }
92 }
93
94 private static void SaveGameIOProperty(GameIOContext context)
95 {
96 Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
97 KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)>[] array = _contextVars.ToArray();
98 foreach (KeyValuePair<string, (PropertyInfo, Func<object>, Action<object>)> keyValuePair in array)
99 {
100 keyValuePair.Deconstruct(out var key, out var value);
101 (PropertyInfo, Func<object>, Action<object>) tuple = value;
102 string text = key;
103 var (propertyInfo, func, _) = tuple;
104 try
105 {
106 object value2 = func();
107 string key2 = propertyInfo.DeclaringType.FullName + ":" + text;
108 dictionary[key2] = value2;
109 }
110 catch (Exception arg)
111 {
112 Debug.LogError($"#io failed to save context var {text}\n{arg}");
113 }
114 }
115 context.Save("context_vars", dictionary);
116 }
117}
static void SubscribeEvent(string eventId, Action< object > handler)
static Func< object > CreateGetterDelegate(MethodInfo method)
override void Register(PropertyInfo property)
static readonly Dictionary< string,(PropertyInfo property, Func< object > getter, Action< object > setter)> _contextVars
static void SaveGameIOProperty(GameIOContext context)
static Action< object > CreateSetterDelegate(MethodInfo method)
static void LoadGameIOProperty(GameIOContext context)