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);
}
NULL, // #597
NULL, // #598
NULL, // #599
-NULL, // #600
+VM_spawn2, // #600
NULL, // #601
NULL, // #602
NULL, // #603
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)
// 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
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);
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))
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;
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
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);
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
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;
+ }
}
/*
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;
// 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;
}
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);
}
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
}
// 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;
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
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
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
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;
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);
}
NULL, // #597
NULL, // #598
NULL, // #599
-NULL, // #600
+VM_spawn2, // #600
NULL, // #601
NULL, // #602
NULL, // #603