From: TimePath Date: Sun, 18 Feb 2018 04:24:28 +0000 (+1100) Subject: Add spawn2, a new spawn builtin X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=12a5782d8c014cec619e85f75dde95a568875bd1;p=xonotic%2Fdarkplaces.git Add spawn2, a new spawn builtin Entities are allocated outside the normal pool, for full qc control --- diff --git a/clvm_cmds.c b/clvm_cmds.c index 290cabca..56b002e1 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -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 diff --git a/mvm_cmds.c b/mvm_cmds.c index ace22bfa..80ede5f1 100644 --- a/mvm_cmds.c +++ b/mvm_cmds.c @@ -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) diff --git a/progsvm.h b/progsvm.h index 0a46d2aa..8e548cee 100644 --- 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)) diff --git a/prvm_cmds.c b/prvm_cmds.c index e2b023e2..1fd15b7d 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -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 diff --git a/prvm_cmds.h b/prvm_cmds.h index 01209758..0df2c8ea 100644 --- a/prvm_cmds.h +++ b/prvm_cmds.h @@ -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); diff --git a/prvm_edict.c b/prvm_edict.c index 79c937a4..dea9efe4 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -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; diff --git a/prvm_exec.c b/prvm_exec.c index 37daaaa2..adac881b 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -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 diff --git a/prvm_execprogram.h b/prvm_execprogram.h index 6578d789..b6739111 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -129,7 +129,7 @@ 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; @@ -298,13 +298,13 @@ 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); @@ -316,13 +316,13 @@ 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); @@ -335,7 +335,7 @@ 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); @@ -363,7 +363,7 @@ 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); @@ -380,7 +380,7 @@ 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); @@ -844,7 +844,7 @@ 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; diff --git a/svvm_cmds.c b/svvm_cmds.c index b5f96a84..a012c7ea 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -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