forked from gilzoide/godot-lua-pluginscript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpluginscript_class_metadata.lua
More file actions
300 lines (279 loc) · 11.4 KB
/
pluginscript_class_metadata.lua
File metadata and controls
300 lines (279 loc) · 11.4 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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
-- @file pluginscript_class_metadata.lua Helpers for Script/Class metadata (properties, methods, signals)
-- This file is part of Godot Lua PluginScript: https://github.com/gilzoide/godot-lua-pluginscript
--
-- Copyright (C) 2021 Gil Barbosa Reis.
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the “Software”), to
-- deal in the Software without restriction, including without limitation the
-- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-- sell copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-- IN THE SOFTWARE.
--- Scripts metadata.
-- This includes properties, signals and methods.
-- @module script_metadata
-- Map names and types to godot_variant_type
local property_types = {
bool = VariantType.Bool, [bool] = VariantType.Bool,
int = VariantType.Int, [int] = VariantType.Int,
float = VariantType.Real, [float] = VariantType.Real,
String = VariantType.String, [String] = VariantType.String,
string = VariantType.String, [string] = VariantType.String,
Vector2 = VariantType.Vector2, [Vector2] = VariantType.Vector2,
Rect2 = VariantType.Rect2, [Rect2] = VariantType.Rect2,
Vector3 = VariantType.Vector3, [Vector3] = VariantType.Vector3,
Transform2D = VariantType.Transform2D, [Transform2D] = VariantType.Transform2D,
Plane = VariantType.Plane, [Plane] = VariantType.Plane,
Quat = VariantType.Quat, [Quat] = VariantType.Quat,
AABB = VariantType.AABB, [AABB] = VariantType.AABB,
Basis = VariantType.Basis, [Basis] = VariantType.Basis,
Transform = VariantType.Transform, [Transform] = VariantType.Transform,
Color = VariantType.Color, [Color] = VariantType.Color,
NodePath = VariantType.NodePath, [NodePath] = VariantType.NodePath,
RID = VariantType.RID, [RID] = VariantType.RID,
Object = VariantType.Object, [Object] = VariantType.Object,
Dictionary = VariantType.Dictionary, [Dictionary] = VariantType.Dictionary,
Array = VariantType.Array, [Array] = VariantType.Array,
PoolByteArray = VariantType.PoolByteArray, [PoolByteArray] = VariantType.PoolByteArray,
PoolIntArray = VariantType.PoolIntArray, [PoolIntArray] = VariantType.PoolIntArray,
PoolRealArray = VariantType.PoolRealArray, [PoolRealArray] = VariantType.PoolRealArray,
PoolStringArray = VariantType.PoolStringArray, [PoolStringArray] = VariantType.PoolStringArray,
PoolVector2Array = VariantType.PoolVector2Array, [PoolVector2Array] = VariantType.PoolVector2Array,
PoolVector3Array = VariantType.PoolVector3Array, [PoolVector3Array] = VariantType.PoolVector3Array,
PoolColorArray = VariantType.PoolColorArray, [PoolColorArray] = VariantType.PoolColorArray,
}
local property_initializer_for_type = {
[VariantType.Bool] = function(default_value)
return default_value or false
end,
[VariantType.Int] = function(default_value)
return default_value or 0
end,
[VariantType.Real] = function(default_value)
return default_value or 0
end,
[VariantType.String] = function(default_value)
return default_value and String(default_value) or String()
end,
[VariantType.Vector2] = function(default_value)
return Vector2(default_value)
end,
[VariantType.Rect2] = function(default_value)
return Rect2(default_value)
end,
[VariantType.Vector3] = function(default_value)
return Vector3(default_value)
end,
[VariantType.Transform2D] = function(default_value)
return Transform2D(default_value)
end,
[VariantType.Plane] = function(default_value)
return Plane(default_value)
end,
[VariantType.Quat] = function(default_value)
return Quat(default_value)
end,
[VariantType.AABB] = function(default_value)
return AABB(default_value)
end,
[VariantType.Basis] = function(default_value)
return Basis(default_value)
end,
[VariantType.Transform] = function(default_value)
return Transform(default_value)
end,
[VariantType.Color] = function(default_value)
return Color(default_value)
end,
[VariantType.NodePath] = function(default_value)
return NodePath(default_value)
end,
[VariantType.RID] = function(default_value)
return RID(default_value)
end,
[VariantType.Object] = function(default_value)
return default_value or Object.null
end,
[VariantType.Dictionary] = function(default_value)
return Dictionary(default_value)
end,
[VariantType.Array] = function(default_value)
return default_value and Array.from(default_value) or Array()
end,
[VariantType.PoolByteArray] = function(default_value)
return default_value and PoolByteArray.from(default_value) or PoolByteArray()
end,
[VariantType.PoolIntArray] = function(default_value)
return default_value and PoolIntArray.from(default_value) or PoolIntArray()
end,
[VariantType.PoolRealArray] = function(default_value)
return default_value and PoolRealArray.from(default_value) or PoolRealArray()
end,
[VariantType.PoolStringArray] = function(default_value)
return default_value and PoolStringArray.from(default_value) or PoolStringArray()
end,
[VariantType.PoolVector2Array] = function(default_value)
return default_value and PoolVector2Array.from(default_value) or PoolVector2Array()
end,
[VariantType.PoolVector3Array] = function(default_value)
return default_value and PoolVector3Array.from(default_value) or PoolVector3Array()
end,
[VariantType.PoolColorArray] = function(default_value)
return default_value and PoolColorArray.from(default_value) or PoolColorArray()
end,
}
local function get_property_type(value)
local t = type(value)
if t == 'boolean' then
return VariantType.Bool
elseif t == 'string' then
return VariantType.String
elseif ffi_istype(int, value) then
return VariantType.Int
elseif t == 'number' or tonumber(value) then
return VariantType.Real
elseif t == 'table' then
return VariantType.Dictionary
elseif t == 'cdata' and value.varianttype then
return value.varianttype
end
return VariantType.Nil
end
local Property = {}
local function is_property(value)
return getmetatable(value) == Property
end
local function property_to_dictionary(prop)
local default_value = prop.default_value
local dict = Dictionary {
default_value = default_value,
type = prop.type,
usage = prop.usage,
rset_mode = prop.rset_mode,
hint = prop.hint,
hint_string = prop.hint_string,
}
return dict, default_value
end
--- Adds `metadata` to a property.
-- If `metadata` is not a table, creates a table with this value as `default_value`.
-- The `metadata` table may include the following fields:
--
-- * `default_value` or `default` or `1`: default property value, returned when
-- Object has no other value set for it.
-- If absent, `type` must be given and a default value for the type will be used instead.
-- * `type` or `2`: property type. If absent, it is inferred from `default_value`.
-- May be a `Enumerations.VariantType` (`VariantType.Vector2`), the type directly (`Vector2`),
-- or a Resource class (`AudioStream`)
-- * (*optional*) `get` or `getter`: getter function. May be a string with the method name
-- to be called or any callable value, like functions and tables with a `__call`
-- metamethod.
-- * (*optional*) `set` or `setter`: setter function. May be a string with the method name
-- to be called or any callable value, like functions and tables with a `__call`
-- metamethod.
-- * (*optional*) `hint`: one of `Enumerations.PropertyHint`. Default to `PropertyHint.NONE`.
-- * (*optional*) `hint_string`: the hint text, required for some hints like `RANGE`.
-- * (*optional*) `usage`: one of `Enumerations.PropertyUsage`. Default to `PropertyUsage.NOEDITOR`.
-- * (*optional*) `rset_mode`: one of `Enumerations.RPCMode`. Default to `RPCMode.DISABLED`.
--
-- TODO: accept hints directly (`range = '1,10'`; `enum = 'value1,value2,value3'`; `file = '*.png'`, etc...).
-- @usage
-- MyClass.some_prop = property(42)
-- MyClass.some_prop_with_metadata = property {
-- type = int,
-- set = function(self, value)
-- self.some_prop_with_metadata = value
-- self:emit('some_prop_with_metadata_changed', value)
-- end,
-- hint = PropertyHint.RANGE,
-- hint_text = '1,100',
-- }
-- @param metadata Property default value or metadata table
-- @treturn table
-- @raise If neither default value, type or getter is passed.
-- @see lps_coroutine.lua
function property(metadata)
local prop = setmetatable({}, Property)
local default_value, property_type, getter
if type(metadata) ~= 'table' then
default_value = metadata
property_type = get_property_type(metadata)
else
default_value = metadata.default_value or metadata.default or metadata[1]
local explicit_type = metadata.type or metadata[2]
if is_class_wrapper(explicit_type) then
assert(explicit_type:inherits('Resource'), string_format("Only classes based on Resource are supported as property types, found %q", explicit_type.class_name))
property_type = VariantType.Object
prop.hint = PropertyHint.RESOURCE_TYPE
prop.hint_string = explicit_type.class_name
else
property_type = property_types[explicit_type] or explicit_type or get_property_type(default_value)
prop.hint = metadata.hint
prop.hint_string = metadata.hint_string
end
prop.usage = metadata.usage
prop.rset_mode = metadata.rset_mode
getter = metadata.get or metadata.getter
if is_a_string(getter) then
getter = MethodBindByName:new(getter)
end
local setter = metadata.set or metadata.setter
if is_a_string(setter) then
setter = MethodBindByName:new(setter)
end
prop.setter = setter
end
assert(default_value ~= nil or property_type ~= VariantType.Nil or getter ~= nil, "Expected either default value, type or getter for property")
prop.default_value = default_value
prop.type = property_type
prop.getter = getter
prop.usage = prop.usage or PropertyUsage.NOEDITOR
return prop
end
--- Alias for `property` that always adds `PropertyUsage.EDITOR` to the usage flags.
-- This is a shortcut for creating properties that are exported to the editor.
-- @param metadata Property default value or metadata table
-- @see property
function export(metadata)
local prop = property(metadata)
prop.usage = prop.usage and bor(prop.usage, PropertyUsage.EDITOR) or PropertyUsage.DEFAULT
return prop
end
local Signal = {}
local function is_signal(value)
return getmetatable(value) == Signal
end
local function signal_to_dictionary(sig)
local args = Array()
for i = 1, #sig do
args:append(Dictionary{ name = String(sig[i]) })
end
local dict = Dictionary()
dict.args = args
return dict
end
--- Create a signal table.
-- This is only useful for declaring scripts' signals.
-- @usage
-- MyClass.something_happened = signal()
-- MyClass.something_happened_with_args = signal('arg1', 'arg2', 'etc')
-- @param ... Signal argument names
-- @treturn table
-- @see lps_coroutine.lua
function signal(...)
return setmetatable({ ... }, Signal)
end
local function method_to_dictionary(f)
return Dictionary()
end