diff --git a/cgame/Makefile b/cgame/Makefile index 30281b9..bc8a7e8 100644 --- a/cgame/Makefile +++ b/cgame/Makefile @@ -56,6 +56,7 @@ OBJ = \ cg_drawtools.o \ cg_draw.o \ cg_consolecmds.o \ + cg_lua.o \ lua_vector.o \ lua_qmath.o \ @@ -136,6 +137,7 @@ cg_servercmds.o : cg_servercmds.c; $(DO_CC) cg_snapshot.o : cg_snapshot.c; $(DO_CC) cg_view.o : cg_view.c; $(DO_CC) cg_weapons.o : cg_weapons.c; $(DO_CC) +cg_lua.o : cg_lua.c; $(DO_CC) fx_compression.o : fx_compression.c; $(DO_CC) fx_grenade.o : fx_grenade.c; $(DO_CC) fx_item.o : fx_item.c; $(DO_CC) diff --git a/cgame/cg_local.h b/cgame/cg_local.h index 01114ec..d2d0a52 100644 --- a/cgame/cg_local.h +++ b/cgame/cg_local.h @@ -1821,6 +1821,12 @@ extern vmCvar_t rpg_forceFieldSet; // grp cvars extern vmCvar_t grp_berp; +// lua +#ifdef CG_LUA +extern vmCvar_t cg_debugLua; +extern vmCvar_t cg_logLua; +#endif + diff --git a/cgame/cg_lua.c b/cgame/cg_lua.c new file mode 100644 index 0000000..d7f88df --- /dev/null +++ b/cgame/cg_lua.c @@ -0,0 +1,368 @@ +// 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 diff --git a/cgame/cg_lua.h b/cgame/cg_lua.h new file mode 100644 index 0000000..a11ebaa --- /dev/null +++ b/cgame/cg_lua.h @@ -0,0 +1,69 @@ +#ifndef _G_LUA_H +#define _G_LUA_H + +#include "cg_local.h" + +#if (defined __linux__ || defined __WIN32__) // linux or mingw +#include "../game/lua.h" +#include "../game/lauxlib.h" +#include "../game/lualib.h" +#else +#include "../game/lua.h" +#include "../game/lauxlib.h" +#include "../game/lualib.h" +#endif + +#define NUM_VMS 1 + +#if defined __linux__ +#define HOSTARCH "UNIX" +#define EXTENSION "so" +#elif defined WIN32 +#define HOSTARCH "WIN32" +#define EXTENSION "dll" +#elif defined __APPLE__ +#define HOSTARCH "UNIX" +#define EXTENSION "dylib" +#endif + +#define Lua_RegisterGlobal(L, n, v) (lua_pushstring(L, v), lua_setglobal(L, n)) +#define Lua_RegConstInteger(L, n) (lua_pushstring(L, #n), lua_pushinteger(L, n), lua_settable(L, -3)) +#define Lua_RegConstString(L, n) (lua_pushstring(L, #n), lua_pushstring(L, n), lua_settable(L, -3)) + +typedef struct { + int id; + char filename[MAX_QPATH]; + char *code; + int code_size; + int error; + lua_State *L; +} lvm_t; + +extern lvm_t *lVM[NUM_VMS]; + +void QDECL LUA_DEBUG(const char *fmt, ...); +void QDECL LUA_LOG(const char *fmt, ...); +qboolean CG_LuaInit(void); +qboolean CG_LuaCall(lvm_t *vm, char *func, int nargs, int nresults); +qboolean CG_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs); +qboolean CG_LuaGetFunction(lvm_t *vm, char *name); +qboolean CG_LuaGetFunctionT(lua_State *T, char *name); +qboolean CG_LuaStartVM(lvm_t *vm); +void CG_LuaStopVM(lvm_t *vm); +void CG_LuaShutdown(void); +void CG_LuaStatus(void); +lvm_t *CG_LuaGetVM(lua_State *L); + +// lua_cgame.c +int Luaopen_CGame(lua_State *L); + +// lua_qmath.c +int Luaopen_Qmath(lua_State *L); + +// lua_vector.c +int Luaopen_Vector(lua_State *L); +void Lua_PushVector(lua_State *L, vec3_t v); +vec_t *Lua_GetVector(lua_State *L, int argNum); +int Lua_IsVector(lua_State *L, int index); +vec3_t *Lua_GetVectorMisc(lua_State *L, int *index); +#endif diff --git a/cgame/cg_main.c b/cgame/cg_main.c index 75d0278..0771a27 100644 --- a/cgame/cg_main.c +++ b/cgame/cg_main.c @@ -195,6 +195,12 @@ vmCvar_t rpg_forceFieldSet; // grp cvars vmCvar_t grp_berp; +// lua +#ifdef CG_LUA +vmCvar_t cg_debugLua; +vmCvar_t cg_logLua; +#endif + //RPG-X | Phenix | 05/02/2006 //Ban System (and it's backup cvars) @@ -342,7 +348,14 @@ static cvarTable_t cvarTable[] = { //{ &cg_playerID, "cg_playerID", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART } // grp cvars - { &grp_berp, "grp_berp", "0", CVAR_ARCHIVE | CVAR_LATCH } + { &grp_berp, "grp_berp", "0", CVAR_ARCHIVE | CVAR_LATCH }, + + // lua +#ifdef CG_LUA + { &cg_debugLua, "cg_debuglua", "0", CVAR_ARCHIVE | CVAR_LATCH }, + { &cg_logLua, "cg_loglua", "0", CVAR_ARCHIVE } +#endif + }; static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); diff --git a/cgame/cgame.vcxproj b/cgame/cgame.vcxproj index ab1ec04..319b2de 100644 --- a/cgame/cgame.vcxproj +++ b/cgame/cgame.vcxproj @@ -269,6 +269,7 @@ WIN32;NDEBUG;_WINDOWS true + Disabled WIN32;_DEBUG;_WINDOWS @@ -461,6 +462,7 @@ + diff --git a/cgame/cgame.vcxproj.filters b/cgame/cgame.vcxproj.filters index bd58327..ee12c12 100644 --- a/cgame/cgame.vcxproj.filters +++ b/cgame/cgame.vcxproj.filters @@ -128,6 +128,9 @@ Source Files + + Source Files + @@ -163,6 +166,9 @@ Header Files + + Header Files + diff --git a/stefgame.suo b/stefgame.suo index 4471281..53f0796 100644 Binary files a/stefgame.suo and b/stefgame.suo differ