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(&sectors[i]);
827 		LUA_InvalidateUserdata(&sectors[i].lines);
828 		LUA_InvalidateUserdata(&sectors[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, &sectors[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 = &sectors[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