// g_lua.c #include "cg_lua.h" #ifdef G_LUA lvm_t *lVM[NUM_VMS]; fileHandle_t lualog; void QDECL LUA_DEBUG(const char *fmt, ...) { va_list argptr; char text[1024]; if(cg_debugLua.integer >= 1) { va_start(argptr, fmt); Com_sprintf(text, sizeof(text), fmt, argptr); va_end(argptr); CG_Printf(S_COLOR_YELLOW "LUA DEBUG:" S_COLOR_WHITE " %s\n", text); } } void QDECL LUA_LOG(const char *fmt, ...) { va_list argptr; char buff[1024], string[1024]; int min, tens, sec; va_start(argptr, fmt); Com_sprintf(buff, sizeof(buff), fmt, argptr); va_end(argptr); if(cg_logLua.integer) { sec = cg.time / 1000; min = sec / 60; sec -= min * 60; tens = sec / 10; sec -= tens * 10; Com_sprintf(string, sizeof(string), "%i:%i%i %s", min, tens, sec, buff); trap_FS_Write(string, strlen(string), lualog); } } qboolean LoadLuaFile(char *path, int num_vm) { int flen = 0; char *code; fileHandle_t f; lvm_t *vm; flen = trap_FS_FOpenFile(path, &f, FS_READ); if(flen < 0) { LUA_LOG("Lua: can not open file %s\n", path); CG_Printf(S_COLOR_YELLOW "Lua: can not open file %s\n", path); trap_FS_FCloseFile(f); return qfalse; } else { code = (char *)malloc(flen + 1); if(!code) return qfalse; trap_FS_Read(code, flen, f); *(code + flen) = '\0'; trap_FS_FCloseFile(f); vm = (lvm_t *) malloc(sizeof(lvm_t)); if(vm == NULL) { LUA_LOG("Lua: failed to allocate memory for lua VM\n"); CG_Printf(S_COLOR_YELLOW "Lua: failed to allocate memory for lua VM\n"); return qfalse; } memset(vm, 0, sizeof(lvm_t)); vm->id = -1; Q_strncpyz(vm->filename, path, sizeof(vm->filename)); vm->code = code; vm->code_size = flen; vm->error = 0; if(CG_LuaStartVM(vm) == qfalse) { CG_LuaStopVM(vm); vm = NULL; return qfalse; } else { vm->id = num_vm; lVM[num_vm] = vm; return qtrue; } } //return qfalse; } qboolean CG_LuaInit() { CG_Printf("------- CG_LuaInit -------\n"); // not much to do for now if(cg_logLua.integer) { trap_FS_FOpenFile("./cg_lua.log", &lualog, FS_APPEND); } CG_Printf("------- CG_LuaInit Finish -------\n"); return qtrue; } qboolean CG_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs) { int res = lua_resume(T, nargs); if(res == LUA_ERRRUN) { LUA_LOG("Lua: %s error running lua script: %s\n", func, lua_tostring(T, -1)); CG_Printf(S_COLOR_YELLOW "Lua: %s error running lua script: %s\n", func, lua_tostring(T, -1)); lua_pop(T, 1); vm->error++; return qfalse; } else if(res == LUA_ERRMEM) { LUA_LOG("Lua: memory allocation error #2 ( %s )\n", vm->filename); vm->error++; return qfalse; } else if(res == LUA_ERRERR) { LUA_LOG("Lua: traceback error ( %s )\n", vm->filename); CG_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename); vm->error++; return qfalse; } return qtrue; } qboolean CG_LuaCall(lvm_t * vm, char *func, int nargs, int nresults) { int res = lua_pcall(vm->L, nargs, nresults, 0); if(res == LUA_ERRRUN) { LUA_LOG("Lua: %s error running lua script: %s\n", func, lua_tostring(vm->L, -1)); CG_Printf(S_COLOR_YELLOW "Lua: %s error running lua script: %s\n", func, lua_tostring(vm->L, -1)); lua_pop(vm->L, 1); vm->error++; return qfalse; } else if(res == LUA_ERRMEM) { LUA_LOG("Lua: memory allocation error #2 ( %s )\n", vm->filename); vm->error++; return qfalse; } else if(res == LUA_ERRERR) { LUA_LOG("Lua: traceback error ( %s )\n", vm->filename); CG_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename); vm->error++; return qfalse; } return qtrue; } #define SAY_ALL 0 #define SAY_TEAM 1 qboolean CG_LuaGetFunctionT(lua_State *T, char *name) { if(T) { lua_getglobal(T, name); if(lua_isfunction(T, -1)) { return qtrue; } else { lua_pop(T, 1); return qfalse; } } return qfalse; } qboolean CG_LuaGetFunction(lvm_t * vm, char *name) { if(vm->L) { lua_getglobal(vm->L, name); if(lua_isfunction(vm->L, -1)) { return qtrue; } else { lua_pop(vm->L, 1); return qfalse; } } return qfalse; } qboolean CG_LuaStartVM(lvm_t * vm) { int res = 0; char homepath[MAX_QPATH], gamepath[MAX_QPATH]; vm->L = luaL_newstate(); if(!vm->L) { LUA_LOG("Lua: Lua failed to initialise.\n"); return qfalse; } luaL_openlibs(vm->L); trap_Cvar_VariableStringBuffer("fs_homepath", homepath, sizeof(homepath)); trap_Cvar_VariableStringBuffer("fs_game", gamepath, sizeof(gamepath)); lua_getglobal(vm->L, LUA_LOADLIBNAME); if(lua_istable(vm->L, -1)) { lua_pushstring(vm->L, va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); lua_setfield(vm->L, -2, "path"); lua_pushstring(vm->L, va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); lua_setfield(vm->L, -2, "cpath"); } lua_pop(vm->L, 1); Lua_RegisterGlobal(vm->L, "LUA_PATH", va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); Lua_RegisterGlobal(vm->L, "LUA_CPATH", va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); Lua_RegisterGlobal(vm->L, "LUA_DIRSEP", LUA_DIRSEP); lua_newtable(vm->L); Lua_RegConstInteger(vm->L, CS_PLAYERS); Lua_RegConstInteger(vm->L, EXEC_NOW); Lua_RegConstInteger(vm->L, EXEC_INSERT); Lua_RegConstInteger(vm->L, EXEC_APPEND); Lua_RegConstInteger(vm->L, FS_READ); Lua_RegConstInteger(vm->L, FS_WRITE); Lua_RegConstInteger(vm->L, FS_APPEND); Lua_RegConstInteger(vm->L, FS_APPEND_SYNC); Lua_RegConstInteger(vm->L, SAY_ALL); Lua_RegConstInteger(vm->L, SAY_TEAM); Lua_RegConstString(vm->L, HOSTARCH); luaopen_base(vm->L); luaopen_string(vm->L); luaopen_coroutine(vm->L); Luaopen_Qmath(vm->L); Luaopen_Vector(vm->L); res = luaL_loadbuffer(vm->L, vm->code, vm->code_size, vm->filename); if(res == LUA_ERRSYNTAX) { LUA_LOG("Lua: syntax error during pre-compilation: %s\n", (char *)lua_tostring(vm->L, -1)); CG_Printf(S_COLOR_YELLOW "Lua: syntax error: %s\n", (char *)lua_tostring(vm->L, -1)); lua_pop(vm->L, 1); vm->error++; return qfalse; } else if(res == LUA_ERRMEM) { LUA_LOG("Lua: memory allocation error #1 ( %s )\n", vm->filename); vm->error++; return qfalse; } if(!CG_LuaCall(vm, "CG_LuaStartVM", 0, 0)) return qfalse; LUA_LOG("Lua: Loading %s\n", vm->filename); return qtrue; } void CG_LuaStopVM(lvm_t * vm) { if(vm == NULL) return; if(vm->code != NULL) { free(vm->code); vm->code = NULL; } if(vm->id >= 0) { if(lVM[vm->id] == vm) lVM[vm->id] = NULL; if(!vm->error) { LUA_LOG("Lua: Lua module [%s] unloaded.\n", vm->filename); } } free(vm); } void CG_LuaShutdown() { int i; lvm_t *vm; for(i = 0; i < NUM_VMS; i++) { vm = lVM[i]; if(vm) { CG_LuaStopVM(vm); } } trap_FS_FCloseFile(lualog); } void CG_LuaStatus(void) { int i, cnt = 0; for(i = 0; i < NUM_VMS; i++) if(lVM[i]) cnt++; if(cnt == 0) { CG_Printf("Lua: no scripts loaded.\n"); return; } else if(cnt == 1) { CG_Printf("Lua: showing lua information ( 1 module loaded )\n"); } else { CG_Printf("Lua: showing lua information ( %d modules loaded )\n", cnt); } CG_Printf("%-2s %-24s\n", "VM", "Filename"); CG_Printf("-- ------------------------\n"); for(i = 0; i < NUM_VMS; i++) { if(lVM[i]) { CG_Printf("%2d %-24s\n", lVM[i]->id, lVM[i]->filename); } } CG_Printf("-- ------------------------\n"); } lvm_t *CG_LuaGetVM(lua_State * L) { int i; for(i = 0; i < NUM_VMS; i++) if(lVM[i] && lVM[i]->L == L) return lVM[i]; return NULL; } #endif