Skip to content

Commit 71fb8ab

Browse files
committed
WIP OptionsContext and GameMenu
1 parent 10f80d5 commit 71fb8ab

File tree

5 files changed

+493
-175
lines changed

5 files changed

+493
-175
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
-- Category / Group / Section
2+
3+
-- OptionType
4+
local optionType : OptionType = {
5+
InputBox = 0,
6+
Checkbox = 1,
7+
Slider = 2,
8+
ComboBox = 3,
9+
}
10+
OptionType = optionType;
11+
12+
-- OptionCategory
13+
local optionCategoryType : OptionCategoryType = {
14+
Gameplay = "Gameplay",
15+
Keybindings = "Keybindings",
16+
Accessibility = "Accessibility",
17+
System = "System",
18+
}
19+
OptionCategoryType = optionCategoryType;
20+
21+
-- Option
22+
type Option =
23+
{
24+
name : string,
25+
type : OptionType,
26+
27+
defaultValue : any,
28+
value : any,
29+
}
30+
31+
-- OptionsSection
32+
type OptionsSection =
33+
{
34+
name : string,
35+
options : LookupTable<Option>,
36+
}
37+
38+
-- OptionsGroup
39+
type OptionsGroup =
40+
{
41+
name : string,
42+
sections : LookupTable<OptionsSection>,
43+
}
44+
45+
-- OptionsCategory
46+
type OptionsCategory =
47+
{
48+
name : string,
49+
groups : LookupTable<OptionsGroup>,
50+
}
51+
52+
-- Context
53+
type OptionsContext =
54+
{
55+
categories : LookupTable<OptionsCategory>,
56+
}
57+
58+
-- LookupTable
59+
type LookupTable<T> = {
60+
nameToIndex : { [string]: number },
61+
list : { T },
62+
}
63+
64+
-- Metatables
65+
local OptionMetatable = {
66+
Get = function(self : Option) : any
67+
return self.value;
68+
end,
69+
GetDefault = function(self : Option) : any
70+
return self.defaultValue;
71+
end,
72+
Set = function(self : Option, value : any) : ()
73+
self.value = value;
74+
end,
75+
Reset = function(self : Option) : ()
76+
self.value = self.defaultValue;
77+
end,
78+
}
79+
OptionMetatable.__index = OptionMetatable
80+
81+
local LookupTableMetatable = {
82+
Get = function(self : LookupTable<any>, name : string) : number
83+
local index = self.nameToIndex[name];
84+
if (index == nil) then
85+
-- Create a new entry
86+
local value = { name = name };
87+
table.insert(self.list, value);
88+
index = #self.list;
89+
self.nameToIndex[name] = index;
90+
end
91+
92+
return index;
93+
end,
94+
Has = function(self : LookupTable<any>, name : string) : boolean
95+
return self.nameToIndex[name] ~= nil;
96+
end,
97+
}
98+
LookupTableMetatable.__index = LookupTableMetatable;
99+
100+
local SectionMetatable = {
101+
GetOption = function(self : OptionsSection, name : string) : Option
102+
if (not self.options:Has(name)) then
103+
error(`Section {self.name} does not have option {name}`, 2);
104+
end
105+
106+
-- Return existing object
107+
local index = self.options:Get(name);
108+
return self.options.list[index];
109+
end,
110+
RegisterOption = function(self : OptionsSection, name : string, defaultValue : any, type : OptionType) : Option
111+
if (self.options:Has(name)) then
112+
error(`Section {self.name} already has option {name}`, 2);
113+
end
114+
115+
local index = self.options:Get(name);
116+
local object = self.options.list[index];
117+
object.name = name;
118+
object.type = type;
119+
object.defaultValue = defaultValue;
120+
object.value = defaultValue;
121+
setmetatable(object, OptionMetatable);
122+
123+
return object;
124+
end,
125+
}
126+
SectionMetatable.__index = SectionMetatable;
127+
setmetatable(SectionMetatable, LookupTableMetatable);
128+
129+
local GroupMetatable = {
130+
Get = function(self : OptionsGroup, name : string) : OptionsSection
131+
if (not self.sections:Has(name)) then
132+
local index = self.sections:Get(name);
133+
local object = self.sections.list[index];
134+
object.options = {
135+
nameToIndex = {},
136+
list = {},
137+
};
138+
139+
setmetatable(object, SectionMetatable);
140+
setmetatable(object.options, LookupTableMetatable);
141+
return object;
142+
end
143+
144+
-- Return existing object
145+
local index = self.sections:Get(name);
146+
return self.sections.list[index];
147+
end,
148+
}
149+
GroupMetatable.__index = GroupMetatable;
150+
setmetatable(GroupMetatable, LookupTableMetatable);
151+
152+
local CategoryMetatable = {
153+
Get = function(self : OptionsCategory, name : string) : OptionsGroup
154+
if (not self.groups:Has(name)) then
155+
local index = self.groups:Get(name);
156+
local object = self.groups.list[index];
157+
object.sections = {
158+
nameToIndex = {},
159+
list = {},
160+
};
161+
162+
setmetatable(object, GroupMetatable);
163+
setmetatable(object.sections, LookupTableMetatable);
164+
return object;
165+
end
166+
167+
-- Return existing object
168+
local index = self.groups:Get(name);
169+
return self.groups.list[index];
170+
end,
171+
}
172+
CategoryMetatable.__index = CategoryMetatable;
173+
setmetatable(CategoryMetatable, LookupTableMetatable);
174+
175+
local ContextMetatable = {
176+
GetCategory = function(self : OptionsContext, optionCategory : OptionCategoryType) : OptionsCategory
177+
if (not self:Has(optionCategory)) then
178+
local index = LookupTableMetatable.Get(self.categories, optionCategory);
179+
local object = self.categories.list[index];
180+
object.groups = {
181+
nameToIndex = {},
182+
list = {},
183+
};
184+
185+
setmetatable(object, CategoryMetatable);
186+
setmetatable(object.groups, LookupTableMetatable);
187+
return object;
188+
end
189+
190+
-- Return existing object
191+
local index = LookupTableMetatable.Get(self.categories, optionCategory);
192+
return self.categories.list[index];
193+
end,
194+
GetCategories = function(self : OptionsContext) : { OptionsCategory }
195+
return self.categories.list;
196+
end,
197+
Has = function(self : OptionsContext, name : string) : boolean
198+
return self.categories.nameToIndex[name] ~= nil;
199+
end,
200+
}
201+
ContextMetatable.__index = ContextMetatable;
202+
203+
local optionsContext : OptionsContext = {
204+
categories = {
205+
nameToIndex = {},
206+
list = {},
207+
}
208+
};
209+
210+
-- This might look ugly but it's needed to make the context global and not as a copy
211+
__global_optionsContext = optionsContext;
212+
setmetatable(__global_optionsContext, ContextMetatable);
213+
214+
__global_optionsContext:GetCategory(OptionCategoryType.Gameplay);
215+
__global_optionsContext:GetCategory(OptionCategoryType.Keybindings);
216+
__global_optionsContext:GetCategory(OptionCategoryType.Accessibility);
217+
__global_optionsContext:GetCategory(OptionCategoryType.System);
218+
219+
return __global_optionsContext;
220+
221+
-- Usage:
222+
--local optionCategory = OptionsContext:GetCategory(OptionCategoryType.Gameplay);
223+
--local optionGroup = optionCategory:Get("Nameplates");
224+
--local optionSection = optionGroup:Get("General");
225+
--local enabledOption = optionSection:Get("Enabled"); -- ERROR
226+
--local enabledOption = optionSection.RegisterOption("Enabled", true, OptionType.Checkbox););
227+
--local isEnabled = enabledOption:Get();

Source/Resources/Scripts/Types.def

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,4 +377,22 @@ declare Container :
377377
{
378378
RequestSwapSlots : ((containerIndex : number, srcSlotIndex : number, destSlotIndex : number) -> boolean),
379379
GetContainerItems : ((containerIndex : number) -> { ContainerItemEventData }),
380-
}
380+
}
381+
382+
type OptionType =
383+
{
384+
InputBox : number,
385+
Checkbox : number,
386+
Slider : number,
387+
ComboBox : number,
388+
}
389+
declare OptionType : OptionType;
390+
391+
type OptionCategoryType =
392+
{
393+
Gameplay : string,
394+
Keybindings : string,
395+
Accessibility : string,
396+
System : string,
397+
}
398+
declare OptionCategoryType : OptionCategoryType;

0 commit comments

Comments
 (0)