mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-22 12:01:25 +00:00
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
|
@ -155,8 +155,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#endif
|
||||
|
||||
#ifdef __amd64__
|
||||
//nah... not gonna work too well
|
||||
#undef VM_Q1
|
||||
//I'm slowly getting these working in 64bit
|
||||
#undef Q3CLIENT
|
||||
#undef Q3SERVER
|
||||
#undef PLUGINS
|
||||
|
|
|
@ -43,6 +43,7 @@ Also, can efficiency be improved much?
|
|||
|
||||
|
||||
|
||||
#define RETURNOFFSETMARKER NULL
|
||||
|
||||
typedef enum vm_type_e
|
||||
{
|
||||
|
@ -149,6 +150,7 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int
|
|||
#endif
|
||||
|
||||
#if defined(__amd64__)
|
||||
return 0; //give up early, don't even try going there
|
||||
sprintf(dllname, "%samd.so", name);
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
sprintf(dllname, "%sx86.so", name);
|
||||
|
@ -254,25 +256,25 @@ typedef struct vmHeader_s
|
|||
typedef struct qvm_s
|
||||
{
|
||||
// segments
|
||||
unsigned long *cs; // code segment, each instruction is 2 longs
|
||||
unsigned int *cs; // code segment, each instruction is 2 ints
|
||||
qbyte *ds; // data segment, partially filled on load (data, lit, bss)
|
||||
qbyte *ss; // stack segment, (follows immediatly after ds, corrupting data before vm)
|
||||
|
||||
// pointer registers
|
||||
unsigned long *pc; // program counter, points to cs, goes up
|
||||
unsigned long *sp; // stack pointer, initially points to end of ss, goes down
|
||||
unsigned long bp; // base pointer, initially len_ds+len_ss/2
|
||||
unsigned int *pc; // program counter, points to cs, goes up
|
||||
unsigned int *sp; // stack pointer, initially points to end of ss, goes down
|
||||
unsigned int bp; // base pointer, initially len_ds+len_ss/2
|
||||
|
||||
unsigned long *min_sp;
|
||||
unsigned long *max_sp;
|
||||
unsigned long min_bp;
|
||||
unsigned long max_bp;
|
||||
unsigned int *min_sp;
|
||||
unsigned int *max_sp;
|
||||
unsigned int min_bp;
|
||||
unsigned int max_bp;
|
||||
|
||||
// status
|
||||
unsigned int len_cs; // size of cs
|
||||
unsigned int len_ds; // size of ds
|
||||
unsigned int len_ss; // size of ss
|
||||
unsigned long ds_mask; // ds mask (ds+ss)
|
||||
unsigned int ds_mask; // ds mask (ds+ss)
|
||||
|
||||
// memory
|
||||
unsigned int mem_size;
|
||||
|
@ -427,9 +429,9 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
|
|||
|
||||
// memory
|
||||
qvm->ds_mask = qvm->len_ds*sizeof(qbyte)+(qvm->len_ss+16*4)*sizeof(qbyte);//+4 for a stack check decrease
|
||||
for (i = 0; i < 31; i++)
|
||||
for (i = 0; i < sizeof(qvm->ds_mask)*8-1; i++)
|
||||
{
|
||||
if ((1<<i) >= qvm->ds_mask) //is this bit greater than our minimum?
|
||||
if ((1<<(unsigned int)i) >= qvm->ds_mask) //is this bit greater than our minimum?
|
||||
break;
|
||||
}
|
||||
qvm->len_ss = (1<<i) - qvm->len_ds*sizeof(qbyte) - 4; //expand the stack space to fill it.
|
||||
|
@ -437,25 +439,25 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
|
|||
qvm->len_ss -= qvm->len_ss&7;
|
||||
|
||||
|
||||
qvm->mem_size=qvm->len_cs*sizeof(long)*2 + qvm->ds_mask;
|
||||
qvm->mem_size=qvm->len_cs*sizeof(int)*2 + qvm->ds_mask;
|
||||
qvm->mem_ptr=Z_Malloc(qvm->mem_size);
|
||||
// set pointers
|
||||
qvm->cs=(long*)qvm->mem_ptr;
|
||||
qvm->ds=(qbyte*)(qvm->mem_ptr+qvm->len_cs*sizeof(long)*2);
|
||||
qvm->cs=(unsigned int*)qvm->mem_ptr;
|
||||
qvm->ds=(qbyte*)(qvm->mem_ptr+qvm->len_cs*sizeof(int)*2);
|
||||
qvm->ss=(qbyte*)((qbyte*)qvm->ds+qvm->len_ds*sizeof(qbyte));
|
||||
//waste 32 bits here.
|
||||
//As the opcodes often check stack 0 and 1, with a backwards stack, 1 can leave the stack area. This is where we compensate for it.
|
||||
// setup registers
|
||||
qvm->pc=qvm->cs;
|
||||
qvm->sp=(long*)(qvm->ss+qvm->len_ss);
|
||||
qvm->sp=(unsigned int*)(qvm->ss+qvm->len_ss);
|
||||
qvm->bp=qvm->len_ds+qvm->len_ss/2;
|
||||
// qvm->cycles=0;
|
||||
qvm->syscall=syscall;
|
||||
|
||||
qvm->ds_mask--;
|
||||
|
||||
qvm->min_sp = (long*)(qvm->ds+qvm->len_ds+qvm->len_ss/2);
|
||||
qvm->max_sp = (long*)(qvm->ds+qvm->len_ds+qvm->len_ss);
|
||||
qvm->min_sp = (unsigned int*)(qvm->ds+qvm->len_ds+qvm->len_ss/2);
|
||||
qvm->max_sp = (unsigned int*)(qvm->ds+qvm->len_ds+qvm->len_ss);
|
||||
qvm->min_bp = qvm->len_ds;
|
||||
qvm->max_bp = qvm->len_ds+qvm->len_ss/2;
|
||||
|
||||
|
@ -464,14 +466,14 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
|
|||
// load instructions
|
||||
{
|
||||
qbyte *src=raw+header->codeOffset;
|
||||
long *dst=qvm->cs;
|
||||
int *dst=(int*)qvm->cs;
|
||||
int total=header->instructionCount;
|
||||
qvm_op_t op;
|
||||
|
||||
for(n=0; n<total; n++)
|
||||
{
|
||||
op=*src++;
|
||||
*dst++=(long)op;
|
||||
*dst++=(int)op;
|
||||
switch(op)
|
||||
{
|
||||
case OP_ENTER:
|
||||
|
@ -495,11 +497,11 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
|
|||
case OP_GTF:
|
||||
case OP_GEF:
|
||||
case OP_BLOCK_COPY:
|
||||
*dst++=LittleLong(*(long*)src);
|
||||
*dst++=LittleLong(*(int*)src);
|
||||
src+=4;
|
||||
break;
|
||||
case OP_ARG:
|
||||
*dst++=(long)*src++;
|
||||
*dst++=(int)*src++;
|
||||
break;
|
||||
default:
|
||||
*dst++=0;
|
||||
|
@ -512,8 +514,8 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
|
|||
|
||||
// load data segment
|
||||
{
|
||||
long *src=(long*)(raw+header->dataOffset);
|
||||
long *dst=(long*)qvm->ds;
|
||||
int *src=(int*)(raw+header->dataOffset);
|
||||
int *dst=(int*)qvm->ds;
|
||||
int total=header->dataLength/4;
|
||||
|
||||
for(n=0; n<total; n++)
|
||||
|
@ -562,9 +564,9 @@ static void inline QVM_Call(qvm_t *vm, int addr)
|
|||
{
|
||||
// system trap function
|
||||
{
|
||||
long *fp;
|
||||
int *fp;
|
||||
|
||||
fp=(long*)(vm->ds+vm->bp)+2;
|
||||
fp=(int*)(vm->ds+vm->bp)+2;
|
||||
vm->sp[0] = vm->syscall(vm->ds, vm->ds_mask, -addr-1, fp);
|
||||
return;
|
||||
}
|
||||
|
@ -573,7 +575,7 @@ static void inline QVM_Call(qvm_t *vm, int addr)
|
|||
if(addr>=vm->len_cs)
|
||||
Sys_Error("VM run time error: program jumped off to hyperspace\n");
|
||||
|
||||
vm->sp[0]=(long)(vm->pc-vm->cs); // push pc /return address/
|
||||
vm->sp[0]=(vm->pc-vm->cs); // push pc /return address/
|
||||
vm->pc=vm->cs+addr*2;
|
||||
if (!vm->pc)
|
||||
Sys_Error("VM run time error: program called the void\n");
|
||||
|
@ -585,15 +587,15 @@ static void inline QVM_Call(qvm_t *vm, int addr)
|
|||
** [oPC][0][.......]| <- oldBP
|
||||
** ^BP
|
||||
*/
|
||||
static void inline QVM_Enter(qvm_t *vm, long size)
|
||||
static void inline QVM_Enter(qvm_t *vm, int size)
|
||||
{
|
||||
long *fp;
|
||||
int *fp;
|
||||
|
||||
vm->bp-=size;
|
||||
if(vm->bp<vm->min_bp)
|
||||
Sys_Error("VM run time error: out of stack\n");
|
||||
|
||||
fp=(long*)(vm->ds+vm->bp);
|
||||
fp=(int*)(vm->ds+vm->bp);
|
||||
fp[0]=vm->sp-vm->max_sp; // unknown /maybe size/
|
||||
fp[1]=*vm->sp++; // saved PC
|
||||
|
||||
|
@ -603,21 +605,21 @@ static void inline QVM_Enter(qvm_t *vm, long size)
|
|||
/*
|
||||
** QVM_Return
|
||||
*/
|
||||
static void inline QVM_Return(qvm_t *vm, long size)
|
||||
static void inline QVM_Return(qvm_t *vm, int size)
|
||||
{
|
||||
long *fp;
|
||||
int *fp;
|
||||
|
||||
fp=(long*)(vm->ds+vm->bp);
|
||||
fp=(int*)(vm->ds+vm->bp);
|
||||
vm->bp+=size;
|
||||
|
||||
if(vm->bp>vm->max_bp)
|
||||
Sys_Error("VM run time error: freed too much stack\n");
|
||||
|
||||
if(fp[1]>=vm->len_cs*2)
|
||||
if (vm->cs+fp[1]) //this being false causes the program to quit.
|
||||
Sys_Error("VM run time error: program returned to hyperspace\n");
|
||||
if ((int)(vm->cs+fp[1]) != (int)RETURNOFFSETMARKER) //this being false causes the program to quit.
|
||||
Sys_Error("VM run time error: program returned to hyperspace (%p, %p)\n", (char*)vm->cs, (char*)fp[1]);
|
||||
if(fp[1]<0)
|
||||
if (vm->cs+fp[1])
|
||||
if ((int)(vm->cs+fp[1]) != (int)RETURNOFFSETMARKER)
|
||||
Sys_Error("VM run time error: program returned to negative hyperspace\n");
|
||||
|
||||
if (vm->sp-vm->max_sp != fp[0])
|
||||
|
@ -641,19 +643,19 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
#define POP(t) qvm->sp+=t;if (qvm->sp > qvm->max_sp) Sys_Error("QVM Stack underflow");
|
||||
#define PUSH(v) qvm->sp--;if (qvm->sp < qvm->min_sp) Sys_Error("QVM Stack overflow");*qvm->sp=v
|
||||
qvm_op_t op=-1;
|
||||
unsigned long param;
|
||||
unsigned int param;
|
||||
|
||||
long *fp;
|
||||
unsigned long *oldpc;
|
||||
int *fp;
|
||||
unsigned int *oldpc;
|
||||
|
||||
oldpc = qvm->pc;
|
||||
|
||||
// setup execution environment
|
||||
qvm->pc=NULL;
|
||||
qvm->pc=RETURNOFFSETMARKER;
|
||||
// qvm->cycles=0;
|
||||
// prepare local stack
|
||||
qvm->bp -= 15*4; //we have to do this each call for the sake of (reliable) recursion.
|
||||
fp=(long*)(qvm->ds+qvm->bp);
|
||||
fp=(int*)(qvm->ds+qvm->bp);
|
||||
// push all params
|
||||
fp[0]=0;
|
||||
fp[1]=0;
|
||||
|
@ -698,7 +700,7 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
case OP_LEAVE:
|
||||
QVM_Return(qvm, param);
|
||||
|
||||
if (!qvm->pc)
|
||||
if ((int)qvm->pc == (int)RETURNOFFSETMARKER)
|
||||
{
|
||||
// pick return value from stack
|
||||
qvm->pc = oldpc;
|
||||
|
@ -746,35 +748,35 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
POP(2);
|
||||
break;
|
||||
case OP_LTI:
|
||||
if(*(signed long*)&qvm->sp[1]<*(signed long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(signed int*)&qvm->sp[1]<*(signed int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_LEI:
|
||||
if(*(signed long*)&qvm->sp[1]<=*(signed long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(signed int*)&qvm->sp[1]<=*(signed int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_GTI:
|
||||
if(*(signed long*)&qvm->sp[1]>*(signed long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(signed int*)&qvm->sp[1]>*(signed int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_GEI:
|
||||
if(*(signed long*)&qvm->sp[1]>=*(signed long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(signed int*)&qvm->sp[1]>=*(signed int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_LTU:
|
||||
if(*(unsigned long*)&qvm->sp[1]<*(unsigned long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(unsigned int*)&qvm->sp[1]<*(unsigned int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_LEU:
|
||||
if(*(unsigned long*)&qvm->sp[1]<=*(unsigned long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(unsigned int*)&qvm->sp[1]<=*(unsigned int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_GTU:
|
||||
if(*(unsigned long*)&qvm->sp[1]>*(unsigned long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(unsigned int*)&qvm->sp[1]>*(unsigned int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_GEU:
|
||||
if(*(unsigned long*)&qvm->sp[1]>=*(unsigned long*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
if(*(unsigned int*)&qvm->sp[1]>=*(unsigned int*)&qvm->sp[0]) QVM_Goto(qvm, param);
|
||||
POP(2);
|
||||
break;
|
||||
case OP_EQF:
|
||||
|
@ -804,13 +806,13 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
|
||||
// memory I/O: masks protect main memory
|
||||
case OP_LOAD1:
|
||||
*(unsigned long*)&qvm->sp[0]=*(unsigned char*)&qvm->ds[qvm->sp[0]&qvm->ds_mask];
|
||||
*(unsigned int*)&qvm->sp[0]=*(unsigned char*)&qvm->ds[qvm->sp[0]&qvm->ds_mask];
|
||||
break;
|
||||
case OP_LOAD2:
|
||||
*(unsigned long*)&qvm->sp[0]=*(unsigned short*)&qvm->ds[qvm->sp[0]&qvm->ds_mask];
|
||||
*(unsigned int*)&qvm->sp[0]=*(unsigned short*)&qvm->ds[qvm->sp[0]&qvm->ds_mask];
|
||||
break;
|
||||
case OP_LOAD4:
|
||||
*(unsigned long*)&qvm->sp[0]=*(unsigned long*)&qvm->ds[qvm->sp[0]&qvm->ds_mask];
|
||||
*(unsigned int*)&qvm->sp[0]=*(unsigned int*)&qvm->ds[qvm->sp[0]&qvm->ds_mask];
|
||||
break;
|
||||
case OP_STORE1:
|
||||
*(qbyte*)&qvm->ds[qvm->sp[1]&qvm->ds_mask]=(qbyte)(qvm->sp[0]&0xFF);
|
||||
|
@ -821,11 +823,11 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
POP(2);
|
||||
break;
|
||||
case OP_STORE4:
|
||||
*(unsigned long*)&qvm->ds[qvm->sp[1]&qvm->ds_mask]=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->ds[qvm->sp[1]&qvm->ds_mask]=*(unsigned int*)&qvm->sp[0];
|
||||
POP(2);
|
||||
break;
|
||||
case OP_ARG:
|
||||
*(unsigned long*)&qvm->ds[(param+qvm->bp)&qvm->ds_mask]=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->ds[(param+qvm->bp)&qvm->ds_mask]=*(unsigned int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_BLOCK_COPY:
|
||||
|
@ -838,73 +840,73 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
|
||||
// integer arithmetic
|
||||
case OP_SEX8:
|
||||
if(*(signed long*)&qvm->sp[0]&0x80) *(signed long*)&qvm->sp[0]|=0xFFFFFF00;
|
||||
if(*(signed int*)&qvm->sp[0]&0x80) *(signed int*)&qvm->sp[0]|=0xFFFFFF00;
|
||||
break;
|
||||
case OP_SEX16:
|
||||
if(*(signed long*)&qvm->sp[0]&0x8000) *(signed long*)&qvm->sp[0]|=0xFFFF0000;
|
||||
if(*(signed int*)&qvm->sp[0]&0x8000) *(signed int*)&qvm->sp[0]|=0xFFFF0000;
|
||||
break;
|
||||
case OP_NEGI:
|
||||
*(signed long*)&qvm->sp[0]=-*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[0]=-*(signed int*)&qvm->sp[0];
|
||||
break;
|
||||
case OP_ADD:
|
||||
*(signed long*)&qvm->sp[1]+=*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[1]+=*(signed int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_SUB:
|
||||
*(signed long*)&qvm->sp[1]-=*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[1]-=*(signed int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_DIVI:
|
||||
*(signed long*)&qvm->sp[1]/=*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[1]/=*(signed int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_DIVU:
|
||||
*(unsigned long*)&qvm->sp[1]/=(*(unsigned long*)&qvm->sp[0]);
|
||||
*(unsigned int*)&qvm->sp[1]/=(*(unsigned int*)&qvm->sp[0]);
|
||||
POP(1);
|
||||
break;
|
||||
case OP_MODI:
|
||||
*(signed long*)&qvm->sp[1]%=*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[1]%=*(signed int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_MODU:
|
||||
*(unsigned long*)&qvm->sp[1]%=(*(unsigned long*)&qvm->sp[0]);
|
||||
*(unsigned int*)&qvm->sp[1]%=(*(unsigned int*)&qvm->sp[0]);
|
||||
POP(1);
|
||||
break;
|
||||
case OP_MULI:
|
||||
*(signed long*)&qvm->sp[1]*=*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[1]*=*(signed int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_MULU:
|
||||
*(unsigned long*)&qvm->sp[1]*=(*(unsigned long*)&qvm->sp[0]);
|
||||
*(unsigned int*)&qvm->sp[1]*=(*(unsigned int*)&qvm->sp[0]);
|
||||
POP(1);
|
||||
break;
|
||||
|
||||
// logic
|
||||
case OP_BAND:
|
||||
*(unsigned long*)&qvm->sp[1]&=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->sp[1]&=*(unsigned int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_BOR:
|
||||
*(unsigned long*)&qvm->sp[1]|=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->sp[1]|=*(unsigned int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_BXOR:
|
||||
*(unsigned long*)&qvm->sp[1]^=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->sp[1]^=*(unsigned int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_BCOM:
|
||||
*(unsigned long*)&qvm->sp[0]=~*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->sp[0]=~*(unsigned int*)&qvm->sp[0];
|
||||
break;
|
||||
case OP_LSH:
|
||||
*(unsigned long*)&qvm->sp[1]<<=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->sp[1]<<=*(unsigned int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_RSHI:
|
||||
*(signed long*)&qvm->sp[1]>>=*(signed long*)&qvm->sp[0];
|
||||
*(signed int*)&qvm->sp[1]>>=*(signed int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
case OP_RSHU:
|
||||
*(unsigned long*)&qvm->sp[1]>>=*(unsigned long*)&qvm->sp[0];
|
||||
*(unsigned int*)&qvm->sp[1]>>=*(unsigned int*)&qvm->sp[0];
|
||||
POP(1);
|
||||
break;
|
||||
|
||||
|
@ -931,10 +933,10 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
|
|||
|
||||
// format conversion
|
||||
case OP_CVIF:
|
||||
*(float*)&qvm->sp[0]=(float)(signed long)qvm->sp[0];
|
||||
*(float*)&qvm->sp[0]=(float)(signed int)qvm->sp[0];
|
||||
break;
|
||||
case OP_CVFI:
|
||||
*(signed long*)&qvm->sp[0]=(signed long)(*(float*)&qvm->sp[0]);
|
||||
*(signed int*)&qvm->sp[0]=(signed int)(*(float*)&qvm->sp[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -959,8 +961,9 @@ void VM_PrintInfo(vm_t *vm)
|
|||
{
|
||||
qvm_t *qvm;
|
||||
|
||||
if(!vm->name[0]) return;
|
||||
Con_Printf("%s (%p): ", vm->name, (int)vm->hInst);
|
||||
if(!vm->name[0])
|
||||
return;
|
||||
Con_Printf("%s (%p): ", vm->name, vm->hInst);
|
||||
|
||||
switch(vm->type)
|
||||
{
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
|
||||
|
||||
typedef int (EXPORT_FN *sys_calldll_t) (int arg, ...);
|
||||
typedef long (*sys_callqvm_t) (void *offset, unsigned int mask, int fn, const long *arg);
|
||||
typedef int (*sys_callqvm_t) (void *offset, unsigned int mask, int fn, const int *arg);
|
||||
|
||||
typedef struct vm_s vm_t;
|
||||
|
||||
// for syscall users
|
||||
#define VM_LONG(x) (*(long*)&(x))
|
||||
#define VM_LONG(x) (*(int*)&(x))
|
||||
#define VM_FLOAT(x) (*(float*)&(x))
|
||||
#define VM_POINTER(x) ((x)?(void*)((char *)offset+((x)%mask)):NULL)
|
||||
#define VM_OOB(p,l) (p + l >= mask || VM_POINTER(p) < offset)
|
||||
|
|
|
@ -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…
Reference in a new issue