-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSettingEntryBase.cs
More file actions
271 lines (231 loc) · 11.5 KB
/
SettingEntryBase.cs
File metadata and controls
271 lines (231 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// Based on code made by MarC0 / ManlyMarco
// Copyright 2018 GNU General Public License v3.0
using BepInEx;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace ConfigurationManager
{
/// <summary>
/// Class representing all data about a setting collected by ConfigurationManager.
/// </summary>
public abstract class SettingEntryBase
{
/// <summary>
/// List of values this setting can take
/// </summary>
public object[] AcceptableValues { get; protected set; }
/// <summary>
/// Range of the values this setting can take
/// </summary>
public KeyValuePair<object, object> AcceptableValueRange { get; protected set; }
/// <summary>
/// Should the setting be shown as a percentage (only applies to value range settings)
/// </summary>
public bool? ShowRangeAsPercent { get; protected set; }
/// <summary>
/// Custom setting draw action.
/// Use either CustomDrawer or CustomHotkeyDrawer, using both at the same time leads to undefined behaviour.
/// </summary>
public Action<BepInEx.Configuration.ConfigEntryBase> CustomDrawer { get; private set; }
/// <summary>
/// Custom setting draw action that allows polling keyboard input with the Input class.
/// Use either CustomDrawer or CustomHotkeyDrawer, using both at the same time leads to undefined behaviour.
/// </summary>
public CustomHotkeyDrawerFunc CustomHotkeyDrawer { get; private set; }
/// <summary>
/// Custom setting draw action that allows polling keyboard input with the Input class.
/// </summary>
/// <param name="setting">Setting currently being set, is available</param>
/// <param name="isCurrentlyAcceptingInput">Set this ref parameter to true when you want the current setting drawer to receive Input events. Remember to set it to false after you are done!</param>
public delegate void CustomHotkeyDrawerFunc(BepInEx.Configuration.ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);
/// <summary>
/// Show this setting in the settings screen at all? If false, don't show.
/// </summary>
public bool? Browsable { get; protected set; }
/// <summary>
/// Category the setting is under. Null to be directly under the plugin.
/// </summary>
public string Category { get; protected set; }
/// <summary>
/// If set, a "Default" button will be shown next to the setting to allow resetting to default.
/// </summary>
public object DefaultValue { get; protected set; }
/// <summary>
/// Force the "Reset" button to not be displayed, even if a valid DefaultValue is available.
/// </summary>
public bool HideDefaultButton { get; protected set; }
/// <summary>
/// Force the setting name to not be displayed. Should only be used with a <see cref="CustomDrawer"/> to get more space.
/// Can be used together with <see cref="HideDefaultButton"/> to gain even more space.
/// </summary>
public bool HideSettingName { get; protected set; }
/// <summary>
/// Optional description shown when hovering over the setting
/// </summary>
public string Description { get; protected internal set; }
/// <summary>
/// Name of the setting
/// </summary>
public virtual string DispName { get; protected internal set; }
/// <summary>
/// Plugin this setting belongs to
/// </summary>
public BepInPlugin PluginInfo { get; protected internal set; }
/// <summary>
/// Only allow showing of the value. False whenever possible by default.
/// </summary>
public bool? ReadOnly { get; protected set; }
/// <summary>
/// Type of the variable
/// </summary>
public abstract Type SettingType { get; }
/// <summary>
/// Instance of the plugin that owns this setting
/// </summary>
public BaseUnityPlugin PluginInstance { get; private set; }
/// <summary>
/// Is this setting advanced
/// </summary>
public bool? IsAdvanced { get; internal set; }
/// <summary>
/// Order of the setting on the settings list relative to other settings in a category. 0 by default, lower is higher on the list.
/// </summary>
public int Order { get; protected set; }
/// <summary>
/// Get the value of this setting
/// </summary>
public abstract object Get();
/// <summary>
/// Set the value of this setting
/// </summary>
public void Set(object newVal)
{
if (ReadOnly != true)
SetValue(newVal);
}
/// <summary>
/// Implementation of <see cref="Set"/>
/// </summary>
protected abstract void SetValue(object newVal);
/// <summary>
/// Custom converter from setting type to string for the textbox
/// </summary>
public Func<object, string> ObjToStr { get; internal set; }
/// <summary>
/// Custom converter from string to setting type for the textbox
/// </summary>
public Func<string, object> StrToObj { get; internal set; }
private static readonly PropertyInfo[] MyProperties = typeof(SettingEntryBase).GetProperties(BindingFlags.Instance | BindingFlags.Public);
private static readonly FieldInfo[] MyFields = typeof(SettingEntryBase).GetFields(BindingFlags.Instance | BindingFlags.Public);
internal string SettingID => PluginInfo == null ? "" : $"{PluginInfo.GUID}-{Category}-{DispName}";
internal void SetFromAttributes(object[] attribs, BaseUnityPlugin pluginInstance)
{
PluginInstance = pluginInstance;
PluginInfo = pluginInstance?.Info.Metadata;
if (attribs == null || attribs.Length == 0) return;
foreach (var attrib in attribs)
{
switch (attrib)
{
case null: break;
case DisplayNameAttribute da:
DispName = da.DisplayName;
break;
case CategoryAttribute ca:
Category = ca.Category;
break;
case DescriptionAttribute de:
Description = de.Description;
break;
case DefaultValueAttribute def:
DefaultValue = def.Value;
break;
case ReadOnlyAttribute ro:
ReadOnly = ro.IsReadOnly;
break;
case BrowsableAttribute bro:
Browsable = bro.Browsable;
break;
case Action<SettingEntryBase> newCustomDraw:
CustomDrawer = _ => newCustomDraw(this);
break;
case string str:
switch (str)
{
case "ReadOnly": ReadOnly = true; break;
case "Browsable": Browsable = true; break;
case "Unbrowsable": case "Hidden": Browsable = false; break;
case "Advanced": IsAdvanced = true; break;
}
break;
// Copy attributes from a specially formatted object, currently recommended
default:
var attrType = attrib.GetType();
if (attrType.Name == "ConfigurationManagerAttributes")
{
var otherProperties = attrType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var propertyPair in MyProperties.Join(otherProperties, my => my.Name, other => other.Name, (my, other) => new { my, other }))
{
try
{
var val = propertyPair.other.GetValue(attrib);
if (val != null)
propertyPair.my.SetValue(this, val);
}
catch (Exception ex)
{
ConfigurationManager.LogInfo($"Failed to copy value {propertyPair.my.Name} from provided tag object {attrType.FullName} - " + ex.Message);
}
}
foreach (var propertyPair in MyFields.Join(otherProperties, my => my.Name, other => other.Name, (my, other) => new { my, other }))
{
try
{
var val = propertyPair.other.GetValue(attrib);
if (val != null)
propertyPair.my.SetValue(this, val);
}
catch (Exception ex)
{
ConfigurationManager.LogInfo($"Failed to copy value {propertyPair.my.Name} from provided tag object {attrType.FullName} - " + ex.Message);
}
}
var otherFields = attrType.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var fieldPair in MyFields.Join(otherFields, my => my.Name, other => other.Name, (my, other) => new { my, other }))
{
try
{
var val = fieldPair.other.GetValue(attrib);
if (val != null)
fieldPair.my.SetValue(this, val);
}
catch (Exception ex)
{
ConfigurationManager.LogInfo($"Failed to copy value {fieldPair.my.Name} from provided tag object {attrType.FullName} - " + ex.Message);
}
}
foreach (var fieldPair in MyProperties.Join(otherFields, my => my.Name, other => other.Name, (my, other) => new { my, other }))
{
try
{
var val = fieldPair.other.GetValue(attrib);
if (val != null)
fieldPair.my.SetValue(this, val);
}
catch (Exception ex)
{
ConfigurationManager.LogInfo($"Failed to copy value {fieldPair.my.Name} from provided tag object {attrType.FullName} - " + ex.Message);
}
}
break;
}
return;
}
}
}
public override string ToString() => SettingID;
}
}