1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 2012-2016 by John "JTE" Muniz.
4 // Copyright (C) 2012-2020 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file lua_script.c
11 /// \brief Lua scripting basics
12
13 #include "doomdef.h"
14 #include "fastcmp.h"
15 #include "dehacked.h"
16 #include "deh_lua.h"
17 #include "z_zone.h"
18 #include "w_wad.h"
19 #include "p_setup.h"
20 #include "r_state.h"
21 #include "r_sky.h"
22 #include "g_game.h"
23 #include "f_finale.h"
24 #include "byteptr.h"
25 #include "p_saveg.h"
26 #include "p_local.h"
27 #include "p_slopes.h" // for P_SlopeById
28 #include "p_polyobj.h" // polyobj_t, PolyObjects
29 #ifdef LUA_ALLOW_BYTECODE
30 #include "d_netfil.h" // for LUA_DumpFile
31 #endif
32
33 #include "lua_script.h"
34 #include "lua_libs.h"
35 #include "lua_hook.h"
36
37 #include "doomstat.h"
38 #include "g_state.h"
39
40 lua_State *gL = NULL;
41
42 // List of internal libraries to load from SRB2
43 static lua_CFunction liblist[] = {
44 LUA_EnumLib, // global metatable for enums
45 LUA_SOCLib, // A_Action functions, freeslot
46 LUA_BaseLib, // string concatination by +, CONS_Printf, p_local.h stuff (P_InstaThrust, P_Move), etc.
47 LUA_MathLib, // fixed_t and angle_t math functions
48 LUA_HookLib, // hookAdd and hook-calling functions
49 LUA_ConsoleLib, // console command/variable functions and structs
50 LUA_InfoLib, // info.h stuff: mobjinfo_t, mobjinfo[], state_t, states[]
51 LUA_MobjLib, // mobj_t, mapthing_t
52 LUA_PlayerLib, // player_t
53 LUA_SkinLib, // skin_t, skins[]
54 LUA_ThinkerLib, // thinker_t
55 LUA_MapLib, // line_t, side_t, sector_t, subsector_t
56 LUA_TagLib, // tags
57 LUA_PolyObjLib, // polyobj_t
58 LUA_BlockmapLib, // blockmap stuff
59 LUA_HudLib, // HUD stuff
60 NULL
61 };
62
63 // Lua asks for memory using this.
LUA_Alloc(void * ud,void * ptr,size_t osize,size_t nsize)64 static void *LUA_Alloc(void *ud, void *ptr, size_t osize, size_t nsize)
65 {
66 (void)ud;
67 if (nsize == 0) {
68 if (osize != 0)
69 Z_Free(ptr);
70 return NULL;
71 } else
72 return Z_Realloc(ptr, nsize, PU_LUA, NULL);
73 }
74
75 // Panic function Lua calls when there's an unprotected error.
76 // This function cannot return. Lua would kill the application anyway if it did.
LUA_Panic(lua_State * L)77 FUNCNORETURN static int LUA_Panic(lua_State *L)
78 {
79 CONS_Alert(CONS_ERROR,"LUA PANIC! %s\n",lua_tostring(L,-1));
80 I_Error("An unfortunate Lua processing error occurred in the exe itself. This is not a scripting error on your part.");
81 #ifndef __GNUC__
82 return -1;
83 #endif
84 }
85
86 #define LEVELS1 12 // size of the first part of the stack
87 #define LEVELS2 10 // size of the second part of the stack
88
89 // Error handler used with pcall() when loading scripts or calling hooks
90 // Takes a string with the original error message,
91 // appends the traceback to it, and return the result
LUA_GetErrorMessage(lua_State * L)92 int LUA_GetErrorMessage(lua_State *L)
93 {
94 int level = 1;
95 int firstpart = 1; // still before eventual `...'
96 lua_Debug ar;
97
98 lua_pushliteral(L, "\nstack traceback:");
99 while (lua_getstack(L, level++, &ar))
100 {
101 if (level > LEVELS1 && firstpart)
102 {
103 // no more than `LEVELS2' more levels?
104 if (!lua_getstack(L, level + LEVELS2, &ar))
105 level--; // keep going
106 else
107 {
108 lua_pushliteral(L, "\n ..."); // too many levels
109 while (lua_getstack(L, level + LEVELS2, &ar)) // find last levels
110 level++;
111 }
112 firstpart = 0;
113 continue;
114 }
115 lua_pushliteral(L, "\n ");
116 lua_getinfo(L, "Snl", &ar);
117 lua_pushfstring(L, "%s:", ar.short_src);
118 if (ar.currentline > 0)
119 lua_pushfstring(L, "%d:", ar.currentline);
120 if (*ar.namewhat != '\0') // is there a name?
121 lua_pushfstring(L, " in function " LUA_QS, ar.name);
122 else
123 {
124 if (*ar.what == 'm') // main?
125 lua_pushfstring(L, " in main chunk");
126 else if (*ar.what == 'C' || *ar.what == 't')
127 lua_pushliteral(L, " ?"); // C function or tail call
128 else
129 lua_pushfstring(L, " in function <%s:%d>",
130 ar.short_src, ar.linedefined);
131 }
132 lua_concat(L, lua_gettop(L));
133 }
134 lua_concat(L, lua_gettop(L));
135 return 1;
136 }
137
LUA_Call(lua_State * L,int nargs,int nresults,int errorhandlerindex)138 int LUA_Call(lua_State *L, int nargs, int nresults, int errorhandlerindex)
139 {
140 int err = lua_pcall(L, nargs, nresults, errorhandlerindex);
141
142 if (err)
143 {
144 CONS_Alert(CONS_WARNING, "%s\n", lua_tostring(L, -1));
145 lua_pop(L, 1);
146 }
147
148 return err;
149 }
150
151 // Moved here from lib_getenum.
LUA_PushGlobals(lua_State * L,const char * word)152 int LUA_PushGlobals(lua_State *L, const char *word)
153 {
154 if (fastcmp(word,"gamemap")) {
155 lua_pushinteger(L, gamemap);
156 return 1;
157 } else if (fastcmp(word,"udmf")) {
158 lua_pushboolean(L, udmf);
159 return 1;
160 } else if (fastcmp(word,"maptol")) {
161 lua_pushinteger(L, maptol);
162 return 1;
163 } else if (fastcmp(word,"ultimatemode")) {
164 lua_pushboolean(L, ultimatemode != 0);
165 return 1;
166 } else if (fastcmp(word,"mariomode")) {
167 lua_pushboolean(L, mariomode != 0);
168 return 1;
169 } else if (fastcmp(word,"twodlevel")) {
170 lua_pushboolean(L, twodlevel != 0);
171 return 1;
172 } else if (fastcmp(word,"circuitmap")) {
173 lua_pushboolean(L, circuitmap);
174 return 1;
175 } else if (fastcmp(word,"stoppedclock")) {
176 lua_pushboolean(L, stoppedclock);
177 return 1;
178 } else if (fastcmp(word,"netgame")) {
179 lua_pushboolean(L, netgame);
180 return 1;
181 } else if (fastcmp(word,"multiplayer")) {
182 lua_pushboolean(L, multiplayer);
183 return 1;
184 } else if (fastcmp(word,"modeattacking")) {
185 lua_pushboolean(L, modeattacking);
186 return 1;
187 } else if (fastcmp(word,"splitscreen")) {
188 lua_pushboolean(L, splitscreen);
189 return 1;
190 } else if (fastcmp(word,"gamecomplete")) {
191 lua_pushboolean(L, (gamecomplete != 0));
192 return 1;
193 } else if (fastcmp(word,"marathonmode")) {
194 lua_pushinteger(L, marathonmode);
195 return 1;
196 } else if (fastcmp(word,"devparm")) {
197 lua_pushboolean(L, devparm);
198 return 1;
199 } else if (fastcmp(word,"modifiedgame")) {
200 lua_pushboolean(L, modifiedgame && !savemoddata);
201 return 1;
202 } else if (fastcmp(word,"menuactive")) {
203 lua_pushboolean(L, menuactive);
204 return 1;
205 } else if (fastcmp(word,"paused")) {
206 lua_pushboolean(L, paused);
207 return 1;
208 } else if (fastcmp(word,"bluescore")) {
209 lua_pushinteger(L, bluescore);
210 return 1;
211 } else if (fastcmp(word,"redscore")) {
212 lua_pushinteger(L, redscore);
213 return 1;
214 } else if (fastcmp(word,"timelimit")) {
215 lua_pushinteger(L, cv_timelimit.value);
216 return 1;
217 } else if (fastcmp(word,"pointlimit")) {
218 lua_pushinteger(L, cv_pointlimit.value);
219 return 1;
220 // begin map vars
221 } else if (fastcmp(word,"spstage_start")) {
222 lua_pushinteger(L, spstage_start);
223 return 1;
224 } else if (fastcmp(word,"spmarathon_start")) {
225 lua_pushinteger(L, spmarathon_start);
226 return 1;
227 } else if (fastcmp(word,"sstage_start")) {
228 lua_pushinteger(L, sstage_start);
229 return 1;
230 } else if (fastcmp(word,"sstage_end")) {
231 lua_pushinteger(L, sstage_end);
232 return 1;
233 } else if (fastcmp(word,"smpstage_start")) {
234 lua_pushinteger(L, smpstage_start);
235 return 1;
236 } else if (fastcmp(word,"smpstage_end")) {
237 lua_pushinteger(L, smpstage_end);
238 return 1;
239 } else if (fastcmp(word,"titlemap")) {
240 lua_pushinteger(L, titlemap);
241 return 1;
242 } else if (fastcmp(word,"titlemapinaction")) {
243 lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
244 return 1;
245 } else if (fastcmp(word,"bootmap")) {
246 lua_pushinteger(L, bootmap);
247 return 1;
248 } else if (fastcmp(word,"tutorialmap")) {
249 lua_pushinteger(L, tutorialmap);
250 return 1;
251 } else if (fastcmp(word,"tutorialmode")) {
252 lua_pushboolean(L, tutorialmode);
253 return 1;
254 // end map vars
255 // begin CTF colors
256 } else if (fastcmp(word,"skincolor_redteam")) {
257 lua_pushinteger(L, skincolor_redteam);
258 return 1;
259 } else if (fastcmp(word,"skincolor_blueteam")) {
260 lua_pushinteger(L, skincolor_blueteam);
261 return 1;
262 } else if (fastcmp(word,"skincolor_redring")) {
263 lua_pushinteger(L, skincolor_redring);
264 return 1;
265 } else if (fastcmp(word,"skincolor_bluering")) {
266 lua_pushinteger(L, skincolor_bluering);
267 return 1;
268 // end CTF colors
269 // begin timers
270 } else if (fastcmp(word,"invulntics")) {
271 lua_pushinteger(L, invulntics);
272 return 1;
273 } else if (fastcmp(word,"sneakertics")) {
274 lua_pushinteger(L, sneakertics);
275 return 1;
276 } else if (fastcmp(word,"flashingtics")) {
277 lua_pushinteger(L, flashingtics);
278 return 1;
279 } else if (fastcmp(word,"tailsflytics")) {
280 lua_pushinteger(L, tailsflytics);
281 return 1;
282 } else if (fastcmp(word,"underwatertics")) {
283 lua_pushinteger(L, underwatertics);
284 return 1;
285 } else if (fastcmp(word,"spacetimetics")) {
286 lua_pushinteger(L, spacetimetics);
287 return 1;
288 } else if (fastcmp(word,"extralifetics")) {
289 lua_pushinteger(L, extralifetics);
290 return 1;
291 } else if (fastcmp(word,"nightslinktics")) {
292 lua_pushinteger(L, nightslinktics);
293 return 1;
294 } else if (fastcmp(word,"gameovertics")) {
295 lua_pushinteger(L, gameovertics);
296 return 1;
297 } else if (fastcmp(word,"ammoremovaltics")) {
298 lua_pushinteger(L, ammoremovaltics);
299 return 1;
300 // end timers
301 } else if (fastcmp(word,"gametype")) {
302 lua_pushinteger(L, gametype);
303 return 1;
304 } else if (fastcmp(word,"gametyperules")) {
305 lua_pushinteger(L, gametyperules);
306 return 1;
307 } else if (fastcmp(word,"leveltime")) {
308 lua_pushinteger(L, leveltime);
309 return 1;
310 } else if (fastcmp(word,"sstimer")) {
311 lua_pushinteger(L, sstimer);
312 return 1;
313 } else if (fastcmp(word,"curWeather")) {
314 lua_pushinteger(L, curWeather);
315 return 1;
316 } else if (fastcmp(word,"globalweather")) {
317 lua_pushinteger(L, globalweather);
318 return 1;
319 } else if (fastcmp(word,"levelskynum")) {
320 lua_pushinteger(L, levelskynum);
321 return 1;
322 } else if (fastcmp(word,"globallevelskynum")) {
323 lua_pushinteger(L, globallevelskynum);
324 return 1;
325 } else if (fastcmp(word,"mapmusname")) {
326 lua_pushstring(L, mapmusname);
327 return 1;
328 } else if (fastcmp(word,"mapmusflags")) {
329 lua_pushinteger(L, mapmusflags);
330 return 1;
331 } else if (fastcmp(word,"mapmusposition")) {
332 lua_pushinteger(L, mapmusposition);
333 return 1;
334 // local player variables, by popular request
335 } else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1)
336 if (!addedtogame || consoleplayer < 0 || !playeringame[consoleplayer])
337 return 0;
338 LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER);
339 return 1;
340 } else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1)
341 if (displayplayer < 0 || !playeringame[displayplayer])
342 return 0;
343 LUA_PushUserdata(L, &players[displayplayer], META_PLAYER);
344 return 1;
345 } else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen
346 if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer])
347 return 0;
348 LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER);
349 return 1;
350 } else if (fastcmp(word,"isserver")) {
351 lua_pushboolean(L, server);
352 return 1;
353 } else if (fastcmp(word,"isdedicatedserver")) {
354 lua_pushboolean(L, dedicated);
355 return 1;
356 // end local player variables
357 } else if (fastcmp(word,"server")) {
358 if ((!multiplayer || !netgame) && !playeringame[serverplayer])
359 return 0;
360 LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
361 return 1;
362 } else if (fastcmp(word,"emeralds")) {
363 lua_pushinteger(L, emeralds);
364 return 1;
365 } else if (fastcmp(word,"gravity")) {
366 lua_pushinteger(L, gravity);
367 return 1;
368 } else if (fastcmp(word,"VERSION")) {
369 lua_pushinteger(L, VERSION);
370 return 1;
371 } else if (fastcmp(word,"SUBVERSION")) {
372 lua_pushinteger(L, SUBVERSION);
373 return 1;
374 } else if (fastcmp(word,"VERSIONSTRING")) {
375 lua_pushstring(L, VERSIONSTRING);
376 return 1;
377 } else if (fastcmp(word, "token")) {
378 lua_pushinteger(L, token);
379 return 1;
380 } else if (fastcmp(word, "gamestate")) {
381 lua_pushinteger(L, gamestate);
382 return 1;
383 }
384 return 0;
385 }
386
387 // See the above.
LUA_CheckGlobals(lua_State * L,const char * word)388 int LUA_CheckGlobals(lua_State *L, const char *word)
389 {
390 if (fastcmp(word, "redscore"))
391 redscore = (UINT32)luaL_checkinteger(L, 2);
392 else if (fastcmp(word, "bluescore"))
393 bluescore = (UINT32)luaL_checkinteger(L, 2);
394 else if (fastcmp(word, "skincolor_redteam"))
395 skincolor_redteam = (UINT16)luaL_checkinteger(L, 2);
396 else if (fastcmp(word, "skincolor_blueteam"))
397 skincolor_blueteam = (UINT16)luaL_checkinteger(L, 2);
398 else if (fastcmp(word, "skincolor_redring"))
399 skincolor_redring = (UINT16)luaL_checkinteger(L, 2);
400 else if (fastcmp(word, "skincolor_bluering"))
401 skincolor_bluering = (UINT16)luaL_checkinteger(L, 2);
402 else if (fastcmp(word, "emeralds"))
403 emeralds = (UINT16)luaL_checkinteger(L, 2);
404 else if (fastcmp(word, "token"))
405 token = (UINT32)luaL_checkinteger(L, 2);
406 else if (fastcmp(word, "gravity"))
407 gravity = (fixed_t)luaL_checkinteger(L, 2);
408 else if (fastcmp(word, "stoppedclock"))
409 stoppedclock = luaL_checkboolean(L, 2);
410 else if (fastcmp(word, "displayplayer"))
411 {
412 player_t *player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
413
414 if (player)
415 displayplayer = player - players;
416 }
417 else if (fastcmp(word, "mapmusname"))
418 {
419 size_t strlength;
420 const char *str = luaL_checklstring(L, 2, &strlength);
421
422 if (strlength > 6)
423 return luaL_error(L, "string length out of range (maximum 6 characters)");
424
425 if (strlen(str) < strlength)
426 return luaL_error(L, "string must not contain embedded zeros!");
427
428 strncpy(mapmusname, str, strlength);
429 }
430 else if (fastcmp(word, "mapmusflags"))
431 mapmusflags = (UINT16)luaL_checkinteger(L, 2);
432 else
433 return 0;
434
435 // Global variable set, so return and don't error.
436 return 1;
437 }
438
439 // This function decides which global variables you are allowed to set.
setglobals(lua_State * L)440 static int setglobals(lua_State *L)
441 {
442 const char *csname;
443 char *name;
444 enum actionnum actionnum;
445
446 lua_remove(L, 1); // we're not gonna be using _G
447 csname = lua_tostring(L, 1);
448
449 // make an uppercase copy of the name
450 name = Z_StrDup(csname);
451 strupr(name);
452
453 if (fastncmp(name, "A_", 2) && lua_isfunction(L, 2))
454 {
455 // Accept new A_Action functions
456 // Add the action to Lua actions refrence table
457 lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS);
458 lua_pushstring(L, name); // "A_ACTION"
459 lua_pushvalue(L, 2); // function
460 lua_rawset(L, -3); // rawset doesn't trigger this metatable again.
461 // otherwise we would've used setfield, obviously.
462
463 actionnum = LUA_GetActionNumByName(name);
464 if (actionnum < NUMACTIONS)
465 actionsoverridden[actionnum] = true;
466
467 Z_Free(name);
468 return 0;
469 }
470
471 if (LUA_CheckGlobals(L, csname))
472 return 0;
473
474 Z_Free(name);
475 return luaL_error(L, "Implicit global " LUA_QS " prevented. Create a local variable instead.", csname);
476 }
477
478 // Clear and create a new Lua state, laddo!
479 // There's SCRIPTIN to be had!
LUA_ClearState(void)480 static void LUA_ClearState(void)
481 {
482 lua_State *L;
483 int i;
484
485 // close previous state
486 if (gL)
487 lua_close(gL);
488 gL = NULL;
489
490 CONS_Printf(M_GetText("Pardon me while I initialize the Lua scripting interface...\n"));
491
492 // allocate state
493 L = lua_newstate(LUA_Alloc, NULL);
494 lua_atpanic(L, LUA_Panic);
495
496 // open base libraries
497 luaL_openlibs(L);
498 lua_settop(L, 0);
499
500 // make LREG_VALID table for all pushed userdata cache.
501 lua_newtable(L);
502 lua_setfield(L, LUA_REGISTRYINDEX, LREG_VALID);
503
504 // make LREG_METATABLES table for all registered metatables
505 lua_newtable(L);
506 lua_setfield(L, LUA_REGISTRYINDEX, LREG_METATABLES);
507
508 // open srb2 libraries
509 for(i = 0; liblist[i]; i++) {
510 lua_pushcfunction(L, liblist[i]);
511 lua_call(L, 0, 0);
512 }
513
514 // lock the global namespace
515 lua_getmetatable(L, LUA_GLOBALSINDEX);
516 lua_pushcfunction(L, setglobals);
517 lua_setfield(L, -2, "__newindex");
518 lua_newtable(L);
519 lua_setfield(L, -2, "__metatable");
520 lua_pop(L, 1);
521
522 // lua state is ready!
523 gL = L;
524 }
525
526 #ifdef _DEBUG
LUA_ClearExtVars(void)527 void LUA_ClearExtVars(void)
528 {
529 if (!gL)
530 return;
531 lua_newtable(gL);
532 lua_setfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
533 }
534 #endif
535
536 // Use this variable to prevent certain functions from running
537 // if they were not called on lump load
538 // (i.e. they were called in hooks or coroutines etc)
539 INT32 lua_lumploading = 0;
540
541 // Load a script from a MYFILE
LUA_LoadFile(MYFILE * f,char * name,boolean noresults)542 static inline void LUA_LoadFile(MYFILE *f, char *name, boolean noresults)
543 {
544 int errorhandlerindex;
545
546 if (!name)
547 name = wadfiles[f->wad]->filename;
548 CONS_Printf("Loading Lua script from %s\n", name);
549 if (!gL) // Lua needs to be initialized
550 LUA_ClearState();
551 lua_pushinteger(gL, f->wad);
552 lua_setfield(gL, LUA_REGISTRYINDEX, "WAD");
553
554 lua_lumploading++; // turn on loading flag
555
556 lua_pushcfunction(gL, LUA_GetErrorMessage);
557 errorhandlerindex = lua_gettop(gL);
558 if (luaL_loadbuffer(gL, f->data, f->size, va("@%s",name)) || lua_pcall(gL, 0, noresults ? 0 : LUA_MULTRET, lua_gettop(gL) - 1)) {
559 CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1));
560 lua_pop(gL,1);
561 }
562 lua_gc(gL, LUA_GCCOLLECT, 0);
563 lua_remove(gL, errorhandlerindex);
564
565 lua_lumploading--; // turn off again
566 }
567
568 // Load a script from a lump
LUA_LoadLump(UINT16 wad,UINT16 lump,boolean noresults)569 void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults)
570 {
571 MYFILE f;
572 char *name;
573 size_t len;
574 f.wad = wad;
575 f.size = W_LumpLengthPwad(wad, lump);
576 f.data = Z_Malloc(f.size, PU_LUA, NULL);
577 W_ReadLumpPwad(wad, lump, f.data);
578 f.curpos = f.data;
579
580 len = strlen(wadfiles[wad]->filename); // length of file name
581
582 if (wadfiles[wad]->type == RET_LUA)
583 {
584 name = malloc(len+1);
585 strcpy(name, wadfiles[wad]->filename);
586 }
587 else // If it's not a .lua file, copy the lump name in too.
588 {
589 lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump];
590 len += 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
591 name = malloc(len+1);
592 sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->fullname);
593 name[len] = '\0';
594 }
595
596 LUA_LoadFile(&f, name, noresults); // actually load file!
597
598 free(name);
599 Z_Free(f.data);
600 }
601
602 #ifdef LUA_ALLOW_BYTECODE
603 // must match lua_Writer
dumpWriter(lua_State * L,const void * p,size_t sz,void * ud)604 static int dumpWriter(lua_State *L, const void *p, size_t sz, void *ud)
605 {
606 FILE *handle = (FILE*)ud;
607 I_Assert(handle != NULL);
608 (void)L;
609 if (!sz) return 0; // nothing to write? can't fail that! :D
610 return (fwrite(p, 1, sz, handle) != sz); // if fwrite != sz, we've failed.
611 }
612
613 // Compile a script by name and dump it back to disk.
LUA_DumpFile(const char * filename)614 void LUA_DumpFile(const char *filename)
615 {
616 FILE *handle;
617 char filenamebuf[MAX_WADPATH];
618
619 if (!gL) // Lua needs to be initialized
620 LUA_ClearState(false);
621
622 // find the file the SRB2 way
623 strncpy(filenamebuf, filename, MAX_WADPATH);
624 filenamebuf[MAX_WADPATH - 1] = '\0';
625 filename = filenamebuf;
626 if ((handle = fopen(filename, "rb")) == NULL)
627 {
628 // If we failed to load the file with the path as specified by
629 // the user, strip the directories and search for the file.
630 nameonly(filenamebuf);
631
632 // If findfile finds the file, the full path will be returned
633 // in filenamebuf == filename.
634 if (findfile(filenamebuf, NULL, true))
635 {
636 if ((handle = fopen(filename, "rb")) == NULL)
637 {
638 CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), filename);
639 return;
640 }
641 }
642 else
643 {
644 CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), filename);
645 return;
646 }
647 }
648 fclose(handle);
649
650 // pass the path we found to Lua
651 // luaL_loadfile will open and read the file in as a Lua function
652 if (luaL_loadfile(gL, filename)) {
653 CONS_Alert(CONS_ERROR,"%s\n",lua_tostring(gL,-1));
654 lua_pop(gL, 1);
655 return;
656 }
657
658 // dump it back to disk
659 if ((handle = fopen(filename, "wb")) == NULL)
660 CONS_Alert(CONS_ERROR, M_GetText("Can't write to %s\n"), filename);
661 if (lua_dump(gL, dumpWriter, handle))
662 CONS_Printf("Failed while writing %s to disk... Sorry!\n", filename);
663 else
664 CONS_Printf("Successfully compiled %s into bytecode.\n", filename);
665 fclose(handle);
666 lua_pop(gL, 1); // function is still on stack after lua_dump
667 lua_gc(gL, LUA_GCCOLLECT, 0);
668 return;
669 }
670 #endif
671
LUA_EvalMath(const char * word)672 fixed_t LUA_EvalMath(const char *word)
673 {
674 lua_State *L = NULL;
675 char buf[1024], *b;
676 const char *p;
677 fixed_t res = 0;
678
679 // make a new state so SOC can't interefere with scripts
680 // allocate state
681 L = lua_newstate(LUA_Alloc, NULL);
682 lua_atpanic(L, LUA_Panic);
683
684 // open only enum lib
685 lua_pushcfunction(L, LUA_EnumLib);
686 lua_pushboolean(L, true);
687 lua_call(L, 1, 0);
688
689 // change ^ into ^^ for Lua.
690 strcpy(buf, "return ");
691 b = buf+strlen(buf);
692 for (p = word; *p && b < &buf[1022]; p++)
693 {
694 *b++ = *p;
695 if (*p == '^')
696 *b++ = '^';
697 }
698 *b = '\0';
699
700 // eval string.
701 lua_settop(L, 0);
702 if (luaL_dostring(L, buf))
703 {
704 p = lua_tostring(L, -1);
705 while (*p++ != ':' && *p) ;
706 p += 3; // "1: "
707 CONS_Alert(CONS_WARNING, "%s\n", p);
708 }
709 else
710 res = lua_tointeger(L, -1);
711
712 // clean up and return.
713 lua_close(L);
714 return res;
715 }
716
717 // Takes a pointer, any pointer, and a metatable name
718 // Creates a userdata for that pointer with the given metatable
719 // Pushes it to the stack and stores it in the registry.
LUA_PushUserdata(lua_State * L,void * data,const char * meta)720 void LUA_PushUserdata(lua_State *L, void *data, const char *meta)
721 {
722 if (LUA_RawPushUserdata(L, data) == LPUSHED_NEW)
723 {
724 luaL_getmetatable(L, meta);
725 lua_setmetatable(L, -2);
726 }
727 }
728
729 // Same as LUA_PushUserdata but don't set a metatable yet.
LUA_RawPushUserdata(lua_State * L,void * data)730 lpushed_t LUA_RawPushUserdata(lua_State *L, void *data)
731 {
732 lpushed_t status = LPUSHED_NIL;
733
734 void **userdata;
735
736 if (!data) { // push a NULL
737 lua_pushnil(L);
738 return status;
739 }
740
741 lua_getfield(L, LUA_REGISTRYINDEX, LREG_VALID);
742 I_Assert(lua_istable(L, -1));
743
744 lua_pushlightuserdata(L, data);
745 lua_rawget(L, -2);
746
747 if (lua_isnil(L, -1)) { // no userdata? deary me, we'll have to make one.
748 lua_pop(L, 1); // pop the nil
749
750 // create the userdata
751 userdata = lua_newuserdata(L, sizeof(void *));
752 *userdata = data;
753
754 // Set it in the registry so we can find it again
755 lua_pushlightuserdata(L, data); // k (store the userdata via the data's pointer)
756 lua_pushvalue(L, -2); // v (copy of the userdata)
757 lua_rawset(L, -4);
758
759 // stack is left with the userdata on top, as if getting it had originally succeeded.
760
761 status = LPUSHED_NEW;
762 }
763 else
764 status = LPUSHED_EXISTING;
765
766 lua_remove(L, -2); // remove LREG_VALID
767
768 return status;
769 }
770
771 // When userdata is freed, use this function to remove it from Lua.
LUA_InvalidateUserdata(void * data)772 void LUA_InvalidateUserdata(void *data)
773 {
774 void **userdata;
775 if (!gL)
776 return;
777
778 // fetch the userdata
779 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_VALID);
780 I_Assert(lua_istable(gL, -1));
781 lua_pushlightuserdata(gL, data);
782 lua_rawget(gL, -2);
783 if (lua_isnil(gL, -1)) { // not found, not in lua
784 lua_pop(gL, 2); // pop nil and LREG_VALID
785 return;
786 }
787
788 // nullify any additional data
789 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
790 I_Assert(lua_istable(gL, -1));
791 lua_pushlightuserdata(gL, data);
792 lua_pushnil(gL);
793 lua_rawset(gL, -3);
794 lua_pop(gL, 1);
795
796 // invalidate the userdata
797 userdata = lua_touserdata(gL, -1);
798 *userdata = NULL;
799 lua_pop(gL, 1);
800
801 // remove it from the registry
802 lua_pushlightuserdata(gL, data);
803 lua_pushnil(gL);
804 lua_rawset(gL, -3);
805 lua_pop(gL, 1); // pop LREG_VALID
806 }
807
808 // Invalidate level data arrays
LUA_InvalidateLevel(void)809 void LUA_InvalidateLevel(void)
810 {
811 thinker_t *th;
812 size_t i;
813 ffloor_t *rover = NULL;
814 if (!gL)
815 return;
816 for (i = 0; i < NUM_THINKERLISTS; i++)
817 for (th = thlist[i].next; th && th != &thlist[i]; th = th->next)
818 LUA_InvalidateUserdata(th);
819
820 LUA_InvalidateMapthings();
821
822 for (i = 0; i < numsubsectors; i++)
823 LUA_InvalidateUserdata(&subsectors[i]);
824 for (i = 0; i < numsectors; i++)
825 {
826 LUA_InvalidateUserdata(§ors[i]);
827 LUA_InvalidateUserdata(§ors[i].lines);
828 LUA_InvalidateUserdata(§ors[i].tags);
829 if (sectors[i].ffloors)
830 {
831 for (rover = sectors[i].ffloors; rover; rover = rover->next)
832 LUA_InvalidateUserdata(rover);
833 }
834 }
835 for (i = 0; i < numlines; i++)
836 {
837 LUA_InvalidateUserdata(&lines[i]);
838 LUA_InvalidateUserdata(&lines[i].tags);
839 LUA_InvalidateUserdata(lines[i].sidenum);
840 }
841 for (i = 0; i < numsides; i++)
842 LUA_InvalidateUserdata(&sides[i]);
843 for (i = 0; i < numvertexes; i++)
844 LUA_InvalidateUserdata(&vertexes[i]);
845 for (i = 0; i < (size_t)numPolyObjects; i++)
846 {
847 LUA_InvalidateUserdata(&PolyObjects[i]);
848 LUA_InvalidateUserdata(&PolyObjects[i].vertices);
849 LUA_InvalidateUserdata(&PolyObjects[i].lines);
850 }
851 #ifdef HAVE_LUA_SEGS
852 for (i = 0; i < numsegs; i++)
853 LUA_InvalidateUserdata(&segs[i]);
854 for (i = 0; i < numnodes; i++)
855 {
856 LUA_InvalidateUserdata(&nodes[i]);
857 LUA_InvalidateUserdata(nodes[i].bbox);
858 LUA_InvalidateUserdata(nodes[i].children);
859 }
860 #endif
861 }
862
LUA_InvalidateMapthings(void)863 void LUA_InvalidateMapthings(void)
864 {
865 size_t i;
866 if (!gL)
867 return;
868
869 for (i = 0; i < nummapthings; i++)
870 {
871 LUA_InvalidateUserdata(&mapthings[i]);
872 LUA_InvalidateUserdata(&mapthings[i].tags);
873 }
874 }
875
LUA_InvalidatePlayer(player_t * player)876 void LUA_InvalidatePlayer(player_t *player)
877 {
878 if (!gL)
879 return;
880 LUA_InvalidateUserdata(player);
881 LUA_InvalidateUserdata(player->powers);
882 LUA_InvalidateUserdata(&player->cmd);
883 }
884
885 enum
886 {
887 ARCH_NULL=0,
888 ARCH_TRUE,
889 ARCH_FALSE,
890 ARCH_INT8,
891 ARCH_INT16,
892 ARCH_INT32,
893 ARCH_SMALLSTRING,
894 ARCH_LARGESTRING,
895 ARCH_TABLE,
896
897 ARCH_MOBJINFO,
898 ARCH_STATE,
899 ARCH_MOBJ,
900 ARCH_PLAYER,
901 ARCH_MAPTHING,
902 ARCH_VERTEX,
903 ARCH_LINE,
904 ARCH_SIDE,
905 ARCH_SUBSECTOR,
906 ARCH_SECTOR,
907 #ifdef HAVE_LUA_SEGS
908 ARCH_SEG,
909 ARCH_NODE,
910 #endif
911 ARCH_FFLOOR,
912 ARCH_POLYOBJ,
913 ARCH_SLOPE,
914 ARCH_MAPHEADER,
915 ARCH_SKINCOLOR,
916
917 ARCH_TEND=0xFF,
918 };
919
920 static const struct {
921 const char *meta;
922 UINT8 arch;
923 } meta2arch[] = {
924 {META_MOBJINFO, ARCH_MOBJINFO},
925 {META_STATE, ARCH_STATE},
926 {META_MOBJ, ARCH_MOBJ},
927 {META_PLAYER, ARCH_PLAYER},
928 {META_MAPTHING, ARCH_MAPTHING},
929 {META_VERTEX, ARCH_VERTEX},
930 {META_LINE, ARCH_LINE},
931 {META_SIDE, ARCH_SIDE},
932 {META_SUBSECTOR,ARCH_SUBSECTOR},
933 {META_SECTOR, ARCH_SECTOR},
934 #ifdef HAVE_LUA_SEGS
935 {META_SEG, ARCH_SEG},
936 {META_NODE, ARCH_NODE},
937 #endif
938 {META_FFLOOR, ARCH_FFLOOR},
939 {META_POLYOBJ, ARCH_POLYOBJ},
940 {META_SLOPE, ARCH_SLOPE},
941 {META_MAPHEADER, ARCH_MAPHEADER},
942 {META_SKINCOLOR, ARCH_SKINCOLOR},
943 {NULL, ARCH_NULL}
944 };
945
GetUserdataArchType(int index)946 static UINT8 GetUserdataArchType(int index)
947 {
948 UINT8 i;
949 lua_getmetatable(gL, index);
950
951 for (i = 0; meta2arch[i].meta; i++)
952 {
953 luaL_getmetatable(gL, meta2arch[i].meta);
954 if (lua_rawequal(gL, -1, -2))
955 {
956 lua_pop(gL, 2);
957 return meta2arch[i].arch;
958 }
959 lua_pop(gL, 1);
960 }
961
962 lua_pop(gL, 1);
963 return ARCH_NULL;
964 }
965
ArchiveValue(int TABLESINDEX,int myindex)966 static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
967 {
968 if (myindex < 0)
969 myindex = lua_gettop(gL)+1+myindex;
970 switch (lua_type(gL, myindex))
971 {
972 case LUA_TNONE:
973 case LUA_TNIL:
974 WRITEUINT8(save_p, ARCH_NULL);
975 break;
976 // This might be a problem. D:
977 case LUA_TLIGHTUSERDATA:
978 case LUA_TTHREAD:
979 case LUA_TFUNCTION:
980 WRITEUINT8(save_p, ARCH_NULL);
981 return 2;
982 case LUA_TBOOLEAN:
983 WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE);
984 break;
985 case LUA_TNUMBER:
986 {
987 lua_Integer number = lua_tointeger(gL, myindex);
988 if (number >= INT8_MIN && number <= INT8_MAX)
989 {
990 WRITEUINT8(save_p, ARCH_INT8);
991 WRITESINT8(save_p, number);
992 }
993 else if (number >= INT16_MIN && number <= INT16_MAX)
994 {
995 WRITEUINT8(save_p, ARCH_INT16);
996 WRITEINT16(save_p, number);
997 }
998 else
999 {
1000 WRITEUINT8(save_p, ARCH_INT32);
1001 WRITEFIXED(save_p, number);
1002 }
1003 break;
1004 }
1005 case LUA_TSTRING:
1006 {
1007 UINT32 len = (UINT32)lua_objlen(gL, myindex); // get length of string, including embedded zeros
1008 const char *s = lua_tostring(gL, myindex);
1009 UINT32 i = 0;
1010 // if you're wondering why we're writing a string to save_p this way,
1011 // it turns out that Lua can have embedded zeros ('\0') in the strings,
1012 // so we can't use WRITESTRING as that cuts off when it finds a '\0'.
1013 // Saving the size of the string also allows us to get the size of the string on the other end,
1014 // fixing the awful crashes previously encountered for reading strings longer than 1024
1015 // (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?)
1016 // -- Monster Iestyn 05/08/18
1017 if (len < 255)
1018 {
1019 WRITEUINT8(save_p, ARCH_SMALLSTRING);
1020 WRITEUINT8(save_p, len); // save size of string
1021 }
1022 else
1023 {
1024 WRITEUINT8(save_p, ARCH_LARGESTRING);
1025 WRITEUINT32(save_p, len); // save size of string
1026 }
1027 while (i < len)
1028 WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros
1029 break;
1030 }
1031 case LUA_TTABLE:
1032 {
1033 boolean found = false;
1034 INT32 i;
1035 UINT16 t = (UINT16)lua_objlen(gL, TABLESINDEX);
1036
1037 for (i = 1; i <= t && !found; i++)
1038 {
1039 lua_rawgeti(gL, TABLESINDEX, i);
1040 if (lua_rawequal(gL, myindex, -1))
1041 {
1042 t = i;
1043 found = true;
1044 }
1045 lua_pop(gL, 1);
1046 }
1047 if (!found)
1048 {
1049 t++;
1050
1051 if (t == 0)
1052 {
1053 CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
1054 WRITEUINT8(save_p, ARCH_NULL);
1055 return 0;
1056 }
1057 }
1058
1059 WRITEUINT8(save_p, ARCH_TABLE);
1060 WRITEUINT16(save_p, t);
1061
1062 if (!found)
1063 {
1064 lua_pushvalue(gL, myindex);
1065 lua_rawseti(gL, TABLESINDEX, t);
1066 return 1;
1067 }
1068 break;
1069 }
1070 case LUA_TUSERDATA:
1071 switch (GetUserdataArchType(myindex))
1072 {
1073 case ARCH_MOBJINFO:
1074 {
1075 mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
1076 WRITEUINT8(save_p, ARCH_MOBJINFO);
1077 WRITEUINT16(save_p, info - mobjinfo);
1078 break;
1079 }
1080 case ARCH_STATE:
1081 {
1082 state_t *state = *((state_t **)lua_touserdata(gL, myindex));
1083 WRITEUINT8(save_p, ARCH_STATE);
1084 WRITEUINT16(save_p, state - states);
1085 break;
1086 }
1087 case ARCH_MOBJ:
1088 {
1089 mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex));
1090 if (!mobj)
1091 WRITEUINT8(save_p, ARCH_NULL);
1092 else {
1093 WRITEUINT8(save_p, ARCH_MOBJ);
1094 WRITEUINT32(save_p, mobj->mobjnum);
1095 }
1096 break;
1097 }
1098 case ARCH_PLAYER:
1099 {
1100 player_t *player = *((player_t **)lua_touserdata(gL, myindex));
1101 if (!player)
1102 WRITEUINT8(save_p, ARCH_NULL);
1103 else {
1104 WRITEUINT8(save_p, ARCH_PLAYER);
1105 WRITEUINT8(save_p, player - players);
1106 }
1107 break;
1108 }
1109 case ARCH_MAPTHING:
1110 {
1111 mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex));
1112 if (!mapthing)
1113 WRITEUINT8(save_p, ARCH_NULL);
1114 else {
1115 WRITEUINT8(save_p, ARCH_MAPTHING);
1116 WRITEUINT16(save_p, mapthing - mapthings);
1117 }
1118 break;
1119 }
1120 case ARCH_VERTEX:
1121 {
1122 vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex));
1123 if (!vertex)
1124 WRITEUINT8(save_p, ARCH_NULL);
1125 else {
1126 WRITEUINT8(save_p, ARCH_VERTEX);
1127 WRITEUINT16(save_p, vertex - vertexes);
1128 }
1129 break;
1130 }
1131 case ARCH_LINE:
1132 {
1133 line_t *line = *((line_t **)lua_touserdata(gL, myindex));
1134 if (!line)
1135 WRITEUINT8(save_p, ARCH_NULL);
1136 else {
1137 WRITEUINT8(save_p, ARCH_LINE);
1138 WRITEUINT16(save_p, line - lines);
1139 }
1140 break;
1141 }
1142 case ARCH_SIDE:
1143 {
1144 side_t *side = *((side_t **)lua_touserdata(gL, myindex));
1145 if (!side)
1146 WRITEUINT8(save_p, ARCH_NULL);
1147 else {
1148 WRITEUINT8(save_p, ARCH_SIDE);
1149 WRITEUINT16(save_p, side - sides);
1150 }
1151 break;
1152 }
1153 case ARCH_SUBSECTOR:
1154 {
1155 subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex));
1156 if (!subsector)
1157 WRITEUINT8(save_p, ARCH_NULL);
1158 else {
1159 WRITEUINT8(save_p, ARCH_SUBSECTOR);
1160 WRITEUINT16(save_p, subsector - subsectors);
1161 }
1162 break;
1163 }
1164 case ARCH_SECTOR:
1165 {
1166 sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex));
1167 if (!sector)
1168 WRITEUINT8(save_p, ARCH_NULL);
1169 else {
1170 WRITEUINT8(save_p, ARCH_SECTOR);
1171 WRITEUINT16(save_p, sector - sectors);
1172 }
1173 break;
1174 }
1175 #ifdef HAVE_LUA_SEGS
1176 case ARCH_SEG:
1177 {
1178 seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
1179 if (!seg)
1180 WRITEUINT8(save_p, ARCH_NULL);
1181 else {
1182 WRITEUINT8(save_p, ARCH_SEG);
1183 WRITEUINT16(save_p, seg - segs);
1184 }
1185 break;
1186 }
1187 case ARCH_NODE:
1188 {
1189 node_t *node = *((node_t **)lua_touserdata(gL, myindex));
1190 if (!node)
1191 WRITEUINT8(save_p, ARCH_NULL);
1192 else {
1193 WRITEUINT8(save_p, ARCH_NODE);
1194 WRITEUINT16(save_p, node - nodes);
1195 }
1196 break;
1197 }
1198 #endif
1199 case ARCH_FFLOOR:
1200 {
1201 ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
1202 if (!rover)
1203 WRITEUINT8(save_p, ARCH_NULL);
1204 else {
1205 UINT16 i = P_GetFFloorID(rover);
1206 if (i == UINT16_MAX) // invalid ID
1207 WRITEUINT8(save_p, ARCH_NULL);
1208 else
1209 {
1210 WRITEUINT8(save_p, ARCH_FFLOOR);
1211 WRITEUINT16(save_p, rover->target - sectors);
1212 WRITEUINT16(save_p, i);
1213 }
1214 }
1215 break;
1216 }
1217 case ARCH_POLYOBJ:
1218 {
1219 polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex));
1220 if (!polyobj)
1221 WRITEUINT8(save_p, ARCH_NULL);
1222 else {
1223 WRITEUINT8(save_p, ARCH_POLYOBJ);
1224 WRITEUINT16(save_p, polyobj-PolyObjects);
1225 }
1226 break;
1227 }
1228 case ARCH_SLOPE:
1229 {
1230 pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
1231 if (!slope)
1232 WRITEUINT8(save_p, ARCH_NULL);
1233 else {
1234 WRITEUINT8(save_p, ARCH_SLOPE);
1235 WRITEUINT16(save_p, slope->id);
1236 }
1237 break;
1238 }
1239 case ARCH_MAPHEADER:
1240 {
1241 mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
1242 if (!header)
1243 WRITEUINT8(save_p, ARCH_NULL);
1244 else {
1245 WRITEUINT8(save_p, ARCH_MAPHEADER);
1246 WRITEUINT16(save_p, header - *mapheaderinfo);
1247 }
1248 break;
1249 }
1250
1251 case ARCH_SKINCOLOR:
1252 {
1253 skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex));
1254 WRITEUINT8(save_p, ARCH_SKINCOLOR);
1255 WRITEUINT16(save_p, info - skincolors);
1256 break;
1257 }
1258 default:
1259 WRITEUINT8(save_p, ARCH_NULL);
1260 return 2;
1261 }
1262 break;
1263 }
1264 return 0;
1265 }
1266
ArchiveExtVars(void * pointer,const char * ptype)1267 static void ArchiveExtVars(void *pointer, const char *ptype)
1268 {
1269 int TABLESINDEX;
1270 UINT16 i;
1271
1272 if (!gL) {
1273 if (fastcmp(ptype,"player")) // players must always be included, even if no vars
1274 WRITEUINT16(save_p, 0);
1275 return;
1276 }
1277
1278 TABLESINDEX = lua_gettop(gL);
1279
1280 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
1281 I_Assert(lua_istable(gL, -1));
1282 lua_pushlightuserdata(gL, pointer);
1283 lua_rawget(gL, -2);
1284 lua_remove(gL, -2); // pop LREG_EXTVARS
1285
1286 if (!lua_istable(gL, -1))
1287 { // no extra values table
1288 lua_pop(gL, 1);
1289 if (fastcmp(ptype,"player")) // players must always be included, even if no vars
1290 WRITEUINT16(save_p, 0);
1291 return;
1292 }
1293
1294 lua_pushnil(gL);
1295 for (i = 0; lua_next(gL, -2); i++)
1296 lua_pop(gL, 1);
1297
1298 // skip anything that has an empty table and isn't a player.
1299 if (i == 0)
1300 {
1301 if (fastcmp(ptype,"player")) // always include players even if they have no extra variables
1302 WRITEUINT16(save_p, 0);
1303 lua_pop(gL, 1);
1304 return;
1305 }
1306
1307 if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header
1308 WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum);
1309 WRITEUINT16(save_p, i);
1310 lua_pushnil(gL);
1311 while (lua_next(gL, -2))
1312 {
1313 I_Assert(lua_type(gL, -2) == LUA_TSTRING);
1314 WRITESTRING(save_p, lua_tostring(gL, -2));
1315 if (ArchiveValue(TABLESINDEX, -1) == 2)
1316 CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1));
1317 lua_pop(gL, 1);
1318 }
1319
1320 lua_pop(gL, 1);
1321 }
1322
NetArchive(lua_State * L)1323 static int NetArchive(lua_State *L)
1324 {
1325 int TABLESINDEX = lua_upvalueindex(1);
1326 int i, n = lua_gettop(L);
1327 for (i = 1; i <= n; i++)
1328 ArchiveValue(TABLESINDEX, i);
1329 return n;
1330 }
1331
ArchiveTables(void)1332 static void ArchiveTables(void)
1333 {
1334 int TABLESINDEX;
1335 UINT16 i, n;
1336 UINT8 e;
1337
1338 if (!gL)
1339 return;
1340
1341 TABLESINDEX = lua_gettop(gL);
1342
1343 n = (UINT16)lua_objlen(gL, TABLESINDEX);
1344 for (i = 1; i <= n; i++)
1345 {
1346 lua_rawgeti(gL, TABLESINDEX, i);
1347 lua_pushnil(gL);
1348 while (lua_next(gL, -2))
1349 {
1350 // Write key
1351 e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
1352 if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
1353 {
1354 lua_pushvalue(gL, -2);
1355 CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -1), luaL_typename(gL, -1), i);
1356 lua_pop(gL, 1);
1357 }
1358 // Write value
1359 e = ArchiveValue(TABLESINDEX, -1);
1360 if (e == 1)
1361 n++; // the table contained a new table we'll have to archive. :(
1362 else if (e == 2) // invalid value type
1363 {
1364 lua_pushvalue(gL, -2);
1365 CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -1), luaL_typename(gL, -1));
1366 lua_pop(gL, 1);
1367 }
1368
1369 lua_pop(gL, 1);
1370 }
1371 WRITEUINT8(save_p, ARCH_TEND);
1372
1373 // Write metatable ID
1374 if (lua_getmetatable(gL, -1))
1375 {
1376 // registry.metatables[metatable]
1377 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
1378 lua_pushvalue(gL, -2);
1379 lua_gettable(gL, -2);
1380 WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
1381 lua_pop(gL, 3);
1382 }
1383 else
1384 WRITEUINT16(save_p, 0);
1385
1386 lua_pop(gL, 1);
1387 }
1388 }
1389
UnArchiveValue(int TABLESINDEX)1390 static UINT8 UnArchiveValue(int TABLESINDEX)
1391 {
1392 UINT8 type = READUINT8(save_p);
1393 switch (type)
1394 {
1395 case ARCH_NULL:
1396 lua_pushnil(gL);
1397 break;
1398 case ARCH_TRUE:
1399 lua_pushboolean(gL, true);
1400 break;
1401 case ARCH_FALSE:
1402 lua_pushboolean(gL, false);
1403 break;
1404 case ARCH_INT8:
1405 lua_pushinteger(gL, READSINT8(save_p));
1406 break;
1407 case ARCH_INT16:
1408 lua_pushinteger(gL, READINT16(save_p));
1409 break;
1410 case ARCH_INT32:
1411 lua_pushinteger(gL, READFIXED(save_p));
1412 break;
1413 case ARCH_SMALLSTRING:
1414 case ARCH_LARGESTRING:
1415 {
1416 UINT32 len;
1417 char *value;
1418 UINT32 i = 0;
1419
1420 // See my comments in the ArchiveValue function;
1421 // it's much the same for reading strings as writing them!
1422 // (i.e. we can't use READSTRING either)
1423 // -- Monster Iestyn 05/08/18
1424 if (type == ARCH_SMALLSTRING)
1425 len = READUINT8(save_p); // length of string, including embedded zeros
1426 else
1427 len = READUINT32(save_p); // length of string, including embedded zeros
1428 value = malloc(len); // make temp buffer of size len
1429 // now read the actual string
1430 while (i < len)
1431 value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros
1432 lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros)
1433 free(value); // free the buffer
1434 break;
1435 }
1436 case ARCH_TABLE:
1437 {
1438 UINT16 tid = READUINT16(save_p);
1439 lua_rawgeti(gL, TABLESINDEX, tid);
1440 if (lua_isnil(gL, -1))
1441 {
1442 lua_pop(gL, 1);
1443 lua_newtable(gL);
1444 lua_pushvalue(gL, -1);
1445 lua_rawseti(gL, TABLESINDEX, tid);
1446 return 2;
1447 }
1448 break;
1449 }
1450 case ARCH_MOBJINFO:
1451 LUA_PushUserdata(gL, &mobjinfo[READUINT16(save_p)], META_MOBJINFO);
1452 break;
1453 case ARCH_STATE:
1454 LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE);
1455 break;
1456 case ARCH_MOBJ:
1457 LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ);
1458 break;
1459 case ARCH_PLAYER:
1460 LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER);
1461 break;
1462 case ARCH_MAPTHING:
1463 LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING);
1464 break;
1465 case ARCH_VERTEX:
1466 LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX);
1467 break;
1468 case ARCH_LINE:
1469 LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE);
1470 break;
1471 case ARCH_SIDE:
1472 LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE);
1473 break;
1474 case ARCH_SUBSECTOR:
1475 LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR);
1476 break;
1477 case ARCH_SECTOR:
1478 LUA_PushUserdata(gL, §ors[READUINT16(save_p)], META_SECTOR);
1479 break;
1480 #ifdef HAVE_LUA_SEGS
1481 case ARCH_SEG:
1482 LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG);
1483 break;
1484 case ARCH_NODE:
1485 LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE);
1486 break;
1487 #endif
1488 case ARCH_FFLOOR:
1489 {
1490 sector_t *sector = §ors[READUINT16(save_p)];
1491 UINT16 id = READUINT16(save_p);
1492 ffloor_t *rover = P_GetFFloorByID(sector, id);
1493 if (rover)
1494 LUA_PushUserdata(gL, rover, META_FFLOOR);
1495 break;
1496 }
1497 case ARCH_POLYOBJ:
1498 LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ);
1499 break;
1500 case ARCH_SLOPE:
1501 LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE);
1502 break;
1503 case ARCH_MAPHEADER:
1504 LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER);
1505 break;
1506 case ARCH_SKINCOLOR:
1507 LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR);
1508 break;
1509 case ARCH_TEND:
1510 return 1;
1511 }
1512 return 0;
1513 }
1514
UnArchiveExtVars(void * pointer)1515 static void UnArchiveExtVars(void *pointer)
1516 {
1517 int TABLESINDEX;
1518 UINT16 field_count = READUINT16(save_p);
1519 UINT16 i;
1520 char field[1024];
1521
1522 if (field_count == 0)
1523 return;
1524 I_Assert(gL != NULL);
1525
1526 TABLESINDEX = lua_gettop(gL);
1527 lua_createtable(gL, 0, field_count); // pointer's ext vars subtable
1528
1529 for (i = 0; i < field_count; i++)
1530 {
1531 READSTRING(save_p, field);
1532 UnArchiveValue(TABLESINDEX);
1533 lua_setfield(gL, -2, field);
1534 }
1535
1536 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_EXTVARS);
1537 I_Assert(lua_istable(gL, -1));
1538 lua_pushlightuserdata(gL, pointer);
1539 lua_pushvalue(gL, -3); // pointer's ext vars subtable
1540 lua_rawset(gL, -3);
1541 lua_pop(gL, 2); // pop LREG_EXTVARS and pointer's subtable
1542 }
1543
NetUnArchive(lua_State * L)1544 static int NetUnArchive(lua_State *L)
1545 {
1546 int TABLESINDEX = lua_upvalueindex(1);
1547 int i, n = lua_gettop(L);
1548 for (i = 1; i <= n; i++)
1549 UnArchiveValue(TABLESINDEX);
1550 return n;
1551 }
1552
UnArchiveTables(void)1553 static void UnArchiveTables(void)
1554 {
1555 int TABLESINDEX;
1556 UINT16 i, n;
1557 UINT16 metatableid;
1558
1559 if (!gL)
1560 return;
1561
1562 TABLESINDEX = lua_gettop(gL);
1563
1564 n = (UINT16)lua_objlen(gL, TABLESINDEX);
1565 for (i = 1; i <= n; i++)
1566 {
1567 lua_rawgeti(gL, TABLESINDEX, i);
1568 while (true)
1569 {
1570 if (UnArchiveValue(TABLESINDEX) == 1) // read key
1571 break;
1572 if (UnArchiveValue(TABLESINDEX) == 2) // read value
1573 n++;
1574 if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved)
1575 {
1576 CONS_Alert(CONS_ERROR, "A nil key in table %d was found! (Invalid key type or corrupted save?)\n", i);
1577 lua_pop(gL, 2); // pop key and value instead of setting them in the table, to prevent Lua panic errors
1578 }
1579 else
1580 lua_rawset(gL, -3);
1581 }
1582
1583 metatableid = READUINT16(save_p);
1584 if (metatableid)
1585 {
1586 // setmetatable(table, registry.metatables[metatableid])
1587 lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
1588 lua_rawgeti(gL, -1, metatableid);
1589 if (lua_isnil(gL, -1))
1590 I_Error("Unknown metatable ID %d\n", metatableid);
1591 lua_setmetatable(gL, -3);
1592 lua_pop(gL, 1);
1593 }
1594
1595 lua_pop(gL, 1);
1596 }
1597 }
1598
LUA_Step(void)1599 void LUA_Step(void)
1600 {
1601 if (!gL)
1602 return;
1603 lua_settop(gL, 0);
1604 lua_gc(gL, LUA_GCSTEP, 1);
1605 }
1606
LUA_Archive(void)1607 void LUA_Archive(void)
1608 {
1609 INT32 i;
1610 thinker_t *th;
1611
1612 if (gL)
1613 lua_newtable(gL); // tables to be archived.
1614
1615 for (i = 0; i < MAXPLAYERS; i++)
1616 {
1617 if (!playeringame[i] && i > 0) // dedicated servers...
1618 continue;
1619 // all players in game will be archived, even if they just add a 0.
1620 ArchiveExtVars(&players[i], "player");
1621 }
1622
1623 for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
1624 {
1625 if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
1626 continue;
1627
1628 // archive function will determine when to skip mobjs,
1629 // and write mobjnum in otherwise.
1630 ArchiveExtVars(th, "mobj");
1631 }
1632
1633 WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
1634
1635 LUAh_NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode
1636 ArchiveTables();
1637
1638 if (gL)
1639 lua_pop(gL, 1); // pop tables
1640 }
1641
LUA_UnArchive(void)1642 void LUA_UnArchive(void)
1643 {
1644 UINT32 mobjnum;
1645 INT32 i;
1646 thinker_t *th;
1647
1648 if (gL)
1649 lua_newtable(gL); // tables to be read
1650
1651 for (i = 0; i < MAXPLAYERS; i++)
1652 {
1653 if (!playeringame[i] && i > 0) // dedicated servers...
1654 continue;
1655 UnArchiveExtVars(&players[i]);
1656 }
1657
1658 do {
1659 mobjnum = READUINT32(save_p); // read a mobjnum
1660 for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
1661 {
1662 if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
1663 continue;
1664 if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
1665 continue;
1666 UnArchiveExtVars(th); // apply variables
1667 }
1668 } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
1669
1670 LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode
1671 UnArchiveTables();
1672
1673 if (gL)
1674 lua_pop(gL, 1); // pop tables
1675 }
1676
1677 // For mobj_t, player_t, etc. to take custom variables.
Lua_optoption(lua_State * L,int narg,const char * def,const char * const lst[])1678 int Lua_optoption(lua_State *L, int narg,
1679 const char *def, const char *const lst[])
1680 {
1681 const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
1682 int i;
1683 for (i=0; lst[i]; i++)
1684 if (fastcmp(lst[i], name))
1685 return i;
1686 return -1;
1687 }
1688
LUA_PushTaggableObjectArray(lua_State * L,const char * field,lua_CFunction iterator,lua_CFunction indexer,lua_CFunction counter,taggroup_t * garray[],size_t * max_elements,void * element_array,size_t sizeof_element,const char * meta)1689 void LUA_PushTaggableObjectArray
1690 ( lua_State *L,
1691 const char *field,
1692 lua_CFunction iterator,
1693 lua_CFunction indexer,
1694 lua_CFunction counter,
1695 taggroup_t *garray[],
1696 size_t * max_elements,
1697 void * element_array,
1698 size_t sizeof_element,
1699 const char *meta)
1700 {
1701 lua_newuserdata(L, 0);
1702 lua_createtable(L, 0, 2);
1703 lua_createtable(L, 0, 2);
1704 lua_pushcfunction(L, iterator);
1705 lua_setfield(L, -2, "iterate");
1706
1707 LUA_InsertTaggroupIterator(L, garray,
1708 max_elements, element_array, sizeof_element, meta);
1709
1710 lua_createtable(L, 0, 1);
1711 lua_pushcfunction(L, indexer);
1712 lua_setfield(L, -2, "__index");
1713 lua_setmetatable(L, -2);
1714 lua_setfield(L, -2, "__index");
1715
1716 lua_pushcfunction(L, counter);
1717 lua_setfield(L, -2, "__len");
1718 lua_setmetatable(L, -2);
1719 lua_setglobal(L, field);
1720 }
1721