]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
Add spawn2, a new spawn builtin TimePath/spawn2
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 18 Feb 2018 04:24:28 +0000 (15:24 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 18 Feb 2018 10:48:34 +0000 (21:48 +1100)
Entities are allocated outside the normal pool, for full qc control

clvm_cmds.c
mvm_cmds.c
progsvm.h
prvm_cmds.c
prvm_cmds.h
prvm_edict.c
prvm_exec.c
prvm_execprogram.h
svvm_cmds.c

index 290cabca3e201213ce07a6768361941c735626c2..56b002e18d89cb73220b25277002dad12d11ab39 100644 (file)
@@ -1878,6 +1878,10 @@ static void VM_CL_copyentity (prvm_prog_t *prog)
                return;
        }
        memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
+       if (PRVM_NUM_FOR_EDICT(out) < 0)
+       {
+               return;
+       }
        CL_LinkEdict(out);
 }
 
@@ -4940,7 +4944,7 @@ NULL,                                                     // #596
 NULL,                                                  // #597
 NULL,                                                  // #598
 NULL,                                                  // #599
-NULL,                                                  // #600
+VM_spawn2,                                             // #600
 NULL,                                                  // #601
 NULL,                                                  // #602
 NULL,                                                  // #603
index ace22bfa74c2ac5009dcde180ea00b2adb0e7dea..80ede5f113606c3c68c527d702fc72b8a70fe177 100644 (file)
@@ -1558,7 +1558,7 @@ NULL,                                                                     // #596
 NULL,                                                                  // #597
 NULL,                                                                  // #598
 NULL,                                                                  // #599
-NULL,                                                                  // #600
+VM_spawn2,                                                             // #600
 VM_M_setkeydest,                                       // #601 void setkeydest(float dest)
 VM_M_getkeydest,                                       // #602 float getkeydest(void)
 VM_M_setmousetarget,                           // #603 void setmousetarget(float trg)
index 0a46d2aaaaad42d1c5951bd98cba02727851a160..8e548cee962d3eaf70c4d9f9051e4d84ac0a54f2 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -648,8 +648,11 @@ typedef struct prvm_prog_s
        // number of reserved edicts (allocated from 1)
        int                                     reserved_edicts; // [INIT]
 
+       size_t edicts_offset;
        prvm_edict_t            *edicts;
+       size_t edictsfields_offset;
        prvm_vec_t              *edictsfields;
+       size_t edictprivate_offset;
        void                            *edictprivate;
 
        // size of the engine private struct
@@ -810,6 +813,8 @@ void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog);
 
 qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e);
 prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog);
+#define SPAWN2_LIMIT 8192
+prvm_edict_t *PRVM_ED_Alloc2(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);
 
@@ -823,9 +828,9 @@ void PRVM_ED_ParseGlobals(prvm_prog_t *prog, const char *data);
 
 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))
+int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline);
+#define        PRVM_EDICT(n) ((((n) >= -SPAWN2_LIMIT) && ((n) < prog->max_edicts)) ? (n) : PRVM_EDICT_NUM_ERROR(prog, (n), __FILE__, __LINE__))
+#define        PRVM_EDICT_NUM(n) (prog->edicts + PRVM_EDICT((int)(n)))
 
 //int NUM_FOR_EDICT_ERROR(prvm_edict_t *e);
 #define PRVM_NUM_FOR_EDICT(e) ((int)((prvm_edict_t *)(e) - prog->edicts))
index e2b023e24e1c16ed18f00abd02a8252bb41f30cb..1fd15b7d0210d520ae886acc4d3d7d4054c9d3f2 100644 (file)
@@ -893,7 +893,7 @@ void VM_ftoe(prvm_prog_t *prog)
        VM_SAFEPARMCOUNT(1, VM_ftoe);
 
        ent = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM0);
-       if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
+       if (ent < -SPAWN2_LIMIT || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
                ent = 0; // return world instead of a free or invalid entity
 
        PRVM_G_INT(OFS_RETURN) = ent;
@@ -975,6 +975,15 @@ void VM_spawn(prvm_prog_t *prog)
        VM_RETURN_EDICT(ed);
 }
 
+void VM_spawn2(prvm_prog_t *prog)
+{
+       prvm_edict_t    *ed;
+       VM_SAFEPARMCOUNT(0, VM_spawn2);
+       prog->xfunction->builtinsprofile += 20;
+       ed = PRVM_ED_Alloc2(prog);
+       VM_RETURN_EDICT(ed);
+}
+
 /*
 =========
 VM_remove
index 0120975805c24be28016c5a7c3848b84c2a808b5..0df2c8eaf6de71ee09cfb233d546ecea41350c5a 100644 (file)
@@ -256,6 +256,7 @@ void VM_itof(prvm_prog_t *prog);
 void VM_ftoe(prvm_prog_t *prog);
 void VM_strftime(prvm_prog_t *prog);
 void VM_spawn (prvm_prog_t *prog);
+void VM_spawn2 (prvm_prog_t *prog);
 void VM_remove (prvm_prog_t *prog);
 void VM_find (prvm_prog_t *prog);
 void VM_findfloat (prvm_prog_t *prog);
index 79c937a492767aa72088748435fe4536a8b49f30..dea9efe4e480fbdf8af899875c86f972210382aa 100644 (file)
@@ -59,6 +59,9 @@ PRVM_MEM_Alloc
 static void PRVM_MEM_Alloc(prvm_prog_t *prog)
 {
        int i;
+       unsigned int edicts_offset;
+       unsigned int edictprivate_offset;
+       unsigned int edictsfields_offset;
 
        // reserve space for the null entity aka world
        // check bound of max_edicts
@@ -69,21 +72,34 @@ static void PRVM_MEM_Alloc(prvm_prog_t *prog)
        prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
 
        // alloc edicts
-       prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
+       edicts_offset = (unsigned int) SPAWN2_LIMIT;
+       prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool, (edicts_offset + prog->limit_edicts) * sizeof(prvm_edict_t));
+       prog->edicts += (prog->edicts_offset = edicts_offset);
 
        // alloc edict private space
-       prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
+       edictprivate_offset = (unsigned int) SPAWN2_LIMIT * prog->edictprivate_size;
+       prog->edictprivate = Mem_Alloc(prog->progs_mempool, edictprivate_offset + prog->max_edicts * prog->edictprivate_size);
+       prog->edictprivate += (prog->edictprivate_offset = edictprivate_offset);
 
        // alloc edict fields
-       prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
+       edictsfields_offset = (unsigned int) SPAWN2_LIMIT * prog->entityfields;
+       prog->entityfieldsarea = edictsfields_offset + prog->max_edicts * prog->entityfields;
        prog->edictsfields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(prvm_vec_t));
+       prog->edictsfields += (prog->edictsfields_offset = edictsfields_offset);
 
        // set edict pointers
-       for(i = 0; i < prog->max_edicts; i++)
+       for(i = -SPAWN2_LIMIT; i < prog->max_edicts; i++)
        {
                prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
                prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
        }
+
+       // todo(TimePath): allow pure entities to be spawned, this little part is a hack
+       for(i = -SPAWN2_LIMIT; i < 0; ++i)
+       {
+               prog->edicts[i].priv.required->free = true;
+               prog->edicts[i].priv.required->freetime = -1337;
+       }
 }
 
 /*
@@ -94,6 +110,8 @@ PRVM_MEM_IncreaseEdicts
 void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog)
 {
        int             i;
+       unsigned int edictsfields_offset;
+       unsigned int edictprivate_offset;
 
        if(prog->max_edicts >= prog->limit_edicts)
                return;
@@ -103,14 +121,19 @@ void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog)
        // increase edicts
        prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
 
-       prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
-       prog->edictsfields = (prvm_vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(prvm_vec_t));
-       prog->edictprivate = (void *)Mem_Realloc(prog->progs_mempool, (void *)prog->edictprivate, prog->max_edicts * prog->edictprivate_size);
+       edictsfields_offset = (unsigned int) SPAWN2_LIMIT * prog->entityfields;
+       prog->entityfieldsarea = edictsfields_offset + prog->max_edicts * prog->entityfields;
+       prog->edictsfields = (prvm_vec_t*)Mem_Realloc(prog->progs_mempool, (void *)(prog->edictsfields - prog->edictsfields_offset), prog->entityfieldsarea * sizeof(prvm_vec_t));
+       prog->edictsfields += (prog->edictsfields_offset = edictsfields_offset);
+
+       edictprivate_offset = (unsigned int) SPAWN2_LIMIT * prog->edictprivate_size;
+       prog->edictprivate = Mem_Realloc(prog->progs_mempool, (void *)(prog->edictprivate - prog->edictprivate_offset), edictprivate_offset + prog->max_edicts * prog->edictprivate_size);
+       prog->edictprivate += (prog->edictprivate_offset = edictprivate_offset);
 
        //set e and v pointers
-       for(i = 0; i < prog->max_edicts; i++)
+       for(i = -SPAWN2_LIMIT; i < prog->max_edicts; i++)
        {
-               prog->edicts[i].priv.required  = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
+               prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
                prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
        }
 
@@ -205,6 +228,10 @@ void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e)
                Mem_Free((char *)e->priv.required->allocation_origin);
        e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
 
+       if (PRVM_NUM_FOR_EDICT(e) < 0)
+       {
+               return;
+       }
        // AK: Let the init_edict function determine if something needs to be initialized
        prog->init_edict(prog, e);
 }
@@ -287,6 +314,24 @@ prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog)
        return e;
 }
 
+prvm_edict_t *PRVM_ED_Alloc2(prvm_prog_t *prog)
+{
+       int i;
+       prvm_edict_t *e;
+
+       for (i = -1; i >= -SPAWN2_LIMIT; --i)
+       {
+               e = PRVM_EDICT_NUM(i);
+               if (PRVM_ED_CanAlloc(prog, e))
+               {
+                       PRVM_ED_ClearEdict(prog, e);
+                       return e;
+               }
+       }
+       prog->error_cmd("%s: PRVM_ED_Alloc2: no free edicts", prog->name);
+       return NULL;
+}
+
 /*
 =================
 PRVM_ED_Free
@@ -2949,7 +2994,7 @@ void PRVM_Prog_Init(prvm_prog_t *prog)
 }
 
 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
-unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline)
+int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline)
 {
        prog->error_cmd("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", prog->name, n, filename, fileline);
        return 0;
index 37daaaa252f19ccf84039862a5c2cd5c9d305c40..adac881b7da87f2e6e97e3f09e814c646a5e4c1d 100644 (file)
@@ -747,11 +747,11 @@ void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessag
        prvm_vec_t tempfloat;
        // these may become out of date when a builtin is called, and are updated accordingly
        prvm_vec_t *cached_edictsfields = prog->edictsfields;
-       unsigned int cached_entityfields = prog->entityfields;
+       int cached_entityfields = prog->entityfields;
        unsigned int cached_entityfields_3 = prog->entityfields - 3;
-       unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
+       int cached_entityfieldsarea = prog->entityfieldsarea;
        unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
-       unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
+       int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
        unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
        unsigned int cached_max_edicts = prog->max_edicts;
        // these do not change
@@ -854,11 +854,11 @@ void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa
        prvm_vec_t tempfloat;
        // these may become out of date when a builtin is called, and are updated accordingly
        prvm_vec_t *cached_edictsfields = prog->edictsfields;
-       unsigned int cached_entityfields = prog->entityfields;
+       int cached_entityfields = prog->entityfields;
        unsigned int cached_entityfields_3 = prog->entityfields - 3;
-       unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
+       int cached_entityfieldsarea = prog->entityfieldsarea;
        unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
-       unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
+       int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
        unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
        unsigned int cached_max_edicts = prog->max_edicts;
        // these do not change
@@ -965,11 +965,11 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa
        prvm_vec_t tempfloat;
        // these may become out of date when a builtin is called, and are updated accordingly
        prvm_vec_t *cached_edictsfields = prog->edictsfields;
-       unsigned int cached_entityfields = prog->entityfields;
+       int cached_entityfields = prog->entityfields;
        unsigned int cached_entityfields_3 = prog->entityfields - 3;
-       unsigned int cached_entityfieldsarea = prog->entityfieldsarea;
+       int cached_entityfieldsarea = prog->entityfieldsarea;
        unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields;
-       unsigned int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
+       int cached_entityfieldsarea_3 = prog->entityfieldsarea - 3;
        unsigned int cached_entityfieldsarea_entityfields_3 = prog->entityfieldsarea - prog->entityfields - 3;
        unsigned int cached_max_edicts = prog->max_edicts;
        // these do not change
index 6578d78902de24c88a91ea591cf09366eaeaa7f6..b67391113bb9d3d7e3a61f352449c9186843018d 100644 (file)
                                prog->xstatement = st + 1 - cached_statements;
                                PRVM_Watchpoint(prog, 1, "Global watchpoint hit by engine", prog->watch_global_type, &prog->watch_global_value, g);
                        }
-                       if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts)
+                       if (prog->watch_field_type != ev_void && prog->watch_edict >= -SPAWN2_LIMIT && prog->watch_edict < prog->max_edicts)
                        {
                                prvm_eval_t *g = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field);
                                prog->xstatement = st + 1 - cached_statements;
                        HANDLE_OPCODE(OP_STOREP_FNC):           // pointers
                                if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields)
                                {
-                                       if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea)
+                                       if ((prvm_int_t)OPB->_int < -(prvm_int_t)prog->edictsfields_offset || (prvm_int_t)OPB->_int >= cached_entityfieldsarea)
                                        {
                                                PRE_ERROR();
                                                prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
                                                goto cleanup;
                                        }
-                                       if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
+                                       if ((prvm_int_t)OPB->_int >= 0 && (prvm_int_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
                                        {
                                                PRE_ERROR();
                                                VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
                        HANDLE_OPCODE(OP_STOREP_V):
                                if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3)
                                {
-                                       if ((prvm_uint_t)OPB->_int > cached_entityfieldsarea_3)
+                                       if ((prvm_int_t)OPB->_int < -(prvm_int_t)prog->edictsfields_offset || (prvm_int_t)OPB->_int >= cached_entityfieldsarea_3)
                                        {
                                                PRE_ERROR();
                                                prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, (int)OPB->_int);
                                                goto cleanup;
                                        }
-                                       if ((prvm_uint_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
+                                       if ((prvm_int_t)OPB->_int >= 0 && (prvm_int_t)OPB->_int < cached_entityfields && !cached_allowworldwrites)
                                        {
                                                PRE_ERROR();
                                                VM_Warning(prog, "assignment to world.%s (field %i) in %s\n", PRVM_GetString(prog, PRVM_ED_FieldAtOfs(prog, OPB->_int)->s_name), (int)OPB->_int, prog->name);
                                DISPATCH_OPCODE();
 
                        HANDLE_OPCODE(OP_ADDRESS):
-                               if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
+                               if ((prvm_uint_t)OPA->edict < -SPAWN2_LIMIT && (prvm_uint_t)OPA->edict >= cached_max_edicts)
                                {
                                        PRE_ERROR();
                                        prog->error_cmd("%s Progs attempted to address an out of bounds edict number", prog->name);
                        HANDLE_OPCODE(OP_LOAD_ENT):
                        HANDLE_OPCODE(OP_LOAD_S):
                        HANDLE_OPCODE(OP_LOAD_FNC):
-                               if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
+                               if ((prvm_int_t)OPA->edict < -SPAWN2_LIMIT && (prvm_int_t)OPA->edict >= cached_max_edicts)
                                {
                                        PRE_ERROR();
                                        prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
                                DISPATCH_OPCODE();
 
                        HANDLE_OPCODE(OP_LOAD_V):
-                               if ((prvm_uint_t)OPA->edict >= cached_max_edicts)
+                               if ((prvm_int_t)OPA->edict < -SPAWN2_LIMIT && (prvm_int_t)OPA->edict >= cached_max_edicts)
                                {
                                        PRE_ERROR();
                                        prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name);
                                        prog->xstatement = st - cached_statements;
                                        PRVM_Watchpoint(prog, 0, "Global watchpoint hit", prog->watch_global_type, &prog->watch_global_value, g);
                                }
-                               if (prog->watch_field_type != ev_void && prog->watch_edict < prog->max_edicts)
+                               if (prog->watch_field_type != ev_void && prog->watch_edict >= -SPAWN2_LIMIT && prog->watch_edict < prog->max_edicts)
                                {
                                        prvm_eval_t *g = PRVM_EDICTFIELDVALUE(prog->edicts + prog->watch_edict, prog->watch_field);
                                        prog->xstatement = st - cached_statements;
index b5f96a84827f8e2a69e5d9fe568a2e6b2b6efce0..a012c7eadb0cde67db46744d9029fda118d2aa22 100644 (file)
@@ -1766,6 +1766,10 @@ static void VM_SV_copyentity(prvm_prog_t *prog)
                return;
        }
        memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
+       if (PRVM_NUM_FOR_EDICT(out) < 0)
+       {
+               return;
+       }
        SV_LinkEdict(out);
 }
 
@@ -3785,7 +3789,7 @@ NULL,                                                     // #596
 NULL,                                                  // #597
 NULL,                                                  // #598
 NULL,                                                  // #599
-NULL,                                                  // #600
+VM_spawn2,                                             // #600
 NULL,                                                  // #601
 NULL,                                                  // #602
 NULL,                                                  // #603