// alloc edict fields
prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
- prog->edictsfields = (vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(vec_t));
+ prog->edictsfields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(prvm_vec_t));
// set edict pointers
for(i = 0; 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.vp = prog->edictsfields + i * prog->entityfields;
+ prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
}
}
prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
- prog->edictsfields = (vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(vec_t));
+ 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);
//set e and v pointers
for(i = 0; 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.vp = prog->edictsfields + i * prog->entityfields;
+ prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
}
prog->end_increase_edicts(prog);
*/
void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e)
{
- memset(e->fields.vp, 0, prog->entityfields * 4);
+ memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
e->priv.required->free = false;
// AK: Let the init_edict function determine if something needs to be initialized
break;
case ev_float:
// LordHavoc: changed from %5.1f to %10.4f
- dpsnprintf (line, linelength, "%10.4f", val->_float);
+ dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float);
break;
case ev_vector:
// LordHavoc: changed from %5.1f to %10.4f
- dpsnprintf (line, linelength, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
+ dpsnprintf (line, linelength, "'" VECTOR_LOSSLESS_FORMAT "'", val->vector[0], val->vector[1], val->vector[2]);
break;
case ev_pointer:
dpsnprintf (line, linelength, "pointer");
line[i] = '\0';
break;
case ev_entity:
- dpsnprintf (line, linelength, "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
+ dpsnprintf (line, linelength, "%i", val->edict);
break;
case ev_function:
f = prog->functions + val->function;
dpsnprintf (line, linelength, "void");
break;
case ev_float:
- dpsnprintf (line, linelength, "%.9g", val->_float);
+ dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float);
break;
case ev_vector:
- dpsnprintf (line, linelength, "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]);
+ dpsnprintf (line, linelength, VECTOR_LOSSLESS_FORMAT, val->vector[0], val->vector[1], val->vector[2]);
break;
default:
dpsnprintf (line, linelength, "bad type %i", type);
char *s;
//size_t i;
ddef_t *def;
- void *val;
+ prvm_eval_t *val;
char valuebuf[MAX_INPUTLINE];
- val = (void *)&prog->globals.generic[ofs];
+ val = (prvm_eval_t *)&prog->globals.fp[ofs];
def = PRVM_ED_GlobalAtOfs(prog, ofs);
if (!def)
dpsnprintf (line, linelength, "GLOBAL%i", ofs);
else
{
- s = PRVM_ValueString (prog, (etype_t)def->type, (prvm_eval_t *)val, valuebuf, sizeof(valuebuf));
+ s = PRVM_ValueString (prog, (etype_t)def->type, val, valuebuf, sizeof(valuebuf));
dpsnprintf (line, linelength, "%s (=%s)", PRVM_GetString(prog, def->s_name), s);
}
{
size_t l;
ddef_t *d;
- int *v;
+ prvm_eval_t *val;
int i, j;
const char *name;
int type;
// Didn't match; skip
continue;
- v = (int *)(ed->fields.vp + d->ofs);
+ val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
// if the value is still all 0, skip the field
type = d->type & ~DEF_SAVEGLOBAL;
for (j=0 ; j<prvm_type_size[type] ; j++)
- if (v[j])
+ if (val->ivector[j])
break;
if (j == prvm_type_size[type])
continue;
strlcat(tempstring, " ", sizeof(tempstring));
strlcat(tempstring, " ", sizeof(tempstring));
- name = PRVM_ValueString(prog, (etype_t)d->type, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf));
+ name = PRVM_ValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf));
if (strlen(name) > sizeof(tempstring2)-4)
{
memcpy (tempstring2, name, sizeof(tempstring2)-4);
void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed)
{
ddef_t *d;
- int *v;
+ prvm_eval_t *val;
int i, j;
const char *name;
int type;
if(strlen(name) > 1 && name[strlen(name)-2] == '_')
continue; // skip _x, _y, _z vars, and ALSO other _? vars as some mods expect them to be never saved (TODO: a gameplayfix for using the "more precise" condition above?)
- v = (int *)(ed->fields.vp + d->ofs);
+ val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
// if the value is still all 0, skip the field
type = d->type & ~DEF_SAVEGLOBAL;
for (j=0 ; j<prvm_type_size[type] ; j++)
- if (v[j])
+ if (val->ivector[j])
break;
if (j == prvm_type_size[type])
continue;
FS_Printf(f,"\"%s\" ",name);
prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_Write, ent=%d, name=%s", i, name);
- FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, (prvm_eval_t *)v, valuebuf, sizeof(valuebuf)));
+ FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)));
prog->statestring = NULL;
}
prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_WriteGlobals, name=%s", name);
FS_Printf(f,"\"%s\" ", name);
- FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs], valuebuf, sizeof(valuebuf)));
+ FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.fp[def->ofs], valuebuf, sizeof(valuebuf)));
prog->statestring = NULL;
}
FS_Print(f,"}\n");
mfunction_t *func;
if (ent)
- val = (prvm_eval_t *)(ent->fields.vp + key->ofs);
+ val = (prvm_eval_t *)(ent->fields.fp + key->ofs);
else
- val = (prvm_eval_t *)(prog->globals.generic + key->ofs);
+ val = (prvm_eval_t *)(prog->globals.fp + key->ofs);
switch (key->type & ~DEF_SAVEGLOBAL)
{
case ev_string:
PRVM_MEM_IncreaseEdicts(prog);
// if IncreaseEdicts was called the base pointer needs to be updated
if (ent)
- val = (prvm_eval_t *)(ent->fields.vp + key->ofs);
+ val = (prvm_eval_t *)(ent->fields.fp + key->ofs);
val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
break;
goto fail;
}
- v = (prvm_eval_t *)(ed->fields.vp + key->ofs);
+ v = (prvm_eval_t *)(ed->fields.fp + key->ofs);
s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
if(Cmd_Argc() == 5)
{
goto fail;
}
- v = (prvm_eval_t *) &prog->globals.generic[key->ofs];
+ v = (prvm_eval_t *) &prog->globals.fp[key->ofs];
s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
if(Cmd_Argc() == 4)
{
// clear it
if (ent != prog->edicts) // hack
- memset (ent->fields.vp, 0, prog->entityfields * 4);
+ memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
data = PRVM_ED_ParseEdict (prog, data, ent);
parsed++;
*out++ = '\\';
*out++ = '0' + ((*in & 0700) >> 6);
*out++ = '0' + ((*in & 0070) >> 3);
- *out++ = '0' + ((*in & 0007));
+ *out++ = '0' + (*in & 0007) ;
outsize -= 4;
}
}
PRVM_LoadProgs
===============
*/
-void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, 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_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)
{
int i;
dprograms_t *dprograms;
dstatement_t *instatements;
ddef_t *infielddefs;
ddef_t *inglobaldefs;
- float *inglobals;
+ int *inglobals;
dfunction_t *infunctions;
char *instrings;
fs_offset_t filesize;
int a;
int b;
int c;
+ union
+ {
+ unsigned int i;
+ float f;
+ }
+ u;
+ unsigned int d;
char vabuf[1024];
if (prog->loaded)
Host_LockSession(); // all progs can use the session cvar
Crypto_LoadKeys(); // all progs might use the keys at init time
- dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
+ if (data)
+ {
+ dprograms = (dprograms_t *) data;
+ filesize = size;
+ }
+ else
+ dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name);
// TODO bounds check header fields (e.g. numstatements), they must never go behind end of file
prog->progs_numfunctions = LittleLong(dprograms->numfunctions);
instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings));
prog->progs_numstrings = LittleLong(dprograms->numstrings);
- inglobals = (float *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals));
+ inglobals = (int *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals));
prog->progs_numglobals = LittleLong(dprograms->numglobals);
prog->progs_entityfields = LittleLong(dprograms->entityfields);
prog->numglobals = prog->progs_numglobals;
prog->entityfields = prog->progs_entityfields;
- if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings >= (int)filesize)
+ if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings > (int)filesize)
prog->error_cmd("%s: %s strings go past end of file", prog->name, filename);
prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings);
memcpy(prog->strings, instrings, prog->progs_numstrings);
// we need to expand the globaldefs and fielddefs to include engine defs
prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t));
- prog->globals.generic = (float *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace) * sizeof(float));
+ prog->globals.fp = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace + 2) * sizeof(prvm_vec_t));
+ // + 2 is because of an otherwise occurring overrun in RETURN instruction
+ // when trying to return the last or second-last global
+ // (RETURN always returns a vector, there is no RETURN_F instruction)
prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t));
// we need to convert the statements to our memory format
prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t));
#define remapfield(index) (index)
// copy globals
+ // FIXME: LordHavoc: this uses a crude way to identify integer constants, rather than checking for matching globaldefs and checking their type
for (i = 0;i < prog->progs_numglobals;i++)
- ((int *)prog->globals.generic)[remapglobal(i)] = LittleLong(((int *)inglobals)[i]);
+ {
+ u.i = LittleLong(inglobals[i]);
+ // most globals are 0, we only need to deal with the ones that are not
+ if (u.i)
+ {
+ d = u.i & 0xFF800000;
+ if ((d == 0xFF800000) || (d == 0))
+ {
+ // Looks like an integer (expand to int64)
+ prog->globals.ip[remapglobal(i)] = u.i;
+ }
+ else
+ {
+ // Looks like a float (expand to double)
+ prog->globals.fp[remapglobal(i)] = u.f;
+ }
+ }
+ }
// LordHavoc: TODO: support 32bit progs statement formats
// copy, remap globals in statements, bounds check
}
// we're done with the file now
- Mem_Free(dprograms);
+ if(!data)
+ Mem_Free(dprograms);
dprograms = NULL;
// check required functions
const char *name;
prvm_edict_t *ed;
ddef_t *d;
- int *v;
+ prvm_eval_t *val;
// TODO
/*
name = PRVM_GetString(prog, d->s_name);
if (name[strlen(name)-2] == '_')
continue; // skip _x, _y, _z vars
- v = (int *)(ed->fields.vp + d->ofs);
+ val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
// if the value is still all 0, skip the field
for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
{
- if (v[j])
+ if (val->ivector[j])
{
counts[i]++;
break;
// if it's in the tempstrings area, use a reserved range
// (otherwise we'd get millions of useless string offsets cluttering the database)
if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize)
-#if 1
return prog->stringssize + (s - (char *)prog->tempstringsbuf.data);
-#endif
// see if it's a known string address
for (i = 0;i < prog->numknownstrings;i++)
if (prog->knownstrings[i] == s)