Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/object/make_virtuals.py
9902 views
1
script_call = """ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\
2
if (_script_instance) {\\
3
Callable::CallError ce;\\
4
$CALLSIARGS\\
5
$CALLSIBEGIN_script_instance->callp(_gdvirtual_##$VARNAME##_sn, $CALLSIARGPASS, ce);\\
6
if (ce.error == Callable::CallError::CALL_OK) {\\
7
$CALLSIRET\\
8
return true;\\
9
}\\
10
}"""
11
12
script_has_method = """ScriptInstance *_script_instance = ((Object *)(this))->get_script_instance();\\
13
if (_script_instance && _script_instance->has_method(_gdvirtual_##$VARNAME##_sn)) {\\
14
return true;\\
15
}"""
16
17
proto = """#define GDVIRTUAL$VER($ALIAS $RET m_name $ARG)\\
18
mutable void *_gdvirtual_##$VARNAME = nullptr;\\
19
_FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_call($CALLARGS) $CONST {\\
20
static const StringName _gdvirtual_##$VARNAME##_sn = StringName(#m_name, true);\\
21
$SCRIPTCALL\\
22
if (_get_extension()) {\\
23
if (unlikely(!_gdvirtual_##$VARNAME)) {\\
24
MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
25
uint32_t hash = mi.get_compatibility_hash();\\
26
_gdvirtual_##$VARNAME = nullptr;\\
27
if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
28
_gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
29
} else if (_get_extension()->get_virtual2) {\\
30
_gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
31
}\\
32
_GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
33
_GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME);\\
34
if (_gdvirtual_##$VARNAME == nullptr) {\\
35
_gdvirtual_##$VARNAME = reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR);\\
36
}\\
37
}\\
38
if (_gdvirtual_##$VARNAME != reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\
39
$CALLPTRARGS\\
40
$CALLPTRRETDEF\\
41
if (_get_extension()->call_virtual_with_data) {\\
42
_get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\
43
$CALLPTRRET\\
44
} else {\\
45
((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\
46
$CALLPTRRET\\
47
}\\
48
return true;\\
49
}\\
50
}\\
51
$REQCHECK\\
52
$RVOID\\
53
return false;\\
54
}\\
55
_FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_overridden() const {\\
56
static const StringName _gdvirtual_##$VARNAME##_sn = StringName(#m_name, true);\\
57
$SCRIPTHASMETHOD\\
58
if (_get_extension()) {\\
59
if (unlikely(!_gdvirtual_##$VARNAME)) {\\
60
MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
61
uint32_t hash = mi.get_compatibility_hash();\\
62
_gdvirtual_##$VARNAME = nullptr;\\
63
if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
64
_gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
65
} else if (_get_extension()->get_virtual2) {\\
66
_gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
67
}\\
68
_GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
69
_GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME);\\
70
if (_gdvirtual_##$VARNAME == nullptr) {\\
71
_gdvirtual_##$VARNAME = reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR);\\
72
}\\
73
}\\
74
if (_gdvirtual_##$VARNAME != reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\
75
return true;\\
76
}\\
77
}\\
78
return false;\\
79
}\\
80
_FORCE_INLINE_ static MethodInfo _gdvirtual_##$VARNAME##_get_method_info() {\\
81
MethodInfo method_info;\\
82
method_info.name = #m_name;\\
83
method_info.flags = $METHOD_FLAGS;\\
84
$FILL_METHOD_INFO\\
85
return method_info;\\
86
}
87
88
"""
89
90
91
def generate_version(argcount, const=False, returns=False, required=False, compat=False):
92
s = proto
93
if compat:
94
s = s.replace("$SCRIPTCALL", "")
95
s = s.replace("$SCRIPTHASMETHOD", "")
96
else:
97
s = s.replace("$SCRIPTCALL", script_call)
98
s = s.replace("$SCRIPTHASMETHOD", script_has_method)
99
100
sproto = str(argcount)
101
method_info = ""
102
method_flags = "METHOD_FLAG_VIRTUAL"
103
if returns:
104
sproto += "R"
105
s = s.replace("$RET", "m_ret,")
106
s = s.replace("$RVOID", "(void)r_ret;") # If required, may lead to uninitialized errors
107
s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;")
108
method_info += "method_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n"
109
method_info += "\t\tmethod_info.return_val_metadata = GetTypeInfo<m_ret>::METADATA;"
110
else:
111
s = s.replace("$RET ", "")
112
s = s.replace("\t\t$RVOID\\\n", "")
113
s = s.replace("\t\t\t$CALLPTRRETDEF\\\n", "")
114
115
if const:
116
sproto += "C"
117
method_flags += " | METHOD_FLAG_CONST"
118
s = s.replace("$CONST", "const")
119
else:
120
s = s.replace("$CONST ", "")
121
122
if required:
123
sproto += "_REQUIRED"
124
method_flags += " | METHOD_FLAG_VIRTUAL_REQUIRED"
125
s = s.replace(
126
"$REQCHECK",
127
'ERR_PRINT_ONCE("Required virtual method " + get_class() + "::" + #m_name + " must be overridden before calling.");',
128
)
129
else:
130
s = s.replace("\t\t$REQCHECK\\\n", "")
131
132
if compat:
133
sproto += "_COMPAT"
134
s = s.replace("$COMPAT", "true")
135
s = s.replace("$ALIAS", "m_alias,")
136
s = s.replace("$VARNAME", "m_alias")
137
else:
138
s = s.replace("$COMPAT", "false")
139
s = s.replace("$ALIAS ", "")
140
s = s.replace("$VARNAME", "m_name")
141
142
s = s.replace("$METHOD_FLAGS", method_flags)
143
s = s.replace("$VER", sproto)
144
argtext = ""
145
callargtext = ""
146
callsiargs = ""
147
callsiargptrs = ""
148
callptrargsptr = ""
149
if argcount > 0:
150
argtext += ", "
151
callsiargs = f"Variant vargs[{argcount}] = {{ "
152
callsiargptrs = f"\t\t\tconst Variant *vargptrs[{argcount}] = {{ "
153
callptrargsptr = f"\t\t\tGDExtensionConstTypePtr argptrs[{argcount}] = {{ "
154
callptrargs = ""
155
for i in range(argcount):
156
if i > 0:
157
argtext += ", "
158
callargtext += ", "
159
callsiargs += ", "
160
callsiargptrs += ", "
161
callptrargs += "\t\t\t"
162
callptrargsptr += ", "
163
argtext += f"m_type{i + 1}"
164
callargtext += f"m_type{i + 1} arg{i + 1}"
165
callsiargs += f"arg{i + 1}"
166
callsiargptrs += f"&vargs[{i}]"
167
callptrargs += (
168
f"PtrToArg<m_type{i + 1}>::EncodeT argval{i + 1} = (PtrToArg<m_type{i + 1}>::EncodeT)arg{i + 1};\\\n"
169
)
170
callptrargsptr += f"&argval{i + 1}"
171
if method_info:
172
method_info += "\\\n\t\t"
173
method_info += f"method_info.arguments.push_back(GetTypeInfo<m_type{i + 1}>::get_class_info());\\\n"
174
method_info += f"\t\tmethod_info.arguments_metadata.push_back(GetTypeInfo<m_type{i + 1}>::METADATA);"
175
176
if argcount:
177
callsiargs += " };\\\n"
178
callsiargptrs += " };"
179
s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs)
180
s = s.replace("$CALLSIARGPASS", f"(const Variant **)vargptrs, {argcount}")
181
callptrargsptr += " };"
182
s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr)
183
s = s.replace("$CALLPTRARGPASS", "reinterpret_cast<GDExtensionConstTypePtr *>(argptrs)")
184
else:
185
s = s.replace("\t\t\t$CALLSIARGS\\\n", "")
186
s = s.replace("$CALLSIARGPASS", "nullptr, 0")
187
s = s.replace("\t\t\t$CALLPTRARGS\\\n", "")
188
s = s.replace("$CALLPTRARGPASS", "nullptr")
189
190
if returns:
191
if argcount > 0:
192
callargtext += ", "
193
callargtext += "m_ret &r_ret"
194
s = s.replace("$CALLSIBEGIN", "Variant ret = ")
195
s = s.replace("$CALLSIRET", "r_ret = VariantCaster<m_ret>::cast(ret);")
196
s = s.replace("$CALLPTRRETPASS", "&ret")
197
s = s.replace("$CALLPTRRET", "r_ret = (m_ret)ret;")
198
else:
199
s = s.replace("$CALLSIBEGIN", "")
200
s = s.replace("\t\t\t\t$CALLSIRET\\\n", "")
201
s = s.replace("$CALLPTRRETPASS", "nullptr")
202
s = s.replace("\t\t\t\t$CALLPTRRET\\\n", "")
203
204
s = s.replace(" $ARG", argtext)
205
s = s.replace("$CALLARGS", callargtext)
206
if method_info:
207
s = s.replace("$FILL_METHOD_INFO", method_info)
208
else:
209
s = s.replace("\t\t$FILL_METHOD_INFO\\\n", method_info)
210
211
return s
212
213
214
def run(target, source, env):
215
max_versions = 12
216
217
txt = """/* THIS FILE IS GENERATED DO NOT EDIT */
218
#pragma once
219
220
#include "core/object/script_instance.h"
221
222
inline constexpr uintptr_t _INVALID_GDVIRTUAL_FUNC_ADDR = static_cast<uintptr_t>(-1);
223
224
#ifdef TOOLS_ENABLED
225
#define _GDVIRTUAL_TRACK(m_virtual)\\
226
if (_get_extension()->reloadable) {\\
227
VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\
228
tracker->method = (void **)&m_virtual;\\
229
tracker->next = virtual_method_list;\\
230
virtual_method_list = tracker;\\
231
}
232
#else
233
#define _GDVIRTUAL_TRACK(m_virtual)
234
#endif
235
236
#ifndef DISABLE_DEPRECATED
237
#define _GDVIRTUAL_GET_DEPRECATED(m_virtual, m_name_sn, m_compat)\\
238
else if (m_compat || ClassDB::get_virtual_method_compatibility_hashes(get_class_static(), m_name_sn).size() == 0) {\\
239
if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\
240
m_virtual = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &m_name_sn);\\
241
} else if (_get_extension()->get_virtual) {\\
242
m_virtual = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &m_name_sn);\\
243
}\\
244
}
245
#else
246
#define _GDVIRTUAL_GET_DEPRECATED(m_name, m_name_sn, m_compat)
247
#endif
248
249
"""
250
251
for i in range(max_versions + 1):
252
txt += f"/* {i} Arguments */\n\n"
253
txt += generate_version(i, False, False)
254
txt += generate_version(i, False, True)
255
txt += generate_version(i, True, False)
256
txt += generate_version(i, True, True)
257
txt += generate_version(i, False, False, True)
258
txt += generate_version(i, False, True, True)
259
txt += generate_version(i, True, False, True)
260
txt += generate_version(i, True, True, True)
261
txt += generate_version(i, False, False, False, True)
262
txt += generate_version(i, False, True, False, True)
263
txt += generate_version(i, True, False, False, True)
264
txt += generate_version(i, True, True, False, True)
265
266
with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
267
f.write(txt)
268
269