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
This commit is contained in:
Walter Julius Hennecke 2012-11-19 18:13:03 +01:00
parent 94ffb3ea61
commit 75f20c6eef
7 changed files with 167 additions and 33 deletions

View file

@ -512,6 +512,7 @@ list_iter_p iterTimedMessages;
*/ */
static char *TimedMessage( void ){ static char *TimedMessage( void ){
char* message; char* message;
timedMessage_t *msg;
if(!level.timedMessages->length) { if(!level.timedMessages->length) {
return "^1RPG-X ERROR: No messages to display"; 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; return message;
} }

View file

@ -7439,7 +7439,8 @@ static void Cmd_Camtest_f(gentity_t *ent) {
} }
void Cmd_CamtestEnd_f(gentity_t *ent) { void Cmd_CamtestEnd_f(gentity_t *ent) {
Cinematic_DeactivateCameraMode(ent); //Cinematic_DeactivateCameraMode(ent);
G_LuaNumThreads();
} }
// END CCAM // END CCAM

View file

@ -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_EntitySpawn(char *function, int entnum);
qboolean LuaHook_G_EntityReached(char *function, int entnum); qboolean LuaHook_G_EntityReached(char *function, int entnum);
qboolean LuaHook_G_EntityReachedAngular(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); void G_LuaStatus(gentity_t * ent);
qboolean G_LuaInit(void); qboolean G_LuaInit(void);
@ -2099,5 +2101,10 @@ struct safeZone_s {
vec3_t mins; vec3_t mins;
} safeZone_s; } safeZone_s;
// timed messages
typedef struct timedMessage_s timedMessage_t;
struct timedMessage_s {
char* message;
} timedMessage_s;
#endif //_G_LOCAL_H_ #endif //_G_LOCAL_H_

View file

@ -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); G_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename);
vm->error++; vm->error++;
return qfalse; 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; return qtrue;
} }
@ -264,22 +281,22 @@ qboolean G_LuaStartVM(lvm_t * vm)
if(lua_istable(vm->L, -1)) if(lua_istable(vm->L, -1))
{ {
lua_pushstring(vm->L, va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", 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,
homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP));
lua_setfield(vm->L, -2, "path"); lua_setfield(vm->L, -2, "path");
lua_pushstring(vm->L, va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", 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, EXTENSION,
homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION));
lua_setfield(vm->L, -2, "cpath"); lua_setfield(vm->L, -2, "cpath");
} }
lua_pop(vm->L, 1); lua_pop(vm->L, 1);
Lua_RegisterGlobal(vm->L, "LUA_PATH", va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", 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,
homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, 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", 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, EXTENSION,
homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION));
Lua_RegisterGlobal(vm->L, "LUA_DIRSEP", LUA_DIRSEP); Lua_RegisterGlobal(vm->L, "LUA_DIRSEP", LUA_DIRSEP);
lua_newtable(vm->L); lua_newtable(vm->L);
@ -588,6 +605,7 @@ qboolean LuaHook_G_EntityThink(char *function, int entnum)
continue; continue;
} }
} else { } else {
t = vm->L;
if(!G_LuaGetFunctionT(t, function)) if(!G_LuaGetFunctionT(t, function))
continue; continue;
ent = &g_entities[entnum]; ent = &g_entities[entnum];
@ -1071,4 +1089,49 @@ qboolean LuaHook_G_EntitySpawn(char *function, int entnum)
return qfalse; 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 #endif

View file

@ -906,10 +906,11 @@ void SP_target_location (gentity_t *ent);
static void G_LoadTimedMessages(void) { static void G_LoadTimedMessages(void) {
fileHandle_t f; fileHandle_t f;
char* buffer; char* buffer;
char* ptr; char* textPtr;
char* message; char* token;
int len; int len;
int i, n; int i;
timedMessage_t *msg;
len = trap_FS_FOpenFile("timedmessages.cfg", &f, FS_READ); len = trap_FS_FOpenFile("timedmessages.cfg", &f, FS_READ);
if(!len) return; if(!len) return;
@ -930,26 +931,49 @@ static void G_LoadTimedMessages(void) {
} }
trap_FS_Read(buffer, len, f); 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(i = 0; i < 10; i++) {
for(n = 0; ptr[n] != ';' && ptr[n] != 0; n++); token = COM_Parse(&textPtr);
if(ptr[n] == 0) break;
message = (char *)malloc(sizeof(char)*(n+1)); if(!token[0]) {
if(!message) { break;
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;
} }
memset(message, 0, sizeof(message)); if(!strcmp(token, "message")) {
strncpy(message, ptr, n); if(COM_ParseString(&textPtr, &token)) {
list_add(level.timedMessages, message, strlen(message)); 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); trap_FS_FCloseFile(f);

View file

@ -738,6 +738,35 @@ char* Q_strrchr( const char* string, int c )
return sp; 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 Q_strncpyz

View file

@ -688,9 +688,17 @@ int Q_isalpha( int c );
int Q_stricmp (const char *s1, const char *s2); int Q_stricmp (const char *s1, const char *s2);
int Q_strncmp (const char *s1, const char *s2, int n); int Q_strncmp (const char *s1, const char *s2, int n);
int Q_stricmpn (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_strlwr( char *s1 );
char *Q_strupr( char *s1 ); char* Q_strupr( char *s1 );
char *Q_strrchr( const char* string, int c ); 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 // buffer size safe library replacements
void Q_strncpyz( char *dest, const char *src, int destsize ); void Q_strncpyz( char *dest, const char *src, int destsize );