X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=prvm_edict.c;h=83d194d3453915d614144031e37009e2a19b73e6;hb=320b43dcc126fa57ea6674ce2b99c04dcee1869d;hp=0c9b0d77304c55cba155cf7aa31e26edc30d50fc;hpb=0bf7bf2f4201bb0391abedfadd480bd7a435508d;p=xonotic%2Fdarkplaces.git diff --git a/prvm_edict.c b/prvm_edict.c index 0c9b0d77..83d194d3 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -48,6 +48,7 @@ cvar_t prvm_garbagecollection_enable = {CVAR_CLIENT | CVAR_SERVER, "prvm_garbage cvar_t prvm_garbagecollection_notify = {CVAR_CLIENT | CVAR_SERVER, "prvm_garbagecollection_notify", "0", "print out a notification for each resource freed by garbage collection"}; cvar_t prvm_garbagecollection_scan_limit = {CVAR_CLIENT | CVAR_SERVER, "prvm_garbagecollection_scan_limit", "10000", "scan this many fields or resources per frame to free up unreferenced resources"}; cvar_t prvm_garbagecollection_strings = {CVAR_CLIENT | CVAR_SERVER, "prvm_garbagecollection_strings", "1", "automatically call strunzone() on strings that are not referenced"}; +cvar_t prvm_stringdebug = {CVAR_CLIENT | CVAR_SERVER, "prvm_stringdebug", "0", "Print debug and warning messages related to strings"}; static double prvm_reuseedicts_always_allow = 0; qboolean prvm_runawaycheck = true; @@ -204,7 +205,7 @@ void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e) { memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); e->priv.required->free = false; - e->priv.required->freetime = realtime; + e->priv.required->freetime = host.realtime; if(e->priv.required->allocation_origin) Mem_Free((char *)e->priv.required->allocation_origin); e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog); @@ -236,13 +237,13 @@ qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e) { if(!e->priv.required->free) return false; - if(prvm_reuseedicts_always_allow == realtime) + if(prvm_reuseedicts_always_allow == host.realtime) return true; - if(realtime <= e->priv.required->freetime + 0.1 && prvm_reuseedicts_neverinsameframe.integer) + if(host.realtime <= e->priv.required->freetime + 0.1 && prvm_reuseedicts_neverinsameframe.integer) return false; // never allow reuse in same frame (causes networking trouble) if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value) return true; - if(realtime > e->priv.required->freetime + 1) + if(host.realtime > e->priv.required->freetime + 1) return true; return false; // entity slot still blocked because the entity was freed less than one second ago } @@ -308,7 +309,7 @@ void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed) prog->free_edict(prog, ed); ed->priv.required->free = true; - ed->priv.required->freetime = realtime; + ed->priv.required->freetime = host.realtime; if(ed->priv.required->allocation_origin) { Mem_Free((char *)ed->priv.required->allocation_origin); @@ -714,7 +715,6 @@ PRVM_ED_Write For savegames ============= */ -extern cvar_t developer_entityparsing; void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed) { ddef_t *d; @@ -1164,11 +1164,10 @@ static void PRVM_ED_EdictGet_f(cmd_state_t *cmd) if(Cmd_Argc(cmd) == 5) { cvar_t *cvar = Cvar_FindVar(cmd->cvars, Cmd_Argv(cmd, 4), cmd->cvars_flagsmask); - if (cvar && cvar->flags & CVAR_READONLY) - { - Con_Printf("prvm_edictget: %s is read-only\n", cvar->name); - goto fail; - } + if (cvar) + if(Cvar_Readonly(cvar, "prvm_edictget")) + goto fail; + Cvar_Get(cmd->cvars, Cmd_Argv(cmd, 4), s, cmd->cvars_flagsmask, NULL); } else @@ -1207,11 +1206,9 @@ static void PRVM_ED_GlobalGet_f(cmd_state_t *cmd) if(Cmd_Argc(cmd) == 4) { cvar_t *cvar = Cvar_FindVar(cmd->cvars, Cmd_Argv(cmd, 3), cmd->cvars_flagsmask); - if (cvar && cvar->flags & CVAR_READONLY) - { - Con_Printf("prvm_globalget: %s is read-only\n", cvar->name); - goto fail; - } + if (cvar) + if(Cvar_Readonly(cvar, "prvm_globalget")) + goto fail; Cvar_Get(cmd->cvars, Cmd_Argv(cmd, 3), s, cmd->cvars_flagsmask, NULL); } else @@ -1345,7 +1342,7 @@ const char *PRVM_ED_ParseEdict (prvm_prog_t *prog, const char *data, prvm_edict_ if (!init) { ent->priv.required->free = true; - ent->priv.required->freetime = realtime; + ent->priv.required->freetime = host.realtime; } return data; @@ -1380,7 +1377,7 @@ void PRVM_ED_LoadFromFile (prvm_prog_t *prog, const char *data) spawned = 0; died = 0; - prvm_reuseedicts_always_allow = realtime; + prvm_reuseedicts_always_allow = host.realtime; // parse ents while (1) @@ -1979,7 +1976,7 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file prog->profiletime = Sys_DirtyTime(); - prog->starttime = realtime; + prog->starttime = host.realtime; Con_DPrintf("%s programs occupy %iK.\n", prog->name, (int)(filesize/1024)); @@ -2394,7 +2391,9 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da if(!cvar) { const char *value; - char buf[64]; + char buf[128]; + int prec[3]; + float f; Con_DPrintf("PRVM_LoadProgs: no cvar for autocvar global %s in %s, creating...\n", name, prog->name); switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) { @@ -2402,11 +2401,33 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * da if((float)((int)(val->_float)) == val->_float) dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float)); else - dpsnprintf(buf, sizeof(buf), "%.9g", val->_float); + { + // ftos_slow + f = val->_float; + for (int precision = 7; precision <= 9; ++precision) { + dpsnprintf(buf, sizeof(buf), "%.*g", precision, f); + if ((float)atof(buf) == f) { + break; + } + } + } value = buf; break; case ev_vector: - dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf; + for (i = 0; i < 3; ++i) + { + prec[i] = 9; + f = val->vector[i]; + for (int precision = 7; precision <= 9; ++precision) { + dpsnprintf(buf, sizeof(buf), "%.*g", precision, f); + if ((float)atof(buf) == f) { + prec[i] = precision; + break; + } + } + } + dpsnprintf(buf, sizeof(buf), "%.*g %.*g %.*g", prec[0], val->vector[0], prec[1], val->vector[1], prec[2], val->vector[2]); + value = buf; break; case ev_string: value = PRVM_GetString(prog, val->string); @@ -2468,7 +2489,7 @@ fail: ; } - prog->loaded = TRUE; + prog->loaded = true; PRVM_UpdateBreakpoints(prog); @@ -2485,7 +2506,7 @@ fail: // Inittime is at least the time when this function finished. However, // later events may bump it. - prog->inittime = realtime; + prog->inittime = host.realtime; } @@ -2722,7 +2743,7 @@ void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text) Con_Printf("PRVM_Breakpoint: %s\n", text); PRVM_PrintState(prog, stack_index); if (prvm_breakpointdump.integer) - Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name)); + SV_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name)); } void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n) @@ -2916,47 +2937,26 @@ PRVM_Init */ void PRVM_Init (void) { - Cmd_AddCommand(&cmd_client, "prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls"); - Cmd_AddCommand(&cmd_client, "prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console"); - Cmd_AddCommand(&cmd_client, "prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console"); - Cmd_AddCommand(&cmd_client, "prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_client, "cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument"); - Cmd_AddCommand(&cmd_client, "menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument"); - Cmd_AddCommand(&cmd_client, "sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument"); - Cmd_AddCommand(&cmd_client, "prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint"); - Cmd_AddCommand(&cmd_client, "prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); - Cmd_AddCommand(&cmd_client, "prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); - - Cmd_AddCommand(&cmd_server, "prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls"); - Cmd_AddCommand(&cmd_server, "prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console"); - Cmd_AddCommand(&cmd_server, "prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console"); - Cmd_AddCommand(&cmd_server, "prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)"); - Cmd_AddCommand(&cmd_server, "cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument"); - Cmd_AddCommand(&cmd_server, "menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument"); - Cmd_AddCommand(&cmd_server, "sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument"); - Cmd_AddCommand(&cmd_server, "prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint"); - Cmd_AddCommand(&cmd_server, "prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); - Cmd_AddCommand(&cmd_server, "prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); + Cmd_AddCommand(CMD_SHARED, "prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls"); + Cmd_AddCommand(CMD_SHARED, "prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console"); + Cmd_AddCommand(CMD_SHARED, "prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console"); + Cmd_AddCommand(CMD_SHARED, "prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)"); + Cmd_AddCommand(CMD_SHARED, "cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument"); + Cmd_AddCommand(CMD_SHARED, "menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument"); + Cmd_AddCommand(CMD_SHARED, "sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument"); + Cmd_AddCommand(CMD_SHARED, "prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint"); + Cmd_AddCommand(CMD_SHARED, "prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); + Cmd_AddCommand(CMD_SHARED, "prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint"); Cvar_RegisterVariable (&prvm_language); Cvar_RegisterVariable (&prvm_traceqc); @@ -2975,6 +2975,7 @@ void PRVM_Init (void) Cvar_RegisterVariable (&prvm_garbagecollection_notify); Cvar_RegisterVariable (&prvm_garbagecollection_scan_limit); Cvar_RegisterVariable (&prvm_garbagecollection_strings); + Cvar_RegisterVariable (&prvm_stringdebug); // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!) prvm_runawaycheck = !COM_CheckParm("-norunaway"); @@ -3008,7 +3009,8 @@ const char *PRVM_GetString(prvm_prog_t *prog, int num) if (num < 0) { // invalid - VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num); + if (prvm_stringdebug.integer) + VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num); return ""; } else if (num < prog->stringssize) @@ -3024,7 +3026,8 @@ const char *PRVM_GetString(prvm_prog_t *prog, int num) return (char *)prog->tempstringsbuf.data + num; else { - VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize); + if (prvm_stringdebug.integer) + VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize); return ""; } } @@ -3036,7 +3039,8 @@ const char *PRVM_GetString(prvm_prog_t *prog, int num) { if (!prog->knownstrings[num]) { - VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num); + if (prvm_stringdebug.integer) + VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num); return ""; } // refresh the garbage collection on the string - this guards @@ -3048,14 +3052,16 @@ const char *PRVM_GetString(prvm_prog_t *prog, int num) } else { - VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings); + if (prvm_stringdebug.integer) + VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings); return ""; } } else { // invalid string offset - VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize); + if (prvm_stringdebug.integer) + VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize); return ""; } } @@ -3187,7 +3193,7 @@ int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer) for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++) if (!prog->knownstrings[i]) break; - s = PRVM_Alloc(bufferlength); + s = (char *)PRVM_Alloc(bufferlength); PRVM_NewKnownString(prog, i, KNOWNSTRINGFLAG_GCMARK, s); if(prog->leaktest_active) prog->knownstrings_origin[i] = PRVM_AllocationOrigin(prog);