typedef struct prvm_edict_private_s
{
qboolean free;
- float freetime; // realtime of last change to "free" (i.e. also set on allocation)
+ double freetime; // realtime of last change to "free" (i.e. also set on allocation)
int mark; // used during leaktest (0 = unref, >0 = referenced); special values during server physics:
#define PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN -1
#define PRVM_EDICT_MARK_SETORIGIN_CAUGHT -2
}
prvm_stringbuffer_t;
+// flags for knownstrings
+#define KNOWNSTRINGFLAG_ENGINE 1
+#define KNOWNSTRINGFLAG_GCMARK 2
+#define KNOWNSTRINGFLAG_GCPRUNE 4 // cleared by GCMARK code, string is freed if prune remains after two sweeps
+
+typedef enum prvm_prog_garbagecollection_state_stage_e
+{
+ PRVM_GC_START = 0,
+ PRVM_GC_GLOBALS_MARK,
+ PRVM_GC_FIELDS_MARK,
+ PRVM_GC_KNOWNSTRINGS_SWEEP,
+ PRVM_GC_RESET,
+}
+prvm_prog_garbagecollection_state_stage_t;
+
+typedef struct prvm_prog_garbagecollection_state_s
+{
+ int stage;
+ int globals_mark_progress;
+ int fields_mark_progress;
+ int fields_mark_progress_entity;
+ int knownstrings_sweep_progress;
+}
+prvm_prog_garbagecollection_state_t;
+
// [INIT] variables flagged with this token can be initialized by 'you'
// NOTE: external code has to create and free the mempools but everything else is done by prvm !
typedef struct prvm_prog_s
// (simple optimization of the free string search)
int firstfreeknownstring;
const char **knownstrings;
- unsigned char *knownstrings_freeable;
+ unsigned char *knownstrings_flags;
const char **knownstrings_origin;
const char ***stringshash;
memexpandablearray_t stringbuffersarray;
+ // garbage collection status
+ prvm_prog_garbagecollection_state_t gc;
+
// all memory allocations related to this vm_prog (code, edicts, strings)
mempool_t *progs_mempool; // [INIT]
fssearch_t *opensearches[PRVM_MAX_OPENSEARCHES];
const char * opensearches_origin[PRVM_MAX_OPENSEARCHES];
skeleton_t *skeletons[MAX_EDICTS];
+ cmd_state_t *console_cmd; // points to the relevant console command interpreter for this vm (&cmd_client or &cmd_server), also used to access cvars
// buffer for storing all tempstrings created during one invocation of ExecuteProgram
sizebuf_t tempstringsbuf;
- // in csqc the polygonbegin,polygonvertex,polygonend sequencing is
- // stateful, so this tracks the last polygonbegin's choice of
+ // polygonbegin, polygonvertex, polygonend state
+ // the polygon is buffered here until polygonend commits it to the relevant
+ // CL_Mesh entity, because important decisions depend on the vertex data
+ // provided (e.g. whether the polygon is transparent), we can't really do much
+ // with it until we have all of the data...
+
+ // this tracks the last polygonbegin's choice of
// CL_Mesh_CSQC or CL_Mesh_UI for this polygon
dp_model_t *polygonbegin_model;
// indicates if polygonbegin should be interpreted as 2d
// where the behavior is always 3D unless DRAWFLAG_2D is passed, but
// DRAWFLAG_2D conflicts with our DRAWFLAG_SCREEN.
qboolean polygonbegin_guess2d;
+ // the texture name and drawflags provided to polygonbegin
+ char polygonbegin_texname[MAX_QPATH];
+ int polygonbegin_drawflags;
+ // the vertex data
+ int polygonbegin_numvertices;
+ int polygonbegin_maxvertices;
+ float *polygonbegin_vertexdata;
// copies of some vars that were former read from sv
int num_edicts;
int reserved_edicts; // [INIT]
prvm_edict_t *edicts;
- prvm_vec_t *edictsfields;
+ union
+ {
+ prvm_vec_t *fp;
+ prvm_int_t *ip;
+ } edictsfields;
void *edictprivate;
// size of the engine private struct
// flag - used to store general flags like PRVM_GE_SELF, etc.
int flag;
- const char *extensionstring; // [INIT]
+ const char **extensionstring; // [INIT]
qboolean loadintoworld; // [INIT]
extern const int vm_cl_numbuiltins;
extern const int vm_m_numbuiltins;
-extern const char * vm_sv_extensions; // client also uses this
-extern const char * vm_m_extensions;
+extern const char *vm_sv_extensions[]; // client also uses this
+extern const char *vm_m_extensions[];
void SVVM_init_cmd(prvm_prog_t *prog);
void SVVM_reset_cmd(prvm_prog_t *prog);
void PRVM_Crash(prvm_prog_t *prog);
void PRVM_ShortStackTrace(prvm_prog_t *prog, char *buf, size_t bufsize);
const char *PRVM_AllocationOrigin(prvm_prog_t *prog);
+void PRVM_GarbageCollection(prvm_prog_t *prog);
ddef_t *PRVM_ED_FindField(prvm_prog_t *prog, const char *name);
ddef_t *PRVM_ED_FindGlobal(prvm_prog_t *prog, const char *name);
void PRVM_ED_LoadFromFile(prvm_prog_t *prog, const char *data);
unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline);
-#define PRVM_EDICT(n) (((unsigned)(n) < (unsigned int)prog->max_edicts) ? (unsigned int)(n) : PRVM_EDICT_NUM_ERROR(prog, (unsigned int)(n), __FILE__, __LINE__))
-#define PRVM_EDICT_NUM(n) (prog->edicts + PRVM_EDICT(n))
+#define PRVM_EDICT(n) (((unsigned)(n) < (unsigned int)prog->max_edicts) ? (unsigned int)(n) : PRVM_EDICT_NUM_ERROR(prog, (unsigned int)(n), __FILE__, __LINE__))
+#define PRVM_EDICT_NUM(n) (prog->edicts + PRVM_EDICT(n))
//int NUM_FOR_EDICT_ERROR(prvm_edict_t *e);
#define PRVM_NUM_FOR_EDICT(e) ((int)((prvm_edict_t *)(e) - prog->edicts))
//int PRVM_NUM_FOR_EDICT(prvm_edict_t *e);
-#define PRVM_NEXT_EDICT(e) ((e) + 1)
+#define PRVM_NEXT_EDICT(e) ((e) + 1)
#define PRVM_EDICT_TO_PROG(e) (PRVM_NUM_FOR_EDICT(e))
//int PRVM_EDICT_TO_PROG(prvm_edict_t *e);
//============================================================================
-#define PRVM_G_FLOAT(o) (prog->globals.fp[o])
-#define PRVM_G_INT(o) (prog->globals.ip[o])
-#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(prog->globals.ip[o]))
+#define PRVM_G_FLOAT(o) (prog->globals.fp[o])
+#define PRVM_G_INT(o) (prog->globals.ip[o])
+#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(prog->globals.ip[o]))
#define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o))
-#define PRVM_G_VECTOR(o) (&prog->globals.fp[o])
-#define PRVM_G_STRING(o) (PRVM_GetString(prog, prog->globals.ip[o]))
-//#define PRVM_G_FUNCTION(prog, o) (prog->globals.ip[o])
+#define PRVM_G_VECTOR(o) (&prog->globals.fp[o])
+#define PRVM_G_STRING(o) (PRVM_GetString(prog, prog->globals.ip[o]))
+//#define PRVM_G_FUNCTION(prog, o) (prog->globals.ip[o])
// FIXME: make these go away?
-#define PRVM_E_FLOAT(e,o) (e->fields.fp[o])
-#define PRVM_E_INT(e,o) (e->fields.ip[o])
-//#define PRVM_E_VECTOR(e,o) (&(e->fields.fp[o]))
-#define PRVM_E_STRING(e,o) (PRVM_GetString(prog, e->fields.ip[o]))
+#define PRVM_E_FLOAT(e,o) (e->fields.fp[o])
+#define PRVM_E_INT(e,o) (e->fields.ip[o])
+//#define PRVM_E_VECTOR(e,o) (&(e->fields.fp[o]))
+#define PRVM_E_STRING(e,o) (PRVM_GetString(prog, e->fields.ip[o]))
-extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to
+extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to
// make the new vm mostly independent from the old one, thus if it's necessary, I copy everything
void PRVM_Init_Exec(prvm_prog_t *prog);
Load a program with LoadProgs
*/
// Load expects to be called right after Reset
-void PRVM_Prog_Init(prvm_prog_t *prog);
+void PRVM_Prog_Init(prvm_prog_t *prog, cmd_state_t *cmd);
void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global);
void PRVM_Prog_Reset(prvm_prog_t *prog);