]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/lib/spawnfunc.qh
Merge branch 'master' into terencehill/min_spec_time
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / spawnfunc.qh
1 #pragma once
2
3 /** If this global exists, only functions with spawnfunc_ name prefix qualify as spawn functions */
4 noref bool require_spawnfunc_prefix;
5 .bool spawnfunc_checked;
6
7 // Optional type checking; increases compile time too much to be enabled by default
8 #if 0
9         bool entityfieldassignablefromeditor(int i)
10         {
11                 switch (entityfieldtype(i))
12                 {
13                         case FIELD_STRING:
14                         case FIELD_FLOAT:
15                         case FIELD_VECTOR:
16                                 return true;
17                 }
18                 return false;
19         }
20
21         #define _spawnfunc_checktypes(fld) \
22                 if (s == #fld) \
23                         if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", s);
24 #else
25         #define _spawnfunc_checktypes(fld)
26 #endif
27         #define _spawnfunc_check(fld) \
28                 if (s == #fld) continue;
29
30         noref int __spawnfunc_expecting;
31         noref entity __spawnfunc_expect;
32         noref bool __spawnfunc_unreachable_workaround = true;
33
34     .void(entity) __spawnfunc_constructor;
35     noref IntrusiveList g_spawn_queue;
36
37     #define SPAWNFUNC_INTERNAL_FIELDS(X) \
38         X(string, classname, "spawnfunc") \
39         X(string, target, string_null) \
40         X(string, target2, string_null) \
41         X(string, target3, string_null) \
42         X(string, target4, string_null) \
43         X(string, targetname, string_null) \
44         /**/
45
46     #define X(T, fld, def) .T fld, __spawnfunc_##fld;
47     SPAWNFUNC_INTERNAL_FIELDS(X)
48     #undef X
49
50     void __spawnfunc_defer(entity prototype, void(entity) constructor)
51     {
52         IL_PUSH(g_spawn_queue, prototype);
53         #define X(T, fld, def) { prototype.__spawnfunc_##fld = prototype.fld; prototype.fld = def; }
54         SPAWNFUNC_INTERNAL_FIELDS(X);
55         #undef X
56         prototype.__spawnfunc_constructor = constructor;
57     }
58
59     noref IntrusiveList g_map_entities;
60     #define __spawnfunc_spawn_all() MACRO_BEGIN \
61         g_map_entities = IL_NEW(); \
62         IL_EACH(g_spawn_queue, true, __spawnfunc_spawn(it)); \
63     MACRO_END
64 #ifdef SVQC
65     void _SV_OnEntityPreSpawnFunction(entity this);
66 #endif
67     void __spawnfunc_spawn(entity prototype)
68     {
69         entity e = new(clone);
70         copyentity(prototype, e);
71         IL_PUSH(g_map_entities, e);
72         #define X(T, fld, def) { e.fld = e.__spawnfunc_##fld; e.__spawnfunc_##fld = def; }
73         SPAWNFUNC_INTERNAL_FIELDS(X);
74         #undef X
75 #ifdef SVQC
76         _SV_OnEntityPreSpawnFunction(e);
77         if (wasfreed(e)) {
78             return;
79         }
80 #endif
81         e.__spawnfunc_constructor(e);
82     }
83
84         noref bool __spawnfunc_first;
85
86         #define spawnfunc_1(id) spawnfunc_2(id, FIELDS_UNION)
87         #define spawnfunc_2(id, whitelist) \
88                 void __spawnfunc_##id(entity this); \
89                 [[accumulate]] void spawnfunc_##id(entity this) \
90                 { \
91                     if (!__spawnfunc_first) { \
92                 __spawnfunc_first = true; \
93                 static_init_early(); \
94                     } \
95                     bool dospawn = true; \
96                     if (__spawnfunc_expecting > 1) { __spawnfunc_expecting = false; } \
97                         else if (__spawnfunc_expecting) { \
98                                 /* engine call */ \
99                 if (!g_spawn_queue) { g_spawn_queue = IL_NEW(); } \
100                                 __spawnfunc_expecting = false; \
101                                 this = __spawnfunc_expect; \
102                                 __spawnfunc_expect = NULL; \
103                 dospawn = false; \
104                         } else { \
105                             /* userland call */ \
106                                 assert(this); \
107                         } \
108                         if (!this.sourceLoc) { \
109                                 this.sourceLoc = __FILE__ ":" STR(__LINE__); \
110                         } \
111                         if (!this.spawnfunc_checked) { \
112                                 for (int i = 0, n = numentityfields(); i < n; ++i) { \
113                                         string value = getentityfieldstring(i, this); \
114                                         string s = entityfieldname(i); \
115                                         whitelist(_spawnfunc_checktypes) \
116                                         if (value == "") continue; \
117                                         if (s == "") continue; \
118                                         FIELDS_COMMON(_spawnfunc_check) \
119                                         whitelist(_spawnfunc_check) \
120                                         LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, s, value); \
121                                 } \
122                                 this.spawnfunc_checked = true; \
123                                 if (this) { \
124                     /* not worldspawn, delay spawn */ \
125                     __spawnfunc_defer(this, __spawnfunc_##id); \
126                 } else { \
127                     /* world might not be "worldspawn" */ \
128                     this.__spawnfunc_constructor = __spawnfunc_##id; \
129                 } \
130                         } \
131                         if (dospawn) { __spawnfunc_##id(this); } \
132                         if (__spawnfunc_unreachable_workaround) return; \
133                 } \
134                 void __spawnfunc_##id(entity this)
135
136         #define FIELD_SCALAR(fld, n) \
137                 fld(n)
138         #define FIELD_VEC(fld, n) \
139                 fld(n) \
140                 fld(n##_x) \
141                 fld(n##_y) \
142                 fld(n##_z)
143
144         #define FIELDS_NONE(fld)
145         #define FIELDS_ALL(fld) if (false)
146
147         #define FIELDS_COMMON(fld) \
148                 FIELD_SCALAR(fld, classname) \
149                 FIELD_SCALAR(fld, sourceLoc) \
150                 FIELD_SCALAR(fld, spawnfunc_checked) \
151                 FIELD_VEC(fld, origin) \
152                 /**/
153
154         #define FIELDS_UNION(fld) \
155                 FIELD_SCALAR(fld, Version) \
156                 FIELD_SCALAR(fld, ammo_cells) \
157                 FIELD_SCALAR(fld, ammo_nails) \
158                 FIELD_SCALAR(fld, ammo_rockets) \
159                 FIELD_SCALAR(fld, antiwall_flag) \
160                 FIELD_SCALAR(fld, armorvalue) \
161                 FIELD_SCALAR(fld, atten) \
162                 FIELD_SCALAR(fld, bgmscriptdecay) \
163                 FIELD_SCALAR(fld, bgmscriptsustain) \
164                 FIELD_SCALAR(fld, bgmscript) \
165                 FIELD_SCALAR(fld, button0) \
166                 FIELD_SCALAR(fld, cnt) \
167                 FIELD_SCALAR(fld, colormap) \
168                 FIELD_SCALAR(fld, count) \
169                 FIELD_SCALAR(fld, curvetarget) \
170                 FIELD_SCALAR(fld, cvarfilter) \
171                 FIELD_SCALAR(fld, debrisdamageforcescale) \
172                 FIELD_SCALAR(fld, debrisfadetime) \
173                 FIELD_SCALAR(fld, debrismovetype) \
174                 FIELD_SCALAR(fld, debrisskin) \
175                 FIELD_SCALAR(fld, debristimejitter) \
176                 FIELD_SCALAR(fld, debristime) \
177                 FIELD_SCALAR(fld, debris) \
178                 FIELD_SCALAR(fld, delay) \
179                 FIELD_SCALAR(fld, dmgtime) \
180                 FIELD_SCALAR(fld, dmg) \
181                 FIELD_SCALAR(fld, dmg_edge) \
182                 FIELD_SCALAR(fld, dmg_force) \
183                 FIELD_SCALAR(fld, dmg_radius) \
184                 FIELD_SCALAR(fld, effects) \
185                 FIELD_SCALAR(fld, flags) \
186                 FIELD_SCALAR(fld, fog) \
187                 FIELD_SCALAR(fld, frags) \
188                 FIELD_SCALAR(fld, frame) \
189                 FIELD_SCALAR(fld, gametypefilter) \
190                 FIELD_SCALAR(fld, geomtype) \
191                 FIELD_SCALAR(fld, gravity) \
192                 FIELD_SCALAR(fld, health) \
193                 FIELD_SCALAR(fld, height) \
194                 FIELD_SCALAR(fld, impulse) \
195                 FIELD_SCALAR(fld, killtarget) \
196                 FIELD_SCALAR(fld, lerpfrac) \
197                 FIELD_SCALAR(fld, light_lev) \
198                 FIELD_SCALAR(fld, lip) \
199                 FIELD_SCALAR(fld, loddistance1) \
200                 FIELD_SCALAR(fld, lodmodel1) \
201                 FIELD_SCALAR(fld, ltime) \
202                 FIELD_SCALAR(fld, map) \
203                 FIELD_SCALAR(fld, mdl) \
204                 FIELD_SCALAR(fld, message2) \
205                 FIELD_SCALAR(fld, message) \
206                 FIELD_SCALAR(fld, modelindex) \
207                 FIELD_SCALAR(fld, modelscale) \
208                 FIELD_SCALAR(fld, model) \
209                 FIELD_SCALAR(fld, monsterid) \
210                 FIELD_SCALAR(fld, monster_moveflags) \
211                 FIELD_SCALAR(fld, monster_name) \
212                 FIELD_SCALAR(fld, movetype) \
213                 FIELD_SCALAR(fld, move_movetype) \
214                 FIELD_SCALAR(fld, netname) \
215                 FIELD_SCALAR(fld, nextthink) \
216                 FIELD_SCALAR(fld, noalign) \
217                 FIELD_SCALAR(fld, noise1) \
218                 FIELD_SCALAR(fld, noise2) \
219                 FIELD_SCALAR(fld, noise) \
220                 FIELD_SCALAR(fld, phase) \
221                 FIELD_SCALAR(fld, platmovetype) \
222                 FIELD_SCALAR(fld, race_place) \
223                 FIELD_SCALAR(fld, radius) \
224                 FIELD_SCALAR(fld, respawntimestart) \
225                 FIELD_SCALAR(fld, respawntimejitter) \
226                 FIELD_SCALAR(fld, respawntime) \
227                 FIELD_SCALAR(fld, restriction) \
228                 FIELD_SCALAR(fld, scale) \
229                 FIELD_SCALAR(fld, skin) \
230                 FIELD_SCALAR(fld, solid) \
231                 FIELD_SCALAR(fld, sound1) \
232                 FIELD_SCALAR(fld, sounds) \
233                 FIELD_SCALAR(fld, spawnflags) \
234                 FIELD_SCALAR(fld, spawnmob) \
235                 FIELD_SCALAR(fld, speed) \
236                 FIELD_SCALAR(fld, strength) \
237                 FIELD_SCALAR(fld, style) \
238                 FIELD_SCALAR(fld, target2) \
239                 FIELD_SCALAR(fld, target3) \
240                 FIELD_SCALAR(fld, target4) \
241                 FIELD_SCALAR(fld, targetname) \
242                 FIELD_SCALAR(fld, target) \
243                 FIELD_SCALAR(fld, target_random) \
244                 FIELD_SCALAR(fld, target_range) \
245                 FIELD_SCALAR(fld, team) \
246                 FIELD_SCALAR(fld, turret_scale_health) \
247                 FIELD_SCALAR(fld, turret_scale_range) \
248                 FIELD_SCALAR(fld, turret_scale_respawn) \
249                 FIELD_SCALAR(fld, volume) \
250                 FIELD_SCALAR(fld, wait) \
251                 FIELD_SCALAR(fld, warpzone_fadeend) \
252                 FIELD_SCALAR(fld, warpzone_fadestart) \
253                 FIELD_SCALAR(fld, weapon) \
254                 FIELD_SCALAR(fld, worldtype) \
255                 FIELD_VEC(fld, absmax) \
256                 FIELD_VEC(fld, absmin) \
257                 FIELD_VEC(fld, angles) \
258                 FIELD_VEC(fld, avelocity) \
259                 FIELD_VEC(fld, debrisavelocityjitter) \
260                 FIELD_VEC(fld, debrisvelocity) \
261                 FIELD_VEC(fld, debrisvelocityjitter) \
262                 FIELD_VEC(fld, color) \
263                 FIELD_VEC(fld, mangle) \
264                 FIELD_VEC(fld, maxs) \
265                 FIELD_VEC(fld, mins) \
266                 FIELD_VEC(fld, modelscale_vec) \
267                 FIELD_VEC(fld, velocity) \
268                 /**/
269
270         #define spawnfunc(...) EVAL_spawnfunc(OVERLOAD(spawnfunc, __VA_ARGS__))
271         #define EVAL_spawnfunc(...) __VA_ARGS__