improved q1qvm support - now runs on 64bit servers with 32bit qvm
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2635 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
eaf6335e74
commit
06da06f9b3
10 changed files with 351 additions and 159 deletions
|
@ -1959,7 +1959,10 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
|
|||
{
|
||||
if (!strcmp(sv.strings.model_precache[i], m))
|
||||
{
|
||||
m = sv.strings.model_precache[i];
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype != GT_Q1QVM)
|
||||
#endif
|
||||
m = sv.strings.model_precache[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1967,9 +1970,14 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
|
|||
{
|
||||
if (i!=MAX_MODELS)
|
||||
{
|
||||
sv.strings.model_precache[i] = PR_AddString(prinst, m, 0);
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype == GT_Q1QVM)
|
||||
sv.strings.model_precache[i] = m; //in a qvm, we expect the caller to have used a static location.
|
||||
else
|
||||
#endif
|
||||
m = sv.strings.model_precache[i] = PR_AddString(prinst, m, 0);
|
||||
if (!strcmp(m + strlen(m) - 4, ".bsp"))
|
||||
sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
|
||||
sv.models[i] = Mod_FindName(m);
|
||||
Con_Printf("WARNING: SV_ModelIndex: model %s not precached\n", m);
|
||||
|
||||
if (sv.state != ss_loading)
|
||||
|
@ -1992,7 +2000,7 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
|
|||
}
|
||||
}
|
||||
|
||||
e->v->model = PR_SetString(prinst, sv.strings.model_precache[i]);
|
||||
e->v->model = PR_SetString(prinst, m);
|
||||
e->v->modelindex = i;
|
||||
|
||||
// if it is an inline model, get the size information for it
|
||||
|
@ -3095,7 +3103,7 @@ name checkclient ()
|
|||
*/
|
||||
#define MAX_CHECK 16
|
||||
int c_invis, c_notvis;
|
||||
void PF_checkclient (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
int PF_checkclient_Internal (progfuncs_t *prinst)
|
||||
{
|
||||
edict_t *ent, *self;
|
||||
int l;
|
||||
|
@ -3112,8 +3120,7 @@ void PF_checkclient (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
ent = EDICT_NUM(prinst, sv.lastcheck);
|
||||
if (ent->isfree || ent->v->health <= 0)
|
||||
{
|
||||
RETURN_EDICT(prinst, sv.edicts);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if current entity can't possibly see the check entity, return 0
|
||||
|
@ -3123,13 +3130,17 @@ void PF_checkclient (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
|
||||
{
|
||||
c_notvis++;
|
||||
RETURN_EDICT(prinst, sv.edicts);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// might be able to see it
|
||||
c_invis++;
|
||||
RETURN_EDICT(prinst, ent);
|
||||
return sv.lastcheck;
|
||||
}
|
||||
|
||||
void PF_checkclient (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
RETURN_EDICT(prinst, EDICT_NUM(prinst, PF_checkclient_Internal(prinst)));
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
@ -3760,9 +3771,15 @@ void PF_precache_model_Internal (progfuncs_t *prinst, char *s)
|
|||
PR_BIError (prinst, "Precache name too long");
|
||||
return;
|
||||
}
|
||||
sv.strings.model_precache[i] = PR_AddString(prinst, s, 0);
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype == GT_Q1QVM)
|
||||
sv.strings.model_precache[i] = s;
|
||||
else
|
||||
#endif
|
||||
sv.strings.model_precache[i] = PR_AddString(prinst, s, 0);
|
||||
s = sv.strings.model_precache[i];
|
||||
if (!strcmp(s + strlen(s) - 4, ".bsp"))
|
||||
sv.models[i] = Mod_FindName(sv.strings.model_precache[i]);
|
||||
sv.models[i] = Mod_FindName(s);
|
||||
|
||||
if (sv.state != ss_loading)
|
||||
{
|
||||
|
|
|
@ -155,11 +155,7 @@ typedef enum
|
|||
GAME_SHUTDOWN, // (void);
|
||||
|
||||
GAME_CLIENT_CONNECT, // ( int clientNum ,int isSpectator);
|
||||
// ( int clientNum, qboolean firstTime, qboolean isBot );
|
||||
// return NULL if the client is allowed to connect, otherwise return
|
||||
// a text string with the reason for denial
|
||||
GAME_PUT_CLIENT_IN_SERVER,
|
||||
//GAME_CLIENT_BEGIN, // ( int clientNum ,int isSpectator);
|
||||
|
||||
GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum,int isSpectator );
|
||||
|
||||
|
@ -178,11 +174,7 @@ typedef enum
|
|||
GAME_EDICT_TOUCH, //(self,other)
|
||||
GAME_EDICT_THINK, //(self,other=world,time)
|
||||
GAME_EDICT_BLOCKED, //(self,other)
|
||||
// ConsoleCommand will be called when a command has been issued
|
||||
// that is not recognized as a builtin function.
|
||||
// The game can issue trap_argc() / trap_argv() commands to get the command
|
||||
// and parameters. Return qfalse if the game doesn't recognize it as a command.
|
||||
|
||||
GAME_CLIENT_SAY, //(int isteam)
|
||||
} gameExport_t;
|
||||
|
||||
|
||||
|
@ -267,6 +259,7 @@ typedef struct {
|
|||
} q1qvmglobalvars_t;
|
||||
|
||||
|
||||
//this is not usable in 64bit to refer to a 32bit qvm (hence why we have two versions).
|
||||
typedef struct
|
||||
{
|
||||
edict_t *ents;
|
||||
|
@ -274,7 +267,16 @@ typedef struct
|
|||
q1qvmglobalvars_t *global;
|
||||
field_t *fields;
|
||||
int APIversion;
|
||||
} gameData_t;
|
||||
} gameDataN_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int ents;
|
||||
int sizeofent;
|
||||
unsigned int global;
|
||||
unsigned int fields;
|
||||
int APIversion;
|
||||
} gameData32_t;
|
||||
|
||||
typedef int fileHandle_t;
|
||||
|
||||
|
@ -311,19 +313,22 @@ static edict_t *q1qvmedicts[MAX_Q1QVM_EDICTS];
|
|||
|
||||
|
||||
static void *evars; //pointer to the gamecodes idea of an edict_t
|
||||
static long vevars; //offset into the vm base of evars
|
||||
static int vevars; //offset into the vm base of evars
|
||||
|
||||
char *Q1QVMPF_AddString(progfuncs_t *pf, char *base, int minlength)
|
||||
/*
|
||||
static char *Q1QVMPF_AddString(progfuncs_t *pf, char *base, int minlength)
|
||||
{
|
||||
char *n;
|
||||
int l = strlen(base);
|
||||
Con_Printf("warning: string %s will not be readable from the qvm\n", base);
|
||||
l = l<minlength?minlength:l;
|
||||
n = Z_TagMalloc(l+1, VMFSID_Q1QVM);
|
||||
strcpy(n, base);
|
||||
return n;
|
||||
}
|
||||
*/
|
||||
|
||||
edict_t *Q1QVMPF_EdictNum(progfuncs_t *pf, unsigned int num)
|
||||
static edict_t *Q1QVMPF_EdictNum(progfuncs_t *pf, unsigned int num)
|
||||
{
|
||||
edict_t *e;
|
||||
|
||||
|
@ -341,16 +346,16 @@ edict_t *Q1QVMPF_EdictNum(progfuncs_t *pf, unsigned int num)
|
|||
return e;
|
||||
}
|
||||
|
||||
int Q1QVMPF_NumForEdict(progfuncs_t *pf, edict_t *e)
|
||||
static unsigned int Q1QVMPF_NumForEdict(progfuncs_t *pf, edict_t *e)
|
||||
{
|
||||
return e->entnum;
|
||||
}
|
||||
|
||||
int Q1QVMPF_EdictToProgs(progfuncs_t *pf, edict_t *e)
|
||||
static int Q1QVMPF_EdictToProgs(progfuncs_t *pf, edict_t *e)
|
||||
{
|
||||
return e->entnum*pr_edict_size;
|
||||
}
|
||||
edict_t *Q1QVMPF_ProgsToEdict(progfuncs_t *pf, int num)
|
||||
static edict_t *Q1QVMPF_ProgsToEdict(progfuncs_t *pf, int num)
|
||||
{
|
||||
if (num % pr_edict_size)
|
||||
Con_Printf("Edict To Progs with remainder\n");
|
||||
|
@ -368,7 +373,7 @@ void Q1QVMED_ClearEdict (edict_t *e, qboolean wipe)
|
|||
e->entnum = num;
|
||||
}
|
||||
|
||||
void Q1QVMPF_EntRemove(progfuncs_t *pf, edict_t *e)
|
||||
static void Q1QVMPF_EntRemove(progfuncs_t *pf, edict_t *e)
|
||||
{
|
||||
if (!ED_CanFree(e))
|
||||
return;
|
||||
|
@ -376,7 +381,7 @@ void Q1QVMPF_EntRemove(progfuncs_t *pf, edict_t *e)
|
|||
e->freetime = sv.time;
|
||||
}
|
||||
|
||||
edict_t *Q1QVMPF_EntAlloc(progfuncs_t *pf)
|
||||
static edict_t *Q1QVMPF_EntAlloc(progfuncs_t *pf)
|
||||
{
|
||||
int i;
|
||||
edict_t *e;
|
||||
|
@ -427,7 +432,7 @@ edict_t *Q1QVMPF_EntAlloc(progfuncs_t *pf)
|
|||
return (struct edict_s *)e;
|
||||
}
|
||||
|
||||
int Q1QVMPF_LoadEnts(progfuncs_t *pf, char *mapstring, float spawnflags)
|
||||
static int Q1QVMPF_LoadEnts(progfuncs_t *pf, char *mapstring, float spawnflags)
|
||||
{
|
||||
q1qvmentstring = mapstring;
|
||||
VM_Call(q1qvm, GAME_LOADENTS);
|
||||
|
@ -435,7 +440,7 @@ int Q1QVMPF_LoadEnts(progfuncs_t *pf, char *mapstring, float spawnflags)
|
|||
return pr_edict_size;
|
||||
}
|
||||
|
||||
eval_t *Q1QVMPF_GetEdictFieldValue(progfuncs_t *pf, edict_t *e, char *fieldname, evalc_t *cache)
|
||||
static eval_t *Q1QVMPF_GetEdictFieldValue(progfuncs_t *pf, edict_t *e, char *fieldname, evalc_t *cache)
|
||||
{
|
||||
if (!strcmp(fieldname, "message"))
|
||||
{
|
||||
|
@ -444,24 +449,24 @@ eval_t *Q1QVMPF_GetEdictFieldValue(progfuncs_t *pf, edict_t *e, char *fieldname,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
eval_t *Q1QVMPF_FindGlobal (progfuncs_t *prinst, char *name, progsnum_t num)
|
||||
static eval_t *Q1QVMPF_FindGlobal (progfuncs_t *prinst, char *name, progsnum_t num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
globalvars_t *Q1QVMPF_Globals(progfuncs_t *prinst, int prnum)
|
||||
static globalvars_t *Q1QVMPF_Globals(progfuncs_t *prinst, int prnum)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string_t Q1QVMPF_StringToProgs(progfuncs_t *prinst, char *str)
|
||||
static string_t Q1QVMPF_StringToProgs(progfuncs_t *prinst, char *str)
|
||||
{
|
||||
return (string_t)str;
|
||||
return (string_t)(str - (char*)VM_MemoryBase(q1qvm));
|
||||
}
|
||||
|
||||
char *Q1QVMPF_StringToNative(progfuncs_t *prinst, string_t str)
|
||||
static char *Q1QVMPF_StringToNative(progfuncs_t *prinst, string_t str)
|
||||
{
|
||||
return (char*)str;
|
||||
return (char*)VM_MemoryBase(q1qvm) + str;
|
||||
}
|
||||
|
||||
void PF_WriteByte (progfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -493,12 +498,13 @@ void PF_setspawnparms (progfuncs_t *prinst, struct globalvars_s *pr_globals);
|
|||
void PF_walkmove (progfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
||||
|
||||
int PF_checkclient_Internal (progfuncs_t *prinst);
|
||||
void PF_precache_sound_Internal (progfuncs_t *prinst, char *s);
|
||||
void PF_precache_model_Internal (progfuncs_t *prinst, char *s);
|
||||
void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m);
|
||||
char *PF_infokey_Internal (int entnum, char *value);
|
||||
|
||||
int WrapQCBuiltin(builtin_t func, void *offset, unsigned int mask, const long *arg, char *argtypes)
|
||||
static int WrapQCBuiltin(builtin_t func, void *offset, unsigned int mask, const int *arg, char *argtypes)
|
||||
{
|
||||
globalvars_t gv;
|
||||
int argnum=0;
|
||||
|
@ -534,7 +540,7 @@ int WrapQCBuiltin(builtin_t func, void *offset, unsigned int mask, const long *a
|
|||
}
|
||||
|
||||
#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap %i passes invalid pointer\n", fn); //out of bounds.
|
||||
long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
|
||||
static int syscallqvm (void *offset, unsigned int mask, int fn, const int *arg)
|
||||
{
|
||||
switch (fn)
|
||||
{
|
||||
|
@ -657,8 +663,7 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
|
|||
break;
|
||||
|
||||
case G_CHECKCLIENT:
|
||||
// return PF_checkclientinternal(VM_LONG(arg[0]));
|
||||
break;
|
||||
return PF_checkclient_Internal(svprogfuncs);
|
||||
|
||||
case G_STUFFCMD:
|
||||
{
|
||||
|
@ -695,7 +700,7 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
|
|||
|
||||
case G_FINDRADIUS:
|
||||
{
|
||||
int start = ((char*)VM_POINTER(arg[0]) - (char*)vevars) / pr_edict_size;
|
||||
int start = ((char*)VM_POINTER(arg[0]) - (char*)evars) / pr_edict_size;
|
||||
edict_t *ed;
|
||||
vec3_t diff;
|
||||
float *org = VM_POINTER(arg[1]);
|
||||
|
@ -708,7 +713,7 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
|
|||
continue;
|
||||
VectorSubtract(ed->v->origin, org, diff);
|
||||
if (rad > DotProduct(diff, diff))
|
||||
return (long)((char*)vevars + start*pr_edict_size);
|
||||
return (int)(vevars + start*pr_edict_size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -851,14 +856,20 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
|
|||
break;
|
||||
|
||||
case g_memset:
|
||||
VALIDATEPOINTER(arg[0], arg[2]);
|
||||
memset(VM_POINTER(arg[0]), arg[1], arg[2]);
|
||||
return arg[0];
|
||||
break;
|
||||
{
|
||||
void *dst = VM_POINTER(arg[0]);
|
||||
VALIDATEPOINTER(arg[0], arg[2]);
|
||||
memset(dst, arg[1], arg[2]);
|
||||
return arg[0];
|
||||
}
|
||||
case g_memcpy:
|
||||
VALIDATEPOINTER(arg[0], arg[2]);
|
||||
memmove(VM_POINTER(arg[0]), VM_POINTER(arg[1]), arg[2]);
|
||||
return arg[0];
|
||||
{
|
||||
void *dst = VM_POINTER(arg[0]);
|
||||
void *src = VM_POINTER(arg[1]);
|
||||
VALIDATEPOINTER(arg[0], arg[2]);
|
||||
memmove(dst, src, arg[2]);
|
||||
return arg[0];
|
||||
}
|
||||
break;
|
||||
case g_strncpy:
|
||||
VALIDATEPOINTER(arg[0], arg[2]);
|
||||
|
@ -1006,12 +1017,12 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
|
|||
if (field == NULL)
|
||||
{
|
||||
if (*match == '\0')
|
||||
return VM_LONG(e->v)-WASTED_EDICT_T_SIZE - (int)offset;
|
||||
return ((char*)e->v - (char*)offset)-WASTED_EDICT_T_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strcmp(field, match))
|
||||
return VM_LONG(e->v)-WASTED_EDICT_T_SIZE - (int)offset;
|
||||
return ((char*)e->v - (char*)offset)-WASTED_EDICT_T_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1089,7 +1100,7 @@ Con_DPrintf("PF_readcmd: %s\n%s", s, output);
|
|||
if (VM_OOB(arg[0], arg[1]) || !out)
|
||||
return -1; //please don't corrupt me
|
||||
time(&curtime);
|
||||
curtime + VM_LONG(arg[3]);
|
||||
curtime += VM_LONG(arg[3]);
|
||||
local = localtime(&curtime);
|
||||
strftime(out, VM_LONG(arg[1]), fmt, local);
|
||||
}
|
||||
|
@ -1137,11 +1148,11 @@ Con_DPrintf("PF_readcmd: %s\n%s", s, output);
|
|||
|
||||
case G_NEXTCLIENT:
|
||||
{
|
||||
unsigned int start = ((char*)VM_POINTER(arg[0]) - (char*)vevars) / pr_edict_size;
|
||||
unsigned int start = ((char*)VM_POINTER(arg[0]) - (char*)evars) / pr_edict_size;
|
||||
while (start < sv.allocated_client_slots)
|
||||
{
|
||||
if (svs.clients[start].state == cs_spawned)
|
||||
return (long)((char*)vevars + (start+1) * pr_edict_size);
|
||||
return (int)(vevars + (start+1) * pr_edict_size);
|
||||
start++;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1155,9 +1166,9 @@ Con_DPrintf("PF_readcmd: %s\n%s", s, output);
|
|||
return 0;
|
||||
}
|
||||
|
||||
long EXPORT_FN syscallnative (int arg, ...)
|
||||
static int EXPORT_FN syscallnative (int arg, ...)
|
||||
{
|
||||
long args[13];
|
||||
int args[13];
|
||||
va_list argptr;
|
||||
|
||||
va_start(argptr, arg);
|
||||
|
@ -1201,7 +1212,8 @@ qboolean PR_LoadQ1QVM(void)
|
|||
{
|
||||
static float writable;
|
||||
int i;
|
||||
gameData_t *gd;
|
||||
gameDataN_t *gd, gdm;
|
||||
gameData32_t *gd32;
|
||||
int ret;
|
||||
|
||||
if (q1qvm)
|
||||
|
@ -1218,7 +1230,7 @@ qboolean PR_LoadQ1QVM(void)
|
|||
svprogfuncs = &q1qvmprogfuncs;
|
||||
|
||||
|
||||
q1qvmprogfuncs.AddString = Q1QVMPF_AddString;
|
||||
// q1qvmprogfuncs.AddString = Q1QVMPF_AddString; //using this breaks 64bit support, and is a 'bad plan' elsewhere too,
|
||||
q1qvmprogfuncs.EDICT_NUM = Q1QVMPF_EdictNum;
|
||||
q1qvmprogfuncs.NUM_FOR_EDICT = Q1QVMPF_NumForEdict;
|
||||
q1qvmprogfuncs.EdictToProgs = Q1QVMPF_EdictToProgs;
|
||||
|
@ -1246,21 +1258,33 @@ qboolean PR_LoadQ1QVM(void)
|
|||
Q1QVM_Shutdown();
|
||||
return false;
|
||||
}
|
||||
gd = (gameData_t*)((char*)VM_MemoryBase(q1qvm) + ret);
|
||||
gd32 = (gameData32_t*)((char*)VM_MemoryBase(q1qvm) + ret); //qvm is 32bit
|
||||
|
||||
//when running native64, we need to convert these to real types, so we can use em below
|
||||
gd = &gdm;
|
||||
gd->ents = gd32->ents;
|
||||
gd->sizeofent = gd32->sizeofent;
|
||||
gd->global = gd32->global;
|
||||
gd->fields = gd32->fields;
|
||||
gd->APIversion = gd32->APIversion;
|
||||
|
||||
pr_edict_size = gd->sizeofent;
|
||||
|
||||
vevars = (long)gd->ents;
|
||||
evars = ((char*)VM_MemoryBase(q1qvm) + vevars);
|
||||
//FIXME: range check this pointer
|
||||
//FIXME: range check the globals pointer
|
||||
|
||||
sv.num_edicts = 1;
|
||||
sv.max_edicts = sizeof(q1qvmedicts)/sizeof(q1qvmedicts[0]);
|
||||
|
||||
#define globalint(required, name) pr_nqglobal_struct->name = (int*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name)
|
||||
#define globalfloat(required, name) pr_nqglobal_struct->name = (float*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name)
|
||||
#define globalstring(required, name) pr_nqglobal_struct->name = (string_t*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name)
|
||||
#define globalvec(required, name) pr_nqglobal_struct->V_##name = (vec3_t*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name)
|
||||
#define globalfunc(required, name) pr_nqglobal_struct->name = (int*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name)
|
||||
//WARNING: global is not remapped yet...
|
||||
//This code is written evilly, but works well enough
|
||||
#define globalint(required, name) pr_nqglobal_struct->name = (int*)((char*)VM_MemoryBase(q1qvm)+(long)&gd->global->name) //the logic of this is somewhat crazy
|
||||
#define globalfloat(required, name) pr_nqglobal_struct->name = (float*)((char*)VM_MemoryBase(q1qvm)+(long)&gd->global->name)
|
||||
#define globalstring(required, name) pr_nqglobal_struct->name = (string_t*)((char*)VM_MemoryBase(q1qvm)+(long)&gd->global->name)
|
||||
#define globalvec(required, name) pr_nqglobal_struct->V_##name = (vec3_t*)((char*)VM_MemoryBase(q1qvm)+(long)&gd->global->name)
|
||||
#define globalfunc(required, name) pr_nqglobal_struct->name = (int*)((char*)VM_MemoryBase(q1qvm)+(long)&gd->global->name)
|
||||
globalint (true, self); //we need the qw ones, but any in standard quake and not quakeworld, we don't really care about.
|
||||
globalint (true, other);
|
||||
globalint (true, world);
|
||||
|
@ -1308,8 +1332,7 @@ qboolean PR_LoadQ1QVM(void)
|
|||
pr_nqglobal_struct->trace_endcontents = &writable;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(int)(&gd->global->parm1 + i));
|
||||
//spawnparamglobals[i] = (float *)&gd->global->parm1 + i;
|
||||
spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(long)(&gd->global->parm1 + i));
|
||||
for (; i < NUM_SPAWN_PARMS; i++)
|
||||
spawnparamglobals[i] = NULL;
|
||||
|
||||
|
@ -1327,7 +1350,8 @@ void Q1QVM_ClientConnect(client_t *cl)
|
|||
if (cl->edict->v->netname)
|
||||
{
|
||||
strcpy(cl->namebuf, cl->name);
|
||||
cl->name = cl->edict->v->netname + (char*)VM_MemoryBase(q1qvm);
|
||||
cl->name = Q1QVMPF_StringToNative(svprogfuncs, cl->edict->v->netname);
|
||||
//FIXME: check this pointer
|
||||
strcpy(cl->name, cl->namebuf);
|
||||
}
|
||||
// call the spawn function
|
||||
|
@ -1341,6 +1365,56 @@ void Q1QVM_ClientConnect(client_t *cl)
|
|||
VM_Call(q1qvm, GAME_PUT_CLIENT_IN_SERVER, cl->spectator);
|
||||
}
|
||||
|
||||
qboolean Q1QVM_GameConsoleCommand(void)
|
||||
{
|
||||
int oldself, oldother;
|
||||
if (!q1qvm)
|
||||
return false;
|
||||
|
||||
//FIXME: if an rcon command from someone on the server, mvdsv sets self to match the ip of that player
|
||||
//this is not required (broken by proxies anyway) but is a nice handy feature
|
||||
|
||||
pr_global_struct->time = sv.time;
|
||||
oldself = pr_global_struct->self; //these are usually useless
|
||||
oldother = pr_global_struct->other; //but its possible that someone makes a mod that depends on the 'mod' command working via redirectcmd+co
|
||||
//this at least matches mvdsv
|
||||
pr_global_struct->self = 0;
|
||||
pr_global_struct->other = 0;
|
||||
|
||||
VM_Call(q1qvm, GAME_CONSOLE_COMMAND); //mod uses Cmd_Argv+co to get args
|
||||
|
||||
pr_global_struct->self = oldself;
|
||||
pr_global_struct->other = oldother;
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean Q1QVM_ClientSay(edict_t *player, qboolean team)
|
||||
{
|
||||
qboolean washandled;
|
||||
if (!q1qvm)
|
||||
return false;
|
||||
|
||||
SV_EndRedirect();
|
||||
|
||||
pr_global_struct->time = sv.time;
|
||||
pr_global_struct->self = Q1QVMPF_EdictToProgs(svprogfuncs, player);
|
||||
washandled = VM_Call(q1qvm, GAME_CLIENT_SAY, team);
|
||||
|
||||
SV_BeginRedirect(RD_CLIENT, host_client->language); //put it back to how we expect it was. *shudder*
|
||||
|
||||
return washandled;
|
||||
}
|
||||
|
||||
qboolean Q1QVM_UserInfoChanged(edict_t *player)
|
||||
{
|
||||
if (!q1qvm)
|
||||
return false;
|
||||
|
||||
pr_global_struct->time = sv.time;
|
||||
pr_global_struct->self = Q1QVMPF_EdictToProgs(svprogfuncs, player);
|
||||
return VM_Call(q1qvm, GAME_CLIENT_USERINFO_CHANGED);
|
||||
}
|
||||
|
||||
void Q1QVM_PlayerPreThink(void)
|
||||
{
|
||||
VM_Call(q1qvm, GAME_CLIENT_PRETHINK, host_client->spectator);
|
||||
|
|
|
@ -126,3 +126,27 @@ void PR_ClientUserInfoChanged(char *name, char *oldivalue, char *newvalue);
|
|||
void PR_LocalInfoChanged(char *name, char *oldivalue, char *newvalue);
|
||||
void PF_InitTempStrings(progfuncs_t *prinst);
|
||||
|
||||
#ifdef VM_Q1
|
||||
struct client_s;
|
||||
void Q1QVM_Shutdown(void);
|
||||
qboolean PR_LoadQ1QVM(void);
|
||||
void Q1QVM_ClientConnect(struct client_s *cl);
|
||||
qboolean Q1QVM_GameConsoleCommand(void);
|
||||
qboolean Q1QVM_ClientSay(edict_t *player, qboolean team);
|
||||
qboolean Q1QVM_UserInfoChanged(edict_t *player);
|
||||
void Q1QVM_PlayerPreThink(void);
|
||||
void Q1QVM_RunPlayerThink(void);
|
||||
void Q1QVM_PostThink(void);
|
||||
void Q1QVM_StartFrame(void);
|
||||
void Q1QVM_Touch(void);
|
||||
void Q1QVM_Think(void);
|
||||
void Q1QVM_Blocked(void);
|
||||
void Q1QVM_SetNewParms(void);
|
||||
void Q1QVM_SetChangeParms(void);
|
||||
void Q1QVM_ClientCommand(void);
|
||||
void Q1QVM_DropClient(struct client_s *cl);
|
||||
void Q1QVM_ChainMoved(void);
|
||||
void Q1QVM_EndFrame(void);
|
||||
void Q1QVMED_ClearEdict (edict_t *e, qboolean wipe);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1886,6 +1886,11 @@ void SV_SendGameCommand_f(void)
|
|||
return;
|
||||
#endif
|
||||
|
||||
#ifdef VM_Q1
|
||||
if (Q1QVM_GameConsoleCommand())
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef Q2SERVER
|
||||
if (ge)
|
||||
{
|
||||
|
@ -1980,6 +1985,7 @@ void SV_InitOperatorCommands (void)
|
|||
// Cmd_AddCommand ("writeip", SV_WriteIP_f);
|
||||
|
||||
Cmd_AddCommand ("sv", SV_SendGameCommand_f);
|
||||
Cmd_AddCommand ("mod", SV_SendGameCommand_f);
|
||||
|
||||
Cmd_AddCommand ("killserver", SV_KillServer_f);
|
||||
Cmd_AddCommand ("map", SV_Map_f);
|
||||
|
|
|
@ -908,7 +908,26 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
|
|||
|
||||
|
||||
sv.models[1] = sv.worldmodel;
|
||||
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM)
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype == GT_Q1QVM)
|
||||
{
|
||||
strcpy(sv.strings.sound_precache[0], "");
|
||||
sv.strings.model_precache[0] = "";
|
||||
|
||||
sv.strings.model_precache[1] = sv.modelname; //the qvm doesn't have access to this array
|
||||
for (i=1 ; i<sv.worldmodel->numsubmodels ; i++)
|
||||
{
|
||||
sv.strings.model_precache[1+i] = localmodels[i];
|
||||
sv.models[i+1] = Mod_ForName (localmodels[i], false);
|
||||
}
|
||||
|
||||
//check player/eyes models for hacks
|
||||
sv.model_player_checksum = SV_CheckModel("progs/player.mdl");
|
||||
sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (svs.gametype == GT_PROGS)
|
||||
{
|
||||
strcpy(sv.strings.sound_precache[0], "");
|
||||
sv.strings.model_precache[0] = "";
|
||||
|
@ -992,8 +1011,18 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
|
|||
if (!svs.clients[i].state && svs.clients[i].name[0]) //this is a bot.
|
||||
svs.clients[i].name[0] = '\0'; //make it go away
|
||||
|
||||
svs.clients[i].name = PR_AddString(svprogfuncs, svs.clients[i].namebuf, sizeof(svs.clients[i].namebuf));
|
||||
svs.clients[i].team = PR_AddString(svprogfuncs, svs.clients[i].teambuf, sizeof(svs.clients[i].teambuf));
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype == GT_Q1QVM)
|
||||
{ //we'll fix it up later anyway
|
||||
svs.clients[i].name = svs.clients[i].namebuf;
|
||||
svs.clients[i].team = svs.clients[i].teambuf;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
svs.clients[i].name = PR_AddString(svprogfuncs, svs.clients[i].namebuf, sizeof(svs.clients[i].namebuf));
|
||||
svs.clients[i].team = PR_AddString(svprogfuncs, svs.clients[i].teambuf, sizeof(svs.clients[i].teambuf));
|
||||
}
|
||||
|
||||
#ifdef PEXT_CSQC
|
||||
memset(svs.clients[i].csqcentsequence, 0, sizeof(svs.clients[i].csqcentsequence));
|
||||
|
@ -1053,7 +1082,10 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
|
|||
eval_t *eval;
|
||||
ent = EDICT_NUM(svprogfuncs, 0);
|
||||
ent->isfree = false;
|
||||
ent->v->model = PR_NewString(svprogfuncs, sv.worldmodel->name, 0);
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype != GT_Q1QVM) //we cannot do this with qvm
|
||||
#endif
|
||||
ent->v->model = PR_NewString(svprogfuncs, sv.worldmodel->name, 0);
|
||||
ent->v->modelindex = 1; // world model
|
||||
ent->v->solid = SOLID_BSP;
|
||||
ent->v->movetype = MOVETYPE_PUSH;
|
||||
|
@ -1062,14 +1094,22 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
|
|||
|
||||
if (progstype == PROG_QW && pr_imitatemvdsv.value>0)
|
||||
{
|
||||
ent->v->targetname = PR_NewString(svprogfuncs, "mvdsv", 0);
|
||||
ent->v->netname = PR_NewString(svprogfuncs, va("%s %f %s, build %d\nBuild date: " __DATE__ ", " __TIME__ "", DISTRIBUTIONLONG, 2.4, PLATFORM, build_number()), 0);
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype != GT_Q1QVM) //we cannot do this with qvm
|
||||
#endif
|
||||
{
|
||||
ent->v->targetname = PR_NewString(svprogfuncs, "mvdsv", 0);
|
||||
ent->v->netname = PR_NewString(svprogfuncs, va("%s %f %s, build %d\nBuild date: " __DATE__ ", " __TIME__ "", DISTRIBUTIONLONG, 2.4, PLATFORM, build_number()), 0);
|
||||
}
|
||||
ent->v->impulse = 0;//QWE_VERNUM;
|
||||
ent->v->items = 103;
|
||||
}
|
||||
|
||||
|
||||
pr_global_struct->mapname = PR_NewString(svprogfuncs, sv.name, 0);
|
||||
#ifdef VM_Q1
|
||||
if (svs.gametype != GT_Q1QVM) //we cannot do this with qvm
|
||||
pr_global_struct->mapname = PR_NewString(svprogfuncs, sv.name, 0);
|
||||
#endif
|
||||
// serverflags are for cross level information (sigils)
|
||||
pr_global_struct->serverflags = svs.serverflags;
|
||||
pr_global_struct->time = 0.1; //HACK!!!! A few QuakeC mods expect time to be non-zero in spawn funcs - like prydon gate...
|
||||
|
|
|
@ -2871,6 +2871,12 @@ Spawns a client, uses an impulse, uses that clients think then removes the clien
|
|||
void SV_Impulse_f (void)
|
||||
{
|
||||
int i;
|
||||
if (svs.gametype != GT_PROGS)
|
||||
{
|
||||
Con_Printf("Not supported in this game type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sv.allocated_client_slots; i++)
|
||||
{
|
||||
if (svs.clients[i].state == cs_free)
|
||||
|
|
|
@ -2278,6 +2278,11 @@ void SV_Say (qboolean team)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef VM_Q1
|
||||
if (Q1QVM_ClientSay(sv_player, team))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if ((floodtime=SV_CheckFloodProt(host_client)))
|
||||
{
|
||||
SV_ClientTPrintf(host_client, PRINT_CHAT,
|
||||
|
@ -2740,7 +2745,12 @@ void SV_SetInfo_f (void)
|
|||
if (strstr(Cmd_Argv(1), "\\") || strstr(Cmd_Argv(2), "\\"))
|
||||
return; // illegal char
|
||||
|
||||
strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
|
||||
Q_strncpyz(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), MAX_INFO_STRING);
|
||||
|
||||
#ifdef VM_Q1
|
||||
if (Q1QVM_UserInfoChanged(sv_player))
|
||||
return;
|
||||
#endif
|
||||
|
||||
Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), sizeof(host_client->userinfo));
|
||||
// name is extracted below in ExtractFromUserInfo
|
||||
|
@ -2756,7 +2766,7 @@ void SV_SetInfo_f (void)
|
|||
SV_ExtractFromUserinfo (host_client);
|
||||
|
||||
if (progstype != PROG_QW && !strcmp(Cmd_Argv(1), "bottomcolor"))
|
||||
{
|
||||
{ //team fortress has a nasty habit of booting people without this
|
||||
sv_player->v->team = atoi(Cmd_Argv(2))+1;
|
||||
}
|
||||
|
||||
|
@ -3187,6 +3197,7 @@ void SV_SetUpClientEdict (client_t *cl, edict_t *ent)
|
|||
string_t preserve;
|
||||
preserve = ent->v->netname;
|
||||
Q1QVMED_ClearEdict(ent, true);
|
||||
Con_Printf("client netname: %x\n", preserve);
|
||||
ent->v->netname = preserve;
|
||||
}
|
||||
else
|
||||
|
@ -3194,12 +3205,12 @@ void SV_SetUpClientEdict (client_t *cl, edict_t *ent)
|
|||
{
|
||||
if (progstype != PROG_NQ) //allow frikbots to work in NQ mods (but not qw!)
|
||||
ED_ClearEdict(svprogfuncs, ent);
|
||||
ent->v->netname = PR_SetString(svprogfuncs, cl->name);
|
||||
}
|
||||
ED_Spawned(ent);
|
||||
ent->isfree = false;
|
||||
|
||||
ent->v->colormap = NUM_FOR_EDICT(svprogfuncs, ent);
|
||||
ent->v->netname = PR_SetString(svprogfuncs, cl->name);
|
||||
|
||||
if (pr_teamfield)
|
||||
((string_t *)ent->v)[pr_teamfield] = (string_t)(cl->team-svprogfuncs->stringtable);
|
||||
|
@ -3238,6 +3249,12 @@ void Cmd_Join_f (void)
|
|||
if (!host_client->spectator)
|
||||
return; // already a player
|
||||
|
||||
if (svs.gametype != GT_PROGS)
|
||||
{
|
||||
Con_Printf ("Sorry, not implemented in this gamecode type. Try moaning at the dev team\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(host_client->zquake_extensions & Z_EXT_JOIN_OBSERVE))
|
||||
{
|
||||
Con_Printf ("Your QW client doesn't support this command\n");
|
||||
|
@ -3324,6 +3341,12 @@ void Cmd_Observe_f (void)
|
|||
return;
|
||||
if (host_client->spectator)
|
||||
return; // already a spectator
|
||||
|
||||
if (svs.gametype != GT_PROGS)
|
||||
{
|
||||
Con_Printf ("Sorry, not implemented in this gamecode type. Try moaning at the dev team\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(host_client->zquake_extensions & Z_EXT_JOIN_OBSERVE))
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue