From 2368f5100c732fdcba615a976ae42c859ae418f9 Mon Sep 17 00:00:00 2001 From: TimePath Date: Mon, 28 Dec 2015 18:43:13 +1100 Subject: [PATCH] spawn2 hack --- clvm_cmds.c | 2 +- mvm_cmds.c | 2 +- progsvm.h | 17 ++++++++- prvm_cmds.c | 9 +++++ prvm_cmds.h | 1 + prvm_edict.c | 30 +++++++++++++++ prvm_exec.c | 6 +-- prvm_execprogram.h | 91 +++++++++++++++++++++++++++++++--------------- svvm_cmds.c | 2 +- 9 files changed, 122 insertions(+), 38 deletions(-) diff --git a/clvm_cmds.c b/clvm_cmds.c index 9d41dda6..8fe3ed15 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -4938,7 +4938,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 8483fae9..7095b867 100644 --- a/progsvm.h +++ b/progsvm.h @@ -653,6 +653,12 @@ typedef struct prvm_prog_s prvm_vec_t *edictsfields; void *edictprivate; + struct { + prvm_edict_t *ed; + prvm_vec_t *fields; + void *priv; + } edicts2; + // size of the engine private struct int edictprivate_size; // [INIT] @@ -809,6 +815,7 @@ 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); +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); @@ -824,10 +831,16 @@ 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_NUM(n) (n >= 0 ? (prog->edicts + PRVM_EDICT(n)) : (prog->edicts2.ed + (-(n) - 1))) + +#define SPAWN2_LIMIT (8192) //int NUM_FOR_EDICT_ERROR(prvm_edict_t *e); -#define PRVM_NUM_FOR_EDICT(e) ((int)((prvm_edict_t *)(e) - prog->edicts)) +#define PRVM_NUM_FOR_EDICT(e) \ + (((int)((prvm_edict_t *)(e) - prog->edicts2.ed) >= 0 \ + && (int)((prvm_edict_t *)(e) - prog->edicts2.ed) < SPAWN2_LIMIT) \ + ? (int)((prvm_edict_t *)(e) - prog->edicts2.ed) \ + : (int)((prvm_edict_t *)(e) - prog->edicts)) //int PRVM_NUM_FOR_EDICT(prvm_edict_t *e); #define PRVM_NEXT_EDICT(e) ((e) + 1) diff --git a/prvm_cmds.c b/prvm_cmds.c index e1b248dd..715ef975 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -972,6 +972,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); + prog->globals.ip[OFS_RETURN] = -(int)(ed - prog->edicts2.ed) - 1; +} + /* ========= 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 77a1af71..88164ef4 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -84,6 +84,20 @@ static void PRVM_MEM_Alloc(prvm_prog_t *prog) 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; } + + // pure entities + { + prog->edicts2.ed = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool, SPAWN2_LIMIT * sizeof(prvm_edict_t)); + prog->edicts2.priv = Mem_Alloc(prog->progs_mempool, SPAWN2_LIMIT * prog->edictprivate_size); + prog->edicts2.fields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, SPAWN2_LIMIT * prog->entityfields * sizeof(prvm_vec_t)); + for(i = 0; i < SPAWN2_LIMIT; ++i) + { + prog->edicts2.ed[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edicts2.priv + i * prog->edictprivate_size); + prog->edicts2.ed[i].priv.required->free = true; + prog->edicts2.ed[i].priv.required->freetime = -1337; + prog->edicts2.ed[i].fields.fp = prog->edicts2.fields + i * prog->entityfields; + } + } } /* @@ -287,6 +301,22 @@ prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog) return e; } +prvm_edict_t *PRVM_ED_Alloc2(prvm_prog_t *prog) +{ + int i; + for (i = 0; i < SPAWN2_LIMIT; ++i) + { + prvm_edict_t *e = &prog->edicts2.ed[i]; + if (PRVM_ED_CanAlloc(prog, e)) + { + PRVM_ED_ClearEdict(prog, e); + return e; + } + } + prog->error_cmd("%s: PRVM_ED_Alloc2: no free edicts (%d)", prog->name, i); + return NULL; +} + /* ================= PRVM_ED_Free diff --git a/prvm_exec.c b/prvm_exec.c index ad11c113..4a5d8a31 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -753,7 +753,7 @@ void MVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessag unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; unsigned 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; + int cached_max_edicts = prog->max_edicts; // these do not change mstatement_t *cached_statements = prog->statements; qboolean cached_allowworldwrites = prog->allowworldwrites; @@ -860,7 +860,7 @@ void CLVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; unsigned 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; + int cached_max_edicts = prog->max_edicts; // these do not change mstatement_t *cached_statements = prog->statements; qboolean cached_allowworldwrites = prog->allowworldwrites; @@ -971,7 +971,7 @@ void PRVM_ExecuteProgram (prvm_prog_t *prog, func_t fnum, const char *errormessa unsigned int cached_entityfieldsarea_entityfields = prog->entityfieldsarea - prog->entityfields; unsigned 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; + int cached_max_edicts = prog->max_edicts; // these do not change mstatement_t *cached_statements = prog->statements; qboolean cached_allowworldwrites = prog->allowworldwrites; diff --git a/prvm_execprogram.h b/prvm_execprogram.h index 1607bcfe..88f925fc 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -296,46 +296,68 @@ HANDLE_OPCODE(OP_STOREP_FLD): // integers HANDLE_OPCODE(OP_STOREP_S): HANDLE_OPCODE(OP_STOREP_FNC): // pointers - if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields) + { + int i, fld; + if (OPB->_int >= 0) { + i = OPB->_int / cached_entityfields; + fld = OPB->_int % cached_entityfields; + } else { + int inp = -OPB->_int - 1; + i = -((inp / cached_entityfields) + 1); + fld = inp % cached_entityfields; + // VM_Warning(prog, "storep %i : %i . %i = %i\n", OPB->_int, i, fld); + } + if (i >= cached_max_edicts || i < -SPAWN2_LIMIT) { - if ((prvm_uint_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) - { - 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); - } + PRE_ERROR(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, i); + goto cleanup; } - ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + if (i == 0 && !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); + } + ptr = i >= 0 + ? (prvm_eval_t *)(cached_edictsfields + OPB->_int) + : (prvm_eval_t *)(prog->edicts2.fields + (-i - 1) * cached_entityfields + fld); ptr->_int = OPA->_int; DISPATCH_OPCODE(); + } HANDLE_OPCODE(OP_STOREP_V): - if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3) + { + int i, fld; + if (OPB->_int >= 0) { + i = OPB->_int / cached_entityfields; + fld = OPB->_int % cached_entityfields; + } else { + int o = -OPB->_int - 1; + i = -((o / cached_entityfields) + 1); + fld = o % cached_entityfields; + // VM_Warning(prog, "storep %i : %i . %i = %i\n", OPB->_int, i, fld); + } + if (i >= cached_max_edicts || i < -SPAWN2_LIMIT) { - if ((prvm_uint_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) - { - 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); - } + PRE_ERROR(); + prog->error_cmd("%s attempted to write to an out of bounds edict (%i)", prog->name, i); + goto cleanup; + } + if (i == 0 && !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); } - ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); + ptr = i >= 0 + ? (prvm_eval_t *)(cached_edictsfields + OPB->_int) + : (prvm_eval_t *)(prog->edicts2.fields + (-i - 1) * cached_entityfields + fld); ptr->ivector[0] = OPA->ivector[0]; ptr->ivector[1] = OPA->ivector[1]; ptr->ivector[2] = OPA->ivector[2]; DISPATCH_OPCODE(); + } HANDLE_OPCODE(OP_ADDRESS): - if ((prvm_uint_t)OPA->edict >= cached_max_edicts) + if (OPA->edict >= cached_max_edicts || OPA->edict < -SPAWN2_LIMIT) { PRE_ERROR(); prog->error_cmd("%s Progs attempted to address an out of bounds edict number", prog->name); @@ -355,7 +377,16 @@ goto cleanup; } #endif - OPC->_int = OPA->edict * cached_entityfields + OPB->_int; + if (OPA->edict >= 0) + OPC->_int = OPA->edict * cached_entityfields + OPB->_int; + else { + int e = -OPA->edict - 1; + int out = e * cached_entityfields + OPB->_int; + out = out + 1; + out = 0 - out; + //VM_Warning(prog, "addressing %i . %i = %i\n", OPA->edict, OPB->_int, out); + OPC->_int = out; + } DISPATCH_OPCODE(); HANDLE_OPCODE(OP_LOAD_F): @@ -363,7 +394,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 (OPA->edict >= cached_max_edicts || OPA->edict < -SPAWN2_LIMIT) { PRE_ERROR(); prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name); @@ -380,7 +411,7 @@ DISPATCH_OPCODE(); HANDLE_OPCODE(OP_LOAD_V): - if ((prvm_uint_t)OPA->edict >= cached_max_edicts) + if (OPA->edict >= cached_max_edicts || OPA->edict < -SPAWN2_LIMIT) { PRE_ERROR(); prog->error_cmd("%s Progs attempted to read an out of bounds edict number", prog->name); diff --git a/svvm_cmds.c b/svvm_cmds.c index ff55c4fd..ab7cc087 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -3783,7 +3783,7 @@ NULL, // #596 NULL, // #597 NULL, // #598 NULL, // #599 -NULL, // #600 +VM_spawn2, // #600 NULL, // #601 NULL, // #602 NULL, // #603 -- 2.39.2