]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - progsvm.h
edict: Move free and freetime into prvm_edict_t itself
[xonotic/darkplaces.git] / progsvm.h
index 4c29aa3cd680b0186c9a9534b8825f27baf710c3..92ead5dc772a8393f7a7470fee8cec35be11a78c 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -29,10 +29,20 @@ The code uses void pointers instead.
 #ifndef PROGSVM_H
 #define PROGSVM_H
 
+#include <stddef.h>
+#include "qtypes.h"
+#include "qdefs.h"
+#include "common.h"
+#include "zone.h"
 #include "pr_comp.h"                   // defs shared with qcc
 #include "progdefs.h"                  // generated by program cdefs
 #include "clprogdefs.h"                        // generated by program cdefs
 
+struct framegroupblend_s;
+struct frameblend_s;
+struct cmd_state_s;
+struct qfile_s;
+
 #ifndef DP_SMALLMEMORY
 #define PROFILING
 #endif
@@ -64,23 +74,27 @@ typedef struct prvm_required_field_s
        const char *name;
 } prvm_required_field_t;
 
-
+#define PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN -1
+#define PRVM_EDICT_MARK_SETORIGIN_CAUGHT -2
 // AK: I dont call it engine private cause it doesnt really belongs to the engine
 //     it belongs to prvm.
 typedef struct prvm_edict_private_s
 {
-       qboolean free;
-       float 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
+       // mark for the leak detector
+       int mark;
+       // place in the code where it was allocated (for the leak detector)
        const char *allocation_origin;
 } prvm_edict_private_t;
 
 typedef struct prvm_edict_s
 {
+       // true if this edict is unused
+       qbool free;
+       // sv.time when the object was freed (to prevent early reuse which could
+       // mess up client interpolation or obscure severe QuakeC bugs)
+       double freetime;
+
        // engine-private fields (stored in dynamically resized array)
-       //edict_engineprivate_t *e;
        union
        {
                prvm_edict_private_t *required;
@@ -88,7 +102,7 @@ typedef struct prvm_edict_s
                prvm_int_t *ip;
                // FIXME: this server pointer really means world, not server
                // (it is used by both server qc and client qc, but not menu qc)
-               edict_engineprivate_t *server;
+               struct edict_engineprivate_s *server;
                // add other private structs as you desire
                // new structs have to start with the elements of prvm_edit_private_t
                // e.g. a new struct has to either look like this:
@@ -99,7 +113,7 @@ typedef struct prvm_edict_s
                //              ... } server_edict_private_t;
                // or:
                //      typedef struct server_edict_private_s {
-               //              qboolean free;
+               //              qbool free;
                //              float freetime;
                //              vec3_t moved_from;
                //      vec3_t moved_fromangles;
@@ -489,6 +503,31 @@ typedef struct prvm_stringbuffer_s
 }
 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
@@ -500,8 +539,8 @@ typedef struct prvm_prog_s
        int                             functions_covered;
        char                            *strings;
        int                                     stringssize;
-       ddef_t                          *fielddefs;
-       ddef_t                          *globaldefs;
+       mdef_t                          *fielddefs;
+       mdef_t                          *globaldefs;
        mstatement_t            *statements;
        int                                     entityfields;                   // number of vec_t fields in progs (some variables are 3)
        int                                     entityfieldsarea;               // LadyHavoc: equal to max_edicts * entityfields (for bounds checking)
@@ -547,12 +586,15 @@ 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]
 
@@ -588,26 +630,39 @@ typedef struct prvm_prog_s
        //============================================================================
        // until this point everything also exists (with the pr_ prefix) in the old vm
 
-       qfile_t                         *openfiles[PRVM_MAX_OPENFILES];
+       struct qfile_s                          *openfiles[PRVM_MAX_OPENFILES];
        const char *         openfiles_origin[PRVM_MAX_OPENFILES];
-       fssearch_t                      *opensearches[PRVM_MAX_OPENSEARCHES];
+       struct fssearch_s                       *opensearches[PRVM_MAX_OPENSEARCHES];
        const char *         opensearches_origin[PRVM_MAX_OPENSEARCHES];
-       skeleton_t                      *skeletons[MAX_EDICTS];
+       struct skeleton_s       *skeletons[MAX_EDICTS];
+       struct cmd_state_s      *console_cmd; // points to the relevant console command interpreter for this vm (cmd_local 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;
+       struct model_s          *polygonbegin_model;
        // indicates if polygonbegin should be interpreted as 2d
        // (clearscene sets this to false, renderscene sets this to true, drawpic
        //  also sets this to true)
        // note that in FTEQW polygonbegin with 2 args is handled very differently,
        // where the behavior is always 3D unless DRAWFLAG_2D is passed, but
        // DRAWFLAG_2D conflicts with our DRAWFLAG_SCREEN.
-       qboolean                        polygonbegin_guess2d;
+       qbool                   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;
@@ -620,7 +675,11 @@ typedef struct prvm_prog_s
        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
@@ -632,7 +691,7 @@ typedef struct prvm_prog_s
 
        // allow writing to world entity fields, this is set by server init and
        // cleared before first server frame
-       qboolean                        allowworldwrites;
+       qbool                   allowworldwrites;
 
        // name of the prog, e.g. "Server", "Client" or "Menu" (used for text output)
        const char                      *name; // [INIT]
@@ -640,13 +699,13 @@ typedef struct prvm_prog_s
        // flag - used to store general flags like PRVM_GE_SELF, etc.
        int                             flag;
 
-       const char                      *extensionstring; // [INIT]
+       const char                      **extensionstring; // [INIT]
 
-       qboolean                        loadintoworld; // [INIT]
+       qbool                   loadintoworld; // [INIT]
 
        // used to indicate whether a prog is loaded
-       qboolean                        loaded;
-       qboolean                        leaktest_active;
+       qbool                   loaded;
+       qbool                   leaktest_active;
 
        // translation buffer (only needs to be freed on unloading progs, type is private to prvm_edict.c)
        void *po;
@@ -664,7 +723,7 @@ typedef struct prvm_prog_s
 
        //============================================================================
 
-       ddef_t                          *self; // if self != 0 then there is a global self
+       mdef_t                          *self; // if self != 0 then there is a global self
 
        //============================================================================
        // function pointers
@@ -677,7 +736,7 @@ typedef struct prvm_prog_s
 
        void                            (*count_edicts)(struct prvm_prog_s *prog); // [INIT] used by PRVM_ED_Count_f
 
-       qboolean                        (*load_edict)(struct prvm_prog_s *prog, prvm_edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile
+       qbool                   (*load_edict)(struct prvm_prog_s *prog, prvm_edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile
 
        void                            (*init_cmd)(struct prvm_prog_s *prog); // [INIT] used by PRVM_InitProg
        void                            (*reset_cmd)(struct prvm_prog_s *prog); // [INIT] used by PRVM_ResetProg
@@ -718,8 +777,8 @@ extern const int vm_sv_numbuiltins;
 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);
@@ -757,18 +816,20 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa
 #define PRVM_Free(buffer) Mem_Free(buffer)
 
 void PRVM_Profile (prvm_prog_t *prog, int maxfunctions, double mintime, int sortby);
-void PRVM_Profile_f(cmd_state_t *cmd);
-void PRVM_ChildProfile_f(cmd_state_t *cmd);
-void PRVM_CallProfile_f(cmd_state_t *cmd);
-void PRVM_PrintFunction_f(cmd_state_t *cmd);
+void PRVM_Profile_f(struct cmd_state_s *cmd);
+void PRVM_ChildProfile_f(struct cmd_state_s *cmd);
+void PRVM_CallProfile_f(struct cmd_state_s *cmd);
+void PRVM_PrintFunction_f(struct cmd_state_s *cmd);
 
 void PRVM_PrintState(prvm_prog_t *prog, int stack_index);
 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);
+mdef_t *PRVM_ED_FindField(prvm_prog_t *prog, const char *name);
+mdef_t *PRVM_ED_FindGlobal(prvm_prog_t *prog, const char *name);
+prvm_eval_t *PRVM_ED_FindGlobalEval(prvm_prog_t *prog, const char *name);
 mfunction_t *PRVM_ED_FindFunction(prvm_prog_t *prog, const char *name);
 
 int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *name);
@@ -779,30 +840,34 @@ func_t PRVM_ED_FindFunctionOffset(prvm_prog_t *prog, const char *name);
 
 void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog);
 
-qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e);
+qbool PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e);
 prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog);
 void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed);
 void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e);
 
 void PRVM_PrintFunctionStatements(prvm_prog_t *prog, const char *name);
 void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname);
-void PRVM_ED_Write(prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed);
+void PRVM_ED_Write(prvm_prog_t *prog, struct qfile_s *f, prvm_edict_t *ed);
 const char *PRVM_ED_ParseEdict(prvm_prog_t *prog, const char *data, prvm_edict_t *ent);
 
-void PRVM_ED_WriteGlobals(prvm_prog_t *prog, qfile_t *f);
+void PRVM_ED_WriteGlobals(prvm_prog_t *prog, struct qfile_s *f);
 void PRVM_ED_ParseGlobals(prvm_prog_t *prog, const char *data);
 
+void PRVM_ED_CallPrespawnFunction(prvm_prog_t *prog, prvm_edict_t *ent);
+qbool PRVM_ED_CallSpawnFunction(prvm_prog_t *prog, prvm_edict_t *ent, const char *data, const char *start);
+void PRVM_ED_CallPostspawnFunction (prvm_prog_t *prog, prvm_edict_t *ent);
+
 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);
@@ -811,26 +876,26 @@ unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char
 
 //============================================================================
 
-#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);
 
-void PRVM_ED_PrintEdicts_f(cmd_state_t *cmd);
+void PRVM_ED_PrintEdicts_f(struct cmd_state_s *cmd);
 void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname);
 
 const char *PRVM_GetString(prvm_prog_t *prog, int num);
@@ -840,8 +905,8 @@ int PRVM_SetTempString(prvm_prog_t *prog, const char *s);
 int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer);
 void PRVM_FreeString(prvm_prog_t *prog, int num);
 
-ddef_t *PRVM_ED_FieldAtOfs(prvm_prog_t *prog, int ofs);
-qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash);
+mdef_t *PRVM_ED_FieldAtOfs(prvm_prog_t *prog, unsigned int ofs);
+qbool PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, mdef_t *key, const char *s, qbool parsebackslash);
 char *PRVM_UglyValueString(prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength);
 char *PRVM_GlobalString(prvm_prog_t *prog, int ofs, char *line, size_t linelength);
 char *PRVM_GlobalStringNoContents(prvm_prog_t *prog, int ofs, char *line, size_t linelength);
@@ -855,8 +920,8 @@ Set up the fields marked with [INIT] in the prog struct
 Load a program with LoadProgs
 */
 // Load expects to be called right after Reset
-void PRVM_Prog_Init(prvm_prog_t *prog);
-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_Init(prvm_prog_t *prog, struct cmd_state_s *cmd);
+void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data, int64_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);
 
 void PRVM_StackTrace(prvm_prog_t *prog);
@@ -865,9 +930,9 @@ void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype
 
 void VM_Warning(prvm_prog_t *prog, const char *fmt, ...) DP_FUNC_PRINTF(2);
 
-void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed);
-void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const dp_model_t *model, double curtime);
-void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend);
+void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, struct framegroupblend_s *framegroupblend, const prvm_edict_t *ed);
+void VM_FrameBlendFromFrameGroupBlend(struct frameblend_s *frameblend, const struct framegroupblend_s *framegroupblend, const struct model_s *model, double curtime);
+void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const struct model_s *edmodel, const struct frameblend_s *frameblend);
 void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed);
 
 void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement);