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:
Spoike 2007-09-03 22:37:13 +00:00
parent eaf6335e74
commit 06da06f9b3
10 changed files with 351 additions and 159 deletions

View file

@ -155,8 +155,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif #endif
#ifdef __amd64__ #ifdef __amd64__
//nah... not gonna work too well //I'm slowly getting these working in 64bit
#undef VM_Q1
#undef Q3CLIENT #undef Q3CLIENT
#undef Q3SERVER #undef Q3SERVER
#undef PLUGINS #undef PLUGINS

View file

@ -43,6 +43,7 @@ Also, can efficiency be improved much?
#define RETURNOFFSETMARKER NULL
typedef enum vm_type_e typedef enum vm_type_e
{ {
@ -149,6 +150,7 @@ void *Sys_LoadDLL(const char *name, void **vmMain, int (EXPORT_FN *syscall)(int
#endif #endif
#if defined(__amd64__) #if defined(__amd64__)
return 0; //give up early, don't even try going there
sprintf(dllname, "%samd.so", name); sprintf(dllname, "%samd.so", name);
#elif defined(_M_IX86) || defined(__i386__) #elif defined(_M_IX86) || defined(__i386__)
sprintf(dllname, "%sx86.so", name); sprintf(dllname, "%sx86.so", name);
@ -254,25 +256,25 @@ typedef struct vmHeader_s
typedef struct qvm_s typedef struct qvm_s
{ {
// segments // 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 *ds; // data segment, partially filled on load (data, lit, bss)
qbyte *ss; // stack segment, (follows immediatly after ds, corrupting data before vm) qbyte *ss; // stack segment, (follows immediatly after ds, corrupting data before vm)
// pointer registers // pointer registers
unsigned long *pc; // program counter, points to cs, goes up unsigned int *pc; // program counter, points to cs, goes up
unsigned long *sp; // stack pointer, initially points to end of ss, goes down unsigned int *sp; // stack pointer, initially points to end of ss, goes down
unsigned long bp; // base pointer, initially len_ds+len_ss/2 unsigned int bp; // base pointer, initially len_ds+len_ss/2
unsigned long *min_sp; unsigned int *min_sp;
unsigned long *max_sp; unsigned int *max_sp;
unsigned long min_bp; unsigned int min_bp;
unsigned long max_bp; unsigned int max_bp;
// status // status
unsigned int len_cs; // size of cs unsigned int len_cs; // size of cs
unsigned int len_ds; // size of ds unsigned int len_ds; // size of ds
unsigned int len_ss; // size of ss unsigned int len_ss; // size of ss
unsigned long ds_mask; // ds mask (ds+ss) unsigned int ds_mask; // ds mask (ds+ss)
// memory // memory
unsigned int mem_size; unsigned int mem_size;
@ -427,9 +429,9 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
// memory // memory
qvm->ds_mask = qvm->len_ds*sizeof(qbyte)+(qvm->len_ss+16*4)*sizeof(qbyte);//+4 for a stack check decrease 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; break;
} }
qvm->len_ss = (1<<i) - qvm->len_ds*sizeof(qbyte) - 4; //expand the stack space to fill it. 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->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); qvm->mem_ptr=Z_Malloc(qvm->mem_size);
// set pointers // set pointers
qvm->cs=(long*)qvm->mem_ptr; qvm->cs=(unsigned int*)qvm->mem_ptr;
qvm->ds=(qbyte*)(qvm->mem_ptr+qvm->len_cs*sizeof(long)*2); qvm->ds=(qbyte*)(qvm->mem_ptr+qvm->len_cs*sizeof(int)*2);
qvm->ss=(qbyte*)((qbyte*)qvm->ds+qvm->len_ds*sizeof(qbyte)); qvm->ss=(qbyte*)((qbyte*)qvm->ds+qvm->len_ds*sizeof(qbyte));
//waste 32 bits here. //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. //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 // setup registers
qvm->pc=qvm->cs; 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->bp=qvm->len_ds+qvm->len_ss/2;
// qvm->cycles=0; // qvm->cycles=0;
qvm->syscall=syscall; qvm->syscall=syscall;
qvm->ds_mask--; qvm->ds_mask--;
qvm->min_sp = (long*)(qvm->ds+qvm->len_ds+qvm->len_ss/2); qvm->min_sp = (unsigned int*)(qvm->ds+qvm->len_ds+qvm->len_ss/2);
qvm->max_sp = (long*)(qvm->ds+qvm->len_ds+qvm->len_ss); qvm->max_sp = (unsigned int*)(qvm->ds+qvm->len_ds+qvm->len_ss);
qvm->min_bp = qvm->len_ds; qvm->min_bp = qvm->len_ds;
qvm->max_bp = qvm->len_ds+qvm->len_ss/2; 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 // load instructions
{ {
qbyte *src=raw+header->codeOffset; qbyte *src=raw+header->codeOffset;
long *dst=qvm->cs; int *dst=(int*)qvm->cs;
int total=header->instructionCount; int total=header->instructionCount;
qvm_op_t op; qvm_op_t op;
for(n=0; n<total; n++) for(n=0; n<total; n++)
{ {
op=*src++; op=*src++;
*dst++=(long)op; *dst++=(int)op;
switch(op) switch(op)
{ {
case OP_ENTER: case OP_ENTER:
@ -495,11 +497,11 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
case OP_GTF: case OP_GTF:
case OP_GEF: case OP_GEF:
case OP_BLOCK_COPY: case OP_BLOCK_COPY:
*dst++=LittleLong(*(long*)src); *dst++=LittleLong(*(int*)src);
src+=4; src+=4;
break; break;
case OP_ARG: case OP_ARG:
*dst++=(long)*src++; *dst++=(int)*src++;
break; break;
default: default:
*dst++=0; *dst++=0;
@ -512,8 +514,8 @@ qvm_t *QVM_Load(const char *name, sys_callqvm_t syscall)
// load data segment // load data segment
{ {
long *src=(long*)(raw+header->dataOffset); int *src=(int*)(raw+header->dataOffset);
long *dst=(long*)qvm->ds; int *dst=(int*)qvm->ds;
int total=header->dataLength/4; int total=header->dataLength/4;
for(n=0; n<total; n++) for(n=0; n<total; n++)
@ -562,9 +564,9 @@ static void inline QVM_Call(qvm_t *vm, int addr)
{ {
// system trap function // 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); vm->sp[0] = vm->syscall(vm->ds, vm->ds_mask, -addr-1, fp);
return; return;
} }
@ -573,7 +575,7 @@ static void inline QVM_Call(qvm_t *vm, int addr)
if(addr>=vm->len_cs) if(addr>=vm->len_cs)
Sys_Error("VM run time error: program jumped off to hyperspace\n"); 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; vm->pc=vm->cs+addr*2;
if (!vm->pc) if (!vm->pc)
Sys_Error("VM run time error: program called the void\n"); 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 ** [oPC][0][.......]| <- oldBP
** ^BP ** ^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; vm->bp-=size;
if(vm->bp<vm->min_bp) if(vm->bp<vm->min_bp)
Sys_Error("VM run time error: out of stack\n"); 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[0]=vm->sp-vm->max_sp; // unknown /maybe size/
fp[1]=*vm->sp++; // saved PC fp[1]=*vm->sp++; // saved PC
@ -603,21 +605,21 @@ static void inline QVM_Enter(qvm_t *vm, long size)
/* /*
** QVM_Return ** 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; vm->bp+=size;
if(vm->bp>vm->max_bp) if(vm->bp>vm->max_bp)
Sys_Error("VM run time error: freed too much stack\n"); Sys_Error("VM run time error: freed too much stack\n");
if(fp[1]>=vm->len_cs*2) if(fp[1]>=vm->len_cs*2)
if (vm->cs+fp[1]) //this being false causes the program to quit. 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\n"); Sys_Error("VM run time error: program returned to hyperspace (%p, %p)\n", (char*)vm->cs, (char*)fp[1]);
if(fp[1]<0) 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"); Sys_Error("VM run time error: program returned to negative hyperspace\n");
if (vm->sp-vm->max_sp != fp[0]) 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 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 #define PUSH(v) qvm->sp--;if (qvm->sp < qvm->min_sp) Sys_Error("QVM Stack overflow");*qvm->sp=v
qvm_op_t op=-1; qvm_op_t op=-1;
unsigned long param; unsigned int param;
long *fp; int *fp;
unsigned long *oldpc; unsigned int *oldpc;
oldpc = qvm->pc; oldpc = qvm->pc;
// setup execution environment // setup execution environment
qvm->pc=NULL; qvm->pc=RETURNOFFSETMARKER;
// qvm->cycles=0; // qvm->cycles=0;
// prepare local stack // prepare local stack
qvm->bp -= 15*4; //we have to do this each call for the sake of (reliable) recursion. 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 // push all params
fp[0]=0; fp[0]=0;
fp[1]=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: case OP_LEAVE:
QVM_Return(qvm, param); QVM_Return(qvm, param);
if (!qvm->pc) if ((int)qvm->pc == (int)RETURNOFFSETMARKER)
{ {
// pick return value from stack // pick return value from stack
qvm->pc = oldpc; 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); POP(2);
break; break;
case OP_LTI: 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); POP(2);
break; break;
case OP_LEI: 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); POP(2);
break; break;
case OP_GTI: 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); POP(2);
break; break;
case OP_GEI: 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); POP(2);
break; break;
case OP_LTU: 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); POP(2);
break; break;
case OP_LEU: 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); POP(2);
break; break;
case OP_GTU: 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); POP(2);
break; break;
case OP_GEU: 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); POP(2);
break; break;
case OP_EQF: 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 // memory I/O: masks protect main memory
case OP_LOAD1: 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; break;
case OP_LOAD2: 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; break;
case OP_LOAD4: 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; break;
case OP_STORE1: case OP_STORE1:
*(qbyte*)&qvm->ds[qvm->sp[1]&qvm->ds_mask]=(qbyte)(qvm->sp[0]&0xFF); *(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); POP(2);
break; break;
case OP_STORE4: 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); POP(2);
break; break;
case OP_ARG: 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); POP(1);
break; break;
case OP_BLOCK_COPY: 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 // integer arithmetic
case OP_SEX8: 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; break;
case OP_SEX16: 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; break;
case OP_NEGI: case OP_NEGI:
*(signed long*)&qvm->sp[0]=-*(signed long*)&qvm->sp[0]; *(signed int*)&qvm->sp[0]=-*(signed int*)&qvm->sp[0];
break; break;
case OP_ADD: 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); POP(1);
break; break;
case OP_SUB: 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); POP(1);
break; break;
case OP_DIVI: 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); POP(1);
break; break;
case OP_DIVU: 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); POP(1);
break; break;
case OP_MODI: 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); POP(1);
break; break;
case OP_MODU: 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); POP(1);
break; break;
case OP_MULI: 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); POP(1);
break; break;
case OP_MULU: 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); POP(1);
break; break;
// logic // logic
case OP_BAND: 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); POP(1);
break; break;
case OP_BOR: 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); POP(1);
break; break;
case OP_BXOR: 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); POP(1);
break; break;
case OP_BCOM: case OP_BCOM:
*(unsigned long*)&qvm->sp[0]=~*(unsigned long*)&qvm->sp[0]; *(unsigned int*)&qvm->sp[0]=~*(unsigned int*)&qvm->sp[0];
break; break;
case OP_LSH: 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); POP(1);
break; break;
case OP_RSHI: 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); POP(1);
break; break;
case OP_RSHU: 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); POP(1);
break; break;
@ -931,10 +933,10 @@ int QVM_Exec(register qvm_t *qvm, int command, int arg0, int arg1, int arg2, int
// format conversion // format conversion
case OP_CVIF: case OP_CVIF:
*(float*)&qvm->sp[0]=(float)(signed long)qvm->sp[0]; *(float*)&qvm->sp[0]=(float)(signed int)qvm->sp[0];
break; break;
case OP_CVFI: 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; break;
} }
} }
@ -959,8 +961,9 @@ void VM_PrintInfo(vm_t *vm)
{ {
qvm_t *qvm; qvm_t *qvm;
if(!vm->name[0]) return; if(!vm->name[0])
Con_Printf("%s (%p): ", vm->name, (int)vm->hInst); return;
Con_Printf("%s (%p): ", vm->name, vm->hInst);
switch(vm->type) switch(vm->type)
{ {

View file

@ -11,12 +11,12 @@
typedef int (EXPORT_FN *sys_calldll_t) (int arg, ...); 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; typedef struct vm_s vm_t;
// for syscall users // for syscall users
#define VM_LONG(x) (*(long*)&(x)) #define VM_LONG(x) (*(int*)&(x))
#define VM_FLOAT(x) (*(float*)&(x)) #define VM_FLOAT(x) (*(float*)&(x))
#define VM_POINTER(x) ((x)?(void*)((char *)offset+((x)%mask)):NULL) #define VM_POINTER(x) ((x)?(void*)((char *)offset+((x)%mask)):NULL)
#define VM_OOB(p,l) (p + l >= mask || VM_POINTER(p) < offset) #define VM_OOB(p,l) (p + l >= mask || VM_POINTER(p) < offset)

View file

@ -1959,6 +1959,9 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
{ {
if (!strcmp(sv.strings.model_precache[i], m)) if (!strcmp(sv.strings.model_precache[i], m))
{ {
#ifdef VM_Q1
if (svs.gametype != GT_Q1QVM)
#endif
m = sv.strings.model_precache[i]; m = sv.strings.model_precache[i];
break; break;
} }
@ -1967,9 +1970,14 @@ void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m)
{ {
if (i!=MAX_MODELS) 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")) 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); Con_Printf("WARNING: SV_ModelIndex: model %s not precached\n", m);
if (sv.state != ss_loading) 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; e->v->modelindex = i;
// if it is an inline model, get the size information for it // if it is an inline model, get the size information for it
@ -3095,7 +3103,7 @@ name checkclient ()
*/ */
#define MAX_CHECK 16 #define MAX_CHECK 16
int c_invis, c_notvis; 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; edict_t *ent, *self;
int l; int l;
@ -3112,8 +3120,7 @@ void PF_checkclient (progfuncs_t *prinst, struct globalvars_s *pr_globals)
ent = EDICT_NUM(prinst, sv.lastcheck); ent = EDICT_NUM(prinst, sv.lastcheck);
if (ent->isfree || ent->v->health <= 0) if (ent->isfree || ent->v->health <= 0)
{ {
RETURN_EDICT(prinst, sv.edicts); return 0;
return;
} }
// if current entity can't possibly see the check entity, 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)) ) ) if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
{ {
c_notvis++; c_notvis++;
RETURN_EDICT(prinst, sv.edicts); return 0;
return;
} }
// might be able to see it // might be able to see it
c_invis++; 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"); PR_BIError (prinst, "Precache name too long");
return; return;
} }
#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); sv.strings.model_precache[i] = PR_AddString(prinst, s, 0);
s = sv.strings.model_precache[i];
if (!strcmp(s + strlen(s) - 4, ".bsp")) 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) if (sv.state != ss_loading)
{ {

View file

@ -155,11 +155,7 @@ typedef enum
GAME_SHUTDOWN, // (void); GAME_SHUTDOWN, // (void);
GAME_CLIENT_CONNECT, // ( int clientNum ,int isSpectator); 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_PUT_CLIENT_IN_SERVER,
//GAME_CLIENT_BEGIN, // ( int clientNum ,int isSpectator);
GAME_CLIENT_USERINFO_CHANGED, // ( 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_TOUCH, //(self,other)
GAME_EDICT_THINK, //(self,other=world,time) GAME_EDICT_THINK, //(self,other=world,time)
GAME_EDICT_BLOCKED, //(self,other) GAME_EDICT_BLOCKED, //(self,other)
// ConsoleCommand will be called when a command has been issued GAME_CLIENT_SAY, //(int isteam)
// 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.
} gameExport_t; } gameExport_t;
@ -267,6 +259,7 @@ typedef struct {
} q1qvmglobalvars_t; } q1qvmglobalvars_t;
//this is not usable in 64bit to refer to a 32bit qvm (hence why we have two versions).
typedef struct typedef struct
{ {
edict_t *ents; edict_t *ents;
@ -274,7 +267,16 @@ typedef struct
q1qvmglobalvars_t *global; q1qvmglobalvars_t *global;
field_t *fields; field_t *fields;
int APIversion; 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; 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 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; char *n;
int l = strlen(base); int l = strlen(base);
Con_Printf("warning: string %s will not be readable from the qvm\n", base);
l = l<minlength?minlength:l; l = l<minlength?minlength:l;
n = Z_TagMalloc(l+1, VMFSID_Q1QVM); n = Z_TagMalloc(l+1, VMFSID_Q1QVM);
strcpy(n, base); strcpy(n, base);
return n; 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; edict_t *e;
@ -341,16 +346,16 @@ edict_t *Q1QVMPF_EdictNum(progfuncs_t *pf, unsigned int num)
return e; 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; 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; 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) if (num % pr_edict_size)
Con_Printf("Edict To Progs with remainder\n"); Con_Printf("Edict To Progs with remainder\n");
@ -368,7 +373,7 @@ void Q1QVMED_ClearEdict (edict_t *e, qboolean wipe)
e->entnum = num; 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)) if (!ED_CanFree(e))
return; return;
@ -376,7 +381,7 @@ void Q1QVMPF_EntRemove(progfuncs_t *pf, edict_t *e)
e->freetime = sv.time; e->freetime = sv.time;
} }
edict_t *Q1QVMPF_EntAlloc(progfuncs_t *pf) static edict_t *Q1QVMPF_EntAlloc(progfuncs_t *pf)
{ {
int i; int i;
edict_t *e; edict_t *e;
@ -427,7 +432,7 @@ edict_t *Q1QVMPF_EntAlloc(progfuncs_t *pf)
return (struct edict_s *)e; 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; q1qvmentstring = mapstring;
VM_Call(q1qvm, GAME_LOADENTS); VM_Call(q1qvm, GAME_LOADENTS);
@ -435,7 +440,7 @@ int Q1QVMPF_LoadEnts(progfuncs_t *pf, char *mapstring, float spawnflags)
return pr_edict_size; 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")) if (!strcmp(fieldname, "message"))
{ {
@ -444,24 +449,24 @@ eval_t *Q1QVMPF_GetEdictFieldValue(progfuncs_t *pf, edict_t *e, char *fieldname,
return NULL; 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; return NULL;
} }
globalvars_t *Q1QVMPF_Globals(progfuncs_t *prinst, int prnum) static globalvars_t *Q1QVMPF_Globals(progfuncs_t *prinst, int prnum)
{ {
return NULL; 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); 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); 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_sound_Internal (progfuncs_t *prinst, char *s);
void PF_precache_model_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); void PF_setmodel_Internal (progfuncs_t *prinst, edict_t *e, char *m);
char *PF_infokey_Internal (int entnum, char *value); 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; globalvars_t gv;
int argnum=0; 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. #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) switch (fn)
{ {
@ -657,8 +663,7 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
break; break;
case G_CHECKCLIENT: case G_CHECKCLIENT:
// return PF_checkclientinternal(VM_LONG(arg[0])); return PF_checkclient_Internal(svprogfuncs);
break;
case G_STUFFCMD: case G_STUFFCMD:
{ {
@ -695,7 +700,7 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
case G_FINDRADIUS: 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; edict_t *ed;
vec3_t diff; vec3_t diff;
float *org = VM_POINTER(arg[1]); float *org = VM_POINTER(arg[1]);
@ -708,7 +713,7 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
continue; continue;
VectorSubtract(ed->v->origin, org, diff); VectorSubtract(ed->v->origin, org, diff);
if (rad > DotProduct(diff, diff)) if (rad > DotProduct(diff, diff))
return (long)((char*)vevars + start*pr_edict_size); return (int)(vevars + start*pr_edict_size);
} }
return 0; return 0;
} }
@ -851,14 +856,20 @@ long syscallqvm (void *offset, unsigned int mask, int fn, const long *arg)
break; break;
case g_memset: case g_memset:
{
void *dst = VM_POINTER(arg[0]);
VALIDATEPOINTER(arg[0], arg[2]); VALIDATEPOINTER(arg[0], arg[2]);
memset(VM_POINTER(arg[0]), arg[1], arg[2]); memset(dst, arg[1], arg[2]);
return arg[0]; return arg[0];
break; }
case g_memcpy: case g_memcpy:
{
void *dst = VM_POINTER(arg[0]);
void *src = VM_POINTER(arg[1]);
VALIDATEPOINTER(arg[0], arg[2]); VALIDATEPOINTER(arg[0], arg[2]);
memmove(VM_POINTER(arg[0]), VM_POINTER(arg[1]), arg[2]); memmove(dst, src, arg[2]);
return arg[0]; return arg[0];
}
break; break;
case g_strncpy: case g_strncpy:
VALIDATEPOINTER(arg[0], arg[2]); 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 (field == NULL)
{ {
if (*match == '\0') 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 else
{ {
if (!strcmp(field, match)) 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) if (VM_OOB(arg[0], arg[1]) || !out)
return -1; //please don't corrupt me return -1; //please don't corrupt me
time(&curtime); time(&curtime);
curtime + VM_LONG(arg[3]); curtime += VM_LONG(arg[3]);
local = localtime(&curtime); local = localtime(&curtime);
strftime(out, VM_LONG(arg[1]), fmt, local); strftime(out, VM_LONG(arg[1]), fmt, local);
} }
@ -1137,11 +1148,11 @@ Con_DPrintf("PF_readcmd: %s\n%s", s, output);
case G_NEXTCLIENT: 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) while (start < sv.allocated_client_slots)
{ {
if (svs.clients[start].state == cs_spawned) 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++; start++;
} }
return 0; return 0;
@ -1155,9 +1166,9 @@ Con_DPrintf("PF_readcmd: %s\n%s", s, output);
return 0; 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_list argptr;
va_start(argptr, arg); va_start(argptr, arg);
@ -1201,7 +1212,8 @@ qboolean PR_LoadQ1QVM(void)
{ {
static float writable; static float writable;
int i; int i;
gameData_t *gd; gameDataN_t *gd, gdm;
gameData32_t *gd32;
int ret; int ret;
if (q1qvm) if (q1qvm)
@ -1218,7 +1230,7 @@ qboolean PR_LoadQ1QVM(void)
svprogfuncs = &q1qvmprogfuncs; 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.EDICT_NUM = Q1QVMPF_EdictNum;
q1qvmprogfuncs.NUM_FOR_EDICT = Q1QVMPF_NumForEdict; q1qvmprogfuncs.NUM_FOR_EDICT = Q1QVMPF_NumForEdict;
q1qvmprogfuncs.EdictToProgs = Q1QVMPF_EdictToProgs; q1qvmprogfuncs.EdictToProgs = Q1QVMPF_EdictToProgs;
@ -1246,21 +1258,33 @@ qboolean PR_LoadQ1QVM(void)
Q1QVM_Shutdown(); Q1QVM_Shutdown();
return false; 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; pr_edict_size = gd->sizeofent;
vevars = (long)gd->ents; vevars = (long)gd->ents;
evars = ((char*)VM_MemoryBase(q1qvm) + vevars); evars = ((char*)VM_MemoryBase(q1qvm) + vevars);
//FIXME: range check this pointer
//FIXME: range check the globals pointer
sv.num_edicts = 1; sv.num_edicts = 1;
sv.max_edicts = sizeof(q1qvmedicts)/sizeof(q1qvmedicts[0]); 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) //WARNING: global is not remapped yet...
#define globalfloat(required, name) pr_nqglobal_struct->name = (float*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name) //This code is written evilly, but works well enough
#define globalstring(required, name) pr_nqglobal_struct->name = (string_t*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name) #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 globalvec(required, name) pr_nqglobal_struct->V_##name = (vec3_t*)((char*)VM_MemoryBase(q1qvm)+(int)&gd->global->name) #define globalfloat(required, name) pr_nqglobal_struct->name = (float*)((char*)VM_MemoryBase(q1qvm)+(long)&gd->global->name)
#define globalfunc(required, name) pr_nqglobal_struct->name = (int*)((char*)VM_MemoryBase(q1qvm)+(int)&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, 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, other);
globalint (true, world); globalint (true, world);
@ -1308,8 +1332,7 @@ qboolean PR_LoadQ1QVM(void)
pr_nqglobal_struct->trace_endcontents = &writable; pr_nqglobal_struct->trace_endcontents = &writable;
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(int)(&gd->global->parm1 + i)); spawnparamglobals[i] = (float*)((char*)VM_MemoryBase(q1qvm)+(long)(&gd->global->parm1 + i));
//spawnparamglobals[i] = (float *)&gd->global->parm1 + i;
for (; i < NUM_SPAWN_PARMS; i++) for (; i < NUM_SPAWN_PARMS; i++)
spawnparamglobals[i] = NULL; spawnparamglobals[i] = NULL;
@ -1327,7 +1350,8 @@ void Q1QVM_ClientConnect(client_t *cl)
if (cl->edict->v->netname) if (cl->edict->v->netname)
{ {
strcpy(cl->namebuf, cl->name); 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); strcpy(cl->name, cl->namebuf);
} }
// call the spawn function // call the spawn function
@ -1341,6 +1365,56 @@ void Q1QVM_ClientConnect(client_t *cl)
VM_Call(q1qvm, GAME_PUT_CLIENT_IN_SERVER, cl->spectator); 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) void Q1QVM_PlayerPreThink(void)
{ {
VM_Call(q1qvm, GAME_CLIENT_PRETHINK, host_client->spectator); VM_Call(q1qvm, GAME_CLIENT_PRETHINK, host_client->spectator);

View file

@ -126,3 +126,27 @@ void PR_ClientUserInfoChanged(char *name, char *oldivalue, char *newvalue);
void PR_LocalInfoChanged(char *name, char *oldivalue, char *newvalue); void PR_LocalInfoChanged(char *name, char *oldivalue, char *newvalue);
void PF_InitTempStrings(progfuncs_t *prinst); 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

View file

@ -1886,6 +1886,11 @@ void SV_SendGameCommand_f(void)
return; return;
#endif #endif
#ifdef VM_Q1
if (Q1QVM_GameConsoleCommand())
return;
#endif
#ifdef Q2SERVER #ifdef Q2SERVER
if (ge) if (ge)
{ {
@ -1980,6 +1985,7 @@ void SV_InitOperatorCommands (void)
// Cmd_AddCommand ("writeip", SV_WriteIP_f); // Cmd_AddCommand ("writeip", SV_WriteIP_f);
Cmd_AddCommand ("sv", SV_SendGameCommand_f); Cmd_AddCommand ("sv", SV_SendGameCommand_f);
Cmd_AddCommand ("mod", SV_SendGameCommand_f);
Cmd_AddCommand ("killserver", SV_KillServer_f); Cmd_AddCommand ("killserver", SV_KillServer_f);
Cmd_AddCommand ("map", SV_Map_f); Cmd_AddCommand ("map", SV_Map_f);

View file

@ -908,7 +908,26 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
sv.models[1] = sv.worldmodel; 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], ""); strcpy(sv.strings.sound_precache[0], "");
sv.strings.model_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. 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[0] = '\0'; //make it go away
#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].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)); svs.clients[i].team = PR_AddString(svprogfuncs, svs.clients[i].teambuf, sizeof(svs.clients[i].teambuf));
}
#ifdef PEXT_CSQC #ifdef PEXT_CSQC
memset(svs.clients[i].csqcentsequence, 0, sizeof(svs.clients[i].csqcentsequence)); memset(svs.clients[i].csqcentsequence, 0, sizeof(svs.clients[i].csqcentsequence));
@ -1053,6 +1082,9 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
eval_t *eval; eval_t *eval;
ent = EDICT_NUM(svprogfuncs, 0); ent = EDICT_NUM(svprogfuncs, 0);
ent->isfree = false; ent->isfree = false;
#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->model = PR_NewString(svprogfuncs, sv.worldmodel->name, 0);
ent->v->modelindex = 1; // world model ent->v->modelindex = 1; // world model
ent->v->solid = SOLID_BSP; ent->v->solid = SOLID_BSP;
@ -1062,14 +1094,22 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
if (progstype == PROG_QW && pr_imitatemvdsv.value>0) if (progstype == PROG_QW && pr_imitatemvdsv.value>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->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->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->impulse = 0;//QWE_VERNUM;
ent->v->items = 103; ent->v->items = 103;
} }
#ifdef VM_Q1
if (svs.gametype != GT_Q1QVM) //we cannot do this with qvm
pr_global_struct->mapname = PR_NewString(svprogfuncs, sv.name, 0); pr_global_struct->mapname = PR_NewString(svprogfuncs, sv.name, 0);
#endif
// serverflags are for cross level information (sigils) // serverflags are for cross level information (sigils)
pr_global_struct->serverflags = svs.serverflags; 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... pr_global_struct->time = 0.1; //HACK!!!! A few QuakeC mods expect time to be non-zero in spawn funcs - like prydon gate...

View file

@ -2871,6 +2871,12 @@ Spawns a client, uses an impulse, uses that clients think then removes the clien
void SV_Impulse_f (void) void SV_Impulse_f (void)
{ {
int i; 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++) for (i = 0; i < sv.allocated_client_slots; i++)
{ {
if (svs.clients[i].state == cs_free) if (svs.clients[i].state == cs_free)

View file

@ -2278,6 +2278,11 @@ void SV_Say (qboolean team)
return; return;
} }
#ifdef VM_Q1
if (Q1QVM_ClientSay(sv_player, team))
return;
#endif
if ((floodtime=SV_CheckFloodProt(host_client))) if ((floodtime=SV_CheckFloodProt(host_client)))
{ {
SV_ClientTPrintf(host_client, PRINT_CHAT, SV_ClientTPrintf(host_client, PRINT_CHAT,
@ -2740,7 +2745,12 @@ void SV_SetInfo_f (void)
if (strstr(Cmd_Argv(1), "\\") || strstr(Cmd_Argv(2), "\\")) if (strstr(Cmd_Argv(1), "\\") || strstr(Cmd_Argv(2), "\\"))
return; // illegal char 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)); Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), sizeof(host_client->userinfo));
// name is extracted below in ExtractFromUserInfo // name is extracted below in ExtractFromUserInfo
@ -2756,7 +2766,7 @@ void SV_SetInfo_f (void)
SV_ExtractFromUserinfo (host_client); SV_ExtractFromUserinfo (host_client);
if (progstype != PROG_QW && !strcmp(Cmd_Argv(1), "bottomcolor")) 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; 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; string_t preserve;
preserve = ent->v->netname; preserve = ent->v->netname;
Q1QVMED_ClearEdict(ent, true); Q1QVMED_ClearEdict(ent, true);
Con_Printf("client netname: %x\n", preserve);
ent->v->netname = preserve; ent->v->netname = preserve;
} }
else 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!) if (progstype != PROG_NQ) //allow frikbots to work in NQ mods (but not qw!)
ED_ClearEdict(svprogfuncs, ent); ED_ClearEdict(svprogfuncs, ent);
ent->v->netname = PR_SetString(svprogfuncs, cl->name);
} }
ED_Spawned(ent); ED_Spawned(ent);
ent->isfree = false; ent->isfree = false;
ent->v->colormap = NUM_FOR_EDICT(svprogfuncs, ent); ent->v->colormap = NUM_FOR_EDICT(svprogfuncs, ent);
ent->v->netname = PR_SetString(svprogfuncs, cl->name);
if (pr_teamfield) if (pr_teamfield)
((string_t *)ent->v)[pr_teamfield] = (string_t)(cl->team-svprogfuncs->stringtable); ((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) if (!host_client->spectator)
return; // already a player 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)) if (!(host_client->zquake_extensions & Z_EXT_JOIN_OBSERVE))
{ {
Con_Printf ("Your QW client doesn't support this command\n"); Con_Printf ("Your QW client doesn't support this command\n");
@ -3325,6 +3342,12 @@ void Cmd_Observe_f (void)
if (host_client->spectator) if (host_client->spectator)
return; // already a 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)) if (!(host_client->zquake_extensions & Z_EXT_JOIN_OBSERVE))
{ {
Con_Printf ("Your QW client doesn't support this command\n"); Con_Printf ("Your QW client doesn't support this command\n");