Skip to content

Commit 010e1ad

Browse files
authored
Merge pull request #4 from Phlarx/additional-settings-examples
Additional settings examples
2 parents 47fbfe6 + da4e6b0 commit 010e1ad

File tree

2 files changed

+251
-2
lines changed

2 files changed

+251
-2
lines changed

Diff for: Plugin_SettingsAdvancedTest.as

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#name "Settings advanced example"
2+
#author "Phlarx"
3+
#category "Examples"
4+
5+
/* This plugin demonstrates some techniques for storing
6+
* data with the Settings interface, when the data types
7+
* are not supported by the Setting annotation.
8+
*
9+
* In this demonstration, we will be storing vec3 objects,
10+
* since they are not supported by the Setting annotation
11+
* directly, but they are still simple enough to be a
12+
* good example.
13+
*
14+
* One shortcoming of this example is that it is rather
15+
* cheap and easy to construct vec3 objects on the fly,
16+
* where needed. These techniques are most useful when
17+
* applied to objects that are more expensive to construct.
18+
*
19+
* These examples are not intended to be the bible for
20+
* achieving these effects, but instead a set of ideas and
21+
* inspirations that you can apply to your use case. The
22+
* strategies used here can be mixed and matched, and built
23+
* upon.
24+
*
25+
* Finally, larger data structures may benefit more from
26+
* being stored separately in their own data file, instead
27+
* of being shoehorned into the Settings ini file. Take note
28+
* of this when deciding which strategy is best for your
29+
* specific application.
30+
*/
31+
32+
/* Our goal for each vec3 is to approximate the following
33+
* (invalid) code:
34+
*
35+
* [Setting]
36+
* vec3 Data;
37+
*
38+
* Each example has:
39+
* - a declaration, which defines the objects that we want
40+
* to store.
41+
* - getters and setters which are able to store the object
42+
* into the settings interface, and retrieve it again.
43+
* - accessors and mutators which are the script's normal
44+
* interactions with the objects.
45+
*
46+
* In addition, the third example, called Qux, has a
47+
* separate pair of functions for data conversion. The other
48+
* two examples do their data conversion at the same place as
49+
* one or more of the parts listed above.
50+
*/
51+
52+
/* [[FooColor declaration]]
53+
* The first vec3, Foo, will be stored by creating separate
54+
* entries for each component. This allows the user to set
55+
* these values within the Settings dialog. Since the Setting
56+
* annotation doesn't provide the facilities to automatically
57+
* synchonize the vec3 directly, we'll need to use both
58+
* OnSettingsChanged and OnSettingsLoad to get the updates
59+
* via the Settings interface, as well as manually change the
60+
* component values when the vec3 is updated.
61+
*
62+
* Here, we see each float component declared individually,
63+
* with a Setting annotation for each, followed by the vec3
64+
* declaration.
65+
*/
66+
[Setting min=0.f max=1.f]
67+
float FooR = 1.f;
68+
[Setting min=0.f max=1.f]
69+
float FooG = 0.f;
70+
[Setting min=0.f max=1.f]
71+
float FooB = 0.f;
72+
vec3 FooColor = vec3(FooR, FooG, FooB);
73+
74+
/* [[BarColor declaration]]
75+
* The second vec3, Bar, does not use separated component values,
76+
* and as such, it will not appear in the Settings dialog. As a
77+
* result, we need to only declare the actual vec3 object.
78+
*/
79+
vec3 BarColor = vec3(0.f, 1.f, 0.f);
80+
81+
/* [[QuxColor declaration]]
82+
* The third vec3 is Qux, and like Bar, is does not appear in the
83+
* Settings dialog, and therefore we only need to declare the vec3.
84+
*/
85+
vec3 QuxColor = vec3(0.f, 0.f, 1.f);
86+
87+
/* OnSettingsChanged is called whenever an update occurs within the
88+
* Settings dialog.
89+
*/
90+
void OnSettingsChanged()
91+
{
92+
/* [[FooColor get value from components]]
93+
* Since Foo is the only strategy which exposes the component
94+
* values to the Settings dialog, it is the only one which needs
95+
* to respond to that event. As the vec3 case is rather simple,
96+
* we can just immediately update the component values.
97+
*/
98+
FooColor.x = FooR;
99+
FooColor.y = FooG;
100+
FooColor.z = FooB;
101+
}
102+
103+
/* OnSettingsSave is called when stopping a plugin, which may be
104+
* caused by, for example, reloading the plugin or exiting the
105+
* game.
106+
*
107+
* Note that the settings data is only written to the disk when
108+
* exiting the game, and is cached otherwise.
109+
*/
110+
void OnSettingsSave(Settings::Section& section)
111+
{
112+
/* [[BarColor set value to Settings]]
113+
* Here, we manually set the component values for Bar to its
114+
* component values. In the Settings ini file, this will look
115+
* almost identical to the approach for Foo, but by using this
116+
* route, the components do not appear within the settings menu,
117+
* and we don't need to worry about keeping the values
118+
* synchonized.
119+
*
120+
* As a side effect of doing this ourselves, values identical to
121+
* the default are not omitted from the ini, in contrast to Foo.
122+
*/
123+
section.SetFloat("BarR", BarColor.x);
124+
section.SetFloat("BarG", BarColor.y);
125+
section.SetFloat("BarB", BarColor.z);
126+
127+
/* [[QuxColor set value to Settings]]
128+
* For Qux, we use a similar approach to Bar by setting the
129+
* Settings ini values directly, but in this case we've used a
130+
* conversion method to convert the value of Qux to some data
131+
* type matively handled by the settings interface. In this case,
132+
* we are using a string holding JSON data. The definition of
133+
* writeQux is found near the bottom of this file.
134+
*/
135+
section.SetString("Qux", writeQux(QuxColor));
136+
}
137+
138+
/* OnSettingsLoad is called when starting a plugin, which may be
139+
* caused by, for example, reloading the plugin or launching the
140+
* game.
141+
*
142+
* Note that the settings data is only read from the disk when
143+
* launching the game, and is cached otherwise.
144+
*/
145+
void OnSettingsLoad(Settings::Section& section)
146+
{
147+
/* [[FooColor get value from components]]
148+
* Since OnSettingsChanged is not triggered at plugin startup,
149+
* we replicate the actions for Foo here.
150+
*/
151+
FooColor.x = FooR;
152+
FooColor.y = FooG;
153+
FooColor.z = FooB;
154+
155+
/* [[BarColor get value from Settings]]
156+
* When loading the values from the settings interface, we are
157+
* simply performing the inverse of what we had done in
158+
* OnSettingsSave. Additionally, we can provide default values
159+
* to use for each component, if that component is found to be
160+
* missing.
161+
*/
162+
BarColor.x = section.GetFloat("BarR", 0.f);
163+
BarColor.y = section.GetFloat("BarG", 1.f);
164+
BarColor.z = section.GetFloat("BarB", 0.f);
165+
166+
/* [[QuxColor get value from Settings]]
167+
* In the case of Qux, the default value is the full json
168+
* description of the object, and the result of the Settings
169+
* load is passed through a converter to create the actual
170+
* object that we want. The definition of parseQux is found
171+
* near the bottom of this file.
172+
*/
173+
QuxColor = parseQux(section.GetString("Qux", "{'r':0,'g':0,'b':1}"));
174+
}
175+
176+
void RenderInterface()
177+
{
178+
UI::Begin("Settings Advanced", UI::WindowFlags::AlwaysAutoResize);
179+
180+
/* [[FooColor accesses and mutations]]
181+
* Our strategy for Foo shows real-time updates in the Settings
182+
* dialog, so we need to manually update the individual
183+
* components whenever Foo is updated.
184+
*/
185+
FooColor = UI::InputColor3("Foo Color", FooColor);
186+
FooR = FooColor.x;
187+
FooG = FooColor.y;
188+
FooB = FooColor.z;
189+
190+
/* [[BarColor accesses and mutations]]
191+
* Since our strategy for Bar does not require updating the stored
192+
* values for use in the Settings dialog, we can use both direct
193+
* accesses and mutations.
194+
*/
195+
BarColor = UI::InputColor3("Bar Color", BarColor);
196+
197+
/* [[QuxColor accesses and mutations]]
198+
* Like Bar, for Qux we can use both direct accesses and mutations.
199+
*/
200+
QuxColor = UI::InputColor3("Qux Color", QuxColor);
201+
202+
UI::End();
203+
}
204+
205+
/* [[QuxColor datatype conversion]]
206+
* Where the component decomposition of Foo and Bar are scattered
207+
* in several placed throughout the source, the breakdown for Qux
208+
* is restricted to just the two conversion functions, parseQux and
209+
* writeQux.
210+
*
211+
* This particular implementation makes use of the Json group within
212+
* the Openplanet API, but a similar effect can be achieved with XML,
213+
* a bespoke serialization format, a unique identifier, or any of a
214+
* number of other things.
215+
216+
* We need both directions for this conversion, and so writeQux is
217+
* the inverse operation of parseQux. To say it another way,
218+
* color == parseQux(writeQux(color)).
219+
*/
220+
vec3 parseQux(string json)
221+
{
222+
Json::Value obj = Json::Parse(json);
223+
vec3 color;
224+
color.x = obj.Get("r", 0.f);
225+
color.y = obj.Get("g", 0.f);
226+
color.z = obj.Get("b", 1.f);
227+
return color;
228+
}
229+
230+
string writeQux(vec3 color)
231+
{
232+
Json::Value obj = Json::Object();
233+
obj["r"] = Json::Value(color.x);
234+
obj["g"] = Json::Value(color.y);
235+
obj["b"] = Json::Value(color.z);
236+
return Json::Write(obj);
237+
}

Diff for: Plugin_SettingsTest.as

+14-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
/* This plugin demonstrates how persistent settings can be created and
66
* automatically stored in Openplanet's Settings.ini file.
77
*
8-
* Settings must be either a bool, int, float, or string. More will be
9-
* added in the future if they are deemed necessary.
8+
* Settings must be either a bool, int, float, string, or enum. More
9+
* will be added in the future if they are deemed necessary.
1010
*/
1111

1212
// Each setting can have a name and description, which will be displayed
@@ -58,6 +58,18 @@ string FooTextMultiline = "Foo!\nThere's multiple lines here.";
5858
[Setting password]
5959
string FooTextPassword = "hunter2";
6060

61+
// Enum settings will appear as a drop-down selector in the settings dialog,
62+
// listing each defined enum value.
63+
[Setting]
64+
MyEnum FooEnum = MyEnum::Foo;
65+
66+
enum MyEnum
67+
{
68+
Foo,
69+
Bar,
70+
Baz
71+
}
72+
6173
// Our main routine
6274
void Main()
6375
{

0 commit comments

Comments
 (0)