static void ArchiveTables(void) { int TABLESINDEX; UINT16 i, n; UINT8 e; if (!gL) return; TABLESINDEX = lua_gettop(gL); n = (UINT16)lua_objlen(gL, TABLESINDEX); for (i = 1; i <= n; i++) { lua_rawgeti(gL, TABLESINDEX, i); lua_pushnil(gL); while (lua_next(gL, -2)) { ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this. e = ArchiveValue(TABLESINDEX, -1); if (e == 1) n++; // the table contained a new table we'll have to archive. :( else if (e == 2) { lua_pushvalue(gL, -2); 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)); lua_pop(gL, 1); } lua_pop(gL, 1); } lua_pop(gL, 1); WRITEUINT8(save_p, ARCH_TEND); } }
/** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. * Used to have size limiting built in - now handed via W_LoadWadFile in w_wad.c * */ UINT8 *PutFileNeeded(void) { size_t i, count = 0; UINT8 *p = netbuffer->u.serverinfo.fileneeded; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus; for (i = 0; i < numwadfiles; i++) { // If it has only music/sound lumps, don't put it in the list if (!wadfiles[i]->important) continue; filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS // Store in the upper four bits if (!cv_downloading.value) filestatus += (2 << 4); // Won't send else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024)) filestatus += (1 << 4); // Will send if requested // else // filestatus += (0 << 4); -- Won't send, too big WRITEUINT8(p, filestatus); count++; WRITEUINT32(p, wadfiles[i]->filesize); nameonly(strcpy(wadfilename, wadfiles[i]->filename)); WRITESTRINGN(p, wadfilename, MAX_WADPATH); WRITEMEM(p, wadfiles[i]->md5sum, 16); } netbuffer->u.serverinfo.fileneedednum = (UINT8)count; return p; }
/** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. * */ UINT8 *PutFileNeeded(void) { size_t i, count = 0; UINT8 *p = netbuffer->u.serverinfo.fileneeded; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus; size_t bytesused = 0; for (i = 0; i < numwadfiles; i++) { // If it has only music/sound lumps, mark it as unimportant if (W_VerifyNMUSlumps(wadfiles[i]->filename)) filestatus = 0; else filestatus = 1; // Important // Store in the upper four bits if (!cv_downloading.value) filestatus += (2 << 4); // Won't send else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)) filestatus += (0 << 4); // Won't send else filestatus += (1 << 4); // Will send if requested bytesused += (nameonlylength(wadfilename) + 22); // Don't write too far... if (bytesused > sizeof(netbuffer->u.serverinfo.fileneeded)) I_Error("Too many wad files added to host a game. (%s, stopped on %s)\n", sizeu1(bytesused), wadfilename); WRITEUINT8(p, filestatus); count++; WRITEUINT32(p, wadfiles[i]->filesize); nameonly(strcpy(wadfilename, wadfiles[i]->filename)); WRITESTRINGN(p, wadfilename, MAX_WADPATH); WRITEMEM(p, wadfiles[i]->md5sum, 16); } netbuffer->u.serverinfo.fileneedednum = (UINT8)count; return p; }
// Wrapper for COM_AddCommand commands void COM_Lua_f(void) { char *buf, *p; UINT8 i, flags; UINT16 len; INT32 playernum = consoleplayer; I_Assert(gL != NULL); lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command I_Assert(lua_istable(gL, -1)); // use buf temporarily -- must use lowercased string buf = Z_StrDup(COM_Argv(0)); strlwr(buf); lua_getfield(gL, -1, buf); // push command info table I_Assert(lua_istable(gL, -1)); lua_remove(gL, -2); // pop COM_Command Z_Free(buf); lua_rawgeti(gL, -1, 2); // push flags from command info table if (lua_isboolean(gL, -1)) flags = (lua_toboolean(gL, -1) ? 1 : 0); else flags = (UINT8)lua_tointeger(gL, -1); lua_pop(gL, 1); // pop flags if (flags & 2) // flag 2: splitscreen player command. { if (!splitscreen) { lua_pop(gL, 1); // pop command info table return; // can't execute splitscreen command without player 2! } playernum = secondarydisplayplayer; } if (netgame) { // Send the command through the network UINT8 argc; lua_pop(gL, 1); // pop command info table if (flags & 1 && !server && !IsPlayerAdmin(playernum)) // flag 1: only server/admin can use this command. { CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; } if (COM_Argc() > UINT8_MAX) argc = UINT8_MAX; else argc = (UINT8)COM_Argc(); if (argc == UINT8_MAX) len = UINT16_MAX; else len = (argc+1)*256; buf = malloc(len); p = buf; WRITEUINT8(p, argc); for (i = 0; i < argc; i++) WRITESTRINGN(p, COM_Argv(i), 255); if (flags & 2) SendNetXCmd2(XD_LUACMD, buf, p-buf); else SendNetXCmd(XD_LUACMD, buf, p-buf); free(buf); return; } // Do the command locally, NetXCmds don't go through outside of GS_LEVEL || GS_INTERMISSION lua_rawgeti(gL, -1, 1); // push function from command info table I_Assert(lua_isfunction(gL, -1)); lua_remove(gL, -2); // pop command info table LUA_PushUserdata(gL, &players[playernum], META_PLAYER); for (i = 1; i < COM_Argc(); i++) lua_pushstring(gL, COM_Argv(i)); LUA_Call(gL, (int)COM_Argc()); // COM_Argc is 1-based, so this will cover the player we passed too. }
static UINT8 ArchiveValue(int TABLESINDEX, int myindex) { if (myindex < 0) myindex = lua_gettop(gL)+1+myindex; switch (lua_type(gL, myindex)) { case LUA_TNONE: case LUA_TNIL: WRITEUINT8(save_p, ARCH_NULL); break; // This might be a problem. D: case LUA_TLIGHTUSERDATA: case LUA_TTHREAD: case LUA_TFUNCTION: WRITEUINT8(save_p, ARCH_NULL); return 2; case LUA_TBOOLEAN: WRITEUINT8(save_p, ARCH_BOOLEAN); WRITEUINT8(save_p, lua_toboolean(gL, myindex)); break; case LUA_TNUMBER: { lua_Integer number = lua_tointeger(gL, myindex); if (number < 0) { WRITEUINT8(save_p, ARCH_SIGNED); WRITEFIXED(save_p, number); } else { WRITEUINT8(save_p, ARCH_UNSIGNED); WRITEANGLE(save_p, number); } break; } case LUA_TSTRING: WRITEUINT8(save_p, ARCH_STRING); WRITESTRING(save_p, lua_tostring(gL, myindex)); break; case LUA_TTABLE: { boolean found = false; INT32 i; UINT16 t = (UINT16)lua_objlen(gL, TABLESINDEX); for (i = 1; i <= t && !found; i++) { lua_rawgeti(gL, TABLESINDEX, i); if (lua_rawequal(gL, myindex, -1)) { t = i; found = true; } lua_pop(gL, 1); } if (!found) t++; WRITEUINT8(save_p, ARCH_TABLE); WRITEUINT16(save_p, t); if (!found) { lua_pushvalue(gL, myindex); lua_rawseti(gL, TABLESINDEX, t); return 1; } break; } case LUA_TUSERDATA: switch (GetUserdataArchType()) { case ARCH_MOBJINFO: { mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex)); WRITEUINT8(save_p, ARCH_MOBJINFO); WRITEUINT8(save_p, info - mobjinfo); break; } case ARCH_STATE: { state_t *state = *((state_t **)lua_touserdata(gL, myindex)); WRITEUINT8(save_p, ARCH_STATE); WRITEUINT8(save_p, state - states); break; } case ARCH_MOBJ: { mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex)); if (!mobj) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_MOBJ); WRITEUINT32(save_p, mobj->mobjnum); } break; } case ARCH_PLAYER: { player_t *player = *((player_t **)lua_touserdata(gL, myindex)); if (!player) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_PLAYER); WRITEUINT8(save_p, player - players); } break; } case ARCH_MAPTHING: { mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex)); if (!mapthing) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_MAPTHING); WRITEUINT16(save_p, mapthing - mapthings); } break; } case ARCH_VERTEX: { vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex)); if (!vertex) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_VERTEX); WRITEUINT16(save_p, vertex - vertexes); } break; } case ARCH_LINE: { line_t *line = *((line_t **)lua_touserdata(gL, myindex)); if (!line) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_LINE); WRITEUINT16(save_p, line - lines); } break; } case ARCH_SIDE: { side_t *side = *((side_t **)lua_touserdata(gL, myindex)); if (!side) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_SIDE); WRITEUINT16(save_p, side - sides); } break; } case ARCH_SUBSECTOR: { subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex)); if (!subsector) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_SUBSECTOR); WRITEUINT16(save_p, subsector - subsectors); } break; } case ARCH_SECTOR: { sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex)); if (!sector) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_SECTOR); WRITEUINT16(save_p, sector - sectors); } break; } case ARCH_MAPHEADER: { mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); if (!header) WRITEUINT8(save_p, ARCH_NULL); else { WRITEUINT8(save_p, ARCH_MAPHEADER); WRITEUINT16(save_p, header - *mapheaderinfo); } break; } default: WRITEUINT8(save_p, ARCH_NULL); return 2; } break; } return 0; }