From 75f20c6eefc5c87da38793aa9a05eff300d23955 Mon Sep 17 00:00:00 2001 From: Walter Julius Hennecke Date: Mon, 19 Nov 2012 18:13:03 +0100 Subject: [PATCH] Multiple fixes * made sure Lua GarbageCollector gets rid of finished lua threads (or at least I hope so) * changed timed message to be stored in a struct as the list isn't safe to use with char* * changed parser and format for timedmessages.cfg --- code/game/g_active.c | 4 ++- code/game/g_cmds.c | 3 +- code/game/g_local.h | 7 ++++ code/game/g_lua.c | 81 +++++++++++++++++++++++++++++++++++++++----- code/game/g_main.c | 62 ++++++++++++++++++++++----------- code/game/q_shared.c | 29 ++++++++++++++++ code/game/q_shared.h | 14 ++++++-- 7 files changed, 167 insertions(+), 33 deletions(-) diff --git a/code/game/g_active.c b/code/game/g_active.c index 1c4d54f..102c344 100644 --- a/code/game/g_active.c +++ b/code/game/g_active.c @@ -512,6 +512,7 @@ list_iter_p iterTimedMessages; */ static char *TimedMessage( void ){ char* message; + timedMessage_t *msg; if(!level.timedMessages->length) { return "^1RPG-X ERROR: No messages to display"; @@ -524,7 +525,8 @@ static char *TimedMessage( void ){ } } - message = (char *)list_cycl_next(iterTimedMessages); + msg = (timedMessage_t *)list_cycl_next(iterTimedMessages); + message = msg->message; return message; } diff --git a/code/game/g_cmds.c b/code/game/g_cmds.c index 16fa138..17b356c 100644 --- a/code/game/g_cmds.c +++ b/code/game/g_cmds.c @@ -7439,7 +7439,8 @@ static void Cmd_Camtest_f(gentity_t *ent) { } void Cmd_CamtestEnd_f(gentity_t *ent) { - Cinematic_DeactivateCameraMode(ent); + //Cinematic_DeactivateCameraMode(ent); + G_LuaNumThreads(); } // END CCAM diff --git a/code/game/g_local.h b/code/game/g_local.h index 9f4093c..93aa9eb 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -1368,6 +1368,8 @@ qboolean LuaHook_G_EntityTrigger(char *function, int entnum, int othernum); qboolean LuaHook_G_EntitySpawn(char *function, int entnum); qboolean LuaHook_G_EntityReached(char *function, int entnum); qboolean LuaHook_G_EntityReachedAngular(char *function, int entnum); +void G_LuaNumThreads(void); +void G_LuaCollectGarbage(void); void G_LuaStatus(gentity_t * ent); qboolean G_LuaInit(void); @@ -2099,5 +2101,10 @@ struct safeZone_s { vec3_t mins; } safeZone_s; +// timed messages +typedef struct timedMessage_s timedMessage_t; +struct timedMessage_s { + char* message; +} timedMessage_s; #endif //_G_LOCAL_H_ diff --git a/code/game/g_lua.c b/code/game/g_lua.c index f4aadb8..ff194d3 100644 --- a/code/game/g_lua.c +++ b/code/game/g_lua.c @@ -172,7 +172,24 @@ qboolean G_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs) { G_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename); vm->error++; return qfalse; - } + } + + if(vm->L != T) { // this is a thread + int n = lua_gettop(vm->L); + int i; + lua_State *p; + + for(i = 0; i <= n; i++) { + if(lua_isthread(vm->L, i)) { + p = lua_tothread(vm->L, i); + + if(p == T) { + lua_remove(vm->L, i); + G_LuaCollectGarbage(); + } + } + } + } return qtrue; } @@ -264,22 +281,22 @@ qboolean G_LuaStartVM(lvm_t * vm) 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)); + 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)); + 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)); + 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)); + 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); @@ -588,6 +605,7 @@ qboolean LuaHook_G_EntityThink(char *function, int entnum) continue; } } else { + t = vm->L; if(!G_LuaGetFunctionT(t, function)) continue; ent = &g_entities[entnum]; @@ -1071,4 +1089,49 @@ qboolean LuaHook_G_EntitySpawn(char *function, int entnum) return qfalse; } +void G_LuaNumThreads(void) { + lvm_t* vm = lVM[0]; + + if(vm) { + lua_State *p; + int n = lua_gettop(vm->L); + int i, cnt = 0; + + for(i = 0; i <= n; i++) { + if(lua_isthread(vm->L, i)) { + cnt++; + p = lua_tothread(vm->L, i); + if(lua_status(p) == LUA_YIELD) { + G_Printf("lua thread %d is YIELDED\n", i); + } else if(lua_status(vm->L) == 0) { + G_Printf("lua thread %d is RUNNING\n", i); + } + } + } + G_Printf("Total lua thread count: %d\n", cnt); + } +} + +void G_LuaCollectGarbage(void) { + lvm_t *vm; + lua_State *p; + int i, n, m; + + for(i = 0; i < NUM_VMS; i++) { + vm = lVM[i]; + + if(vm) { + n = lua_gettop(vm->L); + + for(m = n; m > 0; m--) { + if(lua_isthread(vm->L, m)) { + p = lua_tothread(vm->L, m); + lua_gc(p, LUA_GCCOLLECT, 0); + } + } + lua_gc(vm->L, LUA_GCCOLLECT, 0); + } + } +} + #endif \ No newline at end of file diff --git a/code/game/g_main.c b/code/game/g_main.c index 4387189..5260bac 100644 --- a/code/game/g_main.c +++ b/code/game/g_main.c @@ -906,10 +906,11 @@ void SP_target_location (gentity_t *ent); static void G_LoadTimedMessages(void) { fileHandle_t f; char* buffer; - char* ptr; - char* message; + char* textPtr; + char* token; int len; - int i, n; + int i; + timedMessage_t *msg; len = trap_FS_FOpenFile("timedmessages.cfg", &f, FS_READ); if(!len) return; @@ -930,26 +931,49 @@ static void G_LoadTimedMessages(void) { } trap_FS_Read(buffer, len, f); - ptr = buffer; + + textPtr = buffer; + COM_BeginParseSession(); + token = COM_Parse(&textPtr); + if(token[0] != '{') { + G_Printf("G_LoadTimedMessages - timedmessages.cfg not beginning with '{'\n"); + trap_FS_FCloseFile(f); + free(buffer); + return; + } + for(i = 0; i < 10; i++) { - for(n = 0; ptr[n] != ';' && ptr[n] != 0; n++); - if(ptr[n] == 0) break; - message = (char *)malloc(sizeof(char)*(n+1)); - if(!message) { - G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i byte.\n", (n+1) * sizeof(char) ); - trap_FS_FCloseFile(f); - free(buffer); - if(level.timedMessages != NULL) { - destroy_list(level.timedMessages); - } - return; + token = COM_Parse(&textPtr); + + if(!token[0]) { + break; } - memset(message, 0, sizeof(message)); - strncpy(message, ptr, n); - list_add(level.timedMessages, message, strlen(message)); + if(!strcmp(token, "message")) { + if(COM_ParseString(&textPtr, &token)) { + G_Printf("G_LoadTimedMessages - invalid value '%s'\n", token); + SkipRestOfLine(&textPtr); + continue; + } - ptr += strlen(message)+1; + msg = (timedMessage_t *)malloc(sizeof(timedMessage_s)); + if(msg == NULL) { + G_Printf("G_LoadTimedMessages - was unable to allocate timed message storage\n"); + continue; + } + + msg->message = strdup(token); + G_Printf("------------------------------------------------>'%s'\n", token); + list_add(level.timedMessages, msg, sizeof(timedMessage_s)); + } else { + G_Printf("G_LoadTimedMessages - invalid token '%s'\n", token); + SkipRestOfLine(&textPtr); + continue; + } + + if(token[0] == '}') { + break; + } } trap_FS_FCloseFile(f); diff --git a/code/game/q_shared.c b/code/game/q_shared.c index fed9314..5b5662a 100644 --- a/code/game/q_shared.c +++ b/code/game/q_shared.c @@ -738,6 +738,35 @@ char* Q_strrchr( const char* string, int c ) return sp; } +char* Q_strtok(char* str, const char *tok, int size) { + char *ptr; + char *result; + int i, l; + + if(str == NULL || tok == NULL) { + return NULL; + } + + ptr = (char *)str; + + for(i = 0; i < strlen(str); i++) { + for(l = 0; l < size; l++) { + if(ptr[i] == tok[l]) { + result = (char *)malloc(sizeof(char)+(i+1)); + if(result == NULL) { + return NULL; + } + strncpy(result, str, i); + result[i] = '\0'; + + return result; + } + } + } + + return NULL; +} + /* ============= Q_strncpyz diff --git a/code/game/q_shared.h b/code/game/q_shared.h index c51b7f9..a8ee5a5 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -688,9 +688,17 @@ int Q_isalpha( int c ); int Q_stricmp (const char *s1, const char *s2); int Q_strncmp (const char *s1, const char *s2, int n); int Q_stricmpn (const char *s1, const char *s2, int n); -char *Q_strlwr( char *s1 ); -char *Q_strupr( char *s1 ); -char *Q_strrchr( const char* string, int c ); +char* Q_strlwr( char *s1 ); +char* Q_strupr( char *s1 ); +char* Q_strrchr( const char* string, int c ); +/** + * Goes through a given str searching for one of the given tokens. + * If it finds one it returns a new string containing everything + * from str until the found token (Note: remember to free the result + * if no longer needed). Returns NULL if no token is found. Make sure + * to adjust str for the next call yourself as this function won't do that. + */ +char* Q_strtok(char* str, const char *tok, int size); // buffer size safe library replacements void Q_strncpyz( char *dest, const char *src, int destsize );