diff --git a/Makefile b/Makefile
index 9187cfacf..97231698f 100644
--- a/Makefile
+++ b/Makefile
@@ -223,7 +223,6 @@ SERVER_OBJS := \
$(SRC_DIR)/pr2_cmds.o \
$(SRC_DIR)/pr2_edict.o \
$(SRC_DIR)/pr2_exec.o \
- $(SRC_DIR)/pr2_vm.o \
$(SRC_DIR)/sv_ccmds.o \
$(SRC_DIR)/sv_ents.o \
$(SRC_DIR)/sv_init.o \
@@ -240,7 +239,10 @@ SERVER_OBJS := \
$(SRC_DIR)/sv_demo_misc.o \
$(SRC_DIR)/sv_demo_qtv.o \
$(SRC_DIR)/sv_login.o \
- $(SRC_DIR)/sv_mod_frags.o
+ $(SRC_DIR)/sv_mod_frags.o \
+ $(SRC_DIR)/vm.o \
+ $(SRC_DIR)/vm_interpreted.o \
+ $(SRC_DIR)/vm_x86.o
HELP_OBJS := \
$(patsubst help_%.json,help_%.o,$(wildcard help_*.json))
diff --git a/ezQuake.vcxproj b/ezQuake.vcxproj
index 65140541a..032864c9b 100644
--- a/ezQuake.vcxproj
+++ b/ezQuake.vcxproj
@@ -2133,9 +2133,6 @@ msversion.bat
CppCode
-
- CppCode
-
CppCode
@@ -3016,7 +3013,6 @@ msversion.bat
-
diff --git a/ezQuake.vcxproj.filters b/ezQuake.vcxproj.filters
index 0f115246a..4b8ad0949 100644
--- a/ezQuake.vcxproj.filters
+++ b/ezQuake.vcxproj.filters
@@ -407,9 +407,6 @@
Source Files\Documentation
-
- Source Files\Server
-
Source Files\Server
@@ -1384,9 +1381,6 @@
Source Files\Server
-
- Source Files\Server
-
Source Files\Server
diff --git a/src/cmodel.c b/src/cmodel.c
index 9f93fae92..bdbc74b5c 100644
--- a/src/cmodel.c
+++ b/src/cmodel.c
@@ -23,7 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "common.h"
#include "cvar.h"
#endif
-#include
typedef struct cnode_s {
// common with leaf
@@ -78,8 +77,6 @@ static qbool map_halflife;
static mphysicsnormal_t* map_physicsnormals; // must be same number as clipnodes to save reallocations in worst case scenario
-static byte *cmod_base; // for CM_Load* functions
-
// lumps immediately follow:
typedef struct {
char lumpname[24];
@@ -87,8 +84,8 @@ typedef struct {
int filelen;
} bspx_lump_t;
-void* Mod_BSPX_FindLump(bspx_header_t* bspx_header, char* lumpname, int* plumpsize, byte* mod_base);
-bspx_header_t* Mod_LoadBSPX(int filesize, byte* mod_base);
+static bspx_lump_t* CM_LoadBSPX(vfsfile_t* vf, dheader_t* header, bspx_header_t *xheader);
+static byte* CM_BSPX_ReadLump(vfsfile_t* vf, bspx_header_t *xheader, bspx_lump_t* lump, char* lumpname, int* plumpsize);
/*
===============================================================================
@@ -600,14 +597,14 @@ int CM_FindTouchedLeafs (const vec3_t mins, const vec3_t maxs, int leafs[], int
===============================================================================
*/
-static void CM_LoadEntities (lump_t *l)
+static void CM_LoadEntities (byte *buffer, int length)
{
- if (l->filelen <= 0 || l->filelen >= INT_MAX) {
+ if (!length) {
map_entitystring = NULL;
return;
}
- map_entitystring = (char *) Hunk_AllocName(l->filelen + 1, loadname);
- memcpy(map_entitystring, cmod_base + l->fileofs, l->filelen);
+ map_entitystring = (char *) Hunk_AllocName (length, loadname);
+ memcpy (map_entitystring, buffer, length);
}
@@ -616,18 +613,18 @@ static void CM_LoadEntities (lump_t *l)
CM_LoadSubmodels
=================
*/
-static void CM_LoadSubmodels (lump_t *l)
+static void CM_LoadSubmodels (byte *buffer, int length)
{
dmodel_t *in;
cmodel_t *out;
int i, j, count;
- in = (dmodel_t *)(cmod_base + l->fileofs);
+ in = (dmodel_t *) buffer;
- if (l->filelen % sizeof(*in))
+ if (length % sizeof(*in))
Host_Error ("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
+ count = length / sizeof(*in);
if (count < 1)
Host_Error ("Map with no models");
@@ -685,19 +682,11 @@ static void CM_LoadSubmodels (lump_t *l)
CM_SetParent
=================
*/
-static void CM_SetParent(cnode_t *node, cnode_t *parent)
+static void CM_SetParent (cnode_t *node, cnode_t *parent)
{
- if (node->parent && node->parent == parent) {
- Host_Error("Infinite loop detected in node list (node %p, base %p)\n", node, map_nodes);
- return;
- }
-
node->parent = parent;
-
- if (node->contents < 0) {
+ if (node->contents < 0)
return;
- }
-
CM_SetParent (node->children[0], node);
CM_SetParent (node->children[1], node);
}
@@ -707,62 +696,48 @@ static void CM_SetParent(cnode_t *node, cnode_t *parent)
CM_LoadNodes
=================
*/
-static void CM_LoadNodes (lump_t *l)
+static void CM_LoadNodes (byte *buffer, int length)
{
int i, j, count, p;
dnode_t *in;
cnode_t *out;
- const int max_nodes = (INT_MAX / sizeof(*out));
- in = (dnode_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
+ in = (dnode_t *) buffer;
+ if (length % sizeof(*in))
Host_Error ("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_nodes) {
- Host_Error("CM_LoadMap: invalid node count (%d vs 0-%d)", count, max_nodes);
- }
+ count = length / sizeof(*in);
out = (cnode_t *) Hunk_AllocName ( count*sizeof(*out), loadname);
map_nodes = out;
numnodes = count;
- for (i = 0; i < count; i++, in++, out++) {
+ for (i = 0; i < count; i++, in++, out++)
+ {
p = LittleLong(in->planenum);
- if (p < 0 || p >= numplanes) {
- Host_Error("Node %d has invalid plane# %d (0 to %d)\n", i, p, numplanes);
- return;
- }
out->plane = map_planes + p;
- for (j = 0; j < 2; j++) {
- p = LittleShort(in->children[j]);
- if (p < -numleafs || p >= numnodes) {
- Host_Error("Node %d child[%d] #%d (%d to %d)", i, j, p, -numleafs, numnodes);
- return;
- }
- out->children[j] = (p >= 0) ? (map_nodes + p) : ((cnode_t*)(map_leafs + (-1 - p)));
+ for (j=0 ; j<2 ; j++)
+ {
+ p = LittleShort (in->children[j]);
+ out->children[j] = (p >= 0) ? (map_nodes + p) : ((cnode_t *)(map_leafs + (-1 - p)));
}
}
- CM_SetParent(map_nodes, NULL); // sets nodes and leafs
+ CM_SetParent (map_nodes, NULL); // sets nodes and leafs
}
-static void CM_LoadNodes29a(lump_t *l)
+static void CM_LoadNodes29a(byte *buffer, int length)
{
int i, j, count, p;
dnode29a_t *in;
cnode_t *out;
- const int max_nodes = (INT_MAX / sizeof(*out));
- in = (dnode29a_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
+ in = (dnode29a_t *) buffer;
+ if (length % sizeof(*in))
Host_Error("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_nodes) {
- Host_Error("CM_LoadMap: invalid node count (%d vs 0-%d)", count, max_nodes);
- }
+ count = length / sizeof(*in);
out = (cnode_t *)Hunk_AllocName(count * sizeof(*out), loadname);
map_nodes = out;
@@ -770,18 +745,10 @@ static void CM_LoadNodes29a(lump_t *l)
for (i = 0; i < count; i++, in++, out++) {
p = LittleLong(in->planenum);
- if (p < 0 || p >= numplanes) {
- Host_Error("Node %d has invalid plane# %d (0 to %d)\n", i, p, numplanes);
- return;
- }
out->plane = map_planes + p;
for (j = 0; j < 2; j++) {
p = LittleLong(in->children[j]);
- if (p < -numleafs || p >= numnodes) {
- Host_Error("Node %d child[%d] #%d (%d to %d)", i, j, p, -numleafs, numnodes);
- return;
- }
out->children[j] = (p >= 0) ? (map_nodes + p) : ((cnode_t *)(map_leafs + (-1 - p)));
}
}
@@ -789,21 +756,17 @@ static void CM_LoadNodes29a(lump_t *l)
CM_SetParent(map_nodes, NULL); // sets nodes and leafs
}
-static void CM_LoadNodesBSP2(lump_t *l)
+static void CM_LoadNodesBSP2(byte *buffer, int length)
{
int i, j, count, p;
dnode_bsp2_t *in;
cnode_t *out;
- const int max_nodes = (INT_MAX / sizeof(*out));
- in = (dnode_bsp2_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
+ in = (dnode_bsp2_t *) buffer;
+ if (length % sizeof(*in))
Host_Error("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_nodes) {
- Host_Error("CM_LoadMap: invalid node count (%d vs 0-%d)", count, max_nodes);
- }
+ count = length / sizeof(*in);
out = (cnode_t *)Hunk_AllocName(count * sizeof(*out), loadname);
map_nodes = out;
@@ -811,18 +774,10 @@ static void CM_LoadNodesBSP2(lump_t *l)
for (i = 0; i < count; i++, in++, out++) {
p = LittleLong(in->planenum);
- if (p < 0) {
- Host_Error("Node %d has negative plane# %d\n", i, in->planenum);
- return;
- }
out->plane = map_planes + p;
for (j = 0; j < 2; j++) {
p = LittleLong(in->children[j]);
- if (p < -numleafs || p >= numnodes) {
- Host_Error("Node %d child[%d] #%d (%d to %d)", i, j, p, -numleafs, numnodes);
- return;
- }
out->children[j] = (p >= 0) ? (map_nodes + p) : ((cnode_t *)(map_leafs + (-1 - p)));
}
}
@@ -833,21 +788,17 @@ static void CM_LoadNodesBSP2(lump_t *l)
/*
** CM_LoadLeafs
*/
-static void CM_LoadLeafs (lump_t *l)
+static void CM_LoadLeafs (byte *buffer, int length)
{
dleaf_t *in;
cleaf_t *out;
int i, j, count, p;
- int max_leafs = (INT_MAX / sizeof(*out));
- in = (dleaf_t *)(cmod_base + l->fileofs);
+ in = (dleaf_t *) buffer;
- if (l->filelen % sizeof(*in))
+ if (length % sizeof(*in))
Host_Error ("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_leafs) {
- Host_Error("CM_LoadMap: invalid leaf count (%d vs 0-%d)", count, max_leafs);
- }
+ count = length / sizeof(*in);
out = (cleaf_t *) Hunk_AllocName ( count*sizeof(*out), loadname);
map_leafs = out;
@@ -861,22 +812,19 @@ static void CM_LoadLeafs (lump_t *l)
}
}
-static void CM_LoadLeafs29a (lump_t *l)
+static void CM_LoadLeafs29a (byte *buffer, int length)
{
dleaf29a_t *in;
+
cleaf_t *out;
int i, j, count, p;
- int max_leafs = (INT_MAX / sizeof(*out));
- in = (dleaf29a_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in)) {
+ in = (dleaf29a_t *) buffer;
+ if (length % sizeof(*in)) {
Host_Error("CM_LoadMap: funny lump size");
}
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_leafs) {
- Host_Error("CM_LoadMap: invalid leaf count (%d vs 0-%d)", count, max_leafs);
- }
+ count = length / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
map_leafs = out;
@@ -885,29 +833,26 @@ static void CM_LoadLeafs29a (lump_t *l)
for (i = 0; i < count; i++, in++, out++) {
p = LittleLong(in->contents);
out->contents = p;
- for (j = 0; j < 4; j++) {
+ for (j = 0; j < 4; j++)
out->ambient_sound_level[j] = in->ambient_level[j];
- }
}
+
}
-static void CM_LoadLeafsBSP2 (lump_t *l)
+static void CM_LoadLeafsBSP2 (byte *buffer, int length)
{
dleaf_bsp2_t *in;
+
cleaf_t *out;
int i, j, count, p;
- int max_leafs = (INT_MAX / sizeof(*out));
- in = (dleaf_bsp2_t *)(cmod_base + l->fileofs);
+ in = (dleaf_bsp2_t *) buffer;
- if (l->filelen % sizeof(*in)) {
+ if (length % sizeof(*in)) {
Host_Error("CM_LoadMap: funny lump size");
}
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_leafs) {
- Host_Error("CM_LoadMap: invalid leaf count (%d vs 0-%d)", count, max_leafs);
- }
+ count = length / sizeof(*in);
out = Hunk_AllocName ( count*sizeof(*out), loadname);
map_leafs = out;
@@ -926,20 +871,16 @@ static void CM_LoadLeafsBSP2 (lump_t *l)
CM_LoadClipnodes
=================
*/
-static void CM_LoadClipnodes(lump_t *l)
+static void CM_LoadClipnodes(byte *buffer, int length)
{
dclipnode_t *in;
mclipnode_t *out;
int i, count;
- const int max_clipnodes = (INT_MAX / sizeof(*out));
- in = (dclipnode_t *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
+ in = (dclipnode_t *) buffer;
+ if (length % sizeof(*in))
Host_Error("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_clipnodes) {
- Host_Error("CM_LoadMap: invalid clipnode count (%d vs 0-%d)", count, max_clipnodes);
- }
+ count = length / sizeof(*in);
out = (mclipnode_t *)Hunk_AllocName(count * sizeof(*out), loadname);
map_clipnodes = out;
@@ -947,30 +888,21 @@ static void CM_LoadClipnodes(lump_t *l)
for (i = 0; i < count; i++, out++, in++) {
out->planenum = LittleLong(in->planenum);
- if (out->planenum < 0 || out->planenum >= numplanes) {
- Host_Error("CM_LoadClipNodes: node %d references plane %d (numplanes %d)", i, out->planenum, numplanes);
- return;
- }
out->children[0] = LittleShort(in->children[0]);
out->children[1] = LittleShort(in->children[1]);
}
}
-static void CM_LoadClipnodesBSP2(lump_t *l)
+static void CM_LoadClipnodesBSP2(byte *buffer, int length)
{
dclipnode29a_t *in;
mclipnode_t *out;
int i, count;
- const int max_clipnodes = (INT_MAX / sizeof(*out));
- in = (void *)(cmod_base + l->fileofs);
- if (l->filelen % sizeof(*in)) {
+ in = (void *) buffer;
+ if (length % sizeof(*in))
Host_Error("CM_LoadMap: funny lump size");
- }
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_clipnodes) {
- Host_Error("CM_LoadMap: invalid clipnode count (%d vs 0-%d)", count, max_clipnodes);
- }
+ count = length / sizeof(*in);
out = Hunk_AllocName(count * sizeof(*out), loadname);
map_clipnodes = out;
@@ -978,10 +910,6 @@ static void CM_LoadClipnodesBSP2(lump_t *l)
for (i = 0; i < count; i++, out++, in++) {
out->planenum = LittleLong(in->planenum);
- if (out->planenum < 0 || out->planenum >= numplanes) {
- Host_Error("CM_LoadClipNodes: node %d references plane %d (numplanes %d)", i, out->planenum, numplanes);
- return;
- }
out->children[0] = LittleLong(in->children[0]);
out->children[1] = LittleLong(in->children[1]);
}
@@ -1015,12 +943,11 @@ static qbool CM_LoadPhysicsNormalsData(byte* data, int datalength)
return true;
}
-static void CM_LoadPhysicsNormals(int filelen)
+static void CM_LoadPhysicsNormals(byte *physnormals, int len_physnormals)
{
// Same logic as .lit file support: load from bspx, allow over-ride with .qpn files
// As client-side movement prediction will be incorrect if physics normals don't
// match, I strongly recommend the .bspx solution
- bspx_header_t* bspx;
int i;
qbool bspx_loaded = false;
@@ -1034,12 +961,8 @@ static void CM_LoadPhysicsNormals(int filelen)
map_physicsnormals = Hunk_AllocName(numclipnodes * sizeof(map_physicsnormals[0]), loadname);
// Try and load from BSPX lump
- bspx = Mod_LoadBSPX(filelen, cmod_base);
- if (bspx) {
- int lumpsize = 0;
- void* data = Mod_BSPX_FindLump(bspx, "MVDSV_PHYSICSNORMALS", &lumpsize, cmod_base);
-
- bspx_loaded = CM_LoadPhysicsNormalsData(data, lumpsize);
+ if (physnormals) {
+ bspx_loaded = CM_LoadPhysicsNormalsData(physnormals, len_physnormals);
if (bspx_loaded) {
Con_Printf("Loading BSPX physics normals\n");
}
@@ -1087,14 +1010,9 @@ static void CM_MakeHull0(void)
cnode_t *in, *child;
mclipnode_t *out;
int i, j, count;
- int max_clipnodes = (INT_MAX / sizeof(*out));
in = map_nodes;
count = numnodes;
- if (count < 0 || count > max_clipnodes) {
- Host_Error("CM_LoadMap: invalid clipnode count [MakeHull] (%d vs 0-%d)", count, max_clipnodes);
- return;
- }
out = (mclipnode_t *)Hunk_AllocName(count * sizeof(*out), loadname);
// fix up hull 0 in all cmodels
@@ -1118,23 +1036,18 @@ static void CM_MakeHull0(void)
CM_LoadPlanes
=================
*/
-static void CM_LoadPlanes(lump_t *l)
+static void CM_LoadPlanes(byte *buffer, size_t length)
{
int i, j, count, bits;
mplane_t *out;
dplane_t *in;
- const int max_planes = (INT_MAX / sizeof(*out));
- in = (dplane_t *)(cmod_base + l->fileofs);
+ in = (dplane_t *) buffer;
- if (l->filelen % sizeof(*in))
+ if (length % sizeof(*in))
Host_Error("CM_LoadMap: funny lump size");
- count = l->filelen / sizeof(*in);
- if (count < 0 || count > max_planes) {
- Host_Error("CM_LoadMap: invalid plane count (%d vs 0-%d)", count, max_planes);
- return;
- }
+ count = length / sizeof(*in);
out = (mplane_t *)Hunk_AllocName(count * sizeof(*out), loadname);
map_planes = out;
@@ -1158,7 +1071,7 @@ static void CM_LoadPlanes(lump_t *l)
/*
** DecompressVis
*/
-static byte *DecompressVis(byte *in, byte* limit)
+static byte *DecompressVis(byte *in)
{
static byte decompressed[MAX_MAP_LEAFS / 8];
int c, row;
@@ -1176,10 +1089,6 @@ static byte *DecompressVis(byte *in, byte* limit)
}
do {
- if (in >= limit) {
- return NULL;
- }
-
if (*in) {
*out++ = *in++;
continue;
@@ -1202,149 +1111,84 @@ static byte *DecompressVis(byte *in, byte* limit)
**
** Call after CM_LoadLeafs!
*/
-static void CM_BuildPVS(lump_t *lump_vis, lump_t *lump_leafs)
+static void CM_BuildPVS(byte *visdata, int vis_len, byte *leaf_buf, int leaf_len)
{
- byte *visdata, *scan, *visdata_limit;
+ byte *scan;
dleaf_t *in;
int i;
- int max_visleafs;
map_vis_rowlongs = (visleafs + 31) >> 5;
map_vis_rowbytes = map_vis_rowlongs * 4;
- max_visleafs = (INT_MAX / map_vis_rowbytes);
- if (visleafs < 0 || (visleafs > max_visleafs)) {
- Host_Error("CM_LoadMap: invalid visleafs count [BuildPVS] (%d vs 0-%d)", visleafs, max_visleafs);
- return;
- }
- map_pvs = (byte *)Hunk_Alloc(map_vis_rowbytes * visleafs);
+ map_pvs = (byte *)Hunk_AllocName(map_vis_rowbytes * visleafs, "pvs");
- if (lump_vis->filelen <= 0) {
+ if (!vis_len) {
memset(map_pvs, 0xff, map_vis_rowbytes * visleafs);
return;
}
// FIXME, add checks for lump_vis->filelen and leafs' visofs
- visdata = cmod_base + lump_vis->fileofs;
- visdata_limit = cmod_base + lump_vis->fileofs + lump_vis->filelen;
// go through all leafs and decompress visibility data
- in = (dleaf_t *)(cmod_base + lump_leafs->fileofs);
+ in = (dleaf_t *) leaf_buf;
in++; // pvs row 0 is leaf 1
scan = map_pvs;
for (i = 0; i < visleafs; i++, in++, scan += map_vis_rowbytes) {
int p = LittleLong(in->visofs);
- byte* source;
-
- if (p != -1 && p < 0) {
- Host_Error("CM_BuildPVS: visleaf %d has invalid visofs %d", i, p);
- }
- if (p >= lump_vis->filelen) {
- Host_Error("CM_BuildPVS: visleaf %d has out of range visofs %d (limit %d)", i, p, lump_vis->filelen);
- }
-
- source = (p == -1) ? map_novis : DecompressVis(visdata + p, visdata_limit);
- if (source == NULL) {
- Host_Error("CM_BuildPVS: visleaf %d visofs %d caused invalid read, lumpsize %d", i, p, lump_vis->filelen);
- return;
- }
- memcpy(scan, source, map_vis_rowbytes);
+ memcpy(scan, (p == -1) ? map_novis : DecompressVis(visdata + p), map_vis_rowbytes);
}
}
-static void CM_BuildPVS29a(lump_t *lump_vis, lump_t *lump_leafs)
+static void CM_BuildPVS29a(byte *visdata, int vis_len, byte *leaf_buf, int leaf_len)
{
- byte *visdata, *scan, *visdata_limit;
+ byte *scan;
dleaf29a_t *in;
int i;
- int max_visleafs;
map_vis_rowlongs = (visleafs + 31) >> 5;
map_vis_rowbytes = map_vis_rowlongs * 4;
- max_visleafs = (INT_MAX / map_vis_rowbytes);
- if (visleafs < 0 || (visleafs > max_visleafs)) {
- Host_Error("CM_LoadMap: invalid visleafs count [BuildPVS] (%d vs 0-%d)", visleafs, max_visleafs);
- return;
- }
- map_pvs = (byte *)Hunk_Alloc(map_vis_rowbytes * visleafs);
+ map_pvs = (byte *)Hunk_AllocName(map_vis_rowbytes * visleafs, "pvs");
- if (lump_vis->filelen <= 0) {
+ if (!vis_len) {
memset(map_pvs, 0xff, map_vis_rowbytes * visleafs);
return;
}
- visdata = cmod_base + lump_vis->fileofs;
- visdata_limit = cmod_base + lump_vis->fileofs + lump_vis->filelen;
+ // FIXME, add checks for lump_vis->filelen and leafs' visofs
// go through all leafs and decompress visibility data
- in = (dleaf29a_t *)(cmod_base + lump_leafs->fileofs);
+ in = (dleaf29a_t *) leaf_buf;
in++; // pvs row 0 is leaf 1
scan = map_pvs;
for (i = 0; i < visleafs; i++, in++, scan += map_vis_rowbytes) {
int p = LittleLong(in->visofs);
- byte* source;
-
- if (p != -1 && p < 0) {
- Host_Error("CM_BuildPVS: visleaf %d has invalid visofs %d", i, p);
- }
- if (p >= lump_vis->filelen) {
- Host_Error("CM_BuildPVS: visleaf %d has out of range visofs %d (limit %d)", i, p, lump_vis->filelen);
- }
-
- source = (p == -1) ? map_novis : DecompressVis(visdata + p, visdata_limit);
- if (source == NULL) {
- Host_Error("CM_BuildPVS: visleaf %d visofs %d caused invalid read, lumpsize %d", i, p, lump_vis->filelen);
- return;
- }
- memcpy(scan, source, map_vis_rowbytes);
+ memcpy(scan, (p == -1) ? map_novis : DecompressVis(visdata + p), map_vis_rowbytes);
}
}
-static void CM_BuildPVSBSP2(lump_t *lump_vis, lump_t *lump_leafs)
+static void CM_BuildPVSBSP2(byte *visdata, int vis_len, byte *leaf_buf, int leaf_len)
{
- byte *visdata, *scan, *visdata_limit;
+ byte *scan;
dleaf_bsp2_t *in;
int i;
- int max_visleafs;
map_vis_rowlongs = (visleafs + 31) >> 5;
map_vis_rowbytes = map_vis_rowlongs * 4;
- max_visleafs = (INT_MAX / map_vis_rowbytes);
- if (visleafs < 0 || (visleafs > max_visleafs)) {
- Host_Error("CM_LoadMap: invalid visleafs count [BuildPVS] (%d vs 0-%d)", visleafs, max_visleafs);
- return;
- }
- map_pvs = (byte *)Hunk_Alloc(map_vis_rowbytes * visleafs);
+ map_pvs = (byte *)Hunk_AllocName(map_vis_rowbytes * visleafs, "pvs");
- if (lump_vis->filelen <= 0) {
+ if (!vis_len) {
memset(map_pvs, 0xff, map_vis_rowbytes * visleafs);
return;
}
// FIXME, add checks for lump_vis->filelen and leafs' visofs
- visdata = cmod_base + lump_vis->fileofs;
- visdata_limit = cmod_base + lump_vis->fileofs + lump_vis->filelen;
// go through all leafs and decompress visibility data
- in = (dleaf_bsp2_t *)(cmod_base + lump_leafs->fileofs);
+ in = (dleaf_bsp2_t *) leaf_buf;
in++; // pvs row 0 is leaf 1
scan = map_pvs;
for (i = 0; i < visleafs; i++, in++, scan += map_vis_rowbytes) {
int p = LittleLong(in->visofs);
- byte* source;
-
- if (p != -1 && p < 0) {
- Host_Error("CM_BuildPVS: visleaf %d has invalid visofs %d", i, p);
- }
- if (p >= lump_vis->filelen) {
- Host_Error("CM_BuildPVS: visleaf %d has out of range visofs %d (limit %d)", i, p, lump_vis->filelen);
- }
-
- source = (p == -1) ? map_novis : DecompressVis(visdata + p, visdata_limit);
- if (source == NULL) {
- Host_Error("CM_BuildPVS: visleaf %d visofs %d caused invalid read, lumpsize %d", i, p, lump_vis->filelen);
- return;
- }
- memcpy(scan, source, map_vis_rowbytes);
+ memcpy(scan, (p == -1) ? map_novis : DecompressVis(visdata + p), map_vis_rowbytes);
}
}
@@ -1359,19 +1203,13 @@ static void CM_BuildPHS (void)
int i, j, k, l, index1, bitbyte;
unsigned *dest, *src;
byte *scan;
- int max_visleafs = (INT_MAX / map_vis_rowbytes);
-
- if (visleafs > max_visleafs) {
- Host_Error("CM_LoadMap: invalid visleafs count [BuildPHS] (%d vs 0-%d)", visleafs, max_visleafs);
- return;
- }
map_phs = NULL;
if (map_vis_rowbytes * visleafs > 0x100000) {
return;
}
- map_phs = (byte *) Hunk_Alloc (map_vis_rowbytes * visleafs);
+ map_phs = (byte *) Hunk_AllocName (map_vis_rowbytes * visleafs, "phs");
scan = map_pvs;
dest = (unsigned *)map_phs;
for (i = 0; i < visleafs; i++, dest += map_vis_rowlongs, scan += map_vis_rowbytes)
@@ -1421,152 +1259,219 @@ void CM_InvalidateMap (void)
map_physicsnormals = NULL;
}
-/*
-** CM_LoadMap
-*/
-typedef void(*BuildPVSFunction)(lump_t *lump_vis, lump_t *lump_leafs);
-cmodel_t *CM_LoadMap (char *name, qbool clientload, unsigned *checksum, unsigned *checksum2)
+static vfsfile_t *CM_OpenMap(char *name, dheader_t *header)
{
#ifndef CLIENTONLY
extern cvar_t sv_bspversion, sv_halflifebsp;
#endif
+ vfsfile_t *vf;
+ int i, read;
- unsigned int i;
- dheader_t *header;
- unsigned int *buf;
- unsigned int *padded_buf = NULL;
- BuildPVSFunction cm_load_pvs_func = CM_BuildPVS;
- qbool pad_lumps = false;
- int required_length = 0;
- int filelen = 0;
-
- if (map_name[0]) {
- assert(!strcmp(name, map_name));
-
- if (checksum)
- *checksum = map_checksum;
- *checksum2 = map_checksum2;
- return &map_cmodels[0]; // still have the right version
+ vf = FS_OpenVFS(name, "rb", FS_ANY); // FIXME: should be FS_GAME.
+ if (!vf) {
+ Host_Error ("CM_OpenMap: %s not found", name);
}
- // load the file
- buf = (unsigned int *) FS_LoadTempFile (name, &filelen);
- if (!buf)
- Host_Error ("CM_LoadMap: %s not found", name);
-
- COM_FileBase (name, loadname);
+ read = VFS_READ(vf, header, sizeof(dheader_t), NULL);
+ if (read != sizeof(dheader_t))
+ {
+ Con_Printf("Failed to read BSP header, got %d of %d bytes\n", read, sizeof(dheader_t));
+ VFS_CLOSE(vf);
+ return NULL;
+ }
- header = (dheader_t *)buf;
+ for (i = 0; i < sizeof(dheader_t) / 4; i++) {
+ ((int *)header)[i] = LittleLong(((int *)header)[i]);
+ }
- i = LittleLong (header->version);
- if (i != Q1_BSPVERSION && i != HL_BSPVERSION && i != Q1_BSPVERSION2 && i != Q1_BSPVERSION29a)
- Host_Error ("CM_LoadMap: %s has wrong version number (%i should be %i)", name, i, Q1_BSPVERSION);
+ switch (header->version) {
+ case Q1_BSPVERSION:
+ case HL_BSPVERSION:
+#ifndef CLIENTONLY
+ Cvar_SetROM(&sv_bspversion, "1");
+#endif
+ break;
+ case Q1_BSPVERSION2:
+ case Q1_BSPVERSION29a:
+#ifndef CLIENTONLY
+ Cvar_SetROM(&sv_bspversion, "2");
+#endif
+ break;
+ default:
+ VFS_CLOSE(vf);
+ Host_Error ("CM_OpenMap: %s has wrong version number (%i should be %i)", name, i, Q1_BSPVERSION);
+ break;
+ }
- map_halflife = (i == HL_BSPVERSION);
+ map_halflife = (header->version == HL_BSPVERSION);
#ifndef CLIENTONLY
Cvar_SetROM(&sv_halflifebsp, map_halflife ? "1" : "0");
- Cvar_SetROM(&sv_bspversion, i == Q1_BSPVERSION || i == HL_BSPVERSION ? "1" : "2");
#endif
- // swap all the lumps
- for (i = 0; i < sizeof(dheader_t) / 4; i++) {
- ((int *)header)[i] = LittleLong(((int *)header)[i]);
- }
+ return vf;
+}
- // Align the lumps
- for (i = 0; i < HEADER_LUMPS; ++i) {
- pad_lumps |= (header->lumps[i].fileofs % 4) != 0;
+static qbool CM_CalcChecksum(vfsfile_t *f, dheader_t *header, unsigned *checksum, unsigned *checksum2)
+{
+ byte *buf;
+ int i, read;
- if (header->lumps[i].fileofs < 0 || header->lumps[i].filelen < 0) {
- Host_Error("CM_LoadMap: %s has invalid lump definitions", name);
+ // checksum all of the map, except for entities
+ map_checksum = map_checksum2 = 0;
+ for (i = 0; i < HEADER_LUMPS; i++) {
+ if (i == LUMP_ENTITIES)
+ continue;
+
+ if (VFS_SEEK(f, header->lumps[i].fileofs, SEEK_SET) < 0)
+ {
+ Con_Printf("Seek to BSP lump at %d failed\n", header->lumps[i].fileofs);
+ return false;
}
- if (header->lumps[i].fileofs + header->lumps[i].filelen > filelen || header->lumps[i].fileofs + header->lumps[i].filelen < 0) {
- Host_Error("CM_LoadMap: %s has invalid lump definitions", name);
+
+ buf = Hunk_TempAlloc (header->lumps[i].filelen);
+
+ read = VFS_READ(f, buf, header->lumps[i].filelen, NULL);
+ if (read != header->lumps[i].filelen)
+ {
+ Con_Printf("Failed to read BSP lump, got %d of %d bytes\n", read, header->lumps[i].filelen);
+ return false;
}
- required_length += header->lumps[i].filelen;
+ map_checksum ^= LittleLong(Com_BlockChecksum(buf, header->lumps[i].filelen));
+
+ if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
+ continue;
+
+ map_checksum2 ^= LittleLong(Com_BlockChecksum(buf, header->lumps[i].filelen));
}
- if (pad_lumps) {
- int position = 0;
- int required_size = sizeof(dheader_t) + required_length + HEADER_LUMPS * 4 + 1;
- padded_buf = Q_malloc(required_size);
+ if (checksum)
+ *checksum = map_checksum;
- // Copy header
- memcpy(padded_buf, buf, sizeof(dheader_t));
- header = (dheader_t*)padded_buf;
- position += sizeof(dheader_t);
+ if (checksum2)
+ *checksum2 = map_checksum2;
- // Copy lumps: align on 4-byte boundary
- for (i = 0; i < HEADER_LUMPS; ++i) {
- if (position % 4) {
- position += 4 - (position % 4);
- }
- if (position + header->lumps[i].filelen > required_size) {
- Host_Error("CM_LoadMap: %s caused error while aligning lumps", name);
- }
- memcpy((byte*)padded_buf + position, ((byte*)buf) + header->lumps[i].fileofs, header->lumps[i].filelen);
- header->lumps[i].fileofs = position;
+ return true;
+}
- position += header->lumps[i].filelen;
- }
+static byte *CM_ReadLump(vfsfile_t *vf, lump_t *lump)
+{
+ byte *out;
+ int read;
+
+ if (VFS_SEEK(vf, lump->fileofs, SEEK_SET) < 0)
+ {
+ Con_Printf("Seek to BSP lump at %d failed\n", lump->fileofs);
+ return NULL;
+ }
+ out = Hunk_TempAllocMore(lump->filelen);
- // Use the new buffer
- buf = padded_buf;
+ read = VFS_READ(vf, out, lump->filelen, NULL);
+ if (read != lump->filelen)
+ {
+ Con_Printf("Failed to read BSP lump, got %d of %d bytes\n", read, lump->filelen);
+ return NULL;
}
- cmod_base = (byte *)header;
+ return out;
+}
- // checksum all of the map, except for entities
- map_checksum = map_checksum2 = 0;
- for (i = 0; i < HEADER_LUMPS; i++) {
- if (i == LUMP_ENTITIES)
- continue;
- map_checksum ^= LittleLong(Com_BlockChecksum(cmod_base + header->lumps[i].fileofs, header->lumps[i].filelen));
+/*
+** CM_LoadMap
+*/
+typedef void(*BuildPVSFunction)(byte *vis_buf, int vis_len, byte *leaf_buf, int leaf_len);
+cmodel_t *CM_LoadMap (char *name, qbool clientload, unsigned *checksum, unsigned *checksum2)
+{
+ dheader_t header = { 0 };
+ BuildPVSFunction cm_load_pvs_func = CM_BuildPVS;
+ vfsfile_t *vf;
+ byte *l_planes, *l_leafs, *l_nodes, *l_clipnodes, *l_entities, *l_models, *l_vis;
+ bspx_header_t xheader = { 0 };
+ bspx_lump_t *xlumps;
+ byte *l_physnormals = NULL;
+ int l_physnormals_len = 0;
- if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
- continue;
- map_checksum2 ^= LittleLong(Com_BlockChecksum(cmod_base + header->lumps[i].fileofs, header->lumps[i].filelen));
+ if (map_name[0]) {
+ assert(!strcmp(name, map_name));
+
+ if (checksum)
+ *checksum = map_checksum;
+ *checksum2 = map_checksum2;
+ return &map_cmodels[0]; // still have the right version
+ }
+
+ vf = CM_OpenMap(name, &header);
+ if (!vf)
+ {
+ return NULL;
+ }
+
+ if (!CM_CalcChecksum(vf, &header, checksum, checksum2))
+ {
+ VFS_CLOSE(vf);
+ return NULL;
+ }
+
+ COM_FileBase (name, loadname);
+
+ // Flush to temp zone to leave as much heap available to map loading as possible.
+ Hunk_TempFlush();
+
+ l_planes = CM_ReadLump(vf, &header.lumps[LUMP_PLANES]);
+ l_leafs = CM_ReadLump(vf, &header.lumps[LUMP_LEAFS]);
+ l_nodes = CM_ReadLump(vf, &header.lumps[LUMP_NODES]);
+ l_clipnodes = CM_ReadLump(vf, &header.lumps[LUMP_CLIPNODES]);
+ l_entities = CM_ReadLump(vf, &header.lumps[LUMP_ENTITIES]);
+ l_models = CM_ReadLump(vf, &header.lumps[LUMP_MODELS]);
+ l_vis = CM_ReadLump(vf, &header.lumps[LUMP_VISIBILITY]);
+
+ xlumps = CM_LoadBSPX(vf, &header, &xheader);
+ if (xlumps)
+ l_physnormals = CM_BSPX_ReadLump(vf, &xheader, xlumps, "MVDSV_PHYSICSNORMALS", &l_physnormals_len);
+
+ VFS_CLOSE(vf);
+
+ if (!l_planes || !l_leafs || !l_nodes || !l_clipnodes || !l_entities || !l_models || !l_vis)
+ {
+ return NULL;
}
- if (checksum)
- *checksum = map_checksum;
- *checksum2 = map_checksum2;
// load into heap
- CM_LoadPlanes (&header->lumps[LUMP_PLANES]);
- if (LittleLong(header->version) == Q1_BSPVERSION29a) {
- CM_LoadLeafs29a(&header->lumps[LUMP_LEAFS]);
- CM_LoadNodes29a(&header->lumps[LUMP_NODES]);
- CM_LoadClipnodesBSP2(&header->lumps[LUMP_CLIPNODES]);
+ CM_LoadPlanes (l_planes, header.lumps[LUMP_PLANES].filelen);
+ if (LittleLong(header.version) == Q1_BSPVERSION29a) {
+ CM_LoadLeafs29a(l_leafs, header.lumps[LUMP_LEAFS].filelen);
+ CM_LoadNodes29a(l_nodes, header.lumps[LUMP_NODES].filelen);
+ CM_LoadClipnodesBSP2(l_clipnodes, header.lumps[LUMP_CLIPNODES].filelen);
cm_load_pvs_func = CM_BuildPVS29a;
}
- else if (LittleLong(header->version) == Q1_BSPVERSION2) {
- CM_LoadLeafsBSP2(&header->lumps[LUMP_LEAFS]);
- CM_LoadNodesBSP2(&header->lumps[LUMP_NODES]);
- CM_LoadClipnodesBSP2(&header->lumps[LUMP_CLIPNODES]);
+ else if (LittleLong(header.version) == Q1_BSPVERSION2) {
+ CM_LoadLeafsBSP2(l_leafs, header.lumps[LUMP_LEAFS].filelen);
+ CM_LoadNodesBSP2(l_nodes, header.lumps[LUMP_NODES].filelen);
+ CM_LoadClipnodesBSP2(l_clipnodes, header.lumps[LUMP_CLIPNODES].filelen);
cm_load_pvs_func = CM_BuildPVSBSP2;
}
else {
- CM_LoadLeafs(&header->lumps[LUMP_LEAFS]);
- CM_LoadNodes(&header->lumps[LUMP_NODES]);
- CM_LoadClipnodes(&header->lumps[LUMP_CLIPNODES]);
+ CM_LoadLeafs(l_leafs, header.lumps[LUMP_LEAFS].filelen);
+ CM_LoadNodes(l_nodes, header.lumps[LUMP_NODES].filelen);
+ CM_LoadClipnodes(l_clipnodes, header.lumps[LUMP_CLIPNODES].filelen);
cm_load_pvs_func = CM_BuildPVS;
}
- CM_LoadEntities (&header->lumps[LUMP_ENTITIES]);
- CM_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+ CM_LoadEntities (l_entities, header.lumps[LUMP_ENTITIES].filelen);
+ CM_LoadSubmodels (l_models, header.lumps[LUMP_MODELS].filelen);
- CM_LoadPhysicsNormals(filelen);
+ CM_LoadPhysicsNormals(l_physnormals, l_physnormals_len);
CM_MakeHull0 ();
- cm_load_pvs_func (&header->lumps[LUMP_VISIBILITY], &header->lumps[LUMP_LEAFS]);
+ cm_load_pvs_func (l_vis, header.lumps[LUMP_VISIBILITY].filelen, l_leafs, header.lumps[LUMP_LEAFS].filelen);
if (!clientload) // client doesn't need PHS
CM_BuildPHS ();
strlcpy (map_name, name, sizeof(map_name));
- Q_free(padded_buf);
+ // Flush temp zone to leave as much heap available to mods as possible.
+ Hunk_TempFlush();
return &map_cmodels[0];
}
@@ -1631,6 +1536,41 @@ mphysicsnormal_t CM_PhysicsNormal(int num)
return ret;
}
+static int CM_BSPX_FindOffset(dheader_t *header, int filesize)
+{
+ int i, xofs = 0;
+
+ for (i = 0; i < HEADER_LUMPS; i++) {
+ xofs = max(xofs, header->lumps[i].fileofs + header->lumps[i].filelen);
+ }
+
+ if (xofs + sizeof(bspx_header_t) > filesize) {
+ return -1;
+ }
+
+ return xofs;
+}
+
+static qbool CM_BSPX_LoadLumps(bspx_lump_t *lump, int numlumps, int filesize)
+{
+ int i;
+
+ // byte-swap and check sanity
+ for (i = 0; i < numlumps; i++, lump++) {
+ lump->lumpname[sizeof(lump->lumpname) - 1] = '\0'; // make sure it ends with zero
+ lump->fileofs = LittleLong(lump->fileofs);
+ lump->filelen = LittleLong(lump->filelen);
+ if (lump->fileofs < 0 || lump->filelen < 0 || (unsigned)(lump->fileofs + lump->filelen) >(unsigned)filesize) {
+ Con_Printf("Invalid BSPX lump position, ofs: %d, len: %d, filelen: %d\n", lump->fileofs, lump->filelen, filesize);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifndef SERVERONLY
+// Used by ezquake
void* Mod_BSPX_FindLump(bspx_header_t* bspx_header, char* lumpname, int* plumpsize, byte* mod_base)
{
int i;
@@ -1653,22 +1593,18 @@ void* Mod_BSPX_FindLump(bspx_header_t* bspx_header, char* lumpname, int* plumpsi
return NULL;
}
+// Used by ezquake
bspx_header_t* Mod_LoadBSPX(int filesize, byte* mod_base)
{
dheader_t* header;
bspx_header_t* xheader;
bspx_lump_t* lump;
- int i;
int xofs;
// find end of last lump
header = (dheader_t*)mod_base;
- xofs = 0;
- for (i = 0; i < HEADER_LUMPS; i++) {
- xofs = max(xofs, header->lumps[i].fileofs + header->lumps[i].filelen);
- }
-
- if (xofs + sizeof(bspx_header_t) > filesize) {
+ xofs = CM_BSPX_FindOffset(header, filesize);
+ if (xofs < 0) {
return NULL;
}
@@ -1679,17 +1615,97 @@ bspx_header_t* Mod_LoadBSPX(int filesize, byte* mod_base)
return NULL;
}
- // byte-swap and check sanity
lump = (bspx_lump_t*)(xheader + 1); // lumps immediately follow the header
- for (i = 0; i < xheader->numlumps; i++, lump++) {
- lump->lumpname[sizeof(lump->lumpname) - 1] = '\0'; // make sure it ends with zero
- lump->fileofs = LittleLong(lump->fileofs);
- lump->filelen = LittleLong(lump->filelen);
- if (lump->fileofs < 0 || lump->filelen < 0 || (unsigned)(lump->fileofs + lump->filelen) >(unsigned)filesize) {
- return NULL;
- }
+ if (!CM_BSPX_LoadLumps(lump, xheader->numlumps, filesize)) {
+ return NULL;
}
// success
return xheader;
}
+#endif
+
+static byte* CM_BSPX_ReadLump(vfsfile_t *vf, bspx_header_t *xheader, bspx_lump_t* lump, char* lumpname, int* plumpsize)
+{
+ byte *buffer;
+ int i, read;
+
+ if (!lump) {
+ return NULL;
+ }
+
+ for (i = 0; i < xheader->numlumps; i++, lump++) {
+ if (!strcmp(lump->lumpname, lumpname)) {
+ if (plumpsize) {
+ *plumpsize = lump->filelen;
+ }
+
+ buffer = Hunk_TempAllocMore(lump->filelen);
+ if (VFS_SEEK(vf, lump->fileofs, SEEK_SET) < 0)
+ {
+ Con_Printf("Seek to BSPX lump at %d failed\n", lump->fileofs);
+ return NULL;
+ }
+ read = VFS_READ(vf, buffer, lump->filelen, NULL);
+ if (read != lump->filelen)
+ {
+ Con_Printf("Failed to read BSPX lump, got %d of %d bytes\n", read, lump->filelen);
+ return NULL;
+ }
+
+ return buffer;
+ }
+ }
+
+ return NULL;
+}
+
+static bspx_lump_t* CM_LoadBSPX(vfsfile_t *vf, dheader_t *header, bspx_header_t *xheader)
+{
+ bspx_lump_t* lump;
+ int xofs;
+ int read, lumpssize, filesize;
+
+ filesize = VFS_GETLEN(vf);
+
+ // find end of last lump
+ xofs = CM_BSPX_FindOffset(header, filesize);
+ if (xofs < 0) {
+ return NULL;
+ }
+
+ if (VFS_SEEK(vf, xofs, SEEK_SET) < 0)
+ {
+ return NULL;
+ }
+
+ read = VFS_READ(vf, xheader, sizeof(bspx_header_t), NULL);
+ if (read != sizeof(bspx_header_t))
+ {
+ return NULL;
+ }
+
+ xheader->numlumps = LittleLong(xheader->numlumps);
+
+ lumpssize = sizeof(bspx_lump_t) * xheader->numlumps;
+
+ if (xheader->numlumps < 0 || xofs + sizeof(bspx_header_t) + lumpssize > filesize) {
+ Con_Printf("Corrupt BSPX header\n");
+ return NULL;
+ }
+
+ lump = (bspx_lump_t*)Hunk_TempAllocMore(lumpssize);
+
+ read = VFS_READ(vf, lump, lumpssize, NULL);
+ if (read != lumpssize)
+ {
+ Con_Printf("Failed to read BSPX lumps header, got %d of %d bytes\n", read, lumpssize);
+ return NULL;
+ }
+
+ if (!CM_BSPX_LoadLumps(lump, xheader->numlumps, filesize)) {
+ return NULL;
+ }
+
+ return lump;
+}
diff --git a/src/cmodel.h b/src/cmodel.h
index 85c820ae9..7c7e64ec6 100644
--- a/src/cmodel.h
+++ b/src/cmodel.h
@@ -115,7 +115,9 @@ typedef struct bspx_header_s {
int numlumps;
} bspx_header_t;
+#ifndef SERVERONLY
void* Mod_BSPX_FindLump(bspx_header_t* bspx_header, char* lumpname, int* plumpsize, byte* mod_base);
bspx_header_t* Mod_LoadBSPX(int filesize, byte* mod_base);
+#endif
#endif /* !__CMODEL_H__ */
diff --git a/src/g_public.h b/src/g_public.h
index 483eb5d89..dfd2204c4 100644
--- a/src/g_public.h
+++ b/src/g_public.h
@@ -30,8 +30,35 @@
//
// g_public.h -- game module information visible to server
-#define GAME_API_VERSION 15
+#define GAME_API_VERSION 16
+/*
+ * Changes in GAME_API_VERSION 16:
+ * - server edict data removed from game edict: typedef struct shared_edict_s { entvars_t v;} edict_t;
+ * - SetSting works for PR1 only
+ * - ported VM from Q3
+ * - QVM mods should get mapname and client netnames with infokey trap
+ *
+ * mod should get client netname in GAME_CLIENT_CONNECT call:
+ * self = PROG_TO_EDICT(g_globalvars.self);
+ * self->s.v.netname = netnames[NUM_FOR_EDICT(self)-1];
+ * infokey( self, "netname", self->s.v.netname, 32);
+ *
+ * mod should get mapname in GAME_START_FRAME call:
+ * if (framecount == 0)
+ * {
+ * infokey(world, "mapname", mapname, sizeof(mapname));
+ * infokey(world, "modelname", worldmodel, sizeof(worldmodel));
+ * world->model = worldmodel;
+ * }
+ *
+ * infokey( world, "mapname", mapname, sizeof(mapname) );
+ *
+ * - QVM GAME_CLIENT_USERINFO_CHANGED call now have integer paramater
+ *
+ * called with 0 before changing, with 1 after changing
+ * mod must update client netname in call with param 1 and key = "name"
+ */
//===============================================================
@@ -142,6 +169,8 @@ typedef enum
G_SETPAUSE,
G_SETUSERINFO,
G_MOVETOGOAL,
+ G_VISIBLETO,
+ _G__LASTAPI
} gameImport_t;
// !!! new things comes to end of list !!!
@@ -215,14 +244,30 @@ typedef struct
typedef struct
{
- edict_t *ents;
+ int name;
+ int ofs;
+ int type;
+} field_vm_t;
+
+typedef struct
+{
+ intptr_t ents;
int sizeofent;
- globalvars_t *global;
- field_t *fields;
+ intptr_t global;
+ intptr_t fields;
int APIversion;
int maxentities;
} gameData_t;
+typedef struct
+{
+ int ents_p;
+ int sizeofent;
+ int global_p;
+ int fields_p;
+ int APIversion;
+ int maxentities;
+} gameData_vm_t;
typedef int fileHandle_t;
typedef enum {
diff --git a/src/pmove.c b/src/pmove.c
index b36ea22c8..7e80f2350 100644
--- a/src/pmove.c
+++ b/src/pmove.c
@@ -29,9 +29,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
movevars_t movevars;
playermove_t pmove;
-static float pm_frametime;
+static float pm_frametime;
-static vec3_t pm_forward, pm_right;
+static vec3_t pm_forward, pm_right;
static vec3_t groundnormal;
@@ -40,11 +40,11 @@ vec3_t player_maxs = {16, 16, 32};
#define STEPSIZE 18
-#define pm_flyfriction 4
+#define pm_flyfriction 4
-#define BLOCKED_FLOOR 1
-#define BLOCKED_STEP 2
-#define BLOCKED_OTHER 4
+#define BLOCKED_FLOOR 1
+#define BLOCKED_STEP 2
+#define BLOCKED_OTHER 4
#define BLOCKED_ANY 7
#define MAX_JUMPFIX_DOTPRODUCT -0.1
diff --git a/src/pr2.h b/src/pr2.h
index 44190446e..e0eb152f4 100644
--- a/src/pr2.h
+++ b/src/pr2.h
@@ -23,11 +23,7 @@
#define __PR2_H__
-extern intptr_t sv_syscall(intptr_t arg, ...);
-extern int sv_sys_callex(byte *data, unsigned int len, int fn, pr2val_t*arg);
-typedef void (*pr2_trapcall_t)(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval);
-
-//extern int usedll;
+intptr_t PR2_GameSystemCalls( intptr_t *args );
extern cvar_t sv_progtype;
extern vm_t* sv_vm;
@@ -68,7 +64,7 @@ void PR2_EdictThink(func_t f);
#define PR_EdictThink PR2_EdictThink
void PR2_EdictBlocked(func_t f);
#define PR_EdictBlocked PR2_EdictBlocked
-qbool PR2_UserInfoChanged(void);
+qbool PR2_UserInfoChanged(int after);
#define PR_UserInfoChanged PR2_UserInfoChanged
void PR2_GameShutDown(void);
#define PR_GameShutDown PR2_GameShutDown
diff --git a/src/pr2_cmds.c b/src/pr2_cmds.c
index 2553d058d..4ba2440c7 100644
--- a/src/pr2_cmds.c
+++ b/src/pr2_cmds.c
@@ -24,6 +24,8 @@
#ifdef USE_PR2
#include "qwsvdef.h"
+#include "vm.h"
+#include "vm_local.h"
#define SETUSERINFO_STAR (1<<0) // allow set star keys
@@ -32,8 +34,85 @@
#define Cbuf_ExecuteEx(x) Cbuf_Execute()
#endif
-const char* pr2_ent_data_ptr;
-vm_t* sv_vm = NULL;
+const char *pr2_ent_data_ptr;
+vm_t *sv_vm = NULL;
+extern gameData_t gamedata;
+
+static int PASSFLOAT(float f)
+{
+ floatint_t fi;
+ fi.f = f;
+ return fi.i;
+}
+
+#if 0 // Provided for completness.
+static float GETFLOAT(int i)
+{
+ floatint_t fi;
+ fi.i = i;
+ return fi.f;
+}
+#endif
+
+int NUM_FOR_GAME_EDICT(byte *e)
+{
+ int b;
+
+ b = (byte *)e - (byte *)sv.game_edicts;
+ b /= pr_edict_size;
+
+ if (b < 0 || b >= sv.num_edicts)
+ SV_Error("NUM_FOR_GAME_EDICT: bad pointer");
+
+ return b;
+}
+
+intptr_t PR2_EntityStringLocation(string_t offset, int max_size);
+void static PR2_SetEntityString_model(edict_t *ed, string_t *target, char *s) {
+ if (!sv_vm) {
+ PR1_SetString(target, s);
+ return;
+ }
+
+ switch (sv_vm->type) {
+ case VMI_NONE:
+ PR1_SetString(target, s);
+ return;
+
+ case VMI_NATIVE:
+ if (sv_vm->pr2_references) {
+ char **location =
+ (char **)PR2_EntityStringLocation(*target, sizeof(char *));
+ if (location) {
+ *location = s;
+ }
+ }
+#ifndef idx64
+ else if (target) {
+ *target = (string_t)s;
+ }
+#endif
+ return;
+ case VMI_BYTECODE:
+ case VMI_COMPILED: {
+ int off = VM_ExplicitPtr2VM(sv_vm, (byte *)s);
+
+ if (sv_vm->pr2_references) {
+ string_t *location =
+ (string_t *)PR2_EntityStringLocation(*target, sizeof(string_t));
+
+ if (location) {
+ *location = off;
+ }
+ } else {
+ *target = off;
+ }
+ }
+ return;
+ }
+
+ *target = 0;
+}
/*
============
@@ -52,8 +131,6 @@ void PR2_RunError(char *error, ...)
va_end(argptr);
sv_error = true;
- if( sv_vm->type == VM_BYTECODE )
- QVM_StackTrace( (qvm_t *) sv_vm->hInst );
Con_Printf("%s\n", string);
@@ -66,52 +143,13 @@ void PR2_CheckEmptyString(char *s)
PR2_RunError("Bad string");
}
-void PF2_GetApiVersion(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int = GAME_API_VERSION;
-}
-
-void PF2_GetEntityToken(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- pr2_ent_data_ptr = COM_Parse(pr2_ent_data_ptr);
- strlcpy((char*)VM_POINTER(base,mask,stack[0].string), com_token, stack[1]._int);
-
- retval->_int= pr2_ent_data_ptr != NULL;
-}
-
-void PF2_DPrint(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- Con_DPrintf("%s", VM_POINTER(base,mask,stack[0].string));
-}
-
-void PF2_conprint(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- Sys_Printf("%s", VM_POINTER(base, mask, stack[0].string));
-}
-
-void PF2_Error(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- PR2_RunError((char *)VM_POINTER(base, mask, stack->string));
-}
-
-void PF2_Spawn(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int = NUM_FOR_EDICT( ED_Alloc() );
-}
-
-void PF2_Remove(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- ED_Free(EDICT_NUM(stack[0]._int));
-}
-
-void PF2_precache_sound(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_precache_sound(char *s)
{
int i;
- char*s;
+
if (sv.state != ss_loading)
PR2_RunError("PF_Precache_*: Precache can only be done in spawn "
"functions");
- s = (char *) VM_POINTER(base,mask,stack[0].string);
PR2_CheckEmptyString(s);
for (i = 0; i < MAX_SOUNDS; i++)
@@ -128,16 +166,14 @@ void PF2_precache_sound(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*re
PR2_RunError ("PF_precache_sound: overflow");
}
-void PF2_precache_model(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_precache_model(char *s)
{
int i;
- char *s;
if (sv.state != ss_loading)
PR2_RunError("PF_Precache_*: Precache can only be done in spawn "
"functions");
- s = (char *) VM_POINTER(base,mask,stack[0].string);
PR2_CheckEmptyString(s);
for (i = 0; i < MAX_MODELS; i++)
@@ -154,16 +190,14 @@ void PF2_precache_model(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*re
PR2_RunError ("PF_precache_model: overflow");
}
-void PF2_precache_vwep_model(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_precache_vwep_model(char *s)
{
int i;
- char *s;
if (sv.state != ss_loading)
PR2_RunError("PF_Precache_*: Precache can only be done in spawn "
"functions");
- s = (char *) VM_POINTER(base,mask,stack[0].string);
PR2_CheckEmptyString(s);
// the strings are transferred via the stufftext mechanism, hence the stringency
@@ -174,11 +208,11 @@ void PF2_precache_vwep_model(byte* base, uintptr_t mask, pr2val_t* stack, pr2val
{
if (!sv.vw_model_name[i]) {
sv.vw_model_name[i] = s;
- retval->_int = i;
- return;
+ return i;
}
}
PR2_RunError ("PF_precache_vwep_model: overflow");
+ return 0;
}
/*
@@ -191,18 +225,15 @@ setorigin (entity, origin)
=================
*/
-void PF2_setorigin(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_setorigin(edict_t *e, float x, float y, float z)
{
vec3_t origin;
- edict_t *e;
- e = EDICT_NUM(stack[0]._int);
+ origin[0] = x;
+ origin[1] = y;
+ origin[2] = z;
- origin[0] = stack[1]._float;
- origin[1] = stack[2]._float;
- origin[2] = stack[3]._float;
-
- VectorCopy(origin, e->v.origin);
+ VectorCopy(origin, e->v->origin);
SV_AntilagReset(e);
SV_LinkEdict(e, false);
}
@@ -216,22 +247,18 @@ the size box is rotated by the current angle
setsize (entity, minvector, maxvector)
=================
*/
-void PF2_setsize(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_setsize(edict_t *e, float x1, float y1, float z1, float x2, float y2, float z2)
{
- //vec3_t min, max;
- edict_t *e ;
-
- e = EDICT_NUM(stack[0]._int);
-
- e->v.mins[0] = stack[1]._float;
- e->v.mins[1] = stack[2]._float;
- e->v.mins[2] = stack[3]._float;
+ // vec3_t min, max;
+ e->v->mins[0] = x1;
+ e->v->mins[1] = y1;
+ e->v->mins[2] = z1;
- e->v.maxs[0] = stack[4]._float;
- e->v.maxs[1] = stack[5]._float;
- e->v.maxs[2] = stack[6]._float;
+ e->v->maxs[0] = x2;
+ e->v->maxs[1] = y2;
+ e->v->maxs[2] = z2;
- VectorSubtract(e->v.maxs, e->v.mins, e->v.size);
+ VectorSubtract(e->v->maxs, e->v->mins, e->v->size);
SV_LinkEdict(e, false);
}
@@ -244,17 +271,13 @@ setmodel(entity, model)
Also sets size, mins, and maxs for inline bmodels
=================
*/
-void PF2_setmodel(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_setmodel(edict_t *e, char *m)
{
- edict_t *e;
- char *m;
char **check;
int i;
cmodel_t *mod;
- e = EDICT_NUM(stack[0]._int);
- m = (char *) VM_POINTER(base,mask,stack[1].string);
- if(!m)
+ if (!m)
m = "";
// check to see if model was properly precached
for (i = 0, check = sv.model_precache; *check; i++, check++)
@@ -264,35 +287,21 @@ void PF2_setmodel(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
if (!*check)
PR2_RunError("no precache: %s\n", m);
- PR2_SetEntityString(e, &e->v.model, m);
- e->v.modelindex = i;
+ PR2_SetEntityString_model(e, &e->v->model, m);
+ e->v->modelindex = i;
// if it is an inline model, get the size information for it
if (m[0] == '*')
{
mod = CM_InlineModel (m);
- VectorCopy(mod->mins, e->v.mins);
- VectorCopy(mod->maxs, e->v.maxs);
- VectorSubtract(mod->maxs, mod->mins, e->v.size);
+ VectorCopy(mod->mins, e->v->mins);
+ VectorCopy(mod->maxs, e->v->maxs);
+ VectorSubtract(mod->maxs, mod->mins, e->v->size);
SV_LinkEdict(e, false);
}
}
-/*
-=================
-PF2_bprint
-
-broadcast print to everyone on server
-
-bprint(value)
-=================
-*/
-void PF2_bprint(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- SV_BroadcastPrintfEx(stack[0]._int, stack[2]._int, "%s", VM_POINTER(base,mask,stack[1].string));
-}
-
/*
=================
PF2_sprint
@@ -306,15 +315,13 @@ sprint(clientent, value)
// trap_SPrint() flags
#define SPRINT_IGNOREINDEMO ( 1<<0) // do not put such message in mvd demo
-void PF2_sprint(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_sprint(int entnum, int level, char *s, int flags)
{
client_t *client, *cl;
- int entnum = stack[0]._int;
- int level = stack[1]._int;
- int flags = stack[3]._int; // using this atm just as hint to not put this message in mvd demo
- char *s = (char *) VM_POINTER(base,mask,stack[2].string);
int i;
+ if (gamedata.APIversion < 15)
+ flags = 0;
if (entnum < 1 || entnum > MAX_CLIENTS)
{
Con_Printf("tried to sprint to a non-client %d \n", entnum);
@@ -361,11 +368,9 @@ single print to a specific client
centerprint(clientent, value)
=================
*/
-void PF2_centerprint(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_centerprint(int entnum, char *s)
{
client_t *cl, *spec;
- int entnum = stack[0]._int;
- char *s = (char *) VM_POINTER(base,mask,stack[1].string);
int i;
if (entnum < 1 || entnum > MAX_CLIENTS)
@@ -413,24 +418,18 @@ PF2_ambientsound
=================
*/
-void PF2_ambientsound(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_ambientsound(float x, float y, float z, char *samp, float vol, float attenuation)
{
char **check;
int i, soundnum;
vec3_t pos;
- char *samp;
- float vol;
- float attenuation;
- pos[0] = stack[0]._float;
- pos[1] = stack[1]._float;
- pos[2] = stack[2]._float;
+ pos[0] = x;
+ pos[1] = y;
+ pos[2] = z;
- samp = (char *) VM_POINTER(base,mask,stack[3].string);
if( !samp )
samp = "";
- vol = stack[4]._float;
- attenuation = stack[5]._float;
// check to see if samp was properly precached
for (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++)
@@ -455,32 +454,6 @@ void PF2_ambientsound(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retv
}
-/*
-=================
-PF2_sound
-
-Each entity can have eight independant sound sources, like voice,
-weapon, feet, etc.
-
-Channel 0 is an auto-allocate channel, the others override anything
-already running on that entity/channel pair.
-
-An attenuation of 0 will play full volume everywhere in the level.
-Larger attenuations will drop off.
-
-=================
-*/
-void PF2_sound(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- edict_t *entity = EDICT_NUM(stack[0]._int);
- int channel = stack[1]._int;
- char *sample = (char *) VM_POINTER(base,mask,stack[2].string);
- int volume = stack[3]._float * 255;
- float attenuation = stack[4]._float;
-
- SV_StartSound(entity, channel, sample, volume, attenuation);
-}
-
/*
=================
PF2_traceline
@@ -492,25 +465,22 @@ if the tryents flag is set.
traceline (vector1, vector2, tryents)
=================
*/
-void PF2_traceline(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_traceline(float v1_x, float v1_y, float v1_z,
+ float v2_x, float v2_y, float v2_z,
+ int nomonsters, int entnum)
{
trace_t trace;
edict_t *ent;
vec3_t v1, v2;
- int nomonsters, entnum;
-
- v1[0] = stack[0]._float;
- v1[1] = stack[1]._float;
- v1[2] = stack[2]._float;
-
- v2[0] = stack[3]._float;
- v2[1] = stack[4]._float;
- v2[2] = stack[5]._float;
-
- nomonsters = stack[6]._int;
- entnum = stack[7]._int;
ent = EDICT_NUM(entnum);
+ v1[0] = v1_x;
+ v1[1] = v1_y;
+ v1[2] = v1_z;
+
+ v2[0] = v2_x;
+ v2[1] = v2_y;
+ v2[2] = v2_z;
if (sv_antilag.value == 2)
{
@@ -543,41 +513,32 @@ PF2_TraceCapsule
Used for use tracing and shot targeting
Traces are blocked by bbox and exact bsp entityes, and also slide box entities
if the tryents flag is set.
-
-void trap_TraceCapsule( float v1_x, float v1_y, float v1_z,
- float v2_x, float v2_y, float v2_z,
- int nomonst, int edn ,
- float min_x, float min_y, float min_z,
- float max_x, float max_y, float max_z);
-
=================
*/
-void PF2_TraceCapsule(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_TraceCapsule(float v1_x, float v1_y, float v1_z,
+ float v2_x, float v2_y, float v2_z,
+ int nomonsters, edict_t *ent,
+ float min_x, float min_y, float min_z,
+ float max_x, float max_y, float max_z)
{
trace_t trace;
- edict_t *ent;
vec3_t v1, v2, v3, v4;
- int nomonsters;//, entnum;
-
- v1[0] = stack[0]._float;
- v1[1] = stack[1]._float;
- v1[2] = stack[2]._float;
-
- v2[0] = stack[3]._float;
- v2[1] = stack[4]._float;
- v2[2] = stack[5]._float;
- nomonsters = stack[6]._int;
+ v1[0] = v1_x;
+ v1[1] = v1_y;
+ v1[2] = v1_z;
- ent = EDICT_NUM(stack[7]._int);
+ v2[0] = v2_x;
+ v2[1] = v2_y;
+ v2[2] = v2_z;
- v3[0] = stack[8]._float;
- v3[1] = stack[9]._float;
- v3[2] = stack[10]._float;
+ v3[0] = min_x;
+ v3[1] = min_y;
+ v3[2] = min_z;
- v4[0] = stack[11]._float;
- v4[1] = stack[12]._float;
- v4[2] = stack[13]._float;
+ v4[0] = max_x;
+ v4[1] = max_y;
+ v4[2] = max_z;
trace = SV_Trace(v1, v3, v4, v2, nomonsters, ent);
@@ -641,11 +602,11 @@ int PF2_newcheckclient(int check)
if (i == check)
break; // didn't find anything else
- if (ent->e->free)
+ if (ent->e.free)
continue;
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
continue;
- if ((int) ent->v.flags & FL_NOTARGET)
+ if ((int) ent->v->flags & FL_NOTARGET)
continue;
// anything that is a client, or has a client as an enemy
@@ -653,7 +614,7 @@ int PF2_newcheckclient(int check)
}
// get the PVS for the entity
- VectorAdd (ent->v.origin, ent->v.view_ofs, org);
+ VectorAdd (ent->v->origin, ent->v->view_ofs, org);
checkpvs = CM_LeafPVS (CM_PointInLeaf(org));
return i;
@@ -661,7 +622,7 @@ int PF2_newcheckclient(int check)
#define MAX_CHECK 16
-void PF2_checkclient(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_checkclient(void)
{
edict_t *ent, *self;
int l;
@@ -676,27 +637,22 @@ void PF2_checkclient(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
// return check if it might be visible
ent = EDICT_NUM(sv.lastcheck);
- if (ent->e->free || ent->v.health <= 0)
+ if (ent->e.free || ent->v->health <= 0)
{
// RETURN_EDICT(sv.edicts);
- retval->_int = NUM_FOR_EDICT(sv.edicts);
- return;
+ return NUM_FOR_EDICT(sv.edicts);
}
// if current entity can't possibly see the check entity, return 0
self = PROG_TO_EDICT(pr_global_struct->self);
- VectorAdd(self->v.origin, self->v.view_ofs, view);
+ VectorAdd(self->v->origin, self->v->view_ofs, view);
l = CM_Leafnum(CM_PointInLeaf(view)) - 1;
if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7))))
{
- retval->_int = NUM_FOR_EDICT(sv.edicts);
- return;
-
+ return NUM_FOR_EDICT(sv.edicts);
}
- retval->_int = NUM_FOR_EDICT(ent);
- return;
-
+ return NUM_FOR_EDICT(ent);
}
//============================================================================
@@ -715,15 +671,14 @@ stuffcmd (clientent, value)
#define STUFFCMD_IGNOREINDEMO ( 1<<0) // do not put in mvd demo
#define STUFFCMD_DEMOONLY ( 1<<1) // put in mvd demo only
-void PF2_stuffcmd(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_stuffcmd(int entnum, char *str, int flags)
{
- char *str=NULL, *buf=NULL;
+ char *buf = NULL;
client_t *cl, *spec;
- int entnum = stack[0]._int;
- int flags = stack[2]._int; // using this atm just as hint to not put this in mvd demo
int j;
- str = (char *) VM_POINTER(base,mask,stack[1].string);
+ if (gamedata.APIversion < 15)
+ flags = 0;
if( !str )
PR2_RunError("PF2_stuffcmd: NULL pointer");
@@ -801,19 +756,10 @@ void PF2_stuffcmd(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
/*
=================
-PF2_localcmd
-
-Sends text over to the server's execution buffer
-
-localcmd (string)
+PF2_executecmd
=================
*/
-void PF2_localcmd(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- Cbuf_AddTextEx(&cbuf_server, (char *)VM_POINTER(base,mask,stack[0].string));
-}
-
-void PF2_executecmd(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_executecmd(void)
{
int old_other, old_self; // mod_consolecmd will be executed, so we need to store this
@@ -834,19 +780,12 @@ void readmcmd (string str,string buff, int sizeofbuff)
=================
*/
-void PF2_readcmd (byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_readcmd(char *str, char *buf, int sizebuff)
{
- char *str;
extern char outputbuf[];
- char *buf;
- int sizebuff;
extern redirect_t sv_redirected;
redirect_t old;
- str = (char *) VM_POINTER(base,mask,stack[0].string);
- buf = (char *) VM_POINTER(base,mask,stack[1].string);
- sizebuff = stack[2]._int;
-
Cbuf_ExecuteEx(&cbuf_server);
Cbuf_AddTextEx(&cbuf_server, str);
@@ -875,23 +814,17 @@ void redirectcmd (entity to, string str)
=================
*/
-void PF2_redirectcmd(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_redirectcmd(int entnum, char *str)
{
- char *str;
- int entnum;
- // redirect_t old;
extern redirect_t sv_redirected;
- str = (char *)VM_POINTER(base, mask, stack[1].string);
if (sv_redirected) {
Cbuf_AddTextEx(&cbuf_server, str);
Cbuf_ExecuteEx(&cbuf_server);
return;
}
- entnum = NUM_FOR_EDICT((edict_t *)VM_POINTER(base, mask, stack[0]._int));
-
if (entnum < 1 || entnum > MAX_CLIENTS) {
PR2_RunError("Parm 0 not a client");
}
@@ -902,63 +835,6 @@ void PF2_redirectcmd(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
SV_EndRedirect();
}
-/*
-=================
-PF2_cvar
-
-float trap_cvar( const char *var );
-=================
-*/
-void PF2_cvar(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float = Cvar_Value((char *)VM_POINTER(base,mask,stack[0].string));
-}
-
-/*
-=================
-PF2_cvar_string
-
-void trap_cvar_string( const char *var, char *buffer, int bufsize )
-=================
-*/
-void PF2_cvar_string(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- intptr_t buff_off = stack[1]._int;
- intptr_t buffsize = stack[2]._int;
-
- if( ( buff_off ) &(~mask))
- return;
-
- if( ( buff_off + buffsize ) &(~mask))
- return;
-
- strlcpy((char *)VM_POINTER(base,mask,buff_off),
- Cvar_String((char *)VM_POINTER(base,mask,stack[0].string)), buffsize);
-}
-
-/*
-=================
-PF2_cvar_set
-
-void trap_cvar_set( const char *var, const char *val );
-=================
-*/
-void PF2_cvar_set(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- Cvar_SetByName((char *) VM_POINTER(base,mask,stack[0].string), (char *) VM_POINTER(base,mask,stack[1].string));
-}
-/*
-=================
-PF2_cvar_set_float
-
-void trap_cvar_set_float( const char *var, float val );
-=================
-*/
-void PF2_cvar_set_float(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- Cvar_SetValueByName((char *)VM_POINTER(base,mask,stack[0].string), stack[1]._float);
-}
-
/*
=================
PF2_FindRadius
@@ -968,36 +844,28 @@ gedict_t *findradius( gedict_t * start, vec3_t org, float rad );
=================
*/
-void PF2_FindRadius( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retval )
+intptr_t PF2_FindRadius(int e, float *org, float rad)
{
- int e,j;
+ int j;
edict_t *ed;
- float* org;
vec3_t eorg;
- float rad;
-
- e = NUM_FOR_EDICT( (edict_t *) VM_POINTER( base, mask, stack[0]._int ) );
- org = (float *) VM_POINTER( base, mask, stack[1]._int );
- rad = stack[2]._float;
for ( e++; e < sv.num_edicts; e++ )
{
ed = EDICT_NUM( e );
- if (ed->e->free)
+ if (ed->e.free)
continue;
- if (ed->v.solid == SOLID_NOT)
+ if (ed->v->solid == SOLID_NOT)
continue;
for (j=0 ; j<3 ; j++)
- eorg[j] = org[j] - (ed->v.origin[j] + (ed->v.mins[j] + ed->v.maxs[j])*0.5);
+ eorg[j] = org[j] - (ed->v->origin[j] + (ed->v->mins[j] + ed->v->maxs[j])*0.5);
if (VectorLength(eorg) > rad)
continue;
- retval->_int = POINTER_TO_VM( base, mask, ed );
- return;
+ return VM_Ptr2VM((byte *)ed->v);
}
- retval->_int = 0;
- return;
+ return 0;
}
/*
@@ -1007,34 +875,15 @@ PF2_walkmove
float(float yaw, float dist) walkmove
===============
*/
-void PF2_walkmove(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-//(int entn, float yaw, float dist)
+int PF2_walkmove(edict_t *ent, float yaw, float dist)
{
- edict_t *ent;
- float yaw, dist;
vec3_t move;
- // dfunction_t *oldf;
int oldself;
- // int ret;
- //
-
- /*if( sv_vm->type == VM_BYTECODE)///FIXME !!! not worked yet
- {
- retval->_int = 0;
- return;
- }*/
- // ent = PROG_TO_EDICT(pr_global_struct->self);
- // yaw = G_FLOAT(OFS_PARM0);
- // dist = G_FLOAT(OFS_PARM1);
- ent = EDICT_NUM(stack[0]._int);
- yaw = stack[1]._float;
- dist = stack[2]._float;
+ int ret;
- if (!((int) ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
+ if (!((int) ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
{
- retval->_int = 0;
- return;
-
+ return 0;
}
yaw = yaw * M_PI * 2 / 360;
@@ -1047,13 +896,12 @@ void PF2_walkmove(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
// oldf = pr_xfunction;
oldself = pr_global_struct->self;
- retval->_int = SV_movestep(ent, move, true);
-
+ ret = SV_movestep(ent, move, true);
// restore program state
// pr_xfunction = oldf;
pr_global_struct->self = oldself;
- return;
+ return ret;
}
/*
@@ -1064,26 +912,23 @@ float(float dist) PF2_MoveToGoal
===============
*/
-void PF2_MoveToGoal(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_MoveToGoal(float dist)
{
edict_t *ent, *goal;
- float dist;
// dfunction_t *oldf;
int oldself;
ent = PROG_TO_EDICT(pr_global_struct->self);
- goal = PROG_TO_EDICT(ent->v.goalentity);
- dist = stack[0]._float;
+ goal = PROG_TO_EDICT(ent->v->goalentity);
- if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+ if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
{
- retval->_int = 0;
return;
}
// if the next step hits the enemy, return immediately
- if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
+ if ( PROG_TO_EDICT(ent->v->enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
return;
// save program state, because SV_movestep may call other progs
@@ -1091,7 +936,7 @@ void PF2_MoveToGoal(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
oldself = pr_global_struct->self;
// bump around...
- if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->v.ideal_yaw, dist))
+ if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->v->ideal_yaw, dist))
{
SV_NewChaseDir (ent, goal, dist);
}
@@ -1101,9 +946,6 @@ void PF2_MoveToGoal(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
pr_global_struct->self = oldself;
}
-
-
-
/*
===============
PF2_droptofloor
@@ -1111,32 +953,27 @@ PF2_droptofloor
void(entnum) droptofloor
===============
*/
-void PF2_droptofloor(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+int PF2_droptofloor(edict_t *ent)
{
- edict_t *ent;
vec3_t end;
trace_t trace;
- ent = EDICT_NUM(stack[0]._int);
-
- VectorCopy(ent->v.origin, end);
+ VectorCopy(ent->v->origin, end);
end[2] -= 256;
- trace = SV_Trace(ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
+ trace = SV_Trace(ent->v->origin, ent->v->mins, ent->v->maxs, end, false, ent);
if (trace.fraction == 1 || trace.allsolid)
{
- retval->_int = 0;
- return;
+ return 0;
}
else
{
- VectorCopy(trace.endpos, ent->v.origin);
+ VectorCopy(trace.endpos, ent->v->origin);
SV_LinkEdict(ent, false);
- ent->v.flags = (int) ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);
- retval->_int = 1;
- return;
+ ent->v->flags = (int) ent->v->flags | FL_ONGROUND;
+ ent->v->groundentity = EDICT_TO_PROG(trace.e.ent);
+ return 1;
}
}
@@ -1147,14 +984,10 @@ PF2_lightstyle
void(int style, string value) lightstyle
===============
*/
-void PF2_lightstyle(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_lightstyle(int style, char *val)
{
client_t *client;
- int j,style;
- char* val;
-
- style = stack[0]._int;
- val = (char *) VM_POINTER(base,mask,stack[1]._int);
+ int j;
// change the string in sv
sv.lightstyles[style] = val;
@@ -1181,57 +1014,45 @@ void PF2_lightstyle(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
}
}
}
-/*
-=============
-PF2_checkbottom
-=============
-*/
-void PF2_checkbottom(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int = SV_CheckBottom(EDICT_NUM(stack[0]._int));
-}
/*
=============
PF2_pointcontents
=============
*/
-void PF2_pointcontents(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+int PF2_pointcontents(float x, float y, float z)
{
- vec3_t v;
- v[0] = stack[0]._float;
- v[1] = stack[1]._float;
- v[2] = stack[2]._float;
+ vec3_t origin;
+
+ origin[0] = x;
+ origin[1] = y;
+ origin[2] = z;
- retval->_int = SV_PointContents(v);
+ return SV_PointContents(origin);
}
/*
=============
PF2_nextent
-
+
entity nextent(entity)
=============
*/
-void PF2_nextent(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_nextent(int i)
{
- int i;
edict_t *ent;
- i = stack[0]._int;
while (1)
{
i++;
if (i >= sv.num_edicts)
{
- retval->_int = 0;
- return;
+ return 0;
}
ent = EDICT_NUM(i);
- if (!ent->e->free)
+ if (!ent->e.free)
{
- retval->_int = i;
- return;
+ return i;
}
}
}
@@ -1245,27 +1066,23 @@ fast walk over spawned clients
entity nextclient(entity)
=============
*/
-void PF2_nextclient(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_nextclient(int i)
{
- int i;
edict_t *ent;
- i = NUM_FOR_EDICT((edict_t *) VM_POINTER(base,mask,stack[0]._int));;
while (1)
{
i++;
if (i < 1 || i > MAX_CLIENTS)
{
- retval->_int = 0;
- return;
+ return 0;
}
ent = EDICT_NUM(i);
- if (!ent->e->free) // actually that always true for clients edicts
+ if (!ent->e.free) // actually that always true for clients edicts
{
- if (svs.clients[i-1].state == cs_spawned) // client in game
+ if (svs.clients[i - 1].state == cs_spawned) // client in game
{
- retval->_int = POINTER_TO_VM(base,mask,ent);
- return;
+ return VM_Ptr2VM((byte *)ent->v);
}
}
}
@@ -1278,43 +1095,34 @@ PF2_find
entity find(start,fieldoff,str)
=============
*/
-void PF2_Find (byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_Find(int e, int fofs, char *str)
{
- int e;
- int fofs;
- char* str, *t;
+ char *t;
edict_t *ed;
- e = NUM_FOR_EDICT((edict_t *) VM_POINTER(base,mask,stack[0]._int));
- fofs = stack[1]._int;
-
- str = (char *) VM_POINTER(base,mask,stack[2].string);
-
if(!str)
PR2_RunError ("PF2_Find: bad search string");
for (e++ ; e < sv.num_edicts ; e++)
{
ed = EDICT_NUM(e);
- if (ed->e->free)
+ if (ed->e.free)
continue;
- if (!(intptr_t*)((byte*)ed + fofs))
+ if (!(intptr_t *)((byte *)ed->v + fofs))
continue;
- t = (char *) VM_POINTER(base,mask,*(intptr_t*)((byte*)ed + fofs));
+ t = VM_ArgPtr(*(intptr_t *)((char *)ed->v + fofs));
if (!t)
continue;
if (!strcmp(t,str))
{
- retval->_int = POINTER_TO_VM(base,mask,ed);
- return;
+ return VM_Ptr2VM((byte *)ed->v);
}
}
- retval->_int = 0;
- return;
+ return 0;
}
/*
@@ -1403,11 +1211,8 @@ static client_t *Write_GetClient(void)
return &svs.clients[entnum - 1];
}
-void PF2_WriteByte(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteByte(int to, int data)
{
- int to = stack[0]._int;
- int data = stack[1]._int;
-
if (to == MSG_ONE)
{
client_t *cl = Write_GetClient();
@@ -1425,11 +1230,8 @@ void PF2_WriteByte(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
MSG_WriteByte(WriteDest2(to), data);
}
-void PF2_WriteChar(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteChar(int to, int data)
{
- int to = stack[0]._int;
- int data = stack[1]._int;
-
if (to == MSG_ONE)
{
client_t *cl = Write_GetClient();
@@ -1447,11 +1249,8 @@ void PF2_WriteChar(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
MSG_WriteChar(WriteDest2(to), data);
}
-void PF2_WriteShort(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteShort(int to, int data)
{
- int to = stack[0]._int;
- int data = stack[1]._int;
-
if (to == MSG_ONE)
{
client_t *cl = Write_GetClient();
@@ -1469,11 +1268,8 @@ void PF2_WriteShort(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
MSG_WriteShort(WriteDest2(to), data);
}
-void PF2_WriteLong(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteLong(int to, int data)
{
- int to = stack[0]._int;
- int data = stack[1]._int;
-
if (to == MSG_ONE)
{
client_t *cl = Write_GetClient();
@@ -1491,11 +1287,8 @@ void PF2_WriteLong(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
MSG_WriteLong(WriteDest2(to), data);
}
-void PF2_WriteAngle(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteAngle(int to, float data)
{
- int to = stack[0]._int;
- float data = stack[1]._float;
-
if (to == MSG_ONE)
{
#ifdef FTE_PEXT_FLOATCOORDS
@@ -1518,11 +1311,8 @@ void PF2_WriteAngle(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
MSG_WriteAngle(WriteDest2(to), data);
}
-void PF2_WriteCoord(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteCoord(int to, float data)
{
- int to = stack[0]._int;
- float data = stack[1]._float;
-
if (to == MSG_ONE)
{
#ifdef FTE_PEXT_FLOATCOORDS
@@ -1545,11 +1335,8 @@ void PF2_WriteCoord(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
MSG_WriteCoord(WriteDest2(to), data);
}
-void PF2_WriteString(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteString(int to, char *data)
{
- int to = stack[0]._int;
- char* data = (char *) VM_POINTER(base,mask,stack[1].string);
-
if (to == MSG_ONE)
{
client_t *cl = Write_GetClient();
@@ -1567,12 +1354,8 @@ void PF2_WriteString(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
MSG_WriteString(WriteDest2(to), data);
}
-
-void PF2_WriteEntity(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_WriteEntity(int to, int data)
{
- int to = stack[0]._int;
- int data = stack[1]._int;
-
if (to == MSG_ONE)
{
client_t *cl = Write_GetClient();
@@ -1600,12 +1383,10 @@ PF2_makestatic
==================
*/
-void PF2_makestatic(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_makestatic(edict_t *ent)
{
- entity_state_t* s;
- edict_t *ent;
+ entity_state_t *s;
- ent = EDICT_NUM(stack[0]._int);
if (sv.static_entity_count >= sizeof(sv.static_entities) / sizeof(sv.static_entities[0])) {
ED_Free (ent);
return;
@@ -1614,16 +1395,16 @@ void PF2_makestatic(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
s = &sv.static_entities[sv.static_entity_count];
memset(s, 0, sizeof(sv.static_entities[0]));
s->number = sv.static_entity_count + 1;
- s->modelindex = SV_ModelIndex(PR_GetEntityString(ent->v.model));
+ s->modelindex = SV_ModelIndex(PR_GetEntityString(ent->v->model));
if (!s->modelindex) {
ED_Free (ent);
return;
}
- s->frame = ent->v.frame;
- s->colormap = ent->v.colormap;
- s->skinnum = ent->v.skin;
- VectorCopy(ent->v.origin, s->origin);
- VectorCopy(ent->v.angles, s->angles);
+ s->frame = ent->v->frame;
+ s->colormap = ent->v->colormap;
+ s->skinnum = ent->v->skin;
+ VectorCopy(ent->v->origin, s->origin);
+ VectorCopy(ent->v->angles, s->angles);
++sv.static_entity_count;
// throw the entity away now
@@ -1637,15 +1418,11 @@ void PF2_makestatic(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval
PF2_setspawnparms
==============
*/
-void PF2_setspawnparms(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_setspawnparms(int entnum)
{
int i;
- //edict_t *ent;
- int entnum=stack[0]._int;
client_t *client;
- //ent = EDICT_NUM(entnum);
-
if (entnum < 1 || entnum > MAX_CLIENTS)
PR2_RunError("Entity is not a client");
@@ -1661,13 +1438,13 @@ void PF2_setspawnparms(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*ret
PF2_changelevel
==============
*/
-void PF2_changelevel(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_changelevel(char *s, char *entfile)
{
static int last_spawncount;
- char *s = (char *) VM_POINTER(base,mask,stack[0].string);
- char *entfile = (char *) VM_POINTER(base,mask,stack[1].string);
char expanded[MAX_QPATH];
+ if (gamedata.APIversion < 15)
+ entfile = "";
// check to make sure the level exists.
// this is work around for bellow check about two changelevels,
// which lock server in one map if we trying switch to map which does't exist
@@ -1699,21 +1476,12 @@ PF2_logfrag
logfrag (killer, killee)
==============
*/
-void PF2_logfrag(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_logfrag(int e1, int e2)
{
- // edict_t *ent1, *ent2;
- int e1, e2;
- char *s;
+ char *s;
// -> scream
time_t t;
struct tm *tblock;
- // <-
-
- //ent1 = G_EDICT(OFS_PARM0);
- //ent2 = G_EDICT(OFS_PARM1);
-
- e1 = stack[0]._int;
- e2 = stack[1]._int;
if (e1 < 1 || e1 > MAX_CLIENTS || e2 < 1 || e2 > MAX_CLIENTS)
return;
@@ -1746,21 +1514,11 @@ PF2_getinfokey
string(entity e, string key) infokey
==============
*/
-void PF2_infokey(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_infokey(int e1, char *key, char *valbuff, int sizebuff)
//(int e1, char *key, char *valbuff, int sizebuff)
{
static char ov[256];
-
- // edict_t *e;
- int e1 = stack[0]._int;
- char *key = (char *) VM_POINTER(base,mask,stack[1].string);
- char *valbuff= (char *) VM_POINTER(base,mask,stack[2].string);
char *value;
- int sizebuff= stack[3]._int;
-
- // e = G_EDICT(OFS_PARM0);
- // e1 = NUM_FOR_EDICT(e);
- // key = G_STRING(OFS_PARM1);
value = ov;
@@ -1775,6 +1533,9 @@ void PF2_infokey(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
|| !strcmp(key, "ip") || !strncmp(key, "realip", 7) || !strncmp(key, "download", 9)
|| !strcmp(key, "ping") || !strcmp(key, "*userid") || !strncmp(key, "login", 6)
|| !strcmp(key, "*VIP") || !strcmp(key, "*state")
+ || !strcmp(key, "netname")
+ || !strcmp(key, "mapname") || !strcmp(key, "modelname")
+ || !strcmp(key, "version") || !strcmp(key, "servername")
)
value = "yes";
}
@@ -1784,6 +1545,18 @@ void PF2_infokey(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
SV_TimeOfDay(&date, "%a %b %d, %H:%M:%S %Y");
snprintf(ov, sizeof(ov), "%s", date.str);
}
+ else if (!strcmp(key, "mapname")) {
+ value = sv.mapname;
+ }
+ else if (!strcmp(key, "modelname")) {
+ value = sv.modelname;
+ }
+ else if (!strcmp(key, "version")) {
+ value = VersionStringFull();
+ }
+ else if (!strcmp(key, "servername")) {
+ value = SERVER_NAME;
+ }
else if ((value = Info_ValueForKey(svs.info, key)) == NULL || !*value)
value = Info_Get(&_localinfo_, key);
}
@@ -1805,6 +1578,8 @@ void PF2_infokey(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
value = cl->login;
else if (!strcmp(key, "*VIP")) // qqshka: also located in userinfo, but this is more safe/secure way, imo
snprintf(ov, sizeof(ov), "%d", cl->vip);
+ else if (!strcmp(key, "netname"))
+ value = cl->name;
else if (!strcmp(key, "*state"))
{
switch (cl->state)
@@ -1838,16 +1613,14 @@ PF2_multicast
void(vector where, float set) multicast
==============
*/
-void PF2_multicast(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_multicast(float x, float y, float z, int to)
//(vec3_t o, int to)
{
vec3_t o;
- int to;
- o[0] = stack[0]._float;
- o[1] = stack[1]._float;
- o[2] = stack[2]._float;
- to = stack[3]._int;
+ o[0] = x;
+ o[1] = y;
+ o[2] = z;
SV_Multicast(o, to);
}
@@ -1858,12 +1631,10 @@ PF2_disable_updates
void(entiny whom, float time) disable_updates
==============
*/
-void PF2_disable_updates(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_disable_updates(int entnum, float time1)
//(int entnum, float time)
{
client_t *client;
- int entnum = stack[0]._int;
- float time1 = stack[1]._float;
// entnum = G_EDICTNUM(OFS_PARM0);
// time1 = G_FLOAT(OFS_PARM1);
@@ -1879,119 +1650,6 @@ void PF2_disable_updates(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*r
client->disable_updates_stop = realtime + time1;
}
-/*
-==============
-PR2_FlushSignon();
-==============
-*/
-void PR2_FlushSignon(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- SV_FlushSignon();
-}
-
-/*
-==============
-PF2_cmdargc
-==============
-*/
-void PF2_cmdargc(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int = Cmd_Argc();
-}
-
-/*
-==============
-PF2_cmdargv
-==============
-*/
-void PF2_cmdargv(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-//(int arg, char *valbuff, int sizebuff)
-{
- strlcpy((char *) VM_POINTER(base,mask,stack[1].string), Cmd_Argv(stack[0]._int), stack[2]._int);
-}
-
-/*
-==============
-PF2_cmdargs
-==============
-*/
-void PF2_cmdargs(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-//(char *valbuff, int sizebuff)
-{
- strlcpy((char *) VM_POINTER(base,mask,stack[0].string), Cmd_Args(), stack[1]._int);
-}
-
-/*
-==============
-PF2_tokenize
-==============
-*/
-void PF2_tokenize(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-//(char *str)
-{
- Cmd_TokenizeString((char *) VM_POINTER(base,mask,stack[0].string));
-}
-
-void PF2_fixme(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- PR2_RunError ("unimplemented bulitin");
-}
-
-void PF2_memset(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- memset(VM_POINTER(base, mask, stack[0].string), stack[1]._int, stack[2]._int);
-
- retval->_int = stack[0].string;
-}
-
-void PF2_memcpy(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- memcpy(VM_POINTER(base, mask, stack[0].string), VM_POINTER(base, mask, stack[1].string), stack[2]._int);
-
- retval->_int = stack[0].string;
-}
-void PF2_strncpy(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- strncpy((char *)VM_POINTER(base, mask, stack[0].string), (char *)VM_POINTER(base, mask, stack[1].string), stack[2]._int);
-
- retval->_int = stack[0].string;
-}
-
-void PF2_sin(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=sin(stack[0]._float);
-}
-
-void PF2_cos(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=cos(stack[0]._float);
-}
-
-void PF2_atan2(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=atan2(stack[0]._float,stack[1]._float);
-}
-
-void PF2_sqrt(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=sqrt(stack[0]._float);
-}
-
-void PF2_floor(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=floor(stack[0]._float);
-}
-void PF2_ceil(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=ceil(stack[0]._float);
-}
-
-void PF2_acos(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_float=acos(stack[0]._float);
-}
-
-
#define MAX_PR2_FILES 8
typedef struct
@@ -2006,21 +1664,14 @@ pr2_fopen_files_t pr2_fopen_files[MAX_PR2_FILES];
int pr2_num_open_files = 0;
char* cmodes[]={"rb","r","wb","w","ab","a"};
-/*
-int trap_FS_OpenFile(char*name, fileHandle_t* handle, fsMode_t fmode );
-*/
-//FIXME: read from paks
-void PF2_FS_OpenFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+// FIXME: read from paks
+int PF2_FS_OpenFile(char *name, fileHandle_t *handle, fsMode_t fmode)
{
- char *name=(char*)VM_POINTER(base,mask,stack[0].string);
- fileHandle_t* handle=(fileHandle_t*)VM_POINTER(base,mask,stack[1]._int);
- fsMode_t fmode = (fsMode_t) stack[2]._int;
- int i;
+ int i, ret = -1;
if(pr2_num_open_files >= MAX_PR2_FILES)
{
- retval->_int = -1;
- return ;
+ return -1;
}
*handle = 0;
@@ -2029,14 +1680,12 @@ void PF2_FS_OpenFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
break;
if (i == MAX_PR2_FILES) //too many already open
{
- retval->_int = -1;
- return ;
+ return -1;
}
if (FS_UnsafeFilename(name)) {
// someone tried to be clever.
- retval->_int = -1;
- return ;
+ return -1;
}
strlcpy(pr2_fopen_files[i].name, name, sizeof(pr2_fopen_files[i].name));
pr2_fopen_files[i].accessmode = fmode;
@@ -2052,13 +1701,12 @@ void PF2_FS_OpenFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
if(!pr2_fopen_files[i].handle)
{
- retval->_int = -1;
- return ;
+ return -1;
}
Con_DPrintf( "PF2_FS_OpenFile %s\n", name );
- retval->_int = VFS_GETLEN(pr2_fopen_files[i].handle);
+ ret = VFS_GETLEN(pr2_fopen_files[i].handle);
break;
case FS_WRITE_BIN:
@@ -2070,28 +1718,23 @@ void PF2_FS_OpenFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
pr2_fopen_files[i].handle = FS_OpenVFS(name, cmodes[fmode], FS_GAME_OS);
if ( !pr2_fopen_files[i].handle )
{
- retval->_int = -1;
- return ;
+ return -1;
}
Con_DPrintf( "PF2_FS_OpenFile %s\n", name );
- retval->_int = VFS_TELL(pr2_fopen_files[i].handle);
+ ret = VFS_TELL(pr2_fopen_files[i].handle);
break;
default:
- retval->_int = -1;
- return ;
-
+ return -1;
}
*handle = i+1;
pr2_num_open_files++;
+ return ret;
}
-/*
-void trap_FS_CloseFile( fileHandle_t handle );
-*/
-void PF2_FS_CloseFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+
+void PF2_FS_CloseFile(fileHandle_t fnum)
{
- fileHandle_t fnum = stack[0]._int;
fnum--;
if (fnum < 0 || fnum >= MAX_PR2_FILES)
return; //out of range
@@ -2108,105 +1751,68 @@ void PF2_FS_CloseFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retv
int seek_origin[]={SEEK_CUR,SEEK_END,SEEK_SET};
-/*
-int trap_FS_SeekFile( fileHandle_t handle, int offset, int type );
-*/
-
-void PF2_FS_SeekFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_FS_SeekFile(fileHandle_t fnum, intptr_t offset, fsOrigin_t type)
{
- fileHandle_t fnum = stack[0]._int;
- int offset = stack[1]._int;
- fsOrigin_t type = (fsOrigin_t) stack[2]._int;
fnum--;
if (fnum < 0 || fnum >= MAX_PR2_FILES)
- return; //out of range
+ return 0;//out of range
if(!pr2_num_open_files)
- return;
+ return 0;
if(!(pr2_fopen_files[fnum].handle))
- return;
+ return 0;
if(type < 0 || type >= sizeof(seek_origin) / sizeof(seek_origin[0]))
- return;
+ return 0;
- retval->_int = VFS_SEEK(pr2_fopen_files[fnum].handle, offset, seek_origin[type]);
+ return VFS_SEEK(pr2_fopen_files[fnum].handle, offset, seek_origin[type]);
}
-/*
-int trap_FS_TellFile( fileHandle_t handle );
-*/
-
-void PF2_FS_TellFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_FS_TellFile(fileHandle_t fnum)
{
- fileHandle_t fnum = stack[0]._int;
fnum--;
if (fnum < 0 || fnum >= MAX_PR2_FILES)
- return; //out of range
+ return 0;//out of range
if(!pr2_num_open_files)
- return;
+ return 0;
if(!(pr2_fopen_files[fnum].handle))
- return;
+ return 0;
- retval->_int = VFS_TELL(pr2_fopen_files[fnum].handle);
+ return VFS_TELL(pr2_fopen_files[fnum].handle);
}
-/*
-int trap_FS_WriteFile( char*src, int quantity, fileHandle_t handle );
-*/
-void PF2_FS_WriteFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_FS_WriteFile(char *dest, intptr_t quantity, fileHandle_t fnum)
{
- char*dest;
- intptr_t memoffset = stack[0]._int;
- intptr_t quantity = stack[1]._int;
- fileHandle_t fnum = stack[2]._int;
fnum--;
if (fnum < 0 || fnum >= MAX_PR2_FILES)
- return; //out of range
+ return 0;//out of range
if(!pr2_num_open_files)
- return;
+ return 0;
if(!(pr2_fopen_files[fnum].handle))
- return;
- if( (memoffset) &(~mask))
- return;
-
- if( (memoffset+quantity) &(~mask))
- return;
+ return 0;
- dest = (char*)VM_POINTER(base,mask,memoffset);
- retval->_int = VFS_WRITE(pr2_fopen_files[fnum].handle, dest, quantity);
+ return VFS_WRITE(pr2_fopen_files[fnum].handle, dest, quantity);
}
-/*
-int trap_FS_ReadFile( char*dest, int quantity, fileHandle_t handle );
-*/
-void PF2_FS_ReadFile(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+
+intptr_t PF2_FS_ReadFile(char *dest, intptr_t quantity, fileHandle_t fnum)
{
- char*dest;
- intptr_t memoffset = stack[0]._int;
- intptr_t quantity = stack[1]._int;
- fileHandle_t fnum = stack[2]._int;
fnum--;
if (fnum < 0 || fnum >= MAX_PR2_FILES)
- return; //out of range
+ return 0;//out of range
if(!pr2_num_open_files)
- return;
+ return 0;
if(!(pr2_fopen_files[fnum].handle))
- return;
- if( (memoffset) &(~mask))
- return;
-
- if( (memoffset+quantity) &(~mask))
- return;
+ return 0;
- dest = (char*)VM_POINTER(base,mask,memoffset);
- retval->_int = VFS_READ(pr2_fopen_files[fnum].handle, dest, quantity, NULL);
+ return VFS_READ(pr2_fopen_files[fnum].handle, dest, quantity, NULL);
}
void PR2_FS_Restart(void)
@@ -2231,10 +1837,6 @@ void PR2_FS_Restart(void)
memset(pr2_fopen_files,0,sizeof(pr2_fopen_files));
}
-/*
-int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
-*/
-
static int GetFileList_Compare (const void *p1, const void *p2)
{
return strcmp (*((char**)p1), *((char**)p2));
@@ -2244,7 +1846,8 @@ static int GetFileList_Compare (const void *p1, const void *p2)
#define FILELIST_WITH_PATH (1<<1) // include path to file
#define FILELIST_WITH_EXT (1<<2) // include extension of file
-void PF2_FS_GetFileList(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_FS_GetFileList(char *path, char *ext,
+ char *listbuff, intptr_t buffsize, intptr_t flags)
{
// extern searchpath_t *com_searchpaths; // evil, because this must be used in fs.c only...
char *gpath = NULL;
@@ -2257,39 +1860,21 @@ void PF2_FS_GetFileList(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*re
// searchpath_t *search;
char netpath[MAX_OSPATH], *fullname;
- char *path, *ext, *listbuff, *dirptr;
-
- intptr_t pathoffset = stack[0]._int;
- intptr_t extoffset = stack[1]._int;
- intptr_t listbuffoffset = stack[2]._int;
- intptr_t buffsize = stack[3]._int;
- intptr_t flags = stack[4]._int;
+ char *dirptr;
int numfiles = 0;
int i, j;
- retval->_int = 0;
-
- if( ( listbuffoffset ) & (~mask))
- return;
- if( ( listbuffoffset + buffsize ) & (~mask))
- return;
- if( ( extoffset ) & (~mask))
- return;
- if( ( pathoffset ) & (~mask))
- return;
+ if (gamedata.APIversion < 15)
+ flags = 0;
memset(list, 0, sizeof(list));
- path = (char*)VM_POINTER(base,mask,pathoffset);
- ext = (char*)VM_POINTER(base,mask,extoffset);;
-
- listbuff = (char*)VM_POINTER(base,mask,listbuffoffset);
dirptr = listbuff;
*dirptr = 0;
if (strstr( path, ".." ) || strstr( path, "::" ))
- return; // do not allow relative paths
+ return 0; // do not allow relative paths
// search through the path, one element at a time
for (i = 0, gpath = NULL; i < list_cnt && ( gpath = FS_NextPath( gpath ) ); )
@@ -2360,11 +1945,10 @@ void PF2_FS_GetFileList(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*re
numfiles++;
}
- retval->_int = numfiles;
-
// free allocated mem
for (i = 0; i < list_cnt; i++)
Q_free(list[i]);
+ return numfiles;
}
/*
@@ -2374,68 +1958,21 @@ void PF2_FS_GetFileList(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*re
-1 not found
-2 cannot map
*/
-extern int pr2_numAPI;
-void PF2_Map_Extension(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+intptr_t PF2_Map_Extension(char *name, int mapto)
{
- int mapto = stack[1]._int;
-
- if( mapto < pr2_numAPI)
+ if (mapto < _G__LASTAPI)
{
- retval->_int = -2;
- return;
+ return -2;
}
- retval->_int = -1;
-}
-////////////////////
-//
-// timewaster functions
-//
-////////////////////
-void PF2_strcmp(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int= strcmp( (char *) VM_POINTER(base,mask,stack[0].string),
- (char *) VM_POINTER(base,mask,stack[1].string));
-}
-
-void PF2_strncmp(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int= strncmp( (char *) VM_POINTER(base,mask,stack[0].string),
- (char *) VM_POINTER(base,mask,stack[1].string),stack[2]._int);
-}
-
-void PF2_stricmp(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int= strcasecmp( (char *) VM_POINTER(base,mask,stack[0].string),
- (char *) VM_POINTER(base,mask,stack[1].string));
-}
-
-void PF2_strnicmp(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- retval->_int= strncasecmp( (char *) VM_POINTER(base,mask,stack[0].string),
- (char *) VM_POINTER(base,mask,stack[1].string),stack[2]._int);
-}
-
-void PF2_strlcpy(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{ // (char *dst, char *src, size_t siz)
- retval->_int = strlcpy( (char *) VM_POINTER(base,mask,stack[0].string), (char *) VM_POINTER(base,mask,stack[1].string), stack[2]._int );
+ return -1;
}
-
-void PF2_strlcat(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{ // (char *dst, char *src, size_t siz)
- retval->_int = strlcat( (char *) VM_POINTER(base,mask,stack[0].string), (char *) VM_POINTER(base,mask,stack[1].string), stack[2]._int );
-}
-
/////////Bot Functions
extern cvar_t maxclients, maxspectators;
-void PF2_Add_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retval )
+int PF2_Add_Bot(char *name, int bottomcolor, int topcolor, char *skin)
{
client_t *cl, *newcl = NULL;
- char *name = (char *) VM_POINTER( base, mask, stack[0].string );
- int bottomcolor = stack[1]._int;
- int topcolor = stack[2]._int;
- char *skin = (char *) VM_POINTER( base, mask, stack[3].string );
int edictnum;
int clients, spectators, i;
extern char *shortinfotbl[];
@@ -2468,8 +2005,7 @@ void PF2_Add_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retv
if ( clients >= ( int ) maxclients.value )
{
- retval->_int = 0;
- return;
+ return 0;
}
for ( i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++ )
{
@@ -2481,8 +2017,7 @@ void PF2_Add_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retv
}
if ( !newcl )
{
- retval->_int = 0;
- return;
+ return 0;
}
memset(newcl, 0, sizeof(*newcl));
@@ -2512,22 +2047,22 @@ void PF2_Add_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retv
strlcpy(newcl->name, name, sizeof(newcl->name));
newcl->entgravity = 1.0;
- val = PR2_GetEdictFieldValue( ent, "gravity" );
+ val = PR2_GetEdictFieldValue( ent, "gravity" ); // FIXME: do it similar to maxspeed
if ( val )
val->_float = 1.0;
sv_client->maxspeed = sv_maxspeed.value;
- val = PR2_GetEdictFieldValue( ent, "maxspeed" );
- if ( val )
- val->_float = sv_maxspeed.value;
+
+ if (fofs_maxspeed)
+ EdictFieldFloat(ent, fofs_maxspeed) = sv_maxspeed.value;
newcl->edict = ent;
- ent->v.colormap = edictnum;
- val = PR2_GetEdictFieldValue( ent, "isBot" );
+ ent->v->colormap = edictnum;
+ val = PR2_GetEdictFieldValue(ent, "isBot"); // FIXME: do it similar to maxspeed
if( val )
val->_int = 1;
// restore client name.
- PR_SetEntityString(ent, ent->v.netname, newcl->name);
+ PR_SetEntityString(ent, ent->v->netname, newcl->name);
memset( newcl->stats, 0, sizeof( newcl->stats ) );
SZ_InitEx (&newcl->netchan.message, newcl->netchan.message_buf, (int)sizeof(newcl->netchan.message_buf), true);
@@ -2552,10 +2087,7 @@ void PF2_Add_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retv
newcl->disable_updates_stop = -1.0; // Vladis
-
SV_FullClientUpdate( newcl, &sv.reliable_datagram );
- retval->_int = edictnum;
-
old_self = pr_global_struct->self;
pr_global_struct->time = sv.time;
@@ -2565,7 +2097,7 @@ void PF2_Add_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retv
PR2_GamePutClientInServer(0);
pr_global_struct->self = old_self;
-
+ return edictnum;
}
void RemoveBot(client_t *cl)
@@ -2579,7 +2111,7 @@ void RemoveBot(client_t *cl)
PR2_GameClientDisconnect(0);
cl->old_frags = 0;
- cl->edict->v.frags = 0.0;
+ cl->edict->v->frags = 0.0;
cl->name[0] = 0;
cl->state = cs_free;
@@ -2590,13 +2122,11 @@ void RemoveBot(client_t *cl)
cl->isBot = 0;
}
-void PF2_Remove_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retval )
+void PF2_Remove_Bot(int entnum)
{
client_t *cl;
int old_self;
- int entnum = stack[0]._int;
-
if ( entnum < 1 || entnum > MAX_CLIENTS )
{
Con_Printf( "tried to remove a non-botclient %d \n", entnum );
@@ -2616,16 +2146,16 @@ void PF2_Remove_Bot( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * r
}
-void PF2_SetBotUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retval )
+// FIXME: Why PR2_UserInfoChanged is not called here? Like for normal players.
+// Why we need this special handling in the first place?
+void PF2_SetBotUserInfo(int entnum, char *key, char *value, int flags)
{
client_t *cl;
- int entnum = stack[0]._int;
- char *key = (char *) VM_POINTER( base, mask, stack[1].string );
- char *value = (char *) VM_POINTER( base, mask, stack[2].string );
- int flags = stack[3]._int;
int i;
extern char *shortinfotbl[];
+ if (gamedata.APIversion < 15)
+ flags = 0;
if (strstr(key, "&c") || strstr(key, "&r") || strstr(value, "&c") || strstr(value, "&r"))
return;
@@ -2665,10 +2195,10 @@ void PF2_SetBotUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t
}
}
-void PF2_SetBotCMD( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retval )
+void PF2_SetBotCMD(int entnum, int msec, float a1, float a2, float a3,
+ int forwardmove, int sidemove, int upmove, int buttons, int impulse)
{
client_t *cl;
- int entnum = stack[0]._int;
if ( entnum < 1 || entnum > MAX_CLIENTS )
{
@@ -2681,20 +2211,21 @@ void PF2_SetBotCMD( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * re
Con_Printf( "tried to set cmd a non-botclient %d \n", entnum );
return;
}
- cl->botcmd.msec = stack[1]._int;
- cl->botcmd.angles[0] = stack[2]._float;
- cl->botcmd.angles[1] = stack[3]._float;
- cl->botcmd.angles[2] = stack[4]._float;
- cl->botcmd.forwardmove = stack[5]._int;
- cl->botcmd.sidemove = stack[6]._int;
- cl->botcmd.upmove = stack[7]._int;
- cl->botcmd.buttons = stack[8]._int;
- cl->botcmd.impulse = stack[9]._int;
- if ( cl->edict->v.fixangle)
- {
- VectorCopy(cl->edict->v.angles, cl->botcmd.angles);
+ cl->botcmd.msec = msec;
+ cl->botcmd.angles[0] = a1;
+ cl->botcmd.angles[1] = a2;
+ cl->botcmd.angles[2] = a3;
+ cl->botcmd.forwardmove = forwardmove;
+ cl->botcmd.sidemove = sidemove;
+ cl->botcmd.upmove = upmove;
+ cl->botcmd.buttons = buttons;
+ cl->botcmd.impulse = impulse;
+
+ if (cl->edict->v->fixangle)
+ {
+ VectorCopy(cl->edict->v->angles, cl->botcmd.angles);
cl->botcmd.angles[PITCH] *= -3;
- cl->edict->v.fixangle = 0;
+ cl->edict->v->fixangle = 0;
}
}
@@ -2707,22 +2238,15 @@ void PF2_SetBotCMD( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * re
PF2_QVMstrftime
==============
*/
-void PF2_QVMstrftime(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-//(char *valbuff, int sizebuff, char *fmt, int offset)
+int PF2_QVMstrftime(char *valbuff, int sizebuff, char *fmt, int offset)
{
- char *valbuff = (char *) VM_POINTER(base,mask,stack[0].string);
- int sizebuff = stack[1]._int;
- char *fmt = (char *) VM_POINTER(base,mask,stack[2].string);
- int offset = stack[3]._int;
-
struct tm *newtime;
time_t long_time;
-
- retval->_int = 0;
+ int ret;
if (sizebuff <= 0 || !valbuff) {
Con_DPrintf("PF2_QVMstrftime: wrong buffer\n");
- return;
+ return 0;
}
time(&long_time);
@@ -2732,46 +2256,31 @@ void PF2_QVMstrftime(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retva
if (!newtime)
{
valbuff[0] = 0; // or may be better set to "#bad date#" ?
- return;
+ return 0;
}
- retval->_int = strftime(valbuff, sizebuff-1, fmt, newtime);
+ ret = strftime(valbuff, sizebuff-1, fmt, newtime);
- if (!retval->_int) {
+ if (!ret) {
valbuff[0] = 0; // or may be better set to "#bad date#" ?
Con_DPrintf("PF2_QVMstrftime: buffer size too small\n");
- return;
+ return 0;
}
-}
-
-void PF2_makevectors(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
-{
- AngleVectors ((float *) VM_POINTER(base,mask,stack[0].string),
- pr_global_struct->v_forward,
- pr_global_struct->v_right,
- pr_global_struct->v_up);
+ return ret;
}
// a la the ZQ_PAUSE QC extension
-void PF2_setpause(byte* base, uintptr_t mask, pr2val_t* stack, pr2val_t*retval)
+void PF2_setpause(int pause)
{
- int pause;
-
- pause = stack[0]._int ? 1 : 0;
-
if (pause != (sv.paused & 1))
SV_TogglePause (NULL, 1);
}
-void PF2_SetUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t * retval )
+void PF2_SetUserInfo(int entnum, char *k, char *v, int flags)
{
client_t *cl;
- int entnum = stack[0]._int;
- char *k = (char *) VM_POINTER( base, mask, stack[1].string );
- char *v = (char *) VM_POINTER( base, mask, stack[2].string );
char key[MAX_KEY_STRING];
char value[MAX_KEY_STRING];
- int flags = stack[3]._int;
char s[MAX_KEY_STRING * 4];
int i;
extern char *shortinfotbl[];
@@ -2790,7 +2299,7 @@ void PF2_SetUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t *
// well, our API is weird
if ( cl->isBot )
{
- PF2_SetBotUserInfo( base, mask, stack, retval );
+ PF2_SetBotUserInfo(entnum, k, v, flags);
return;
}
@@ -2809,7 +2318,7 @@ void PF2_SetUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t *
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(cl->edict);
- if( PR2_UserInfoChanged() )
+ if (PR2_UserInfoChanged(0))
return;
}
@@ -2819,6 +2328,7 @@ void PF2_SetUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t *
Info_Set( &cl->_userinfo_ctx_, key, value );
SV_ExtractFromUserinfo( cl, !strcmp( key, "name" ) );
+ PR2_UserInfoChanged(1);
for ( i = 0; shortinfotbl[i] != NULL; i++ )
{
@@ -2840,206 +2350,338 @@ void PF2_SetUserInfo( byte * base, uintptr_t mask, pr2val_t * stack, pr2val_t *
}
}
-//===========================================================================
-// SysCalls
-//===========================================================================
-
-pr2_trapcall_t pr2_API[]=
- {
- PF2_GetApiVersion, //G_GETAPIVERSION
- PF2_DPrint, //G_DPRINT
- PF2_Error, //G_ERROR
- PF2_GetEntityToken, //G_GetEntityToken,
- PF2_Spawn, //G_SPAWN_ENT,
- PF2_Remove, //G_REMOVE_ENT,
- PF2_precache_sound, //G_PRECACHE_SOUND,
- PF2_precache_model, //G_PRECACHE_MODEL,
- PF2_lightstyle, //G_LIGHTSTYLE,
- PF2_setorigin, //G_SETORIGIN,
- PF2_setsize, //G_SETSIZE,
- PF2_setmodel, //G_SETMODEL,
- PF2_bprint, //G_BPRINT,
- PF2_sprint, //G_SPRINT,
- PF2_centerprint, //G_CENTERPRINT,
- PF2_ambientsound, //G_AMBIENTSOUND,
- PF2_sound, //G_SOUND,
- PF2_traceline, //G_TRACELINE,
- PF2_checkclient, //G_CHECKCLIENT,
- PF2_stuffcmd, //G_STUFFCMD,
- PF2_localcmd, //G_LOCALCMD,
- PF2_cvar, //G_CVAR,
- PF2_cvar_set, //G_CVAR_SET,
- PF2_FindRadius, //G_FINDRADIUS
- PF2_walkmove,
- PF2_droptofloor, //G_DROPTOFLOOR,
- PF2_checkbottom, //G_CHECKBOTTOM,
- PF2_pointcontents, //G_POINTCONTENTS,
- PF2_nextent, //G_NEXTENT,
- PF2_fixme, //G_AIM,
- PF2_makestatic, //G_MAKESTATIC,
- PF2_setspawnparms, //G_SETSPAWNPARAMS,
- PF2_changelevel, //G_CHANGELEVEL,
- PF2_logfrag, //G_LOGFRAG,
- PF2_infokey, //G_GETINFOKEY,
- PF2_multicast, //G_MULTICAST,
- PF2_disable_updates, //G_DISABLEUPDATES,
- PF2_WriteByte, //G_WRITEBYTE,
- PF2_WriteChar, //G_WRITECHAR,
- PF2_WriteShort, //G_WRITESHORT,
- PF2_WriteLong, //G_WRITELONG,
- PF2_WriteAngle, //G_WRITEANGLE,
- PF2_WriteCoord, //G_WRITECOORD,
- PF2_WriteString, //G_WRITESTRING,
- PF2_WriteEntity, //G_WRITEENTITY,
- PR2_FlushSignon, //G_FLUSHSIGNON,
- PF2_memset, //g_memset,
- PF2_memcpy, //g_memcpy,
- PF2_strncpy, //g_strncpy,
- PF2_sin, //g_sin,
- PF2_cos, //g_cos,
- PF2_atan2, //g_atan2,
- PF2_sqrt, //g_sqrt,
- PF2_floor, //g_floor,
- PF2_ceil, //g_ceil,
- PF2_acos, //g_acos,
- PF2_cmdargc, //G_CMD_ARGC,
- PF2_cmdargv, //G_CMD_ARGV
- PF2_TraceCapsule,
- PF2_FS_OpenFile,
- PF2_FS_CloseFile,
- PF2_FS_ReadFile,
- PF2_FS_WriteFile,
- PF2_FS_SeekFile,
- PF2_FS_TellFile,
- PF2_FS_GetFileList,
- PF2_cvar_set_float,
- PF2_cvar_string,
- PF2_Map_Extension,
- PF2_strcmp,
- PF2_strncmp,
- PF2_stricmp,
- PF2_strnicmp,
- PF2_Find,
- PF2_executecmd,
- PF2_conprint,
- PF2_readcmd,
- PF2_redirectcmd,
- PF2_Add_Bot,
- PF2_Remove_Bot,
- PF2_SetBotUserInfo,
- PF2_SetBotCMD,
- PF2_QVMstrftime, //G_QVMstrftime
- PF2_cmdargs, //G_CMD_ARGS
- PF2_tokenize, //G_CMD_TOKENIZE
- PF2_strlcpy, //g_strlcpy
- PF2_strlcat, //g_strlcat
- PF2_makevectors, //G_MAKEVECTORS
- PF2_nextclient, //G_NEXTCLIENT
- PF2_precache_vwep_model,//G_PRECACHE_VWEP_MODEL
- PF2_setpause, //G_SETPAUSE
- PF2_SetUserInfo, //G_SETUSERINFO
- PF2_MoveToGoal, //G_MOVETOGOAL
- };
-int pr2_numAPI = sizeof(pr2_API)/sizeof(pr2_API[0]);
-
-intptr_t sv_syscall(intptr_t arg, ...) //must passed ints
-{
- intptr_t args[20];
- va_list argptr;
- pr2val_t ret;
-
- if( arg >= pr2_numAPI )
- PR2_RunError ("sv_syscall: Bad API call number");
-
- va_start(argptr, arg);
- args[0] =va_arg(argptr, intptr_t);
- args[1] =va_arg(argptr, intptr_t);
- args[2] =va_arg(argptr, intptr_t);
- args[3] =va_arg(argptr, intptr_t);
- args[4] =va_arg(argptr, intptr_t);
- args[5] =va_arg(argptr, intptr_t);
- args[6] =va_arg(argptr, intptr_t);
- args[7] =va_arg(argptr, intptr_t);
- args[8] =va_arg(argptr, intptr_t);
- args[9] =va_arg(argptr, intptr_t);
- args[10]=va_arg(argptr, intptr_t);
- args[11]=va_arg(argptr, intptr_t);
- args[12]=va_arg(argptr, intptr_t);
- args[13]=va_arg(argptr, intptr_t);
- args[14]=va_arg(argptr, intptr_t);
- args[15]=va_arg(argptr, intptr_t);
- args[16]=va_arg(argptr, intptr_t);
- args[17]=va_arg(argptr, intptr_t);
- args[18]=va_arg(argptr, intptr_t);
- args[19]=va_arg(argptr, intptr_t);
- va_end(argptr);
-
- pr2_API[arg] ( 0, (uintptr_t)~0, (pr2val_t*)args, &ret);
-
- return ret._int;
-}
-
-int sv_sys_callex(byte *data, unsigned int mask, int fn, pr2val_t*arg)
+void PF2_VisibleTo(int viewer, int first, int len, byte *visible)
{
- pr2val_t ret;
-
- if( fn >= pr2_numAPI )
- PR2_RunError ("sv_sys_callex: Bad API call number");
-
- pr2_API[fn](data, mask, arg,&ret);
- return ret._int;
-}
-
-extern gameData_t *gamedata;
-extern field_t *fields;
-
-#define GAME_API_VERSION_MIN 8
-
-void PR2_InitProg(void)
-{
- extern cvar_t sv_pr2references;
-
- Cvar_SetValue(&sv_pr2references, 0.0f);
-
- if ( !sv_vm ) {
- PR1_InitProg();
- return;
- }
+ int e, last = first + len;
+ edict_t *ent;
+ edict_t *viewer_ent = EDICT_NUM(viewer);
+ vec3_t org;
+ byte *pvs;
- PR2_FS_Restart();
+ if (last > sv.num_edicts)
+ last = sv.num_edicts;
- gamedata = (gameData_t *) VM_Call(sv_vm, GAME_INIT, (int) (sv.time * 1000),
- (int) (Sys_DoubleTime() * 100000), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- if (!gamedata) {
- SV_Error("PR2_InitProg gamedata == NULL");
- }
+ VectorAdd(viewer_ent->v->origin, viewer_ent->v->view_ofs, org);
+ pvs = CM_FatPVS(org);
- gamedata = (gameData_t *)PR2_GetString((intptr_t)gamedata);
- if (gamedata->APIversion < GAME_API_VERSION_MIN || gamedata->APIversion > GAME_API_VERSION) {
- if (GAME_API_VERSION_MIN == GAME_API_VERSION) {
- SV_Error("PR2_InitProg: Incorrect API version (%i should be %i)", gamedata->APIversion, GAME_API_VERSION);
+ for (e = first, ent = EDICT_NUM(e); e < last; e++, ent = NEXT_EDICT(ent))
+ {
+ int i;
+ if (ent->e.num_leafs < 0 || ent->e.free
+ || (e >= 1 && e <= MAX_CLIENTS && svs.clients[e - 1].state != cs_spawned)) {
+ continue; // Ignore free edicts or not active client.
}
- else {
- SV_Error("PR2_InitProg: Incorrect API version (%i should be between %i and %i)", gamedata->APIversion, GAME_API_VERSION_MIN, GAME_API_VERSION);
+ for (i = 0; i < ent->e.num_leafs; i++) {
+ if (pvs[ent->e.leafnums[i] >> 3] & (1 << (ent->e.leafnums[i]&7))) {
+ visible[e - first] = true; // seems to be visible
+ break;
+ }
}
}
+}
- sv_vm->pr2_references = gamedata->APIversion >= 15 && (int)sv_pr2references.value;
-
- sv.edicts = (edict_t *)PR2_GetString((intptr_t)gamedata->ents);
- pr_global_struct = (globalvars_t*)PR2_GetString((intptr_t)gamedata->global);
- pr_globals = (float *) pr_global_struct;
- fields = (field_t*)PR2_GetString((intptr_t)gamedata->fields);
- pr_edict_size = gamedata->sizeofent;
+//===========================================================================
+// SysCalls
+//===========================================================================
- sv.max_edicts = MAX_EDICTS;
- if (gamedata->APIversion >= 14) {
- sv.max_edicts = min(sv.max_edicts, gamedata->maxentities);
- }
- else {
- sv.max_edicts = min(sv.max_edicts, 512);
+#define VMV(x) _vmf(args[x]), _vmf(args[(x) + 1]), _vmf(args[(x) + 2])
+#define VME(x) EDICT_NUM(args[x])
+intptr_t PR2_GameSystemCalls(intptr_t *args) {
+ switch (args[0]) {
+ case G_GETAPIVERSION:
+ return GAME_API_VERSION;
+ case G_DPRINT:
+ Con_DPrintf("%s", (const char *)VMA(1));
+ return 0;
+ case G_ERROR:
+ PR2_RunError(VMA(1));
+ return 0;
+ case G_GetEntityToken:
+ VM_CheckBounds(sv_vm, args[1], args[2]);
+ pr2_ent_data_ptr = COM_Parse(pr2_ent_data_ptr);
+ strlcpy(VMA(1), com_token, args[2]);
+ return pr2_ent_data_ptr != NULL;
+ case G_SPAWN_ENT:
+ return NUM_FOR_EDICT(ED_Alloc());
+ case G_REMOVE_ENT:
+ ED_Free(VME(1));
+ return 0;
+ case G_PRECACHE_SOUND:
+ PF2_precache_sound(VMA(1));
+ return 0;
+ case G_PRECACHE_MODEL:
+ PF2_precache_model(VMA(1));
+ return 0;
+ case G_LIGHTSTYLE:
+ PF2_lightstyle(args[1], VMA(2));
+ return 0;
+ case G_SETORIGIN:
+ PF2_setorigin(VME(1), VMV(2));
+ return 0;
+ case G_SETSIZE:
+ PF2_setsize(VME(1), VMV(2), VMV(5));
+ return 0;
+ case G_SETMODEL:
+ PF2_setmodel(VME(1), VMA(2));
+ return 0;
+ case G_BPRINT: {
+ int flags = args[3];
+ if (gamedata.APIversion < 15)
+ flags = 0;
+ SV_BroadcastPrintfEx(args[1], flags, "%s", VMA(2));
+ }
+ return 0;
+ case G_SPRINT:
+ PF2_sprint(args[1], args[2], VMA(3), args[4]);
+ return 0;
+ case G_CENTERPRINT:
+ PF2_centerprint(args[1], VMA(2));
+ return 0;
+ case G_AMBIENTSOUND:
+ PF2_ambientsound(VMV(1), VMA(4), VMF(5), VMF(6));
+ return 0;
+ case G_SOUND:
+ /*
+ =================
+ PF2_sound
+
+ Each entity can have eight independant sound sources, like voice,
+ weapon, feet, etc.
+
+ Channel 0 is an auto-allocate channel, the others override anything
+ already running on that entity/channel pair.
+
+ An attenuation of 0 will play full volume everywhere in the level.
+ Larger attenuations will drop off.
+ void sound( gedict_t * ed, int channel, char *samp, float vol, float att )
+ =================
+ */
+ SV_StartSound(VME(1), args[2], VMA(3), VMF(4) * 255, VMF(5));
+ return 0;
+ case G_TRACELINE:
+ PF2_traceline(VMV(1), VMV(4), args[7], args[8]);
+ return 0;
+ case G_CHECKCLIENT:
+ return PF2_checkclient();
+ case G_STUFFCMD:
+ PF2_stuffcmd(args[1], VMA(2), args[3]);
+ return 0;
+ case G_LOCALCMD:
+ /* =================
+ Sends text over to the server's execution buffer
+
+ localcmd (string)
+ ================= */
+ Cbuf_AddText(VMA(1));
+ return 0;
+ case G_CVAR:
+ return PASSFLOAT(Cvar_Value(VMA(1)));
+ case G_CVAR_SET:
+ Cvar_SetByName(VMA(1), VMA(2));
+ return 0;
+ case G_FINDRADIUS:
+ return PF2_FindRadius(NUM_FOR_GAME_EDICT(VMA(1)), (float *)VMA(2), VMF(3));
+ case G_WALKMOVE:
+ return PF2_walkmove(VME(1), VMF(2), VMF(3));
+ case G_DROPTOFLOOR:
+ return PF2_droptofloor(VME(1));
+ case G_CHECKBOTTOM:
+ return SV_CheckBottom(VME(1));
+ case G_POINTCONTENTS:
+ return PF2_pointcontents(VMV(1));
+ case G_NEXTENT:
+ return PF2_nextent(args[1]);
+ case G_AIM:
+ return 0;
+ case G_MAKESTATIC:
+ PF2_makestatic(VME(1));
+ return 0;
+ case G_SETSPAWNPARAMS:
+ PF2_setspawnparms(args[1]);
+ return 0;
+ case G_CHANGELEVEL:
+ PF2_changelevel(VMA(1), VMA(2));
+ return 0;
+ case G_LOGFRAG:
+ PF2_logfrag(args[1], args[2]);
+ return 0;
+ case G_GETINFOKEY:
+ VM_CheckBounds(sv_vm, args[3], args[4]);
+ PF2_infokey(args[1], VMA(2), VMA(3), args[4]);
+ return 0;
+ case G_MULTICAST:
+ PF2_multicast(VMV(1), args[4]);
+ return 0;
+ case G_DISABLEUPDATES:
+ PF2_disable_updates(args[1], VMF(2));
+ return 0;
+ case G_WRITEBYTE:
+ PF2_WriteByte(args[1], args[2]);
+ return 0;
+ case G_WRITECHAR:
+ PF2_WriteChar(args[1], args[2]);
+ return 0;
+ case G_WRITESHORT:
+ PF2_WriteShort(args[1], args[2]);
+ return 0;
+ case G_WRITELONG:
+ PF2_WriteLong(args[1], args[2]);
+ return 0;
+ case G_WRITEANGLE:
+ PF2_WriteAngle(args[1], VMF(2));
+ return 0;
+ case G_WRITECOORD:
+ PF2_WriteCoord(args[1], VMF(2));
+ return 0;
+ case G_WRITESTRING:
+ PF2_WriteString(args[1], VMA(2));
+ return 0;
+ case G_WRITEENTITY:
+ PF2_WriteEntity(args[1], args[2]);
+ return 0;
+ case G_FLUSHSIGNON:
+ SV_FlushSignon();
+ return 0;
+ case g_memset:
+ VM_CheckBounds(sv_vm, args[1], args[3]);
+ memset(VMA(1), args[2], args[3]);
+ return args[1];
+ case g_memcpy:
+ VM_CheckBounds2(sv_vm, args[1], args[2], args[3]);
+ memcpy(VMA(1), VMA(2), args[3]);
+ return args[1];
+ case g_strncpy:
+ VM_CheckBounds2(sv_vm, args[1], args[2], args[3]);
+ strncpy(VMA(1), VMA(2), args[3]);
+ return args[1];
+ case g_sin:
+ return PASSFLOAT(sin(VMF(1)));
+ case g_cos:
+ return PASSFLOAT(cos(VMF(1)));
+ case g_atan2:
+ return PASSFLOAT(atan2(VMF(1), VMF(2)));
+ case g_sqrt:
+ return PASSFLOAT(sqrt(VMF(1)));
+ case g_floor:
+ return PASSFLOAT(floor(VMF(1)));
+ case g_ceil:
+ return PASSFLOAT(ceil(VMF(1)));
+ case g_acos:
+ return PASSFLOAT(acos(VMF(1)));
+ case G_CMD_ARGC:
+ return Cmd_Argc();
+ case G_CMD_ARGV:
+ VM_CheckBounds(sv_vm, args[2], args[3]);
+ strlcpy(VMA(2), Cmd_Argv(args[1]), args[3]);
+ return 0;
+ case G_TraceCapsule:
+ PF2_TraceCapsule(VMV(1), VMV(4), args[7], VME(8), VMV(9), VMV(12));
+ return 0;
+ case G_FSOpenFile:
+ return PF2_FS_OpenFile(VMA(1), (fileHandle_t *)VMA(2), (fsMode_t)args[3]);
+ case G_FSCloseFile:
+ PF2_FS_CloseFile((fileHandle_t)args[1]);
+ return 0;
+ case G_FSReadFile:
+ VM_CheckBounds(sv_vm, args[1], args[2]);
+ return PF2_FS_ReadFile(VMA(1), args[2], (fileHandle_t)args[3]);
+ case G_FSWriteFile:
+ VM_CheckBounds(sv_vm, args[1], args[2]);
+ return PF2_FS_WriteFile(VMA(1), args[2], (fileHandle_t)args[3]);
+ case G_FSSeekFile:
+ return PF2_FS_SeekFile((fileHandle_t)args[1], args[2], (fsOrigin_t)args[3]);
+ case G_FSTellFile:
+ return PF2_FS_TellFile((fileHandle_t)args[1]);
+ case G_FSGetFileList:
+ VM_CheckBounds(sv_vm, args[3], args[4]);
+ return PF2_FS_GetFileList(VMA(1), VMA(2), VMA(3), args[4], args[5]);
+ case G_CVAR_SET_FLOAT:
+ Cvar_SetValueByName(VMA(1), VMF(2));
+ return 0;
+ case G_CVAR_STRING:
+ VM_CheckBounds(sv_vm, args[2], args[3]);
+ strlcpy(VMA(2), Cvar_String(VMA(1)), args[3]);
+ return 0;
+ case G_Map_Extension:
+ return PF2_Map_Extension(VMA(1), args[2]);
+ case G_strcmp:
+ return strcmp(VMA(1), VMA(2));
+ case G_strncmp:
+ return strncmp(VMA(1), VMA(2), args[3]);
+ case G_stricmp:
+ return strcasecmp(VMA(1), VMA(2));
+ case G_strnicmp:
+ return strncasecmp(VMA(1), VMA(2), args[3]);
+ case G_Find:
+ return PF2_Find(NUM_FOR_GAME_EDICT(VMA(1)), args[2], VMA(3));
+ case G_executecmd:
+ PF2_executecmd();
+ return 0;
+ case G_conprint:
+ Sys_Printf("%s", VMA(1));
+ return 0;
+ case G_readcmd:
+ VM_CheckBounds(sv_vm, args[2], args[3]);
+ PF2_readcmd(VMA(1), VMA(2), args[3]);
+ return 0;
+ case G_redirectcmd:
+ PF2_redirectcmd(NUM_FOR_GAME_EDICT(VMA(1)), VMA(2));
+ return 0;
+ case G_Add_Bot:
+ return PF2_Add_Bot(VMA(1), args[2], args[3], VMA(4));
+ case G_Remove_Bot:
+ PF2_Remove_Bot(args[1]);
+ return 0;
+ case G_SetBotUserInfo:
+ PF2_SetBotUserInfo(args[1], VMA(2), VMA(3), args[4]);
+ return 0;
+ case G_SetBotCMD:
+ PF2_SetBotCMD(args[1], args[2], VMV(3), args[6], args[7], args[8], args[9], args[10]);
+ return 0;
+ case G_QVMstrftime:
+ VM_CheckBounds(sv_vm, args[1], args[2]);
+ return PF2_QVMstrftime(VMA(1), args[2], VMA(3), args[4]);
+ case G_CMD_ARGS:
+ VM_CheckBounds(sv_vm, args[1], args[2]);
+ strlcpy(VMA(1), Cmd_Args(), args[2]);
+ return 0;
+ case G_CMD_TOKENIZE:
+ Cmd_TokenizeString(VMA(1));
+ return 0;
+ case g_strlcpy:
+ VM_CheckBounds(sv_vm, args[1], args[3]);
+ return strlcpy(VMA(1), VMA(2), args[3]);
+ case g_strlcat:
+ VM_CheckBounds(sv_vm, args[1], args[3]);
+ return strlcat(VMA(1), VMA(2), args[3]);
+ case G_MAKEVECTORS:
+ AngleVectors(VMA(1), pr_global_struct->v_forward, pr_global_struct->v_right,
+ pr_global_struct->v_up);
+ return 0;
+ case G_NEXTCLIENT:
+ return PF2_nextclient(NUM_FOR_GAME_EDICT(VMA(1)));
+ case G_PRECACHE_VWEP_MODEL:
+ return PF2_precache_vwep_model(VMA(1));
+ case G_SETPAUSE:
+ PF2_setpause(args[1]);
+ return 0;
+ case G_SETUSERINFO:
+ PF2_SetUserInfo(args[1], VMA(2), VMA(3), args[4]);
+ return 0;
+ case G_MOVETOGOAL:
+ PF2_MoveToGoal(VMF(1));
+ return 0;
+ case G_VISIBLETO:
+ VM_CheckBounds(sv_vm, args[4], args[3]);
+ memset(VMA(4), 0, args[3]); // Ensure same memory state on each run.
+ PF2_VisibleTo(args[1], args[2], args[3], VMA(4));
+ return 0;
+ default:
+ SV_Error("Bad game system trap: %ld", (long int)args[0]);
}
+ return 0;
}
+
#endif /* USE_PR2 */
#endif // !CLIENTONLY
diff --git a/src/pr2_edict.c b/src/pr2_edict.c
index 519373852..f40fc8cdc 100644
--- a/src/pr2_edict.c
+++ b/src/pr2_edict.c
@@ -37,7 +37,7 @@ eval_t *PR2_GetEdictFieldValue(edict_t *ed, char *field)
for (f = fields; (s = PR2_GetString(f->name)) && *s; f++)
if (!strcasecmp(PR2_GetString(f->name), field))
- return (eval_t *)((char *) ed + f->ofs);
+ return (eval_t *)((char *)ed->v + f->ofs);
return NULL;
}
@@ -52,7 +52,7 @@ int ED2_FindFieldOffset (char *field)
for (f = fields; (s = PR2_GetString(f->name)) && *s; f++)
if (!strcasecmp(PR2_GetString(f->name), field))
- return f->ofs - ((int)(uintptr_t)&(((edict_t *)0)->v));
+ return f->ofs;
return 0;
}
diff --git a/src/pr2_exec.c b/src/pr2_exec.c
index 6a2a7b8df..fa0ea14cb 100644
--- a/src/pr2_exec.c
+++ b/src/pr2_exec.c
@@ -24,27 +24,23 @@
#ifdef USE_PR2
#include "qwsvdef.h"
+#include "vm_local.h"
-qbool PR2_IsValidWriteAddress(register qvm_t * qvm, intptr_t address);
-qbool PR2_IsValidReadAddress(register qvm_t * qvm, intptr_t address);
+gameData_t gamedata;
+extern field_t *fields;
-gameData_t *gamedata;
-
-// 0 = pr1 (qwprogs.dat etc), 1 = native (.so/.dll), 2 = q3vm (.qvm)
+// 0 = pr1 (qwprogs.dat etc), 1 = native (.so/.dll), 2 = q3vm (.qvm), 3 = q3vm (.qvm) with JIT
cvar_t sv_progtype = { "sv_progtype","0" };
// 0 = standard, 1 = pr2 mods set string_t fields as byte offsets to location of actual strings
cvar_t sv_pr2references = {"sv_pr2references", "0"};
-#ifdef QVM_PROFILE
-extern cvar_t sv_enableprofile;
-#endif
-//int usedll;
-
void ED2_PrintEdicts (void);
void PR2_Profile_f (void);
void ED2_PrintEdict_f (void);
void ED_Count (void);
+void VM_VmInfo_f( void );
+
void PR2_Init(void)
{
int p;
@@ -52,12 +48,10 @@ void PR2_Init(void)
Cvar_Register(&sv_progtype);
Cvar_Register(&sv_progsname);
Cvar_Register(&sv_pr2references);
+ Cvar_Register(&vm_rtChecks);
#ifdef WITH_NQPROGS
Cvar_Register(&sv_forcenqprogs);
#endif
-#ifdef QVM_PROFILE
- Cvar_Register(&sv_enableprofile);
-#endif
p = SV_CommandLineProgTypeArgument();
@@ -65,8 +59,8 @@ void PR2_Init(void)
{
usedll = Q_atoi(COM_Argv(p + 1));
- if (usedll > 2)
- usedll = VM_NONE;
+ if (usedll > VMI_COMPILED || usedll < VMI_NONE)
+ usedll = VMI_NONE;
Cvar_SetValue(&sv_progtype,usedll);
}
@@ -76,25 +70,33 @@ void PR2_Init(void)
Cmd_AddCommand ("profile", PR2_Profile_f);
Cmd_AddCommand ("mod", PR2_GameConsoleCommand);
+ Cmd_AddCommand ("vminfo", VM_VmInfo_f);
memset(pr_newstrtbl, 0, sizeof(pr_newstrtbl));
}
+void PR2_Profile_f(void)
+{
+ if(!sv_vm)
+ {
+ PR_Profile_f();
+ return;
+ }
+}
+
//===========================================================================
// PR2_GetString: only called to get direct addresses now
//===========================================================================
char *PR2_GetString(intptr_t num)
{
- qvm_t *qvm;
-
if(!sv_vm)
return PR1_GetString(num);
switch (sv_vm->type)
{
- case VM_NONE:
+ case VMI_NONE:
return PR1_GetString(num);
- case VM_NATIVE:
+ case VMI_NATIVE:
if (num) {
return (char *)num;
}
@@ -102,16 +104,11 @@ char *PR2_GetString(intptr_t num)
return "";
}
- case VM_BYTECODE:
- if (!num) {
+ case VMI_BYTECODE:
+ case VMI_COMPILED:
+ if (num <= 0)
return "";
- }
- qvm = (qvm_t*)(sv_vm->hInst);
- if (! PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + num)) {
- Con_DPrintf("PR2_GetString error off %8x/%8x\n", num, qvm->len_ds );
- return "";
- }
- return (char *) (qvm->ds + num);
+ return VM_ExplicitArgPtr(sv_vm, num);
}
return NULL;
@@ -120,7 +117,7 @@ char *PR2_GetString(intptr_t num)
intptr_t PR2_EntityStringLocation(string_t offset, int max_size)
{
if (offset > 0 && offset < pr_edict_size * sv.max_edicts - max_size) {
- return ((intptr_t)sv.edicts + offset);
+ return ((intptr_t)sv.game_edicts + offset);
}
return 0;
@@ -138,46 +135,39 @@ intptr_t PR2_GlobalStringLocation(string_t offset)
char *PR2_GetEntityString(string_t num)
{
- qvm_t *qvm;
if(!sv_vm)
return PR1_GetString(num);
switch (sv_vm->type)
{
- case VM_NONE:
+ case VMI_NONE:
return PR1_GetString(num);
- case VM_NATIVE:
+ case VMI_NATIVE:
if (num) {
- char** location = (char**)PR2_EntityStringLocation(num, sizeof(char*));
-
- if (location && *location) {
- return *location;
+ if (sv_vm->pr2_references) {
+ char** location = (char**)PR2_EntityStringLocation(num, sizeof(char*));
+ if (location && *location) {
+ return *location;
+ }
+ }
+#ifndef idx64
+ else {
+ return (char *) (num);
}
+#endif
}
return "";
- case VM_BYTECODE:
- if (!num)
+ case VMI_BYTECODE:
+ case VMI_COMPILED:
+ if (num <= 0)
return "";
- qvm = (qvm_t*)(sv_vm->hInst);
if (sv_vm->pr2_references) {
num = *(string_t*)PR2_EntityStringLocation(num, sizeof(string_t));
-
- if (!PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + num)) {
- Con_DPrintf("PR2_GetEntityString error off %8x/%8x\n", num, qvm->len_ds);
- return "";
- }
-
- if (num) {
- return (char *) (qvm->ds+ num);
- }
- }
- else if (PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + num)) {
- return (char *) (qvm->ds+ num);
}
- return "";
+ return VM_ExplicitArgPtr(sv_vm, num);
}
return NULL;
@@ -185,93 +175,23 @@ char *PR2_GetEntityString(string_t num)
//===========================================================================
// PR2_SetString
-// FIXME for VM
+// !!!!IMPOTANT!!!!
+// Server change string pointers in mod memory only in trapcall(strings passed from mod, and placed in mod memory).
+// Never pass pointers outside of the mod memory to mod, this does not work in QVM in 64 bit server.
//===========================================================================
void PR2_SetEntityString(edict_t* ed, string_t* target, char* s)
{
- qvm_t *qvm;
- intptr_t off;
if (!sv_vm) {
PR1_SetString(target, s);
return;
}
-
- switch (sv_vm->type)
- {
- case VM_NONE:
- PR1_SetString(target, s);
- return;
-
- case VM_NATIVE:
- {
- char** location = (char**)PR2_EntityStringLocation(*target, sizeof(char*));
-
- if (location) {
- *location = s;
- }
- }
- return;
-
- case VM_BYTECODE:
- qvm = (qvm_t*)(sv_vm->hInst);
- off = (byte*)s - qvm->ds;
-
- if (sv_vm->pr2_references) {
- string_t* location = (string_t*)PR2_EntityStringLocation(*target, sizeof(string_t));
-
- if (location && PR2_IsValidWriteAddress(qvm, (intptr_t)location)) {
- *location = off;
- }
- }
- else if (PR2_IsValidWriteAddress(qvm, (intptr_t)target)) {
- *target = off;
- }
- return;
- }
-
- *target = 0;
}
-
void PR2_SetGlobalString(string_t* target, char* s)
{
- qvm_t *qvm;
- intptr_t off;
if (!sv_vm) {
PR1_SetString(target, s);
return;
}
-
- switch (sv_vm->type)
- {
- case VM_NONE:
- PR1_SetString(target, s);
- return;
-
- case VM_NATIVE:
- {
- char** location = (char**)PR2_GlobalStringLocation(*target);
- if (location) {
- *location = s;
- }
- }
- return;
-
- case VM_BYTECODE:
- qvm = (qvm_t*)(sv_vm->hInst);
- off = (byte*)s - qvm->ds;
- if (sv_vm->pr2_references) {
- string_t* location = (string_t*)PR2_GlobalStringLocation(*target);
- if (location && PR2_IsValidWriteAddress(qvm, (intptr_t)location)) {
- *location = off;
- }
- }
- else if (PR2_IsValidWriteAddress(qvm, (intptr_t)target)) {
- *target = off;
- }
- return;
- }
-
- *target = 0;
}
/*
@@ -288,7 +208,7 @@ void PR2_LoadEnts(char *data)
pr2_ent_data_ptr = data;
//Init parse
- VM_Call(sv_vm, GAME_LOADENTS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_LOADENTS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
else
{
@@ -301,12 +221,12 @@ void PR2_LoadEnts(char *data)
//===========================================================================
void PR2_GameStartFrame(qbool isBotFrame)
{
- if (isBotFrame && (!sv_vm || sv_vm->type == VM_NONE || !gamedata || gamedata->APIversion < 15)) {
+ if (isBotFrame && (!sv_vm || sv_vm->type == VMI_NONE || gamedata.APIversion < 15)) {
return;
}
if (sv_vm)
- VM_Call(sv_vm, GAME_START_FRAME, (int) (sv.time * 1000), isBotFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 2, GAME_START_FRAME, (int) (sv.time * 1000), (int)isBotFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameStartFrame();
}
@@ -317,7 +237,7 @@ void PR2_GameStartFrame(qbool isBotFrame)
void PR2_GameClientConnect(int spec)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_CLIENT_CONNECT, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 1, GAME_CLIENT_CONNECT, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameClientConnect(spec);
}
@@ -328,7 +248,7 @@ void PR2_GameClientConnect(int spec)
void PR2_GamePutClientInServer(int spec)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_PUT_CLIENT_IN_SERVER, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 1, GAME_PUT_CLIENT_IN_SERVER, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GamePutClientInServer(spec);
}
@@ -339,7 +259,7 @@ void PR2_GamePutClientInServer(int spec)
void PR2_GameClientDisconnect(int spec)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_CLIENT_DISCONNECT, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 1, GAME_CLIENT_DISCONNECT, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameClientDisconnect(spec);
}
@@ -350,7 +270,7 @@ void PR2_GameClientDisconnect(int spec)
void PR2_GameClientPreThink(int spec)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_CLIENT_PRETHINK, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 1, GAME_CLIENT_PRETHINK, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameClientPreThink(spec);
}
@@ -361,7 +281,7 @@ void PR2_GameClientPreThink(int spec)
void PR2_GameClientPostThink(int spec)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_CLIENT_POSTTHINK, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 1, GAME_CLIENT_POSTTHINK, spec, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameClientPostThink(spec);
}
@@ -372,7 +292,7 @@ void PR2_GameClientPostThink(int spec)
qbool PR2_ClientCmd(void)
{
if (sv_vm)
- return VM_Call(sv_vm, GAME_CLIENT_COMMAND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ return VM_Call(sv_vm, 0, GAME_CLIENT_COMMAND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
return PR1_ClientCmd();
}
@@ -399,7 +319,7 @@ qbool PR2_ClientSay(int isTeamSay, char *message)
//
if (sv_vm)
- return VM_Call(sv_vm, GAME_CLIENT_SAY, isTeamSay, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ return VM_Call(sv_vm, 1, GAME_CLIENT_SAY, isTeamSay, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
return PR1_ClientSay(isTeamSay, message);
}
@@ -410,7 +330,7 @@ qbool PR2_ClientSay(int isTeamSay, char *message)
void PR2_GameSetNewParms(void)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_SETNEWPARMS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_SETNEWPARMS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameSetNewParms();
}
@@ -421,7 +341,7 @@ void PR2_GameSetNewParms(void)
void PR2_GameSetChangeParms(void)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_SETCHANGEPARMS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_SETCHANGEPARMS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
{
PR1_GameSetChangeParms();
@@ -434,7 +354,7 @@ void PR2_GameSetChangeParms(void)
void PR2_EdictTouch(func_t f)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_EDICT_TOUCH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_EDICT_TOUCH, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_EdictTouch(f);
}
@@ -445,7 +365,7 @@ void PR2_EdictTouch(func_t f)
void PR2_EdictThink(func_t f)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_EDICT_THINK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_EDICT_THINK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_EdictThink(f);
}
@@ -456,7 +376,7 @@ void PR2_EdictThink(func_t f)
void PR2_EdictBlocked(func_t f)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_EDICT_BLOCKED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_EDICT_BLOCKED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_EdictBlocked(f);
}
@@ -464,12 +384,12 @@ void PR2_EdictBlocked(func_t f)
//===========================================================================
// UserInfoChanged
//===========================================================================
-qbool PR2_UserInfoChanged(void)
+qbool PR2_UserInfoChanged(int after)
{
if (sv_vm)
- return VM_Call(sv_vm, GAME_CLIENT_USERINFO_CHANGED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ return VM_Call(sv_vm, 1, GAME_CLIENT_USERINFO_CHANGED, after, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
- return PR1_UserInfoChanged();
+ return PR1_UserInfoChanged(after);
}
//===========================================================================
@@ -478,7 +398,7 @@ qbool PR2_UserInfoChanged(void)
void PR2_GameShutDown(void)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_GameShutDown();
}
@@ -490,7 +410,7 @@ void PR2_UnLoadProgs(void)
{
if (sv_vm)
{
- VM_Unload( sv_vm );
+ VM_Free( sv_vm );
sv_vm = NULL;
}
else
@@ -504,7 +424,7 @@ void PR2_UnLoadProgs(void)
//===========================================================================
void PR2_LoadProgs(void)
{
- sv_vm = (vm_t *) VM_Load(sv_vm, (vm_type_t) (int) sv_progtype.value, sv_progsname.string, sv_syscall, sv_sys_callex);
+ sv_vm = VM_Create(VM_GAME, sv_progsname.string, PR2_GameSystemCalls, sv_progtype.value );
if ( sv_vm )
{
@@ -545,7 +465,7 @@ void PR2_GameConsoleCommand(void)
break;
}
}
- VM_Call(sv_vm, GAME_CONSOLE_COMMAND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_CONSOLE_COMMAND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
pr_global_struct->self = old_self;
pr_global_struct->other = old_other;
}
@@ -557,21 +477,128 @@ void PR2_GameConsoleCommand(void)
void PR2_PausedTic(float duration)
{
if (sv_vm)
- VM_Call(sv_vm, GAME_PAUSED_TIC, duration*1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 1, GAME_PAUSED_TIC, (int)(duration*1000), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
else
PR1_PausedTic(duration);
}
void PR2_ClearEdict(edict_t* e)
{
- if (sv_vm && sv_vm->pr2_references && (sv_vm->type == VM_NATIVE || sv_vm->type == VM_BYTECODE)) {
+ if (sv_vm && sv_vm->pr2_references && (sv_vm->type == VMI_NATIVE || sv_vm->type == VMI_BYTECODE || sv_vm->type == VMI_COMPILED)) {
int old_self = pr_global_struct->self;
pr_global_struct->self = EDICT_TO_PROG(e);
- VM_Call(sv_vm, GAME_CLEAR_EDICT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ VM_Call(sv_vm, 0, GAME_CLEAR_EDICT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
pr_global_struct->self = old_self;
}
}
+//===========================================================================
+// InitProgs
+//===========================================================================
+
+#define GAME_API_VERSION_MIN 16
+
+void LoadGameData(intptr_t gamedata_ptr)
+{
+#ifdef idx64
+ gameData_vm_t* gamedata_vm;
+
+ if (sv_vm->type == VMI_BYTECODE || sv_vm->type == VMI_COMPILED)
+ {
+ gamedata_vm = (gameData_vm_t *)PR2_GetString(gamedata_ptr);
+ gamedata.ents = (intptr_t)gamedata_vm->ents_p;
+ gamedata.global = (intptr_t)gamedata_vm->global_p;
+ gamedata.fields = (intptr_t)gamedata_vm->fields_p;
+ gamedata.APIversion = gamedata_vm->APIversion;
+ gamedata.sizeofent = gamedata_vm->sizeofent;
+ gamedata.maxentities = gamedata_vm->maxentities;
+ return;
+ }
+#endif
+ gamedata = *(gameData_t *)PR2_GetString(gamedata_ptr);
+}
+
+void LoadFields(void)
+{
+#ifdef idx64
+ if (sv_vm->type == VMI_BYTECODE || sv_vm->type == VMI_COMPILED)
+ {
+ field_vm_t *fieldvm_p;
+ field_t *f;
+ int num = 0;
+ fieldvm_p = (field_vm_t*)PR2_GetString((intptr_t)gamedata.fields);
+ while (fieldvm_p[num].name) {
+ num++;
+ }
+ f = fields = (field_t *)Hunk_Alloc(sizeof(field_t) * (num + 1));
+ while (fieldvm_p->name){
+ f->name = (stringptr_t)fieldvm_p->name;
+ f->ofs = fieldvm_p->ofs;
+ f->type = (fieldtype_t)fieldvm_p->type;
+ f++;
+ fieldvm_p++;
+ }
+ f->name = 0;
+ return;
+ }
+#endif
+ fields = (field_t*)PR2_GetString((intptr_t)gamedata.fields);
+}
+
+extern void PR2_FS_Restart(void);
+
+void PR2_InitProg(void)
+{
+ extern cvar_t sv_pr2references;
+
+ intptr_t gamedata_ptr;
+
+ Cvar_SetValue(&sv_pr2references, 0.0f);
+
+ if (!sv_vm) {
+ PR1_InitProg();
+ return;
+ }
+
+ PR2_FS_Restart();
+
+ gamedata.APIversion = 0;
+ gamedata_ptr = (intptr_t) VM_Call(sv_vm, 2, GAME_INIT, (int)(sv.time * 1000), (int)(Sys_DoubleTime() * 100000), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (!gamedata_ptr) {
+ SV_Error("PR2_InitProg: gamedata == NULL");
+ }
+
+ LoadGameData(gamedata_ptr);
+ if (gamedata.APIversion < GAME_API_VERSION_MIN || gamedata.APIversion > GAME_API_VERSION) {
+ if (GAME_API_VERSION_MIN == GAME_API_VERSION) {
+ SV_Error("PR2_InitProg: Incorrect API version (%i should be %i)", gamedata.APIversion, GAME_API_VERSION);
+ }
+ else {
+ SV_Error("PR2_InitProg: Incorrect API version (%i should be between %i and %i)", gamedata.APIversion, GAME_API_VERSION_MIN, GAME_API_VERSION);
+ }
+ }
+
+ sv_vm->pr2_references = gamedata.APIversion >= 15 && (int)sv_pr2references.value;
+#ifdef idx64
+ if (sv_vm->type == VMI_NATIVE && (!sv_vm->pr2_references || gamedata.APIversion < 15))
+ SV_Error("PR2_InitProg: Native prog must support sv_pr2references for 64bit mode (mod API version (%i should be 15+))", gamedata.APIversion);
+#endif
+ pr_edict_size = gamedata.sizeofent;
+ Con_DPrintf("edict size %d\n", pr_edict_size);
+ sv.game_edicts = (entvars_t *)(PR2_GetString((intptr_t)gamedata.ents));
+ pr_global_struct = (globalvars_t*)PR2_GetString((intptr_t)gamedata.global);
+ pr_globals = (float *)pr_global_struct;
+ LoadFields();
+
+ sv.max_edicts = MAX_EDICTS;
+ if (gamedata.APIversion >= 14) {
+ sv.max_edicts = min(sv.max_edicts, gamedata.maxentities);
+ }
+ else {
+ sv.max_edicts = min(sv.max_edicts, 512);
+ }
+}
+
#endif /* USE_PR2 */
#endif // !CLIENTONLY
diff --git a/src/pr2_vm.c b/src/pr2_vm.c
deleted file mode 100644
index 9f1b55ee7..000000000
--- a/src/pr2_vm.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/*
- * QW262
- * Copyright (C) 2004 [sd] angel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- *
- */
-/*
- Quake3 compatible virtual machine
- map file support
- print StackTrace on errors
- runaway loop protection
- reenterable vmMain
-*/
-
-#ifndef CLIENTONLY
-#ifdef USE_PR2
-
-#include "qwsvdef.h"
-
-#ifdef QVM_PROFILE
-cvar_t sv_enableprofile = {"sv_enableprofile","0"};
-typedef struct
-{
- int address;
-#ifdef _WIN32
- __int64 instruction_count;
-#else
- int instruction_count;
-#endif
-}
-profile_t;
-#define MAX_PROFILE_FUNCS 0x1000
-
-profile_t profile_funcs[MAX_PROFILE_FUNCS];
-int num_profile_func;
-
-qbool PR2_IsValidReadAddress(register qvm_t * qvm, intptr_t address)
-{
- if (address >= (intptr_t)&sv && address < ((intptr_t)&sv) + sizeof(sv) - 4) {
- return true;
- }
- if (address >= (intptr_t)&svs.clients && address < ((intptr_t)&svs.clients) + sizeof(svs.clients) - 4) {
- return true;
- }
- if (address == (intptr_t)VersionStringFull()) {
- return true;
- }
-
- return (address >= (intptr_t)qvm->ds && address < (intptr_t)qvm->ds + qvm->len_ds);
-}
-
-qbool PR2_IsValidWriteAddress(register qvm_t * qvm, intptr_t address)
-{
- if (address >= (intptr_t)&sv && address < ((intptr_t)&sv) + sizeof(sv) - 4) {
- return true;
- }
- if (address >= (intptr_t)&svs.clients && address < ((intptr_t)&svs.clients) + sizeof(svs.clients) - 4) {
- return true;
- }
-
- return (address >= (intptr_t)qvm->ds && address < (intptr_t)qvm->ds + qvm->len_ds);
-}
-
-#define OLD_VM_POINTER(base,mask,x) ((void*)((char *)base+((x)&mask)))
-
-void* VM_POINTER(byte* base, uintptr_t mask, intptr_t offset)
-{
- intptr_t address = (intptr_t) base + offset;
- qvm_t* qvm = (qvm_t*) sv_vm->hInst;
-
- if (PR2_IsValidWriteAddress(qvm, address)) {
- return (void*)address;
- }
-
- return OLD_VM_POINTER(base, mask, offset);
-}
-
-profile_t* ProfileEnterFunction(int address)
-{
- int i;
- for ( i = 0 ; i < num_profile_func ; i++ )
- {
- if(profile_funcs[i].address == address)
- return &profile_funcs[i];
- }
- if( num_profile_func >= MAX_PROFILE_FUNCS )
- {
- profile_funcs[0].address = address;
- profile_funcs[0].instruction_count = 0;
-
- return &profile_funcs[0];
- }
- profile_funcs[num_profile_func].address = address;
- profile_funcs[num_profile_func].instruction_count = 0;
-
- return &profile_funcs[num_profile_func++];
-}
-symbols_t* QVM_FindName( qvm_t * qvm, int off);
-#endif
-
-void PR2_Profile_f(void)
-{
-#ifdef QVM_PROFILE
- profile_t *f, *best;
-#endif
-#ifdef _WIN32
- __int64 max;
-#else
- int max;
-#endif
- int num;
- int i;
- symbols_t *sym;
-
- if(!sv_vm)
- {
- PR_Profile_f();
- return;
- }
-#ifdef QVM_PROFILE
- if(sv_vm->type != VM_BYTECODE)
- return;
- num = 0;
- if(!(int)sv_enableprofile.value)
- {
- Con_Printf ("profiling no enabled\n");
- return;
- }
- do
- {
- max = 0;
- best = NULL;
- for (i=0 ; iinstruction_count > max)
- {
- max = f->instruction_count;
- best = f;
- }
- }
- if (best)
- {
- if (num < 15)
- {
- sym = QVM_FindName( (qvm_t*)(sv_vm->hInst), best->address );
-#ifdef _WIN32
- Con_Printf ("%18I64d %s\n", best->instruction_count, sym->name);
-#else
- Con_Printf ("%9d %s\n", best->instruction_count, sym->name);
-#endif
-
- }
- num++;
- best->instruction_count = 0;
- }
- }
- while (best);
- num_profile_func = 0;
-#endif
-}
-
-void VM_UnloadQVM( qvm_t * qvm )
-{
- if(qvm)
- Q_free( qvm );
-}
-
-void VM_Unload( vm_t * vm )
-{
- if ( !vm )
- return;
- Con_DPrintf( "VM_Unload \"%s\"\n", vm->name );
- switch ( vm->type )
- {
- case VM_NATIVE:
- if ( vm->hInst )
- if ( !Sys_DLClose( (DL_t) vm->hInst ) )
- SV_Error( "VM_Unload: couldn't unload module %s\n", vm->name );
- vm->hInst = NULL;
- break;
- case VM_BYTECODE:
- VM_UnloadQVM( (qvm_t*) vm->hInst );
- break;
- case VM_NONE:
- return;
-
- }
- Q_free( vm );
-}
-
-qbool VM_LoadNative( vm_t * vm )
-{
- char name[MAX_OSPATH];
- char *gpath = NULL;
- void ( *dllEntry ) ( void * );
-
- memset(name, 0, sizeof(name));
- while ( ( gpath = FS_NextPath( gpath ) ) )
- {
- snprintf(name, sizeof(name), "%s/%s." DLEXT, gpath, vm->name);
- vm->hInst = Sys_DLOpen( name );
- if ( vm->hInst )
- {
- Con_DPrintf( "LoadLibrary (%s)\n", name );
- break;
- }
- }
-
- if ( !vm->hInst )
- return false;
-
- dllEntry = (void (EXPORT_FN *)(void *)) Sys_DLProc( (DL_t) vm->hInst, "dllEntry" );
- vm->vmMain = (intptr_t (EXPORT_FN *)(int,int,int,int,int,int,int,int,int,int,int,int,int)) Sys_DLProc( (DL_t) vm->hInst, "vmMain" );
- if ( !dllEntry || !vm->vmMain )
- {
- VM_Unload( vm );
- SV_Error( "VM_LoadNative: couldn't initialize module %s", name );
- }
- dllEntry( (void *) vm->syscall );
-
- Info_SetValueForStarKey( svs.info, "*progs", DLEXT, MAX_SERVERINFO_STRING );
- vm->type = VM_NATIVE;
- return true;
-}
-
-void VM_PrintInfo( vm_t * vm)
-{
- qvm_t *qvm;
- if(!vm)
- {
- Con_Printf( "VM_PrintInfo: NULL vm\n" );
- return;
- }
-
- if(!vm->name[0])
- return;
-
- Con_DPrintf("%s: ", vm->name);
- switch(vm->type)
- {
- case VM_NATIVE:
- Con_DPrintf("native\n");
- break;
- case VM_BYTECODE:
- Con_DPrintf("bytecode interpreted\n");
- if((qvm=(qvm_t *)vm->hInst))
- {
- Con_DPrintf(" code length: %8xh\n", qvm->len_cs*sizeof(qvm->cs[0]));
- Con_DPrintf("instruction count: %8d\n", qvm->len_cs);
- Con_DPrintf(" data length: %8xh\n", qvm->len_ds);
- Con_DPrintf(" stack length: %8xh\n", qvm->len_ss);
- }
- break;
- default:
- Con_DPrintf("unknown\n");
- break;
- }
-
-}
-
-#define MAX_LINE_LENGTH 1024
-
-void LoadMapFile( qvm_t*qvm, char* fname )
-{
- char name[MAX_OSPATH];
- char lineBuffer[MAX_LINE_LENGTH];
- char symname[MAX_LINE_LENGTH];
- int i,off,seg,len,num_symbols = 0;
- symbols_t *sym = NULL;
-
- byte *buff;
- byte *p;
-
- Con_DPrintf("Loading symbol information\n");
- snprintf( name, sizeof( name ), "%s.map", fname );
- buff = FS_LoadTempFile( name , NULL );
- qvm->sym_info = NULL;
- if ( !buff )
- return;
- p=buff;
- while(*p)
- {
- for( i = 0; i < MAX_LINE_LENGTH; i++)
- {
- if( p[i] == 0 || p[i] == '\n')
- break;
- }
- if ( i == MAX_LINE_LENGTH )
- {
- return;
- }
-
- memcpy( lineBuffer, p, i );
- lineBuffer[i] = 0;
- p += i;
- if( *p == '\n') p++;
- if( 3 != sscanf( lineBuffer,"%d %8x %s",&seg,&off,symname) )
- return;
- len = strlen(symname);
- if(!len)continue;
- if( off < 0 )
- continue;
-
- if( seg == 0 && off >= qvm->len_cs)
- {
- Con_DPrintf("bad cs off in map file %s.map\n",fname);
- qvm->sym_info = NULL;
- return;
- }
- if( seg >= 1 && off >= qvm->len_ds )
- {
- Con_DPrintf("bad ds off in map file %s.map\n",fname);
- continue;
- }
-
- if( !qvm->sym_info )
- {
- qvm->sym_info = (symbols_t *) Hunk_Alloc( sizeof(symbols_t) + len + 1);
- sym = qvm->sym_info;
- }
- else
- {
- sym->next = (symbols_t *) Hunk_Alloc( sizeof(symbols_t) + len + 1);
- sym = sym->next;
- }
- sym->seg = seg;
- sym->off = off;
- sym->next= NULL;
- num_symbols++;
- strlcpy(sym->name, symname, len + 1);
- }
- Con_DPrintf("%i symbols loaded from %s\n",num_symbols,name);
-}
-
-qbool VM_LoadBytecode( vm_t * vm, sys_callex_t syscall1 )
-{
- char name[MAX_OSPATH];
- byte *buff;
- vmHeader_t *header;
- qvm_t *qvm;
- char num[32];
- int filesize;
-
- snprintf( name, sizeof( name ), "%s.qvm", vm->name );
-
- Con_DPrintf( "VM_LoadBytecode: load %s\n", name );
- buff = FS_LoadTempFile( name , &filesize );
-
- if ( !buff )
- return false;
-
- // add qvm crc to the serverinfo
- snprintf( num, sizeof(num), "%i", CRC_Block( ( byte * ) buff, filesize ) );
- Info_SetValueForStarKey( svs.info, "*progs", num, MAX_SERVERINFO_STRING );
-
- header = ( vmHeader_t * ) buff;
-
- header->vmMagic = LittleLong( header->vmMagic );
- header->instructionCount = LittleLong( header->instructionCount );
- header->codeOffset = LittleLong( header->codeOffset );
- header->codeLength = LittleLong( header->codeLength );
- header->dataOffset = LittleLong( header->dataOffset );
- header->dataLength = LittleLong( header->dataLength );
- header->litLength = LittleLong( header->litLength );
- header->bssLength = LittleLong( header->bssLength );
-
- // check file
- if ( header->vmMagic != VM_MAGIC || header->instructionCount <= 0 || header->codeLength <= 0 )
- {
- return false;
- }
- // create vitrual machine
- if(vm->hInst)
- qvm = (qvm_t *)vm->hInst;
- else
- qvm = (qvm_t *) Q_malloc (sizeof (qvm_t));
-
- qvm->len_cs = header->instructionCount + 1; //bad opcode padding.
- qvm->len_ds = header->dataOffset + header->litLength + header->bssLength;
- //align ds
- qvm->ds_mask = 1;
- while( qvm->ds_mask < qvm->len_ds) qvm->ds_mask<<=1;
- qvm->len_ds = qvm->ds_mask;
- qvm->ds_mask--;
-
- qvm->len_ss = 0x10000; // default by q3asm
- if ( qvm->len_ds < qvm->len_ss )
- Sys_Error( "VM_LoadBytecode: stacksize greater than data segment" );
-
- qvm->cs = ( qvm_instruction_t * ) Hunk_AllocName( qvm->len_cs * sizeof( qvm_instruction_t ), "qvmcode" );
- qvm->ds = (byte *) Hunk_AllocName( qvm->len_ds, "qvmdata" );
- qvm->ss = qvm->ds + qvm->len_ds - qvm->len_ss;
-
- // setup registers
- qvm->PC = 0;
- qvm->SP = 0;
- qvm->LP = qvm->len_ds - sizeof(int);
- qvm->cycles = 0;
- qvm->reenter = 0;
- qvm->syscall = syscall1;
-
-
- // load instructions
- {
- byte *src = buff + header->codeOffset;
- qvm_instruction_t *dst = qvm->cs;
- opcode_t op;
- int i;
-
- for ( i = 0; i < header->instructionCount; i++, dst++ )
- {
- op = (opcode_t) *src++;
- dst->opcode = op;
- switch ( op )
- {
- case OP_ARG:
- dst->parm._int = ( int ) *src++;
- break;
-
- case OP_ENTER:
- case OP_LEAVE:
- case OP_CONST:
- case OP_LOCAL:
- case OP_EQ:
- case OP_NE:
- case OP_LTI:
- case OP_LEI:
- case OP_GTI:
- case OP_GEI:
- case OP_LTU:
- case OP_LEU:
- case OP_GTU:
- case OP_GEU:
- case OP_EQF:
- case OP_NEF:
- case OP_LTF:
- case OP_LEF:
- case OP_GTF:
- case OP_GEF:
- case OP_BLOCK_COPY:
-
- dst->parm._int = LittleLong( *( int * ) src );
- src += 4;
- break;
-
- default:
- dst->parm._int = 0;
- break;
- }
- }
- dst->opcode = OP_BREAK;
- dst->parm._int = 0;
- }
- // load data segment
- {
- int *src = ( int * ) ( buff + header->dataOffset );
- int *dst = ( int * ) qvm->ds;
- int i;
-
- for ( i = 0; i < header->dataLength / 4; i++ )
- *dst++ = LittleLong( *src++ );
-
- memcpy( dst, src, header->litLength );
- }
-
- LoadMapFile( qvm, vm->name );
- vm->type = VM_BYTECODE;
- vm->hInst = qvm;
- return true;
-}
-
-
-vm_t *VM_Load( vm_t * vm, vm_type_t type, char *name, sys_call_t syscall1, sys_callex_t syscallex )
-{
- if ( !name || !syscall1 || !syscallex )
- Sys_Error( "VM_Load: bad parms" );
-
- if ( vm )
- VM_Unload(vm);
-
- vm = (vm_t *) Q_malloc (sizeof (vm_t));
-
-
-
- Con_Printf( "VM_Load: \"%s\"\n", name );
-
- // prepare vm struct
- memset( vm, 0, sizeof( vm_t ) );
- strlcpy( vm->name, name, sizeof( vm->name ) );
- vm->syscall = syscall1;
-#ifdef QVM_PROFILE
- num_profile_func = 0;
-#endif
-
- switch ( type )
- {
- case VM_NATIVE:
- if ( VM_LoadNative( vm ) )
- break;
- case VM_BYTECODE:
- if ( VM_LoadBytecode( vm, syscallex ) )
- break;
- default:
- Q_free(vm);
- return NULL;
- break;
- }
-
- VM_PrintInfo(vm);
- return vm;
-}
-
-
-int QVM_Exec( register qvm_t * qvm, int command, int arg0, int arg1, int arg2, int arg3,
- int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 );
-
-intptr_t VM_Call( vm_t * vm, int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5,
- int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 )
-{
- if ( !vm )
- Sys_Error( "VM_Call with NULL vm" );
-
- switch ( vm->type )
- {
- case VM_NATIVE:
- return vm->vmMain( command, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 );
- case VM_BYTECODE:
- return QVM_Exec( (qvm_t*) vm->hInst, command, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
- arg11 );
- case VM_NONE:
- Sys_Error( "VM_Call with VM_NONE type vm" );
- }
- Sys_Error( "VM_Call with bad vm->type" );
- return 0;
-}
-
-#define STACK_INT(x) (*(int*)(qvm->ds+qvm->LP+(x)*sizeof(int) ))
-symbols_t* QVM_FindName( qvm_t * qvm, int off)
-{
- symbols_t* sym,*found;
-
- found = NULL;
- for(sym = qvm->sym_info; sym; sym = sym->next)
- {
- if( sym->seg != 0)continue;
- if(!found)
- found = sym;
- if( sym->off <= off && sym->off >found->off )
- found = sym;
- }
- return found;
-}
-void QVM_StackTrace( qvm_t * qvm )
-{
- symbols_t *sym;
- int LP, off, num;
-
- LP = qvm->LP;
- Con_Printf( " code length: %8xh\n", qvm->len_cs * sizeof( qvm->cs[0] ) );
- Con_Printf( "instruction count: %8xh\n", qvm->len_cs );
- Con_Printf( " data length: %8xh\n", qvm->len_ds );
- Con_Printf( " stack length: %8xh\n", qvm->len_ss );
-
- Con_Printf( "PC %8x LP %8x SP %8x\n", qvm->PC, qvm->LP, qvm->SP );
-
- // if ( qvm->sym_info == NULL )
- // return;
-
- sym = QVM_FindName( qvm, qvm->PC );
-
- if ( sym )
- Con_Printf( "PC-%8x %s + %d\n", sym->off, sym->name, qvm->PC - sym->off );
-
- while ( LP < qvm->len_ds - (int) sizeof ( int ) )
- {
- off = *( int * ) ( qvm->ds + LP );
- num = *( int * ) ( qvm->ds + LP + sizeof( int ) );
- LP += num;
- if ( off < 0 || off >= qvm->len_cs )
- {
- Con_Printf( "Error ret address %8x in stack %8x/%8x\n", off, LP, qvm->len_ds );
- return;
- }
- if ( num <= 0 )
- {
- Con_Printf( "Error num in stack %8x/%8x\n", LP, qvm->len_ds );
- return;
- }
-
- sym = QVM_FindName( qvm, off );
- if ( sym )
- Con_Printf( " %8x %s + %d\n", sym->off, sym->name, off - sym->off );
- else
- Con_Printf( " %8x unknown\n", off);
-
- }
-}
-
-void QVM_RunError( qvm_t * qvm, char *error, ... )
-{
- va_list argptr;
- char string[1024];
-
- va_start( argptr, error );
- vsnprintf( string, sizeof(string), error, argptr );
- va_end( argptr );
-
- sv_error = true;
-
- QVM_StackTrace( qvm );
-
- Con_Printf( "%s\n", string );
-
- SV_Error( "QVM Program error" );
-}
-
-int trap_Call( qvm_t * qvm, int apinum )
-{
- int ret;
-
- qvm->SP++;
- ret = qvm->syscall( qvm->ds, qvm->ds_mask, apinum, ( pr2val_t* ) ( qvm->ds + qvm->LP + 2*sizeof(int) ) );
-
- return ret;
-}
-
-
-void PrintInstruction( qvm_t * qvm );
-
-int QVM_Exec( register qvm_t * qvm, int command, int arg0, int arg1, int arg2, int arg3,
- int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 )
-{
- qvm_parm_type_t opStack[OPSTACKSIZE + 1]; //in q3 stack var of QVM_Exec size~0x400;
-#ifdef QVM_RUNAWAY_PROTECTION
- int cycles[MAX_PROC_CALL],cycles_p=0;
-#endif
-#ifdef QVM_PROFILE
- profile_t *profile_func = NULL;
- symbols_t *sym;
-#endif
- int savePC, saveSP, saveLP, ivar = 0;
- qvm_instruction_t op;
-
- savePC = qvm->PC;
- saveSP = qvm->SP;
- saveLP = qvm->LP;
-
-
-#ifdef QVM_PROFILE
- if((int)sv_enableprofile.value)
- profile_func = ProfileEnterFunction(0);
-#endif
- if ( !qvm->reenter )
- {
- //FIXME check last exit REGISTERS
- qvm->LP = qvm->len_ds - sizeof(int);
- }
- if ( qvm->reenter++ > MAX_vmMain_Call )
- QVM_RunError( qvm, "QVM_Exec MAX_vmMain_Call reached");
-
- qvm->PC = 0;
- qvm->SP = 0;
- qvm->LP -= 14 * sizeof(int);
-
- STACK_INT( 0 ) = 0; // return addres;
- STACK_INT( 1 ) = 14 * sizeof(int); //11 params + command + retaddr + num args;
- STACK_INT( 2 ) = command;
- STACK_INT( 3 ) = arg0;
- STACK_INT( 4 ) = arg1;
- STACK_INT( 5 ) = arg2;
- STACK_INT( 6 ) = arg3;
- STACK_INT( 7 ) = arg4;
- STACK_INT( 8 ) = arg5;
- STACK_INT( 9 ) = arg6;
- STACK_INT( 10 ) = arg7;
- STACK_INT( 11 ) = arg8;
- STACK_INT( 12 ) = arg9;
- STACK_INT( 13 ) = arg10;
- STACK_INT( 14 ) = arg11;
-#ifdef QVM_RUNAWAY_PROTECTION
- cycles[cycles_p] = 0;
-#endif
-
- do
- {
-#ifdef SAFE_QVM
- if ( qvm->PC >= qvm->len_cs || qvm->PC < 0 )
- QVM_RunError( qvm, "QVM PC out of range, %8d\n", qvm->PC );
-
- if ( qvm->SP < 0 )
- QVM_RunError( qvm, "QVM opStack underflow at %8x", qvm->PC );
-
- if ( qvm->SP > OPSTACKSIZE )
- QVM_RunError( qvm, "QVM opStack overflow at %8x", qvm->PC );
-
- if ( qvm->LP < qvm->len_ds - qvm->len_ss )
- QVM_RunError( qvm, "QVM Stack overflow at %8x", qvm->PC );
-
- if ( qvm->LP >= qvm->len_ds )
- QVM_RunError( qvm, "QVM Stack underflow at %8x", qvm->PC );
-#endif
-#ifdef QVM_RUNAWAY_PROTECTION
- if(cycles[cycles_p]++ > MAX_CYCLES)
- QVM_RunError( qvm, "QVM runaway loop error", qvm->PC );
-#endif
-#ifdef QVM_PROFILE
- if((int)sv_enableprofile.value)
- profile_func->instruction_count++;
-#endif
- op = qvm->cs[qvm->PC++];
- switch ( op.opcode )
- {
- case OP_UNDEF:
- QVM_RunError( qvm, "OP_UNDEF\n" );
- break;
-
- case OP_IGNORE:
- break;
-
- case OP_BREAK:
- QVM_RunError( qvm, "OP_BREAK\n" );
- break;
-
- case OP_ENTER:
- qvm->LP -= op.parm._int;
-#ifdef PARANOID
- if ( qvm->LP < qvm->len_ds - qvm->len_ss )
- {
- QVM_StackTrace( qvm );
- Sys_Error( "QVM Stack overflow on enter at %8x", qvm->PC );
- }
-#endif
- STACK_INT( 1 ) = op.parm._int;
-#ifdef QVM_RUNAWAY_PROTECTION
- if(++cycles_p >= MAX_PROC_CALL)
- QVM_RunError( qvm, "MAX_PROC_CALL reached\n" );
- cycles[cycles_p] = 0;
-#endif
- break;
-
- case OP_LEAVE:
- qvm->LP += op.parm._int;
-#ifdef PARANOID
- if ( qvm->LP >= qvm->len_ds )
- QVM_RunError( qvm, "QVM Stack underflow on leave at %8x", qvm->PC );
-#endif
- qvm->PC = STACK_INT( 0 );
-#ifdef QVM_PROFILE
- if((int)sv_enableprofile.value)
- {
- sym = QVM_FindName( qvm, qvm->PC );
- profile_func = ProfileEnterFunction(sym->off);
- }
-#endif
-
-#ifdef QVM_RUNAWAY_PROTECTION
- cycles_p--;
-#endif
- break;
-
- case OP_CALL:
- STACK_INT( 0 ) = qvm->PC;
- ivar = opStack[qvm->SP--]._int;
- if ( ivar < 0 )
- {
- ivar = trap_Call( qvm, -ivar - 1 );
- opStack[qvm->SP]._int = ivar;
- }
- else
- {
- qvm->PC = ivar;
-#ifdef QVM_PROFILE
- if((int)sv_enableprofile.value)
- profile_func = ProfileEnterFunction(ivar);
-#endif
-
- }
- break;
- case OP_PUSH:
- qvm->SP++;
- break;
-
- case OP_POP:
- qvm->SP--;
- break;
-
- case OP_CONST:
- qvm->SP++;
- opStack[qvm->SP]._int = op.parm._int;
- break;
-
- case OP_LOCAL:
- qvm->SP++;
- opStack[qvm->SP]._int = qvm->LP + op.parm._int;
- break;
-
- case OP_JUMP:
- qvm->PC = opStack[qvm->SP--]._int;
- break;
- //-----Compare Operators
- case OP_EQ:
- if ( opStack[qvm->SP - 1]._int == opStack[qvm->SP]._int )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_NE:
- if ( opStack[qvm->SP - 1]._int != opStack[qvm->SP]._int )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
- //singed int compare
- case OP_LTI:
- if ( opStack[qvm->SP - 1]._int < opStack[qvm->SP]._int )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_LEI:
- if ( opStack[qvm->SP - 1]._int <= opStack[qvm->SP]._int )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_GTI:
- if ( opStack[qvm->SP - 1]._int > opStack[qvm->SP]._int )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_GEI:
- if ( opStack[qvm->SP - 1]._int >= opStack[qvm->SP]._int )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
- //unsinged int compare
- case OP_LTU:
- if ( opStack[qvm->SP - 1]._uint < opStack[qvm->SP]._uint )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_LEU:
- if ( opStack[qvm->SP - 1]._uint <= opStack[qvm->SP]._uint )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_GTU:
- if ( opStack[qvm->SP - 1]._uint > opStack[qvm->SP]._uint )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_GEU:
- if ( opStack[qvm->SP - 1]._uint >= opStack[qvm->SP]._uint )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
- //float
- case OP_EQF:
- if ( opStack[qvm->SP - 1]._float == opStack[qvm->SP]._float )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_NEF:
- if ( opStack[qvm->SP - 1]._float != opStack[qvm->SP]._float )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_LTF:
- if ( opStack[qvm->SP - 1]._float < opStack[qvm->SP]._float )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_LEF:
- if ( opStack[qvm->SP - 1]._float <= opStack[qvm->SP]._float )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_GTF:
- if ( opStack[qvm->SP - 1]._float > opStack[qvm->SP]._float )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
-
- case OP_GEF:
- if ( opStack[qvm->SP - 1]._float >= opStack[qvm->SP]._float )
- qvm->PC = op.parm._int;
- qvm->SP -= 2;
- break;
- //-------------------
- case OP_LOAD1:
- ivar = opStack[qvm->SP]._int;
-
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "data load 1 out of range %8x\n", ivar );
- opStack[qvm->SP]._int = *( char * ) ( qvm->ds + ivar );
-#else
- opStack[qvm->SP]._int = *( char * ) ( qvm->ds + (ivar&qvm->ds_mask) );
-#endif
- break;
-
- case OP_LOAD2:
- ivar = opStack[qvm->SP]._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "data load 2 out of range %8x\n", ivar );
- opStack[qvm->SP]._int = *( short * ) ( qvm->ds + ivar );
-#else
- opStack[qvm->SP]._int = *( short * ) ( qvm->ds + (ivar&qvm->ds_mask) );
-#endif
- break;
-
- case OP_LOAD4:
- ivar = opStack[qvm->SP]._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "data load 4 out of range %8x\n", ivar );
- opStack[qvm->SP]._int = *( int * ) ( qvm->ds + ivar );
-#else
- opStack[qvm->SP]._int = *( int * ) ( qvm->ds + (ivar&qvm->ds_mask) );
-#endif
- break;
- case OP_STORE1:
- ivar = opStack[qvm->SP - 1]._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidWriteAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "data store 1 out of range %8x\n", ivar );
- *( char * ) ( qvm->ds + ivar ) = opStack[qvm->SP]._int & 0xff;
-#else
- *( char * ) ( qvm->ds + (ivar&qvm->ds_mask) ) = opStack[qvm->SP]._int & 0xff;
-#endif
- qvm->SP -= 2;
- break;
- case OP_STORE2:
- ivar = opStack[qvm->SP - 1]._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidWriteAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "data store 2 out of range %8x\n", ivar );
- *( short * ) ( qvm->ds + ivar ) = opStack[qvm->SP]._int & 0xffff;
-#else
- *( short * ) ( qvm->ds + (ivar&qvm->ds_mask) ) = opStack[qvm->SP]._int & 0xffff;
-#endif
- qvm->SP -= 2;
- break;
-
- case OP_STORE4:
- ivar = opStack[qvm->SP - 1]._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidWriteAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "data store 4 out of range %8x\n", ivar );
- *( int * ) ( qvm->ds + ivar ) = opStack[qvm->SP]._int;
-#else
- *( int * ) ( qvm->ds + (ivar&qvm->ds_mask) ) = opStack[qvm->SP]._int;
-#endif
- qvm->SP -= 2;
- break;
-
- case OP_ARG:
- ivar = qvm->LP + op.parm._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidWriteAddress(qvm, (intptr_t)qvm->ds + ivar))
- QVM_RunError( qvm, "arg out of range %8x\n", ivar );
- *( int * ) ( qvm->ds + ivar ) = opStack[qvm->SP--]._int;
-#else
- *( int * ) ( qvm->ds + (ivar&qvm->ds_mask) ) = opStack[qvm->SP--]._int;
-#endif
- break;
-
- case OP_BLOCK_COPY:
- {
- int off1,off2,len;
- off1 = opStack[qvm->SP - 1]._int;
- off2 = opStack[qvm->SP]._int;
- len = op.parm._int;
-#ifdef QVM_DATA_PROTECTION
- if (!PR2_IsValidWriteAddress(qvm, (intptr_t)qvm->ds + off1) || !PR2_IsValidWriteAddress(qvm, (intptr_t)qvm->ds + off1 + len) ||
- !PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + off2) || !PR2_IsValidReadAddress(qvm, (intptr_t)qvm->ds + off2 + len)) {
- QVM_RunError(qvm, "block copy out of range %8x\n", ivar);
- }
- memmove( qvm->ds + off1, qvm->ds + off2, len );
-#else
- memmove( qvm->ds + (off1 & qvm->ds_mask), qvm->ds + (off2 & qvm->ds_mask), len );
-#endif
- qvm->SP -= 2;
- }
- break;
- //integer arifmetic
- case OP_SEX8:
- if( opStack[qvm->SP]._int & 0x80 )
- opStack[qvm->SP]._int |=0xFFFFFF00;
- else
- opStack[qvm->SP]._int &=0x000000FF;
- break;
-
- case OP_SEX16:
- if( opStack[qvm->SP]._int & 0x8000 )
- opStack[qvm->SP]._int |=0xFFFF0000;
- else
- opStack[qvm->SP]._int &=0x0000FFFF;
- break;
-
- case OP_NEGI:
- opStack[qvm->SP]._int = -opStack[qvm->SP]._int;
- break;
-
- case OP_ADD:
- opStack[qvm->SP - 1]._int += opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_SUB:
- opStack[qvm->SP - 1]._int -= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_DIVI:
- opStack[qvm->SP - 1]._int /= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_DIVU:
- opStack[qvm->SP - 1]._uint /= opStack[qvm->SP]._uint;
- qvm->SP--;
- break;
-
- case OP_MODI:
- opStack[qvm->SP - 1]._int %= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_MODU:
- opStack[qvm->SP - 1]._uint %= opStack[qvm->SP]._uint;
- qvm->SP--;
- break;
-
- case OP_MULI:
- opStack[qvm->SP - 1]._int *= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_MULU:
- opStack[qvm->SP - 1]._uint *= opStack[qvm->SP]._uint;
- qvm->SP--;
- break;
- //bits
- case OP_BAND:
- opStack[qvm->SP - 1]._int &= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_BOR:
- opStack[qvm->SP - 1]._int |= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_BXOR:
- opStack[qvm->SP - 1]._int ^= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_BCOM:
- opStack[qvm->SP]._int = ~opStack[qvm->SP]._int;
- break;
-
- case OP_LSH:
- opStack[qvm->SP - 1]._int <<= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_RSHI:
- opStack[qvm->SP - 1]._int >>= opStack[qvm->SP]._int;
- qvm->SP--;
- break;
-
- case OP_RSHU:
- opStack[qvm->SP - 1]._uint >>= opStack[qvm->SP]._uint;
- qvm->SP--;
- break;
- //float arithmetic
- case OP_NEGF:
- opStack[qvm->SP]._float = -opStack[qvm->SP]._float;
- break;
-
- case OP_ADDF:
- opStack[qvm->SP - 1]._float += opStack[qvm->SP]._float;
- qvm->SP--;
- break;
-
- case OP_SUBF:
- opStack[qvm->SP - 1]._float -= opStack[qvm->SP]._float;
- qvm->SP--;
- break;
-
- case OP_MULF:
- opStack[qvm->SP - 1]._float *= opStack[qvm->SP]._float;
- qvm->SP--;
- break;
-
- case OP_DIVF:
- opStack[qvm->SP - 1]._float /= opStack[qvm->SP]._float;
- qvm->SP--;
- break;
-
- case OP_CVIF:
- opStack[qvm->SP]._float = opStack[qvm->SP]._int;
- break;
-
- case OP_CVFI:
- opStack[qvm->SP]._int = opStack[qvm->SP]._float;
- break;
- default:
- QVM_RunError( qvm, "invalid opcode %2.2x at off=%8x\n", op.opcode, qvm->PC - 1 );
- QVM_StackTrace( qvm );
- Sys_Error( "invalid opcode %2.2x at off=%8x\n", op.opcode, qvm->PC - 1 );
- }
-
- }
- while ( qvm->PC > 0 );
-
- ivar = opStack[qvm->SP]._int;
- qvm->PC = savePC;
- qvm->SP = saveSP;
- qvm->LP = saveLP;
- qvm->reenter--;
- return ivar;
-}
-/*
- QVM Debug stuff
-*/
-char *opcode_names[] = {
- "OP_UNDEF",
-
- "OP_IGNORE",
-
- "OP_BREAK",
-
- "OP_ENTER",
- "OP_LEAVE",
- "OP_CALL",
- "OP_PUSH",
- "OP_POP",
-
- "OP_CONST",
- "OP_LOCAL",
-
- "OP_JUMP",
-
- //-------------------
-
- "OP_EQ",
- "OP_NE",
-
- "OP_LTI",
- "OP_LEI",
- "OP_GTI",
- "OP_GEI",
-
- "OP_LTU",
- "OP_LEU",
- "OP_GTU",
- "OP_GEU",
-
- "OP_EQF",
- "OP_NEF",
-
- "OP_LTF",
- "OP_LEF",
- "OP_GTF",
- "OP_GEF",
-
- //-------------------
-
- "OP_LOAD1",
- "OP_LOAD2",
- "OP_LOAD4",
- "OP_STORE1",
- "OP_STORE2",
- "OP_STORE4", // *(stack[top-1]) = stack[yop
- "OP_ARG",
- "OP_BLOCK_COPY",
-
- //-------------------
-
- "OP_SEX8",
- "OP_SEX16",
-
- "OP_NEGI",
- "OP_ADD",
- "OP_SUB",
- "OP_DIVI",
- "OP_DIVU",
- "OP_MODI",
- "OP_MODU",
- "OP_MULI",
- "OP_MULU",
-
- "OP_BAND",
- "OP_BOR",
- "OP_BXOR",
- "OP_BCOM",
-
- "OP_LSH",
- "OP_RSHI",
- "OP_RSHU",
-
- "OP_NEGF",
- "OP_ADDF",
- "OP_SUBF",
- "OP_DIVF",
- "OP_MULF",
-
- "OP_CVIF",
- "OP_CVFI"
- };
-
-void PrintInstruction( qvm_t * qvm )
-{
- qvm_instruction_t op = qvm->cs[qvm->PC];
- Con_DPrintf( "PC %8x LP %8x SP %8x\n", qvm->PC, qvm->LP, qvm->SP );
-
- switch ( op.opcode )
- {
- case OP_ARG:
- case OP_ENTER:
- case OP_LEAVE:
- case OP_CONST:
- case OP_LOCAL:
- case OP_EQ:
- case OP_NE:
- case OP_LTI:
- case OP_LEI:
- case OP_GTI:
- case OP_GEI:
- case OP_LTU:
- case OP_LEU:
- case OP_GTU:
- case OP_GEU:
- case OP_EQF:
- case OP_NEF:
- case OP_LTF:
- case OP_LEF:
- case OP_GTF:
- case OP_GEF:
- case OP_BLOCK_COPY:
- Con_DPrintf( "%10.10s %8d\n", opcode_names[op.opcode], op.parm._int );
- break;
-
- default:
- Con_DPrintf( "%10.10s\n", opcode_names[op.opcode] );
- break;
-
- }
-
-}
-
-#endif /* USE_PR2 */
-
-#endif // !CLIENTONLY
diff --git a/src/pr2_vm.h b/src/pr2_vm.h
deleted file mode 100644
index 9cd030128..000000000
--- a/src/pr2_vm.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * QW262
- * Copyright (C) 2004 [sd] angel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- */
-
-#ifndef __PR2_VM_H__
-#define __PR2_VM_H__
-
-#define SAFE_QVM
-#define QVM_RUNAWAY_PROTECTION
-#define QVM_DATA_PROTECTION
-#define QVM_PROFILE
-
-#ifdef _WIN32
-#define EXPORT_FN __cdecl
-#else
-#define EXPORT_FN
-#endif
-
-#define OPSTACKSIZE 0x100
-#define MAX_PROC_CALL 100
-#define MAX_vmMain_Call 100
-#define MAX_CYCLES 3000000
-
-// this gives gcc warnings unfortunatelly
-//#define VM_POINTER(base,mask,x) ((x)?(void*)((char *)base+((x)&mask)):NULL)
-
-// #define VM_POINTER(base,mask,x) ((void*)((char *)base+((x)&mask)))
-void* VM_POINTER(byte* base, uintptr_t mask, intptr_t offset);
-
-// meag: can leave this right now only because it is only used to return pointers to edicts
-#define POINTER_TO_VM(base,mask,x) ((x)?(intptr_t)((char *)(x) - (char*)base)&mask:0)
-
-typedef union pr2val_s
-{
- stringptr_t string;
- float _float;
- intptr_t _int;
-} pr2val_t;
-
-typedef intptr_t (EXPORT_FN *sys_call_t) (intptr_t arg, ...);
-typedef int (*sys_callex_t) (byte *data, unsigned int mask, int fn, pr2val_t* arg);
-
-typedef enum vm_type_e
-{
- VM_NONE,
- VM_NATIVE,
- VM_BYTECODE
-} vm_type_t;
-
-
-typedef struct vm_s {
- // common
- vm_type_t type;
- char name[MAX_QPATH];
- // shared
- void *hInst;
- sys_call_t syscall;
-
- // native
- intptr_t (*vmMain) (int command, int arg0, int arg1, int arg2, int arg3,
- int arg4, int arg5, int arg6, int arg7, int arg8, int arg9,
- int arg10, int arg11);
-
- // whether or not pr2 references should be enabled (set on GAME_INIT)
- qbool pr2_references;
-} vm_t ;
-
-typedef enum
-{
- OP_UNDEF,
-
- OP_IGNORE,
-
- OP_BREAK,
-
- OP_ENTER,
- OP_LEAVE,
- OP_CALL,
- OP_PUSH,
- OP_POP,
-
- OP_CONST,
- OP_LOCAL,
-
- OP_JUMP,
-
- //-------------------
-
- OP_EQ,
- OP_NE,
-
- OP_LTI,
- OP_LEI,
- OP_GTI,
- OP_GEI,
-
- OP_LTU,
- OP_LEU,
- OP_GTU,
- OP_GEU,
-
- OP_EQF,
- OP_NEF,
-
- OP_LTF,
- OP_LEF,
- OP_GTF,
- OP_GEF,
-
- //-------------------
-
- OP_LOAD1,
- OP_LOAD2,
- OP_LOAD4,
- OP_STORE1,
- OP_STORE2,
- OP_STORE4, // *(stack[top-1]) = stack[yop
- OP_ARG,
- OP_BLOCK_COPY,
-
- //-------------------
-
- OP_SEX8,
- OP_SEX16,
-
- OP_NEGI,
- OP_ADD,
- OP_SUB,
- OP_DIVI,
- OP_DIVU,
- OP_MODI,
- OP_MODU,
- OP_MULI,
- OP_MULU,
-
- OP_BAND,
- OP_BOR,
- OP_BXOR,
- OP_BCOM,
-
- OP_LSH,
- OP_RSHI,
- OP_RSHU,
-
- OP_NEGF,
- OP_ADDF,
- OP_SUBF,
- OP_DIVF,
- OP_MULF,
-
- OP_CVIF,
- OP_CVFI
-} opcode_t;
-
-typedef union {
- int _int;
- unsigned int _uint;
- float _float;
-} qvm_parm_type_t;
-
-
-typedef struct {
- opcode_t opcode;
- qvm_parm_type_t parm;
-} qvm_instruction_t;
-
-typedef struct symbols_s
-{
- int off;
- int seg;
- struct symbols_s *next;
- char name[1];
-}symbols_t;
-
-typedef struct {
- // segments
- qvm_instruction_t *cs;
- unsigned char *ds; // DATASEG + LITSEG + BSSSEG
- unsigned char *ss; // q3asm add stack at end of BSSSEG, defaultsize = 0x10000
-
- // pointer registers
- int PC; // program counter, points to cs, goes up
- int SP; // operation stack pointer, initially 0, goes up index of opStack in QVM_Exec
- int LP; // subroutine stack/local vars space, initially points to end of ss
-
- // status
- int len_cs; // size of cs
- int len_ds; // size of ds align up to power of 2
- int ds_mask; // bit mask of len_ds
- int len_ss; // size of ss
-
- int cycles; // command cicles executed
- int reenter;
- symbols_t* sym_info;
- sys_callex_t syscall;
-} qvm_t;
-
-
-/*
-========================================================================
-
-QVM files
-
-========================================================================
-*/
-
-#define VM_MAGIC 0x12721444
-typedef struct
-{
- int vmMagic;
-
- int instructionCount;
-
- int codeOffset;
- int codeLength;
-
- int dataOffset;
- int dataLength;
- int litLength; // ( dataLength - litLength ) should be byteswapped on load
- int bssLength; // zero filled memory appended to datalength
-} vmHeader_t;
-
-typedef enum
-{
- CODESEG,
- DATASEG, // initialized 32 bit data, will be byte swapped
- LITSEG, // strings
- BSSSEG, // 0 filled
- NUM_SEGMENTS
-} segmentName_t;
-
-
-extern char* opcode_names[];
-extern void VM_Unload(vm_t *vm);
-vm_t* VM_Load(vm_t *vm, vm_type_t type, char *name,sys_call_t syscall,sys_callex_t syscallex);
-extern intptr_t VM_Call(vm_t *vm, int /*command*/, int /*arg0*/, int , int , int , int , int ,
- int , int , int , int , int , int /*arg11*/);
-void QVM_StackTrace( qvm_t * qvm );
-void VM_PrintInfo( vm_t * vm);
-
-#endif /* !__PR2_VM_H__ */
diff --git a/src/pr_cmds.c b/src/pr_cmds.c
index c70e9b299..9be324511 100644
--- a/src/pr_cmds.c
+++ b/src/pr_cmds.c
@@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static tokenizecontext_t pr1_tokencontext;
#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
-#define RETURN_STRING(s) (PR1_SetString(&((int *)pr_globals)[OFS_RETURN], s))
+#define RETURN_STRING(s) (PR1_SetString(&((int *)pr_globals)[OFS_RETURN], s))
/*
===============================================================================
@@ -127,7 +127,7 @@ void PF_setorigin (void)
e = G_EDICT(OFS_PARM0);
org = G_VECTOR(OFS_PARM1);
- VectorCopy (org, e->v.origin);
+ VectorCopy (org, e->v->origin);
SV_AntilagReset (e);
SV_LinkEdict (e, false);
}
@@ -150,9 +150,9 @@ void PF_setsize (void)
e = G_EDICT(OFS_PARM0);
min = G_VECTOR(OFS_PARM1);
max = G_VECTOR(OFS_PARM2);
- VectorCopy (min, e->v.mins);
- VectorCopy (max, e->v.maxs);
- VectorSubtract (max, min, e->v.size);
+ VectorCopy (min, e->v->mins);
+ VectorCopy (max, e->v->maxs);
+ VectorSubtract (max, min, e->v->size);
SV_LinkEdict (e, false);
}
@@ -182,33 +182,33 @@ static void PF_setmodel (void)
PR_RunError ("PF_setmodel: no precache: %s\n", m);
ok:
- e->v.model = G_INT(OFS_PARM1);
- e->v.modelindex = i;
+ e->v->model = G_INT(OFS_PARM1);
+ e->v->modelindex = i;
// if it is an inline model, get the size information for it
if (m[0] == '*')
{
mod = CM_InlineModel (m);
- VectorCopy (mod->mins, e->v.mins);
- VectorCopy (mod->maxs, e->v.maxs);
- VectorSubtract (mod->maxs, mod->mins, e->v.size);
+ VectorCopy (mod->mins, e->v->mins);
+ VectorCopy (mod->maxs, e->v->maxs);
+ VectorSubtract (mod->maxs, mod->mins, e->v->size);
SV_LinkEdict (e, false);
}
else if (pr_nqprogs)
{
// hacks to make NQ progs happy
- if (!strcmp(PR1_GetString(e->v.model), "maps/b_explob.bsp"))
+ if (!strcmp(PR1_GetString(e->v->model), "maps/b_explob.bsp"))
{
- VectorClear (e->v.mins);
- VectorSet (e->v.maxs, 32, 32, 64);
+ VectorClear (e->v->mins);
+ VectorSet (e->v->maxs, 32, 32, 64);
}
else
{
// FTE does this, so we do, too; I'm not sure if it makes a difference
- VectorSet (e->v.mins, -16, -16, -16);
- VectorSet (e->v.maxs, 16, 16, 16);
+ VectorSet (e->v->mins, -16, -16, -16);
+ VectorSet (e->v->maxs, 16, 16, 16);
}
- VectorSubtract (e->v.maxs, e->v.mins, e->v.size);
+ VectorSubtract (e->v->maxs, e->v->mins, e->v->size);
SV_LinkEdict (e, false);
}
}
@@ -726,11 +726,11 @@ int PF_newcheckclient (int check)
if (i == check)
break; // didn't find anything else
- if (ent->e->free)
+ if (ent->e.free)
continue;
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
continue;
- if ((int)ent->v.flags & FL_NOTARGET)
+ if ((int)ent->v->flags & FL_NOTARGET)
continue;
// anything that is a client, or has a client as an enemy
@@ -738,7 +738,7 @@ int PF_newcheckclient (int check)
}
// get the PVS for the entity
- VectorAdd (ent->v.origin, ent->v.view_ofs, org);
+ VectorAdd (ent->v->origin, ent->v->view_ofs, org);
checkpvs = CM_LeafPVS (CM_PointInLeaf(org));
return i;
@@ -776,7 +776,7 @@ static void PF_checkclient (void)
// return check if it might be visible
ent = EDICT_NUM(sv.lastcheck);
- if (ent->e->free || ent->v.health <= 0)
+ if (ent->e.free || ent->v->health <= 0)
{
RETURN_EDICT(sv.edicts);
return;
@@ -784,7 +784,7 @@ static void PF_checkclient (void)
// if current entity can't possibly see the check entity, return 0
self = PROG_TO_EDICT(pr_global_struct->self);
- VectorAdd (self->v.origin, self->v.view_ofs, vieworg);
+ VectorAdd (self->v->origin, self->v->view_ofs, vieworg);
l = CM_Leafnum(CM_PointInLeaf(vieworg)) - 1;
if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) )
{
@@ -1228,15 +1228,15 @@ static void PF_findradius (void)
for (i = 0; i < numtouch; i++)
{
ent = touchlist[i];
- if (ent->v.solid == SOLID_NOT)
+ if (ent->v->solid == SOLID_NOT)
continue; // FIXME?
for (j = 0; j < 3; j++)
- eorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j]) * 0.5);
+ eorg[j] = org[j] - (ent->v->origin[j] + (ent->v->mins[j] + ent->v->maxs[j]) * 0.5);
if (DotProduct(eorg, eorg) > rad_2)
continue;
- ent->v.chain = EDICT_TO_PROG(chain);
+ ent->v->chain = EDICT_TO_PROG(chain);
chain = ent;
}
@@ -1315,7 +1315,7 @@ void PF_Find (void)
for (e++ ; e < sv.num_edicts ; e++)
{
ed = EDICT_NUM(e);
- if (ed->e->free)
+ if (ed->e.free)
continue;
t = E_STRING(ed,f);
if (!t)
@@ -1457,7 +1457,7 @@ void PF_walkmove (void)
yaw = G_FLOAT(OFS_PARM0);
dist = G_FLOAT(OFS_PARM1);
- if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+ if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
{
G_FLOAT(OFS_RETURN) = 0;
return;
@@ -1496,19 +1496,19 @@ void PF_droptofloor (void)
ent = PROG_TO_EDICT(pr_global_struct->self);
- VectorCopy (ent->v.origin, end);
+ VectorCopy (ent->v->origin, end);
end[2] -= 256;
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, end, false, ent);
if (trace.fraction == 1 || trace.allsolid)
G_FLOAT(OFS_RETURN) = 0;
else
{
- VectorCopy (trace.endpos, ent->v.origin);
+ VectorCopy (trace.endpos, ent->v->origin);
SV_LinkEdict (ent, false);
- ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);
+ ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+ ent->v->groundentity = EDICT_TO_PROG(trace.e.ent);
G_FLOAT(OFS_RETURN) = 1;
}
}
@@ -1624,7 +1624,7 @@ void PF_nextent (void)
return;
}
ent = EDICT_NUM(i);
- if (!ent->e->free)
+ if (!ent->e.free)
{
RETURN_EDICT(ent);
return;
@@ -1658,9 +1658,9 @@ void PF_changeyaw (void)
float ideal, current, move, speed;
ent = PROG_TO_EDICT(pr_global_struct->self);
- current = anglemod( ent->v.angles[1] );
- ideal = ent->v.ideal_yaw;
- speed = ent->v.yaw_speed;
+ current = anglemod( ent->v->angles[1] );
+ ideal = ent->v->ideal_yaw;
+ speed = ent->v->yaw_speed;
if (current == ideal)
return;
@@ -1686,7 +1686,7 @@ void PF_changeyaw (void)
move = -speed;
}
- ent->v.angles[1] = anglemod (current + move);
+ ent->v->angles[1] = anglemod (current + move);
}
/*
@@ -1786,7 +1786,7 @@ static void NQP_Skip (int count)
nqp_buf.cursize -= count;
}
-static void NQP_Process(void)
+static void NQP_Process (void)
{
int cmd;
@@ -1830,16 +1830,13 @@ static void NQP_Process(void)
else if (cmd == nq_svc_setview) {
if (nqp_buf.cursize < 3)
goto waitformore;
- // nq_svc_setview
- NQP_Skip(3); // TODO: make an extension for this
+ NQP_Skip (3); // TODO: make an extension for this
}
- else if (cmd == svc_updatefrags) {
+ else if (cmd == svc_updatefrags)
nqp_expect = 4;
- }
else if (cmd == nq_svc_updatecolors) {
- if (nqp_buf.cursize < 3) {
+ if (nqp_buf.cursize < 3)
goto waitformore;
- }
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
MSG_WriteByte (&sv.reliable_datagram, nqp_buf_data[1]);
MSG_WriteString (&sv.reliable_datagram, "topcolor");
@@ -1853,14 +1850,12 @@ static void NQP_Process(void)
else if (cmd == nq_svc_updatename) {
int slot;
byte *p;
- if (nqp_buf.cursize < 3) {
+ if (nqp_buf.cursize < 3)
goto waitformore;
- }
slot = nqp_buf_data[1];
p = (byte *)memchr (nqp_buf_data + 2, 0, nqp_buf.cursize - 2);
- if (!p) {
+ if (!p)
goto waitformore;
- }
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
MSG_WriteByte (&sv.reliable_datagram, slot);
MSG_WriteString (&sv.reliable_datagram, "name");
@@ -1875,97 +1870,84 @@ static void NQP_Process(void)
NQP_Skip ((p - nqp_buf_data) + 1);
}
else if (cmd == svc_cdtrack) {
- if (nqp_buf.cursize < 3) {
+ if (nqp_buf.cursize < 3)
goto waitformore;
- }
NQP_Flush (2);
NQP_Skip (1);
}
else if (cmd == svc_finale) {
byte *p = (byte *)memchr (nqp_buf_data + 1, 0, nqp_buf.cursize - 1);
- if (!p) {
+ if (!p)
goto waitformore;
- }
nqp_expect = (p - nqp_buf_data) + 1;
}
else if (cmd == svc_intermission) {
int i;
NQP_Flush (1);
- for (i = 0; i < 3; i++) {
- MSG_WriteCoord(&sv.reliable_datagram, svs.clients[0].edict->v.origin[i]);
- }
- for (i = 0; i < 3; i++) {
- MSG_WriteAngle(&sv.reliable_datagram, svs.clients[0].edict->v.angles[i]);
- }
+ for (i = 0; i < 3; i++)
+ MSG_WriteCoord (&sv.reliable_datagram, svs.clients[0].edict->v->origin[i]);
+ for (i = 0; i < 3; i++)
+ MSG_WriteAngle (&sv.reliable_datagram, svs.clients[0].edict->v->angles[i]);
}
else if (cmd == nq_svc_cutscene) {
byte *p = (byte *)memchr (nqp_buf_data + 1, 0, nqp_buf.cursize - 1);
- if (!p) {
+ if (!p)
goto waitformore;
- }
MSG_WriteByte (&sv.reliable_datagram, svc_stufftext);
MSG_WriteString (&sv.reliable_datagram, "//cutscene\n"); // ZQ extension
NQP_Skip (p - nqp_buf_data + 1);
}
- else if (cmd == svc_temp_entity) {
+ else if (nqp_buf_data[0] == svc_temp_entity) {
if (nqp_buf.cursize < 2)
break;
- switch (nqp_buf_data[1]) {
- case TE_SPIKE:
- case TE_SUPERSPIKE:
- case TE_EXPLOSION:
- case TE_TAREXPLOSION:
- case TE_WIZSPIKE:
- case TE_KNIGHTSPIKE:
- case TE_LAVASPLASH:
- case TE_TELEPORT:
- if (nqp_buf.cursize < 2 + 3 * msg_coordsize) {
- goto waitformore;
- }
- NQP_Flush(2 + 3 * msg_coordsize);
- break;
- case TE_GUNSHOT:
- if (nqp_buf.cursize < 2 + 3 * msg_coordsize) {
- goto waitformore;
- }
- NQP_Flush(2);
- MSG_WriteByte(&sv.reliable_datagram, 1);
- NQP_Flush(3 * msg_coordsize);
- break;
+switch (nqp_buf_data[1]) {
+ case TE_SPIKE:
+ case TE_SUPERSPIKE:
+ case TE_EXPLOSION:
+ case TE_TAREXPLOSION:
+ case TE_WIZSPIKE:
+ case TE_KNIGHTSPIKE:
+ case TE_LAVASPLASH:
+ case TE_TELEPORT:
+ nqp_expect = 8;
+ break;
+ case TE_GUNSHOT:
+ if (nqp_buf.cursize < 8)
+ goto waitformore;
+ NQP_Flush (2);
+ MSG_WriteByte (&sv.reliable_datagram, 1);
+ NQP_Flush (6);
+ break;
- case TE_LIGHTNING1:
- case TE_LIGHTNING2:
- case TE_LIGHTNING3:
- if (nqp_buf.cursize < 2 + 2 + 6 * msg_coordsize) {
- goto waitformore;
- }
- NQP_Flush(4 + 6 * msg_coordsize);
- break;
- case NQ_TE_BEAM:
- {
- int entnum;
- if (nqp_buf.cursize < 4 + 6 * msg_coordsize) {
- goto waitformore;
- }
- MSG_WriteByte(&sv.reliable_datagram, svc_temp_entity);
- MSG_WriteByte(&sv.reliable_datagram, TE_LIGHTNING1);
- entnum = nqp_buf_data[2] + nqp_buf_data[3] * 256;
- if ((unsigned int)entnum > 1023)
- entnum = 0;
- MSG_WriteShort(&sv.reliable_datagram, (short)(entnum - 1288));
- NQP_Skip(4);
- NQP_Flush(6 * msg_coordsize);
- break;
- }
+ case TE_LIGHTNING1:
+ case TE_LIGHTNING2:
+ case TE_LIGHTNING3:
+ nqp_expect = 16;
+ break;
+ case NQ_TE_BEAM:
+ { int entnum;
+ if (nqp_buf.cursize < 16)
+ goto waitformore;
+ MSG_WriteByte (&sv.reliable_datagram, svc_temp_entity);
+ MSG_WriteByte (&sv.reliable_datagram, TE_LIGHTNING1);
+ entnum = nqp_buf_data[2] + nqp_buf_data[3]*256;
+ if ((unsigned int)entnum > 1023)
+ entnum = 0;
+ MSG_WriteShort (&sv.reliable_datagram, (short)(entnum - 1288));
+ NQP_Skip (4);
+ nqp_expect = 12;
+ break;
+ }
+
+ case NQ_TE_EXPLOSION2:
+ nqp_expect = 10;
+ break;
+ default:
+ Con_Printf ("WARNING: progs.dat sent an unsupported svc_temp_entity: %i\n", nqp_buf_data[1]);
+ goto ignore;
+}
- case NQ_TE_EXPLOSION2:
- // TODO: Convert to TE_BLOOD (2 + 3 * coord + 2 bytes)
- break;
- default:
- Con_Printf("WARNING: progs.dat sent an unsupported svc_temp_entity: %i\n", nqp_buf_data[1]);
- goto ignore;
- }
}
else {
Con_Printf ("WARNING: progs.dat sent an unsupported svc: %i\n", cmd);
@@ -2236,16 +2218,16 @@ void PF_makestatic (void)
s = &sv.static_entities[sv.static_entity_count];
memset(s, 0, sizeof(sv.static_entities[0]));
s->number = sv.static_entity_count + 1;
- s->modelindex = SV_ModelIndex(PR_GetEntityString(ent->v.model));
+ s->modelindex = SV_ModelIndex(PR_GetEntityString(ent->v->model));
if (!s->modelindex) {
ED_Free (ent);
return;
}
- s->frame = ent->v.frame;
- s->colormap = ent->v.colormap;
- s->skinnum = ent->v.skin;
- VectorCopy(ent->v.origin, s->origin);
- VectorCopy(ent->v.angles, s->angles);
+ s->frame = ent->v->frame;
+ s->colormap = ent->v->colormap;
+ s->skinnum = ent->v->skin;
+ VectorCopy(ent->v->origin, s->origin);
+ VectorCopy(ent->v->angles, s->angles);
++sv.static_entity_count;
// throw the entity away now
@@ -2854,4 +2836,4 @@ void PR_InitBuiltins (void)
}
}
-#endif // CLIENTONLY
+#endif // CLIENTONLY
\ No newline at end of file
diff --git a/src/pr_edict.c b/src/pr_edict.c
index 3ac261d11..2115f64d5 100644
--- a/src/pr_edict.c
+++ b/src/pr_edict.c
@@ -92,9 +92,9 @@ Sets everything to NULL
*/
void ED_ClearEdict (edict_t *e)
{
- memset(&e->v, 0, pr_edict_size - sizeof(edict_t) + sizeof(entvars_t));
- e->e->lastruntime = 0;
- e->e->free = false;
+ memset(e->v, 0, pr_edict_size);
+ e->e.lastruntime = 0;
+ e->e.free = false;
PR_ClearEdict(e);
}
@@ -119,7 +119,7 @@ edict_t *ED_Alloc (void)
e = EDICT_NUM(i);
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
- if (e->e->free && (e->e->freetime < 2 || sv.time - e->e->freetime > 0.5))
+ if (e->e.free && (e->e.freetime < 2 || sv.time - e->e.freetime > 0.5))
{
ED_ClearEdict(e);
return e;
@@ -156,21 +156,21 @@ void ED_Free (edict_t *ed)
{
SV_UnlinkEdict (ed); // unlink from world bsp
- ed->e->free = true;
- ed->v.model = 0;
- ed->v.takedamage = 0;
- ed->v.modelindex = 0;
- ed->v.colormap = 0;
- ed->v.skin = 0;
- ed->v.frame = 0;
- ed->v.health = 0;
- ed->v.classname = 0;
- VectorClear (ed->v.origin);
- VectorClear (ed->v.angles);
- ed->v.nextthink = -1;
- ed->v.solid = 0;
-
- ed->e->freetime = sv.time;
+ ed->e.free = true;
+ ed->v->model = 0;
+ ed->v->takedamage = 0;
+ ed->v->modelindex = 0;
+ ed->v->colormap = 0;
+ ed->v->skin = 0;
+ ed->v->frame = 0;
+ ed->v->health = 0;
+ ed->v->classname = 0;
+ VectorClear (ed->v->origin);
+ VectorClear (ed->v->angles);
+ ed->v->nextthink = -1;
+ ed->v->solid = 0;
+
+ ed->e.freetime = sv.time;
}
//===========================================================================
@@ -324,7 +324,7 @@ eval_t *PR1_GetEdictFieldValue(edict_t *ed, char *field)
if (!def)
return NULL;
- return (eval_t *)((char *)&ed->v + def->ofs*4);
+ return (eval_t *)((char *)ed->v + def->ofs*4);
}
/*
@@ -500,7 +500,7 @@ void ED_Print (edict_t *ed)
char *name;
int type;
- if (ed->e->free)
+ if (ed->e.free)
{
Con_Printf ("FREE\n");
return;
@@ -513,7 +513,7 @@ void ED_Print (edict_t *ed)
if (name[strlen(name)-2] == '_')
continue; // skip _x, _y, _z vars
- v = (int *)((char *)&ed->v + d->ofs*4);
+ v = (int *)((char *)ed->v + d->ofs*4);
// if the value is still all 0, skip the field
type = d->type & ~DEF_SAVEGLOBAL;
@@ -554,7 +554,7 @@ void ED_Write (FILE *f, edict_t *ed)
fprintf (f, "{\n");
- if (ed->e->free)
+ if (ed->e.free)
{
fprintf (f, "}\n");
return;
@@ -567,7 +567,7 @@ void ED_Write (FILE *f, edict_t *ed)
if (name[strlen(name)-2] == '_')
continue; // skip _x, _y, _z vars
- v = (int *)((char *)&ed->v + d->ofs*4);
+ v = (int *)((char *)ed->v + d->ofs*4);
// if the value is still all 0, skip the field
type = d->type & ~DEF_SAVEGLOBAL;
@@ -653,14 +653,14 @@ void ED_Count (void)
for (i=0 ; ie->free)
+ if (ent->e.free)
continue;
active++;
- if (ent->v.solid)
+ if (ent->v->solid)
solid++;
- if (ent->v.model)
+ if (ent->v->model)
models++;
- if (ent->v.movetype == MOVETYPE_STEP)
+ if (ent->v->movetype == MOVETYPE_STEP)
step++;
}
@@ -936,12 +936,12 @@ const char *ED_ParseEdict (const char *data, edict_t *ent)
snprintf (com_token, MAX_COM_TOKEN, "0 %s 0", temp);
}
- if (!ED_ParseEpair ((void *)&ent->v, key, com_token))
+ if (!ED_ParseEpair ((void *)ent->v, key, com_token))
SV_Error ("ED_ParseEdict: parse error");
}
if (!init)
- ent->e->free = true;
+ ent->e.free = true;
return data;
}
@@ -991,16 +991,16 @@ void ED_LoadFromFile (const char *data)
// remove things from different skill levels or deathmatch
if ((int)deathmatch.value)
{
- if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
+ if (((int)ent->v->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
{
ED_Free (ent);
inhibit++;
continue;
}
}
- else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY))
- || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))
- || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) )
+ else if ((current_skill == 0 && ((int)ent->v->spawnflags & SPAWNFLAG_NOT_EASY))
+ || (current_skill == 1 && ((int)ent->v->spawnflags & SPAWNFLAG_NOT_MEDIUM))
+ || (current_skill >= 2 && ((int)ent->v->spawnflags & SPAWNFLAG_NOT_HARD)) )
{
ED_Free (ent);
inhibit++;
@@ -1010,7 +1010,7 @@ void ED_LoadFromFile (const char *data)
//
// immediately call spawn function
//
- if (!ent->v.classname)
+ if (!ent->v->classname)
{
Con_Printf ("No classname for:\n");
ED_Print (ent);
@@ -1019,7 +1019,7 @@ void ED_LoadFromFile (const char *data)
}
// look for the spawn function
- func = ED_FindFunction ( PR1_GetString(ent->v.classname) );
+ func = ED_FindFunction ( PR1_GetString(ent->v->classname) );
if (!func)
{
@@ -1187,7 +1187,7 @@ void PR1_LoadProgs (void)
pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
pr_globals = (float *)pr_global_struct;
- pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);
+ pr_edict_size = progs->entityfields * 4;
// byte swap the lumps
for (i = 0; i < progs->numstatements; i++)
@@ -1232,7 +1232,7 @@ void PR1_LoadProgs (void)
void PR1_InitProg(void)
{
- sv.edicts = (edict_t*) Hunk_AllocName (MAX_EDICTS * pr_edict_size, "edicts");
+ sv.game_edicts = (entvars_t*) Hunk_AllocName (MAX_EDICTS * pr_edict_size, "edicts");
sv.max_edicts = MAX_EDICTS;
}
@@ -1260,15 +1260,14 @@ edict_t *EDICT_NUM(int n)
{
if (n < 0 || n >= sv.max_edicts)
SV_Error ("EDICT_NUM: bad number %i", n);
- return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);
+ return &sv.edicts[n];
}
int NUM_FOR_EDICT(edict_t *e)
{
int b;
- b = (byte *)e - (byte *)sv.edicts;
- b /= pr_edict_size;
+ b = e->e.entnum;
if (b < 0 || b >= sv.num_edicts)
SV_Error ("NUM_FOR_EDICT: bad pointer");
diff --git a/src/pr_exec.c b/src/pr_exec.c
index 7c07fe392..1a302349d 100644
--- a/src/pr_exec.c
+++ b/src/pr_exec.c
@@ -546,11 +546,11 @@ void PR_ExecuteProgram (func_t fnum)
case OP_STOREP_FLD: // integers
case OP_STOREP_S:
case OP_STOREP_FNC: // pointers
- ptr = (eval_t *)((byte *)sv.edicts + b->_int);
+ ptr = (eval_t *)((byte *)sv.game_edicts + b->_int);
ptr->_int = a->_int;
break;
case OP_STOREP_V:
- ptr = (eval_t *)((byte *)sv.edicts + b->_int);
+ ptr = (eval_t *)((byte *)sv.game_edicts + b->_int);
ptr->vector[0] = a->vector[0];
ptr->vector[1] = a->vector[1];
ptr->vector[2] = a->vector[2];
@@ -563,7 +563,7 @@ void PR_ExecuteProgram (func_t fnum)
#endif
if (ed == (edict_t *)sv.edicts && sv.state == ss_active)
PR_RunError ("assignment to world entity");
- c->_int = (byte *)((int *)&ed->v + PR_FIELDOFS(b->_int)) - (byte *)sv.edicts;
+ c->_int = (byte *)((int *)ed->v + PR_FIELDOFS(b->_int)) - (byte *)sv.game_edicts;
break;
case OP_LOAD_F:
@@ -578,7 +578,7 @@ void PR_ExecuteProgram (func_t fnum)
//need for checking 'cmd mmode player N', if N >= 0x10000000 =(signed)=> negative
if (b->_int >= 0)
{
- a = (eval_t *)((int *)&ed->v + PR_FIELDOFS(b->_int));
+ a = (eval_t *)((int *)ed->v + PR_FIELDOFS(b->_int));
c->_int = a->_int;
}
else
@@ -590,7 +590,7 @@ void PR_ExecuteProgram (func_t fnum)
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
#endif
- a = (eval_t *)((int *)&ed->v + PR_FIELDOFS(b->_int));
+ a = (eval_t *)((int *)ed->v + PR_FIELDOFS(b->_int));
c->vector[0] = a->vector[0];
c->vector[1] = a->vector[1];
c->vector[2] = a->vector[2];
@@ -653,12 +653,12 @@ void PR_ExecuteProgram (func_t fnum)
case OP_STATE:
ed = PROG_TO_EDICT(pr_global_struct->self);
- ed->v.nextthink = pr_global_struct->time + 0.1;
- if (a->_float != ed->v.frame)
+ ed->v->nextthink = pr_global_struct->time + 0.1;
+ if (a->_float != ed->v->frame)
{
- ed->v.frame = a->_float;
+ ed->v->frame = a->_float;
}
- ed->v.think = b->function;
+ ed->v->think = b->function;
break;
default:
diff --git a/src/progs.h b/src/progs.h
index 8751ced78..00055292b 100644
--- a/src/progs.h
+++ b/src/progs.h
@@ -65,12 +65,8 @@ typedef struct sv_edict_s
typedef struct edict_s
{
- sv_edict_t *e; // server side part of the edict_t,
- // basically we can get rid of this pointer at all, since we can access it via sv.sv_edicts[num]
- // but this way it more friendly, I think.
-
- entvars_t v; // C exported fields from progs
- // other fields from progs come immediately after
+ sv_edict_t e; // server side part of the edict_t
+ entvars_t *v; // C exported fields from progs
} edict_t;
//============================================================================
@@ -142,25 +138,25 @@ void ED_LoadFromFile (const char *data);
edict_t *EDICT_NUM(int n);
int NUM_FOR_EDICT(edict_t *e);
-#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))
+#define NEXT_EDICT(e) ((edict_t *)((byte *)(e) + sizeof(edict_t)))
-#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)
-#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))
+#define EDICT_TO_PROG(e) ((byte *)(e)->v - (byte *)sv.game_edicts)
+#define PROG_TO_EDICT(e) (&sv.edicts[(e)/pr_edict_size])
//============================================================================
#define G_FLOAT(o) (pr_globals[o])
#define G_INT(o) (*(int *)&pr_globals[o])
-#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))
+#define G_EDICT(o) (&sv.edicts[(*(int *)&pr_globals[o])/pr_edict_size])
#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))
#define G_VECTOR(o) (&pr_globals[o])
#define G_STRING(o) (PR1_GetString(*(string_t *)&pr_globals[o]))
#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
-#define E_FLOAT(e,o) (((float*)&e->v)[o])
-#define E_INT(e,o) (*(int *)&((float*)&e->v)[o])
-#define E_VECTOR(e,o) (&((float*)&e->v)[o])
-#define E_STRING(e,o) (PR1_GetString(*(string_t *)&((float*)&e->v)[PR_FIELDOFS(o)]))
+#define E_FLOAT(e,o) (((float*)e->v)[o])
+#define E_INT(e,o) (*(int *)&((float*)e->v)[o])
+#define E_VECTOR(e,o) (&((float*)e->v)[o])
+#define E_STRING(e,o) (PR1_GetString(*(string_t *)&((float*)e->v)[PR_FIELDOFS(o)]))
typedef void (*builtin_t) (void);
extern builtin_t *pr_builtins;
@@ -188,8 +184,8 @@ extern int fofs_visibility;
extern int fofs_hide_players;
extern int fofs_teleported;
-#define EdictFieldFloat(ed, fieldoffset) ((eval_t *)((byte *)&(ed)->v + (fieldoffset)))->_float
-#define EdictFieldVector(ed, fieldoffset) ((eval_t *)((byte *)&(ed)->v + (fieldoffset)))->vector
+#define EdictFieldFloat(ed, fieldoffset) ((eval_t *)((byte *)(ed)->v + (fieldoffset)))->_float
+#define EdictFieldVector(ed, fieldoffset) ((eval_t *)((byte *)(ed)->v + (fieldoffset)))->vector
void PR_RunError (char *error, ...);
@@ -233,7 +229,7 @@ qbool PR1_ClientCmd(void);
#define PR1_GameSetNewParms() PR_ExecuteProgram(PR_GLOBAL(SetNewParms))
#define PR1_GameStartFrame() PR_ExecuteProgram (PR_GLOBAL(StartFrame))
#define PR1_ClientKill() PR_ExecuteProgram (PR_GLOBAL(ClientKill))
-#define PR1_UserInfoChanged() (0) // PR1 does not really have it,
+#define PR1_UserInfoChanged(after) (0) // PR1 does not really have it,
// we have mod_UserInfo_Changed but it is slightly different.
#define PR1_LoadEnts ED_LoadFromFile
#define PR1_EdictThink PR_ExecuteProgram
diff --git a/src/q_platform.h b/src/q_platform.h
new file mode 100644
index 000000000..e0b3aac4a
--- /dev/null
+++ b/src/q_platform.h
@@ -0,0 +1,466 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#ifndef __Q_PLATFORM_H
+#define __Q_PLATFORM_H
+
+// this is for determining if we have an asm version of a C function
+#define idx64 0
+
+#ifdef Q3_VM
+
+#define idx386 0
+#define idppc 0
+#define idppc_altivec 0
+#define idsparc 0
+
+#else
+
+#if (defined _M_IX86 || defined __i386__) && !defined(C_ONLY)
+#define idx386 1
+#else
+#define idx386 0
+#endif
+
+#if (defined(powerc) || defined(powerpc) || defined(ppc) || \
+ defined(__ppc) || defined(__ppc__)) && !defined(C_ONLY)
+#define idppc 1
+#if defined(__VEC__)
+#define idppc_altivec 1
+#ifdef MACOS_X // Apple's GCC does this differently than the FSF.
+#define VECCONST_UINT8(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
+ (vector unsigned char) (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)
+#else
+#define VECCONST_UINT8(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
+ (vector unsigned char) {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
+#endif
+#else
+#define idppc_altivec 0
+#endif
+#else
+#define idppc 0
+#define idppc_altivec 0
+#endif
+
+#if defined(__sparc__) && !defined(C_ONLY)
+#define idsparc 1
+#else
+#define idsparc 0
+#endif
+
+#endif
+
+#ifndef __ASM_I386__ // don't include the C bits if included from qasm.h
+
+// for windows fastcall option
+#define QDECL
+
+//================================================================= WIN64/32 ===
+
+#if defined(_WIN64) || defined(__WIN64__)
+
+#undef idx64
+#define idx64 1
+
+#undef QDECL
+#define QDECL __cdecl
+
+#if defined( _MSC_VER )
+#define OS_STRING "win_msvc64"
+#elif defined __MINGW64__
+#define OS_STRING "win_mingw64"
+#else
+#define OS_STRING "win64"
+#endif
+
+#define ID_INLINE static __inline
+#define PATH_SEPARATOR "\\"
+
+#if defined( __WIN64__ )
+#define ARCH_STRING "x86_64"
+#elif defined _M_ALPHA
+#define ARCH_STRING "AXP"
+#endif
+
+#define Q3_LITTLE_ENDIAN
+
+#define DLEXT "dll"
+
+#elif defined(_WIN32) || defined(__WIN32__)
+
+#undef QDECL
+#define QDECL __cdecl
+
+#if defined( _MSC_VER )
+#define OS_STRING "win_msvc"
+#elif defined __MINGW32__
+#define OS_STRING "win_mingw"
+#endif
+
+#define ID_INLINE static __inline
+#define PATH_SEPARATOR "\\"
+
+#if defined( _M_IX86 ) || defined( __i386__ )
+#define ARCH_STRING "x86"
+#elif defined _M_ALPHA
+#define ARCH_STRING "AXP"
+#endif
+
+#define Q3_LITTLE_ENDIAN
+
+#define DLEXT "dll"
+
+#endif
+
+//============================================================== MAC OS X ===
+
+#if defined(MACOS_X) || defined(__APPLE_CC__)
+
+// make sure this is defined, just for sanity's sake...
+#ifndef MACOS_X
+#define MACOS_X
+#endif
+
+#define OS_STRING "macosx"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#ifdef __ppc__
+#define ARCH_STRING "ppc"
+#define Q3_BIG_ENDIAN
+#elif defined __i386__
+#define ARCH_STRING "i386"
+#define Q3_LITTLE_ENDIAN
+#elif defined __x86_64__
+#undef idx64
+#define idx64 1
+#define ARCH_STRING "x86_64"
+#define Q3_LITTLE_ENDIAN
+#endif
+
+#define DLEXT "dylib"
+
+#endif
+
+//================================================================= LINUX ===
+
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(ANDROID) || defined(__ANDROID__)
+
+#include
+
+#if defined(ANDROID) || defined(__ANDROID__)
+#define OS_STRING "android"
+#elif defined(__linux__)
+#define OS_STRING "linux"
+#else
+#define OS_STRING "kFreeBSD"
+#endif
+
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#if defined __i386__
+#define ARCH_STRING "i386"
+#elif defined __x86_64__
+#undef idx64
+#define idx64 1
+#define ARCH_STRING "x86_64"
+#elif defined __powerpc64__
+#define ARCH_STRING "ppc64"
+#elif defined __powerpc__
+#define ARCH_STRING "ppc"
+#elif defined __s390__
+#define ARCH_STRING "s390"
+#elif defined __s390x__
+#define ARCH_STRING "s390x"
+#elif defined __ia64__
+#define ARCH_STRING "ia64"
+#elif defined __alpha__
+#define ARCH_STRING "alpha"
+#elif defined __sparc__
+#define ARCH_STRING "sparc"
+#elif defined __arm__
+#define ARCH_STRING "arm"
+#elif defined __cris__
+#define ARCH_STRING "cris"
+#elif defined __hppa__
+#define ARCH_STRING "hppa"
+#elif defined __mips__
+#define ARCH_STRING "mips"
+#elif defined __sh__
+#define ARCH_STRING "sh"
+#endif
+
+#if __FLOAT_WORD_ORDER == __BIG_ENDIAN
+#define Q3_BIG_ENDIAN
+#else
+#define Q3_LITTLE_ENDIAN
+#endif
+
+#define DLEXT "so"
+
+#endif
+
+//=================================================================== BSD ===
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+
+#include
+#include
+
+#ifndef __BSD__
+ #define __BSD__
+#endif
+
+#if defined(__FreeBSD__)
+#define OS_STRING "freebsd"
+#elif defined(__OpenBSD__)
+#define OS_STRING "openbsd"
+#elif defined(__NetBSD__)
+#define OS_STRING "netbsd"
+#endif
+
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#ifdef __i386__
+#define ARCH_STRING "i386"
+#elif defined __amd64__
+#undef idx64
+#define idx64 1
+#define ARCH_STRING "amd64"
+#elif defined __axp__
+#define ARCH_STRING "alpha"
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define Q3_BIG_ENDIAN
+#else
+#define Q3_LITTLE_ENDIAN
+#endif
+
+#define DLEXT "so"
+
+#endif
+
+//================================================================= SUNOS ===
+
+#ifdef __sun
+
+#include
+#include
+
+#define OS_STRING "solaris"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#ifdef __i386__
+#define ARCH_STRING "i386"
+#elif defined __sparc
+#define ARCH_STRING "sparc"
+#endif
+
+#if defined( _BIG_ENDIAN )
+#define Q3_BIG_ENDIAN
+#elif defined( _LITTLE_ENDIAN )
+#define Q3_LITTLE_ENDIAN
+#endif
+
+#define DLEXT "so"
+
+#endif
+
+//================================================================== IRIX ===
+
+#ifdef __sgi
+
+#define OS_STRING "irix"
+#define ID_INLINE static __inline
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "mips"
+
+#define Q3_BIG_ENDIAN // SGI's MIPS are always big endian
+
+#define DLEXT "so"
+
+#endif
+
+//=============================================================== MORPHOS ===
+
+#ifdef __MORPHOS__
+
+#define OS_STRING "morphos"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "ppc"
+
+#define Q3_BIG_ENDIAN
+
+#define DLEXT "so"
+
+#endif
+
+#ifdef __CYGWIN__
+#define OS_STRING "cygwin"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "x86"
+
+#define Q3_LITTLE_ENDIAN
+
+#define DLEXT "dll"
+
+#endif
+
+#ifdef __DJGPP__
+#define OS_STRING "msdos"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "dos"
+
+#define Q3_LITTLE_ENDIAN
+
+#define DLEXT "dll"
+#endif
+
+
+#ifdef FTE_TARGET_WEB
+#define OS_STRING "emscripten"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "web"
+
+#define Q3_LITTLE_ENDIAN
+
+#define DLEXT "so"
+#endif
+
+#ifdef NACL
+#define OS_STRING "nacl"
+#define ID_INLINE static inline
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "web"
+
+#define Q3_LITTLE_ENDIAN
+
+#define DLEXT "so"
+#endif
+
+//================================================================== Q3VM ===
+
+#ifdef Q3_VM
+
+#define OS_STRING "q3vm"
+#define ID_INLINE static
+#define PATH_SEPARATOR "/"
+
+#define ARCH_STRING "bytecode"
+
+#define DLEXT "qvm"
+
+#endif
+
+//===========================================================================
+
+//catch missing defines in above blocks
+#if !defined( OS_STRING )
+#define ARCH_STRING "unknown"
+//#error "Operating system not supported"
+#endif
+
+#if !defined( ARCH_STRING )
+#define ARCH_STRING "unk"
+//#error "Architecture not supported"
+#endif
+
+#ifndef ID_INLINE
+#define ID_INLINE static
+//#error "ID_INLINE not defined"
+#endif
+
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR "/"
+//#error "PATH_SEPARATOR not defined"
+#endif
+
+#ifndef DLEXT
+#define DLEXT "so"
+//#error "DLEXT not defined"
+#endif
+
+/*
+//endianness
+short ShortSwap (short l);
+int LongSwap (int l);
+float FloatSwap (const float *f);
+
+#if defined( Q3_BIG_ENDIAN ) && defined( Q3_LITTLE_ENDIAN )
+#error "Endianness defined as both big and little"
+#elif defined( Q3_BIG_ENDIAN )
+
+#define LittleShort(x) ShortSwap(x)
+#define LittleLong(x) LongSwap(x)
+#define LittleFloat(x) FloatSwap(&x)
+#define BigShort
+#define BigLong
+#define BigFloat
+
+#elif defined( Q3_LITTLE_ENDIAN )
+
+#define LittleShort
+#define LittleLong
+#define LittleFloat
+#define BigShort(x) ShortSwap(x)
+#define BigLong(x) LongSwap(x)
+#define BigFloat(x) FloatSwap(&x)
+
+#elif defined( Q3_VM )
+
+#define LittleShort
+#define LittleLong
+#define LittleFloat
+#define BigShort
+#define BigLong
+#define BigFloat
+
+#else
+#error "Endianness not defined"
+#endif
+*/
+
+
+//platform string
+#ifdef NDEBUG
+#define PLATFORM_STRING OS_STRING "-" ARCH_STRING
+#else
+#define PLATFORM_STRING OS_STRING "-" ARCH_STRING "-debug"
+#endif
+
+#endif
+
+#endif
diff --git a/src/qwsvdef.h b/src/qwsvdef.h
index b8e782218..56ca74409 100644
--- a/src/qwsvdef.h
+++ b/src/qwsvdef.h
@@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "net.h"
#include "crc.h"
#include "sha1.h"
+#include "sha3.h"
#include "pmove.h"
#include "version.h"
#include "sv_log.h"
diff --git a/src/server.h b/src/server.h
index 505f13fb8..70c8cd8fc 100644
--- a/src/server.h
+++ b/src/server.h
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "progs.h"
#ifdef USE_PR2
-#include "pr2_vm.h"
+#include "vm.h"
#include "pr2.h"
#include "g_public.h"
#endif
@@ -95,10 +95,10 @@ typedef struct
int num_edicts; // increases towards MAX_EDICTS
int num_baseline_edicts;// number of entities that have baselines
- edict_t *edicts; // can NOT be array indexed, because
- // edict_t is variable sized, but can
- // be used to reference the world ent
- sv_edict_t sv_edicts[MAX_EDICTS]; // part of the edict_t
+
+ edict_t edicts[MAX_EDICTS];
+ entvars_t *game_edicts; // can NOT be array indexed, because entvars_t is variable sized
+
int max_edicts; // might not MAX_EDICTS if mod allocates memory
byte *pvs, *phs; // fully expanded and decompressed
@@ -356,6 +356,7 @@ typedef struct client_s
int rip_vip;
double delay;
double disable_updates_stop; // Vladis
+ qbool maxping_met; // set if user meets maxping requirements
packet_t *packets, *last_packet;
#ifdef MVD_PEXT1_HIGHLAGTELEPORT
@@ -1007,6 +1008,7 @@ int Dem_CountTeamPlayers (char *t);
char *quote (char *str);
void CleanName_Init (void);
void SV_LastScores_f (void);
+void SV_LastStats_f (void);
void SV_DemoList_f (void);
void SV_DemoListRegex_f (void);
void SV_MVDRemove_f (void);
diff --git a/src/sv_ccmds.c b/src/sv_ccmds.c
index 11a27f500..e85b7b5c7 100644
--- a/src/sv_ccmds.c
+++ b/src/sv_ccmds.c
@@ -280,8 +280,8 @@ void SV_God_f (void)
if (!SV_SetPlayer ())
return;
- sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
- if (!((int)sv_player->v.flags & FL_GODMODE) )
+ sv_player->v->flags = (int)sv_player->v->flags ^ FL_GODMODE;
+ if (!((int)sv_player->v->flags & FL_GODMODE) )
SV_ClientPrintf (sv_client, PRINT_HIGH, "godmode OFF\n");
else
SV_ClientPrintf (sv_client, PRINT_HIGH, "godmode ON\n");
@@ -299,14 +299,14 @@ void SV_Noclip_f (void)
if (!SV_SetPlayer ())
return;
- if (sv_player->v.movetype != MOVETYPE_NOCLIP)
+ if (sv_player->v->movetype != MOVETYPE_NOCLIP)
{
- sv_player->v.movetype = MOVETYPE_NOCLIP;
+ sv_player->v->movetype = MOVETYPE_NOCLIP;
SV_ClientPrintf (sv_client, PRINT_HIGH, "noclip ON\n");
}
else
{
- sv_player->v.movetype = MOVETYPE_WALK;
+ sv_player->v->movetype = MOVETYPE_WALK;
SV_ClientPrintf (sv_client, PRINT_HIGH, "noclip OFF\n");
}
}
@@ -347,23 +347,23 @@ void SV_Give_f (void)
case '7':
case '8':
case '9':
- sv_player->v.items = (int)sv_player->v.items | IT_SHOTGUN<< (t[0] - '2');
+ sv_player->v->items = (int)sv_player->v->items | IT_SHOTGUN<< (t[0] - '2');
break;
case 's':
- sv_player->v.ammo_shells = v;
+ sv_player->v->ammo_shells = v;
break;
case 'n':
- sv_player->v.ammo_nails = v;
+ sv_player->v->ammo_nails = v;
break;
case 'r':
- sv_player->v.ammo_rockets = v;
+ sv_player->v->ammo_rockets = v;
break;
case 'h':
- sv_player->v.health = v;
+ sv_player->v->health = v;
break;
case 'c':
- sv_player->v.ammo_cells = v;
+ sv_player->v->ammo_cells = v;
break;
}
}
@@ -379,17 +379,17 @@ void SV_Fly_f (void)
if (!SV_SetPlayer ())
return;
- if (sv_player->v.solid != SOLID_SLIDEBOX)
+ if (sv_player->v->solid != SOLID_SLIDEBOX)
return; // dead don't fly
- if (sv_player->v.movetype != MOVETYPE_FLY)
+ if (sv_player->v->movetype != MOVETYPE_FLY)
{
- sv_player->v.movetype = MOVETYPE_FLY;
+ sv_player->v->movetype = MOVETYPE_FLY;
SV_ClientPrintf (sv_client, PRINT_HIGH, "flymode ON\n");
}
else
{
- sv_player->v.movetype = MOVETYPE_WALK;
+ sv_player->v->movetype = MOVETYPE_WALK;
SV_ClientPrintf (sv_client, PRINT_HIGH, "flymode OFF\n");
}
}
@@ -485,6 +485,9 @@ void SV_Map (qbool now)
// check to make sure the level exists
snprintf (expanded, MAX_QPATH, "maps/%s.bsp", level);
+ // Flush FS cache on each map change.
+ FS_FlushFSHash();
+
if (!FS_FLocateFile(expanded, FSLFRT_IFFOUND, NULL))
{
Con_Printf ("Can't find %s\n", expanded);
@@ -1211,7 +1214,7 @@ void SV_Status_f (void)
continue;
s = NET_BaseAdrToString(cl->netchan.remote_address);
Con_Printf ("%-16s %4i %5i %6i %-22s ", cl->name, (int)SV_CalcPing(cl),
- (int)cl->edict->v.frags, cl->userid, (int)sv_use_dns.value ? SV_Resolve(s) : s);
+ (int)cl->edict->v->frags, cl->userid, (int)sv_use_dns.value ? SV_Resolve(s) : s);
if (cl->realip.ip[0])
Con_Printf ("%-15s", NET_BaseAdrToString (cl->realip));
Con_Printf (cl->spectator ? (char *) "(s)" : (char *) "");
@@ -1247,7 +1250,7 @@ void SV_Status_f (void)
s = NET_BaseAdrToString(cl->netchan.remote_address);
Con_Printf ("%-18s %4i %5i %6s %s\n%-36s\n", cl->name, (int)SV_CalcPing(cl),
- (int)cl->edict->v.frags, Q_yelltext((unsigned char*)va("%d", cl->userid)),
+ (int)cl->edict->v->frags, Q_yelltext((unsigned char*)va("%d", cl->userid)),
cl->spectator ? " (s)" : "", (int)sv_use_dns.value ? SV_Resolve(s) : s);
if (cl->realip.ip[0])
diff --git a/src/sv_demo.c b/src/sv_demo.c
index 5fe426a57..47b52a6c3 100644
--- a/src/sv_demo.c
+++ b/src/sv_demo.c
@@ -1251,7 +1251,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t* dest)
MSG_WriteFloat (&buf, sv.time);
// send full levelname
- MSG_WriteString (&buf, PR_GetEntityString(sv.edicts->v.message));
+ MSG_WriteString (&buf, PR_GetEntityString(sv.edicts->v->message));
// send the movevars
MSG_WriteFloat(&buf, movevars.gravity);
@@ -1375,7 +1375,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t* dest)
for (i = 0; i < sv.num_baseline_edicts; ++i) {
edict_t* svent = EDICT_NUM(i);
- entity_state_t* s = &svent->e->baseline;
+ entity_state_t* s = &svent->e.baseline;
if (buf.cursize >= MAX_MSGLEN/2) {
SV_WriteRecordMVDMessage (&buf);
@@ -1496,23 +1496,23 @@ void SV_MVD_SendInitialGamestate(mvddest_t* dest)
flags = (DF_ORIGIN << 0) | (DF_ORIGIN << 1) | (DF_ORIGIN << 2)
| (DF_ANGLES << 0) | (DF_ANGLES << 1) | (DF_ANGLES << 2)
| DF_EFFECTS | DF_SKINNUM
- | (ent->v.health <= 0 ? DF_DEAD : 0)
- | (ent->v.mins[2] != -24 ? DF_GIB : 0)
+ | (ent->v->health <= 0 ? DF_DEAD : 0)
+ | (ent->v->mins[2] != -24 ? DF_GIB : 0)
| DF_WEAPONFRAME | DF_MODEL;
- VectorCopy(ent->v.origin, origin);
- VectorCopy(ent->v.angles, angles);
+ VectorCopy(ent->v->origin, origin);
+ VectorCopy(ent->v->angles, angles);
angles[0] *= -3;
#ifdef USE_PR2
if( player->isBot )
- VectorCopy(ent->v.v_angle, angles);
+ VectorCopy(ent->v->v_angle, angles);
#endif
angles[2] = 0; // no roll angle
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
{ // don't show the corpse looking around...
angles[0] = 0;
- angles[1] = ent->v.angles[1];
+ angles[1] = ent->v->angles[1];
angles[2] = 0;
}
@@ -1520,7 +1520,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t* dest)
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, flags);
- MSG_WriteByte (&buf, ent->v.frame);
+ MSG_WriteByte (&buf, ent->v->frame);
for (j = 0 ; j < 3 ; j++)
if (flags & (DF_ORIGIN << j))
@@ -1531,16 +1531,16 @@ void SV_MVD_SendInitialGamestate(mvddest_t* dest)
MSG_WriteAngle16 (&buf, angles[j]);
if (flags & DF_MODEL)
- MSG_WriteByte (&buf, ent->v.modelindex);
+ MSG_WriteByte (&buf, ent->v->modelindex);
if (flags & DF_SKINNUM)
- MSG_WriteByte (&buf, ent->v.skin);
+ MSG_WriteByte (&buf, ent->v->skin);
if (flags & DF_EFFECTS)
- MSG_WriteByte (&buf, ent->v.effects);
+ MSG_WriteByte (&buf, ent->v->effects);
if (flags & DF_WEAPONFRAME)
- MSG_WriteByte (&buf, ent->v.weaponframe);
+ MSG_WriteByte (&buf, ent->v->weaponframe);
if (buf.cursize > MAX_MSGLEN/2)
{
@@ -1573,21 +1573,21 @@ void SV_MVD_SendInitialGamestate(mvddest_t* dest)
memset(stats, 0, sizeof(stats));
- stats[STAT_HEALTH] = ent->v.health;
- stats[STAT_WEAPON] = SV_ModelIndex(PR_GetEntityString(ent->v.weaponmodel));
- stats[STAT_AMMO] = ent->v.currentammo;
- stats[STAT_ARMOR] = ent->v.armorvalue;
- stats[STAT_SHELLS] = ent->v.ammo_shells;
- stats[STAT_NAILS] = ent->v.ammo_nails;
- stats[STAT_ROCKETS] = ent->v.ammo_rockets;
- stats[STAT_CELLS] = ent->v.ammo_cells;
- stats[STAT_ACTIVEWEAPON] = ent->v.weapon;
+ stats[STAT_HEALTH] = ent->v->health;
+ stats[STAT_WEAPON] = SV_ModelIndex(PR_GetEntityString(ent->v->weaponmodel));
+ stats[STAT_AMMO] = ent->v->currentammo;
+ stats[STAT_ARMOR] = ent->v->armorvalue;
+ stats[STAT_SHELLS] = ent->v->ammo_shells;
+ stats[STAT_NAILS] = ent->v->ammo_nails;
+ stats[STAT_ROCKETS] = ent->v->ammo_rockets;
+ stats[STAT_CELLS] = ent->v->ammo_cells;
+ stats[STAT_ACTIVEWEAPON] = ent->v->weapon;
- if (ent->v.health > 0) // viewheight for PF_DEAD & PF_GIB is hardwired
- stats[STAT_VIEWHEIGHT] = ent->v.view_ofs[2];
+ if (ent->v->health > 0) // viewheight for PF_DEAD & PF_GIB is hardwired
+ stats[STAT_VIEWHEIGHT] = ent->v->view_ofs[2];
// stuff the sigil bits into the high bits of items for sbar
- stats[STAT_ITEMS] = (int) ent->v.items | ((int) PR_GLOBAL(serverflags) << 28);
+ stats[STAT_ITEMS] = (int) ent->v->items | ((int) PR_GLOBAL(serverflags) << 28);
for (j = 0; j < MAX_CL_STATS; j++)
{
diff --git a/src/sv_demo_misc.c b/src/sv_demo_misc.c
index 878e6ead8..644f4c89a 100644
--- a/src/sv_demo_misc.c
+++ b/src/sv_demo_misc.c
@@ -1050,6 +1050,84 @@ void SV_LastScores_f (void)
}
}
+#define STATS_LIMIT_DEFAULT 10
+#define STATS_LIMIT_MAX 50
+void SV_LastStats_f (void)
+{
+ int limit = STATS_LIMIT_DEFAULT;
+ int i;
+ char buf[512];
+ FILE *f = NULL;
+ char path[MAX_OSPATH];
+ dir_t dir;
+ extern redirect_t sv_redirected;
+
+ if (sv_redirected != RD_PACKET)
+ {
+ return;
+ }
+
+ if (Cmd_Argc() > 2)
+ {
+ Con_Printf("usage: laststats []\n = '0' for last %i stats\n = 'n' for last n stats (max %i)\n = '' (empty) for last %i stats\n", STATS_LIMIT_MAX, STATS_LIMIT_MAX, STATS_LIMIT_DEFAULT);
+ return;
+ }
+ else if (Cmd_Argc() == 2)
+ {
+ limit = Q_atoi(Cmd_Argv(1));
+
+ if (limit <= 0 || limit > STATS_LIMIT_MAX)
+ {
+ limit = STATS_LIMIT_MAX;
+ }
+ }
+
+ dir = Sys_listdir(va("%s/%s", fs_gamedir, sv_demoDir.string), sv_demoRegexp.string,
+ SORT_BY_DATE);
+
+ if (!dir.numfiles)
+ {
+ Con_Printf("laststats 0:\n");
+ Con_Printf("[]\n");
+ return;
+ }
+
+ if (limit > dir.numfiles)
+ {
+ limit = dir.numfiles;
+ }
+
+ Con_Printf("laststats %i\n", limit);
+ Con_Printf("[\n");
+
+ for (i = dir.numfiles - limit; i < dir.numfiles; i++)
+ {
+ snprintf(path, MAX_OSPATH, "%s/%s/%s", fs_gamedir, sv_demoDir.string,
+ SV_MVDName2Txt(dir.files[i].name));
+
+ if ((f = fopen(path, "rt")) != NULL)
+ {
+ if (FS_FileLength(f) == 0) {
+ continue;
+ }
+
+ if (i != dir.numfiles - limit)
+ {
+ Con_Printf(",\n");
+ }
+
+ while (fread(buf, 1, sizeof(buf)-1, f))
+ {
+ Con_Printf("%s", (unsigned char*)buf);
+ memset(buf, 0, sizeof(buf));
+ }
+ fclose(f);
+ }
+ }
+
+ Con_Printf("\n]\n");
+}
+
// easyrecord helpers
int Dem_CountPlayers (void)
diff --git a/src/sv_demo_qtv.c b/src/sv_demo_qtv.c
index 11c5bbd8f..6e8b63d9b 100644
--- a/src/sv_demo_qtv.c
+++ b/src/sv_demo_qtv.c
@@ -383,6 +383,7 @@ void SV_MVD_RunPendingConnections (void)
QTVAM_PLAIN,
QTVAM_CCITT,
QTVAM_MD4,
+ QTVAM_SHA3_512,
} authmethod_t;
authmethod_t authmethod = QTVAM_NONE;
start = p->inbuffer;
@@ -456,6 +457,8 @@ void SV_MVD_RunPendingConnections (void)
thisauth = QTVAM_CCITT;
else if (!strcmp(com_token, "MD4"))
thisauth = QTVAM_MD4;
+ else if (!strcmp(com_token, "SHA3_512"))
+ thisauth = QTVAM_SHA3_512;
else
{
thisauth = QTVAM_NONE;
@@ -530,6 +533,21 @@ void SV_MVD_RunPendingConnections (void)
}
break;
+ case QTVAM_SHA3_512:
+ {
+ sha3_context c;
+ const uint8_t *byte_hash;
+ char hash[SHA3_512_DIGEST_HEX_STR_SIZE] = {0};
+
+ sha3_Init512(&c);
+ sha3_Update(&c, p->challenge, strlen(p->challenge));
+ sha3_Update(&c, qtv_password.string, strlen(qtv_password.string));
+ byte_hash = sha3_Finalize(&c);
+ sha3_512_ByteToHex(hash, byte_hash);
+ p->hasauthed = !strcmp(password, hash);
+ }
+ break;
+
default:
e = ("QTVSV 1\n"
"PERROR: FTEQWSV bug detected.\n\n");
@@ -583,6 +601,17 @@ void SV_MVD_RunPendingConnections (void)
send(p->socket, e, strlen(e), 0);
continue;
+ case QTVAM_SHA3_512:
+ e = ("QTVSV 1\n"
+ "AUTH: SHA3_512\n"
+ "CHALLENGE: ");
+
+ send(p->socket, e, strlen(e), 0);
+ send(p->socket, p->challenge, strlen(p->challenge), 0);
+ e = "\n\n";
+ send(p->socket, e, strlen(e), 0);
+ continue;
+
default:
e = ("QTVSV 1\n"
"PERROR: FTEQWSV bug detected.\n\n");
diff --git a/src/sv_ents.c b/src/sv_ents.c
index 319c604be..baafc1779 100644
--- a/src/sv_ents.c
+++ b/src/sv_ents.c
@@ -44,7 +44,7 @@ static qbool SV_AddNailUpdate (edict_t *ent)
if ((int)sv_nailhack.value)
return false;
- if (ent->v.modelindex != sv_nailmodel && ent->v.modelindex != sv_supernailmodel)
+ if (ent->v->modelindex != sv_nailmodel && ent->v->modelindex != sv_supernailmodel)
return false;
if (msg_coordsize != 2)
@@ -80,20 +80,20 @@ static void SV_EmitNailUpdate (sizebuf_t *msg, qbool recorder)
ent = nails[n];
if (recorder)
{
- if (!ent->v.colormap)
+ if (!ent->v->colormap)
{
if (!((++nailcount)&255)) nailcount++;
- ent->v.colormap = nailcount&255;
+ ent->v->colormap = nailcount&255;
}
- MSG_WriteByte (msg, (byte)ent->v.colormap);
+ MSG_WriteByte (msg, (byte)ent->v->colormap);
}
- x = ((int)(ent->v.origin[0] + 4096 + 1) >> 1) & 4095;
- y = ((int)(ent->v.origin[1] + 4096 + 1) >> 1) & 4095;
- z = ((int)(ent->v.origin[2] + 4096 + 1) >> 1) & 4095;
- p = Q_rint(ent->v.angles[0]*(16.0/360.0)) & 15;
- yaw = Q_rint(ent->v.angles[1]*(256.0/360.0)) & 255;
+ x = ((int)(ent->v->origin[0] + 4096 + 1) >> 1) & 4095;
+ y = ((int)(ent->v->origin[1] + 4096 + 1) >> 1) & 4095;
+ z = ((int)(ent->v->origin[2] + 4096 + 1) >> 1) & 4095;
+ p = Q_rint(ent->v->angles[0]*(16.0/360.0)) & 15;
+ yaw = Q_rint(ent->v->angles[1]*(256.0/360.0)) & 255;
bits[0] = x;
bits[1] = (x>>8) | (y<<4);
@@ -355,7 +355,7 @@ static void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, size
}
ent = EDICT_NUM(newnum);
//Con_Printf ("baseline %i\n", newnum);
- SV_WriteDelta (client, &ent->e->baseline, &to->entities[newindex], msg, true);
+ SV_WriteDelta (client, &ent->e.baseline, &to->entities[newindex], msg, true);
newindex++;
continue;
}
@@ -393,13 +393,13 @@ static void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, size
static int TranslateEffects (edict_t *ent)
{
- int fx = (int)ent->v.effects;
+ int fx = (int)ent->v->effects;
if (pr_nqprogs)
fx &= ~EF_MUZZLEFLASH;
if (pr_nqprogs && (fx & EF_DIMLIGHT)) {
- if ((int)ent->v.items & IT_QUAD)
+ if ((int)ent->v->items & IT_QUAD)
fx |= EF_BLUE;
- if ((int)ent->v.items & IT_INVULNERABILITY)
+ if ((int)ent->v->items & IT_INVULNERABILITY)
fx |= EF_RED;
}
return fx;
@@ -432,26 +432,26 @@ static void SV_MVD_WritePlayersToClient ( void )
dcl->parsecount = demo.parsecount;
- VectorCopy(ent->v.origin, dcl->origin);
- VectorCopy(ent->v.angles, dcl->angles);
+ VectorCopy(ent->v->origin, dcl->origin);
+ VectorCopy(ent->v->angles, dcl->angles);
dcl->angles[0] *= -3;
#ifdef USE_PR2
if( cl->isBot )
- VectorCopy(ent->v.v_angle, dcl->angles);
+ VectorCopy(ent->v->v_angle, dcl->angles);
#endif
dcl->angles[2] = 0; // no roll angle
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
{ // don't show the corpse looking around...
dcl->angles[0] = 0;
- dcl->angles[1] = ent->v.angles[1];
+ dcl->angles[1] = ent->v->angles[1];
dcl->angles[2] = 0;
}
- dcl->weaponframe = ent->v.weaponframe;
- dcl->frame = ent->v.frame;
- dcl->skinnum = ent->v.skin;
- dcl->model = ent->v.modelindex;
+ dcl->weaponframe = ent->v->weaponframe;
+ dcl->frame = ent->v->frame;
+ dcl->skinnum = ent->v->skin;
+ dcl->model = ent->v->modelindex;
dcl->effects = TranslateEffects(ent);
dcl->flags = 0;
@@ -460,9 +460,9 @@ static void SV_MVD_WritePlayersToClient ( void )
dcl->sec = sv.time - cl->localtime;
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
dcl->flags |= DF_DEAD;
- if (ent->v.mins[2] != -24)
+ if (ent->v->mins[2] != -24)
dcl->flags |= DF_GIB;
continue;
@@ -486,14 +486,14 @@ qbool SV_PlayerVisibleToClient (client_t* client, int j, byte* pvs, edict_t* sel
if (cl->spectator)
return false;
- if (pvs && ent->e->num_leafs >= 0) {
+ if (pvs && ent->e.num_leafs >= 0) {
// ignore if not touching a PV leaf
- for (i = 0; i < ent->e->num_leafs; i++) {
- if (pvs[ent->e->leafnums[i] >> 3] & (1 << (ent->e->leafnums[i] & 7))) {
+ for (i = 0; i < ent->e.num_leafs; i++) {
+ if (pvs[ent->e.leafnums[i] >> 3] & (1 << (ent->e.leafnums[i] & 7))) {
break;
}
}
- if (i == ent->e->num_leafs) {
+ if (i == ent->e.num_leafs) {
return false; // not visible
}
}
@@ -515,14 +515,14 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
usercmd_t cmd;
int hideent = 0;
int trackent = 0;
- qbool hide_players = fofs_hide_players && ((eval_t *)((byte *)&(client->edict)->v + fofs_hide_players))->_int;
+ qbool hide_players = fofs_hide_players && ((eval_t *)((byte *)(client->edict)->v + fofs_hide_players))->_int;
if (fofs_hideentity)
- hideent = ((eval_t *)((byte *)&(client->edict)->v + fofs_hideentity))->_int / pr_edict_size;
+ hideent = ((eval_t *)((byte *)(client->edict)->v + fofs_hideentity))->_int / pr_edict_size;
if (fofs_trackent)
{
- trackent = ((eval_t *)((byte *)&(client->edict)->v + fofs_trackent))->_int;
+ trackent = ((eval_t *)((byte *)(client->edict)->v + fofs_trackent))->_int;
if (trackent < 1 || trackent > MAX_CLIENTS || svs.clients[trackent - 1].state != cs_spawned)
trackent = 0;
}
@@ -538,7 +538,7 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
if (fofs_visibility) {
// Presume not visible
- ((eval_t *)((byte *)&(cl->edict)->v + fofs_visibility))->_int &= ~(1 << (client - svs.clients));
+ ((eval_t *)((byte *)(cl->edict)->v + fofs_visibility))->_int &= ~(1 << (client - svs.clients));
}
if (cl->state != cs_spawned)
@@ -568,7 +568,7 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
if (fofs_visibility) {
// Update flags so mods can tell what was visible
- ((eval_t *)((byte *)&(ent)->v + fofs_visibility))->_int |= (1 << (client - svs.clients));
+ ((eval_t *)((byte *)(ent)->v + fofs_visibility))->_int |= (1 << (client - svs.clients));
}
if (j == hideent - 1)
@@ -587,18 +587,18 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
pflags = PF_MSEC | PF_COMMAND;
- if (ent->v.modelindex != sv_playermodel)
+ if (ent->v->modelindex != sv_playermodel)
pflags |= PF_MODEL;
for (i=0 ; i<3 ; i++)
- if (ent->v.velocity[i])
+ if (ent->v->velocity[i])
pflags |= PF_VELOCITY1<v.effects)
+ if (ent->v->effects)
pflags |= PF_EFFECTS;
- if (ent->v.skin || ent->v.modelindex >= 256)
+ if (ent->v->skin || ent->v->modelindex >= 256)
pflags |= PF_SKINNUM;
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
pflags |= PF_DEAD;
- if (ent->v.mins[2] != -24)
+ if (ent->v->mins[2] != -24)
pflags |= PF_GIB;
if (cl->spectator)
@@ -608,7 +608,7 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
else if (ent == self_ent)
{ // don't send a lot of data on personal entity
pflags &= ~(PF_MSEC|PF_COMMAND);
- if (ent->v.weaponframe)
+ if (ent->v->weaponframe)
pflags |= PF_WEAPONFRAME;
}
@@ -647,17 +647,17 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
pflags |= pm_code << PF_PMC_SHIFT;
// Z_EXT_PF_ONGROUND protocol extension
- if ((int)ent->v.flags & FL_ONGROUND)
+ if ((int)ent->v->flags & FL_ONGROUND)
pflags |= PF_ONGROUND;
// Z_EXT_PF_SOLID protocol extension
- if (ent->v.solid == SOLID_BBOX || ent->v.solid == SOLID_SLIDEBOX)
+ if (ent->v->solid == SOLID_BBOX || ent->v->solid == SOLID_SLIDEBOX)
pflags |= PF_SOLID;
if (pm_type == PM_LOCK && ent == self_ent)
pflags |= PF_COMMAND; // send forced view angles
- if (client->spec_track && client->spec_track - 1 == j && ent->v.weaponframe)
+ if (client->spec_track && client->spec_track - 1 == j && ent->v->weaponframe)
pflags |= PF_WEAPONFRAME;
MSG_WriteByte (msg, svc_playerinfo);
@@ -665,17 +665,17 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
MSG_WriteShort (msg, pflags);
if (client->mvdprotocolextensions1 & MVD_PEXT1_FLOATCOORDS) {
- MSG_WriteLongCoord(msg, ent->v.origin[0]);
- MSG_WriteLongCoord(msg, ent->v.origin[1]);
- MSG_WriteLongCoord(msg, ent->v.origin[2]);
+ MSG_WriteLongCoord(msg, ent->v->origin[0]);
+ MSG_WriteLongCoord(msg, ent->v->origin[1]);
+ MSG_WriteLongCoord(msg, ent->v->origin[2]);
}
else {
- MSG_WriteCoord(msg, ent->v.origin[0]);
- MSG_WriteCoord(msg, ent->v.origin[1]);
- MSG_WriteCoord(msg, ent->v.origin[2]);
+ MSG_WriteCoord(msg, ent->v->origin[0]);
+ MSG_WriteCoord(msg, ent->v->origin[1]);
+ MSG_WriteCoord(msg, ent->v->origin[2]);
}
- MSG_WriteByte (msg, ent->v.frame);
+ MSG_WriteByte (msg, ent->v->frame);
if (pflags & PF_MSEC)
{
@@ -689,10 +689,10 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
{
cmd = cl->lastcmd;
- if (ent->v.health <= 0)
+ if (ent->v->health <= 0)
{ // don't show the corpse looking around...
cmd.angles[0] = 0;
- cmd.angles[1] = ent->v.angles[1];
+ cmd.angles[1] = ent->v->angles[1];
cmd.angles[0] = 0;
}
@@ -702,7 +702,7 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
if (ent == self_ent)
{
// this is PM_LOCK, we only want to send view angles
- VectorCopy(ent->v.v_angle, cmd.angles);
+ VectorCopy(ent->v->v_angle, cmd.angles);
cmd.forwardmove = 0;
cmd.sidemove = 0;
cmd.upmove = 0;
@@ -717,19 +717,19 @@ static void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, by
for (i=0 ; i<3 ; i++)
if (pflags & (PF_VELOCITY1<v.velocity[i]);
+ MSG_WriteShort (msg, ent->v->velocity[i]);
if (pflags & PF_MODEL)
- MSG_WriteByte (msg, ent->v.modelindex);
+ MSG_WriteByte (msg, ent->v->modelindex);
if (pflags & PF_SKINNUM)
- MSG_WriteByte (msg, (int)ent->v.skin | (((pflags & PF_MODEL)&&(ent->v.modelindex >= 256))<<7));
+ MSG_WriteByte (msg, (int)ent->v->skin | (((pflags & PF_MODEL)&&(ent->v->modelindex >= 256))<<7));
if (pflags & PF_EFFECTS)
MSG_WriteByte (msg, TranslateEffects(ent));
if (pflags & PF_WEAPONFRAME)
- MSG_WriteByte (msg, ent->v.weaponframe);
+ MSG_WriteByte (msg, ent->v->weaponframe);
}
}
@@ -750,19 +750,19 @@ qbool SV_EntityVisibleToClient (client_t* client, int e, byte* pvs)
}
// ignore ents without visible models
- if (!ent->v.modelindex || !*PR_GetEntityString(ent->v.model))
+ if (!ent->v->modelindex || !*PR_GetEntityString(ent->v->model))
return false;
- if ( pvs && ent->e->num_leafs >= 0 )
+ if ( pvs && ent->e.num_leafs >= 0 )
{
int i;
// ignore if not touching a PV leaf
- for (i=0 ; i < ent->e->num_leafs ; i++)
- if (pvs[ent->e->leafnums[i] >> 3] & (1 << (ent->e->leafnums[i]&7) ))
+ for (i=0 ; i < ent->e.num_leafs ; i++)
+ if (pvs[ent->e.leafnums[i] >> 3] & (1 << (ent->e.leafnums[i]&7) ))
break;
- if (i == ent->e->num_leafs)
+ if (i == ent->e.num_leafs)
return false; // not visible
}
@@ -821,13 +821,13 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
int trackent = 0;
if (fofs_hideentity)
- hideent = ((eval_t *)((byte *)&(client->edict)->v + fofs_hideentity))->_int / pr_edict_size;
+ hideent = ((eval_t *)((byte *)(client->edict)->v + fofs_hideentity))->_int / pr_edict_size;
else
hideent = 0;
if (fofs_trackent)
{
- trackent = ((eval_t *)((byte *)&(client->edict)->v + fofs_trackent))->_int;
+ trackent = ((eval_t *)((byte *)(client->edict)->v + fofs_trackent))->_int;
if (trackent < 1 || trackent > MAX_CLIENTS || svs.clients[trackent - 1].state != cs_spawned)
trackent = 0;
}
@@ -835,11 +835,11 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
// we should use org of tracked player in case or trackent.
if (trackent)
{
- VectorAdd (svs.clients[trackent - 1].edict->v.origin, svs.clients[trackent - 1].edict->v.view_ofs, org);
+ VectorAdd (svs.clients[trackent - 1].edict->v->origin, svs.clients[trackent - 1].edict->v->view_ofs, org);
}
else
{
- VectorAdd (client->edict->v.origin, client->edict->v.view_ofs, org);
+ VectorAdd (client->edict->v->origin, client->edict->v->view_ofs, org);
}
pvs = CM_FatPVS (org); // search some PVS
@@ -850,7 +850,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
#define ISUNDERWATER(x) ((x) == CONTENTS_WATER || (x) == CONTENTS_SLIME || (x) == CONTENTS_LAVA)
// server flash should not work underwater
- int content = CM_HullPointContents(&sv.worldmodel->hulls[0], 0, client->edict->v.origin);
+ int content = CM_HullPointContents(&sv.worldmodel->hulls[0], 0, client->edict->v->origin);
disable_updates = !ISUNDERWATER(content);
#undef ISUNDERWATER
@@ -884,14 +884,14 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
{
if (!SV_EntityVisibleToClient(client, e, pvs)) {
if (fofs_visibility) {
- ((eval_t *)((byte *)&(ent)->v + fofs_visibility))->_int &= ~client_flag;
+ ((eval_t *)((byte *)(ent)->v + fofs_visibility))->_int &= ~client_flag;
}
continue;
}
if (fofs_visibility) {
// Don't include other filters in logic for setting this field
- ((eval_t *)((byte *)&(ent)->v + fofs_visibility))->_int |= (1 << (client - svs.clients));
+ ((eval_t *)((byte *)(ent)->v + fofs_visibility))->_int |= (1 << (client - svs.clients));
}
if (e == hideent) {
@@ -902,8 +902,8 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
continue; // added to the special update list
if (clent) {
- VectorAdd(ent->v.absmin, ent->v.absmax, org);
- VectorMA(clent->v.origin, -0.5, org, org);
+ VectorAdd(ent->v->absmin, ent->v->absmax, org);
+ VectorMA(clent->v->origin, -0.5, org, org);
distance = DotProduct(org, org); //Length
// add to the packetentities
@@ -948,12 +948,12 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
state->number = e;
state->flags = 0;
- VectorCopy (ent->v.origin, state->origin);
- VectorCopy (ent->v.angles, state->angles);
- state->modelindex = ent->v.modelindex;
- state->frame = ent->v.frame;
- state->colormap = ent->v.colormap;
- state->skinnum = ent->v.skin;
+ VectorCopy (ent->v->origin, state->origin);
+ VectorCopy (ent->v->angles, state->angles);
+ state->modelindex = ent->v->modelindex;
+ state->frame = ent->v->frame;
+ state->colormap = ent->v->colormap;
+ state->skinnum = ent->v->skin;
state->effects = TranslateEffects(ent);
}
} // server flash
@@ -972,18 +972,18 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
for (e=1, ent=EDICT_NUM(e) ; e < sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
{
// ignore ents without visible models
- if (!ent->v.modelindex || !*PR_GetEntityString(ent->v.model))
+ if (!ent->v->modelindex || !*PR_GetEntityString(ent->v->model))
continue;
// ignore if not touching a PV leaf (meag: this does nothing... complete or remove?)
- if (pvs && ent->e->num_leafs >= 0) {
- for (i = 0; i < ent->e->num_leafs; i++)
- if (pvs[ent->e->leafnums[i] >> 3] & (1 << (ent->e->leafnums[i] & 7)))
+ if (pvs && ent->e.num_leafs >= 0) {
+ for (i = 0; i < ent->e.num_leafs; i++)
+ if (pvs[ent->e.leafnums[i] >> 3] & (1 << (ent->e.leafnums[i] & 7)))
break;
}
- if ((int)ent->v.effects & EF_MUZZLEFLASH) {
- ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;
+ if ((int)ent->v->effects & EF_MUZZLEFLASH) {
+ ent->v->effects = (int)ent->v->effects & ~EF_MUZZLEFLASH;
MSG_WriteByte (msg, svc_muzzleflash);
MSG_WriteShort (msg, e);
}
@@ -1007,17 +1007,17 @@ void SV_SetVisibleEntitiesForBot (client_t* client)
if (!fofs_visibility)
return;
- VectorAdd (client->edict->v.origin, client->edict->v.view_ofs, org);
+ VectorAdd (client->edict->v->origin, client->edict->v->view_ofs, org);
pvs = CM_FatPVS (org); // search some PVS
// players first
for (j = 0; j < MAX_CLIENTS; j++)
{
if (SV_PlayerVisibleToClient(client, j, pvs, client->edict, svs.clients[j].edict)) {
- ((eval_t *)((byte *)&(svs.clients[j].edict)->v + fofs_visibility))->_int |= client_flag;
+ ((eval_t *)((byte *)(svs.clients[j].edict)->v + fofs_visibility))->_int |= client_flag;
}
else {
- ((eval_t *)((byte *)&(svs.clients[j].edict)->v + fofs_visibility))->_int &= ~client_flag;
+ ((eval_t *)((byte *)(svs.clients[j].edict)->v + fofs_visibility))->_int &= ~client_flag;
}
}
@@ -1027,10 +1027,10 @@ void SV_SetVisibleEntitiesForBot (client_t* client)
edict_t* ent = EDICT_NUM (e);
if (SV_EntityVisibleToClient(client, e, pvs)) {
- ((eval_t *)((byte *)&(ent)->v + fofs_visibility))->_int |= client_flag;
+ ((eval_t *)((byte *)(ent)->v + fofs_visibility))->_int |= client_flag;
}
else {
- ((eval_t *)((byte *)&(ent)->v + fofs_visibility))->_int &= ~client_flag;
+ ((eval_t *)((byte *)(ent)->v + fofs_visibility))->_int &= ~client_flag;
}
}
}
diff --git a/src/sv_init.c b/src/sv_init.c
index 96594953a..806b11c67 100644
--- a/src/sv_init.c
+++ b/src/sv_init.c
@@ -105,30 +105,30 @@ static void SV_CreateBaseline (void)
for (entnum = 0; entnum < sv.num_edicts ; entnum++)
{
svent = EDICT_NUM(entnum);
- if (svent->e->free)
+ if (svent->e.free)
continue;
// create baselines for all player slots,
// and any other edict that has a visible model
- if (entnum > MAX_CLIENTS && !svent->v.modelindex)
+ if (entnum > MAX_CLIENTS && !svent->v->modelindex)
continue;
//
// create entity baseline
//
- svent->e->baseline.number = entnum;
- VectorCopy (svent->v.origin, svent->e->baseline.origin);
- VectorCopy (svent->v.angles, svent->e->baseline.angles);
- svent->e->baseline.frame = svent->v.frame;
- svent->e->baseline.skinnum = svent->v.skin;
+ svent->e.baseline.number = entnum;
+ VectorCopy (svent->v->origin, svent->e.baseline.origin);
+ VectorCopy (svent->v->angles, svent->e.baseline.angles);
+ svent->e.baseline.frame = svent->v->frame;
+ svent->e.baseline.skinnum = svent->v->skin;
if (entnum > 0 && entnum <= MAX_CLIENTS)
{
- svent->e->baseline.colormap = entnum;
- svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+ svent->e.baseline.colormap = entnum;
+ svent->e.baseline.modelindex = SV_ModelIndex("progs/player.mdl");
}
else
{
- svent->e->baseline.colormap = 0;
- svent->e->baseline.modelindex = svent->v.modelindex;
+ svent->e.baseline.colormap = 0;
+ svent->e.baseline.modelindex = svent->v->modelindex;
}
}
sv.num_baseline_edicts = sv.num_edicts;
@@ -241,7 +241,7 @@ void SV_SpawnServer(char *mapname, qbool devmap, char* entityfile, qbool loading
if( sv_vm && svs.clients[i].isBot )
{
svs.clients[i].old_frags = 0;
- svs.clients[i].edict->v.frags = 0.0;
+ svs.clients[i].edict->v->frags = 0.0;
svs.clients[i].name[0] = 0;
svs.clients[i].state = cs_free;
Info_RemoveAll(&svs.clients[i]._userinfo_ctx_);
@@ -350,11 +350,10 @@ void SV_SpawnServer(char *mapname, qbool devmap, char* entityfile, qbool loading
for (i = 0; i < sv.max_edicts; i++)
{
- ent = EDICT_NUM(i);
- ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t
- ent->e->entnum = i;
- ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t)
- PR_ClearEdict(ent);
+ sv.edicts[i].v = (entvars_t *)((byte *)sv.game_edicts + i * pr_edict_size);
+ sv.edicts[i].e.entnum = i;
+ sv.edicts[i].e.area.ed = &sv.edicts[i]; // yeah, pretty funny, but this help to find which edict_t own this area (link_t)
+ PR_ClearEdict(&sv.edicts[i]);
}
fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension
@@ -441,7 +440,7 @@ void SV_SpawnServer(char *mapname, qbool devmap, char* entityfile, qbool loading
{
ent = EDICT_NUM(i+1);
// restore client name.
- PR_SetEntityString(ent, ent->v.netname, svs.clients[i].name);
+ PR_SetEntityString(ent, ent->v->netname, svs.clients[i].name);
// reserve edict.
svs.clients[i].edict = ent;
//ZOID - make sure we update frags right
@@ -523,17 +522,17 @@ void SV_SpawnServer(char *mapname, qbool devmap, char* entityfile, qbool loading
#endif
ent = EDICT_NUM(0);
- ent->e->free = false;
- PR_SetEntityString(ent, ent->v.model, sv.modelname);
- ent->v.modelindex = 1; // world model
- ent->v.solid = SOLID_BSP;
- ent->v.movetype = MOVETYPE_PUSH;
+ ent->e.free = false;
+ PR_SetEntityString(ent, ent->v->model, sv.modelname);
+ ent->v->modelindex = 1; // world model
+ ent->v->solid = SOLID_BSP;
+ ent->v->movetype = MOVETYPE_PUSH;
// information about the server
- PR_SetEntityString(ent, ent->v.netname, VersionStringFull());
- PR_SetEntityString(ent, ent->v.targetname, SERVER_NAME);
- ent->v.impulse = VERSION_NUM;
- ent->v.items = pr_numbuiltins - 1;
+ PR_SetEntityString(ent, ent->v->netname, VersionStringFull());
+ PR_SetEntityString(ent, ent->v->targetname, SERVER_NAME);
+ ent->v->impulse = VERSION_NUM;
+ ent->v->items = pr_numbuiltins - 1;
PR_SetGlobalString(PR_GLOBAL(mapname), sv.mapname);
// serverflags are for cross level information (sigils)
diff --git a/src/sv_main.c b/src/sv_main.c
index 73771cb50..97935bafe 100644
--- a/src/sv_main.c
+++ b/src/sv_main.c
@@ -418,7 +418,7 @@ void SV_DropClient(client_t* drop)
// <-- MD
drop->old_frags = 0;
- drop->edict->v.frags = 0.0;
+ drop->edict->v->frags = 0.0;
drop->name[0] = 0;
Info_RemoveAll(&drop->_userinfo_ctx_);
@@ -679,6 +679,22 @@ static void SVC_LastScores (void)
SV_EndRedirect ();
}
+/*
+===================
+SVC_LastStats
+===================
+*/
+void SV_LastStats_f (void);
+static void SVC_LastStats (void)
+{
+ if(!(int)sv_allowlastscores.value)
+ return;
+
+ SV_BeginRedirect (RD_PACKET);
+ SV_LastStats_f ();
+ SV_EndRedirect ();
+}
+
/*
===================
SVC_DemoList
@@ -1385,10 +1401,10 @@ static void SVC_DirectConnect (void)
edictnum = (newcl-svs.clients)+1;
ent = EDICT_NUM(edictnum);
- ent->e->free = false;
+ ent->e.free = false;
newcl->edict = ent;
// restore client name.
- PR_SetEntityString(ent, ent->v.netname, newcl->name);
+ PR_SetEntityString(ent, ent->v->netname, newcl->name);
s = ( vip ? va("%d", vip) : "" );
@@ -1893,6 +1909,8 @@ static void SV_ConnectionlessPacket (void)
SVC_GetChallenge ();
else if (!strcmp(c,"lastscores"))
SVC_LastScores ();
+ else if (!strcmp(c,"laststats"))
+ SVC_LastStats ();
else if (!strcmp(c,"dlist"))
SVC_DemoList ();
else if (!strcmp(c,"dlistr"))
@@ -3120,6 +3138,7 @@ int SV_BoundRate (qbool dl, int rate)
if (rate < 500)
rate = 500;
+
if (rate > 100000 * MAX_DUPLICATE_PACKETS)
rate = 100000 * MAX_DUPLICATE_PACKETS;
@@ -3324,9 +3343,9 @@ void SV_InitLocal (void)
extern cvar_t pm_airstep;
extern cvar_t pm_pground;
extern cvar_t pm_rampjump;
- //extern cvar_t pm_slidefix;
+ extern cvar_t pm_slidefix;
extern cvar_t pm_ktjump;
- //extern cvar_t pm_bunnyspeedcap;
+ extern cvar_t pm_bunnyspeedcap;
// qws = QuakeWorld Server information
static cvar_t qws_name = { "qws_name", SERVER_NAME, CVAR_ROM };
@@ -3431,9 +3450,9 @@ void SV_InitLocal (void)
Cvar_Register (&sv_antilag_no_pred);
Cvar_Register (&sv_antilag_projectiles);
- //Cvar_Register (&pm_bunnyspeedcap);
+ Cvar_Register (&pm_bunnyspeedcap);
Cvar_Register (&pm_ktjump);
- //Cvar_Register (&pm_slidefix);
+ Cvar_Register (&pm_slidefix);
Cvar_Register (&pm_pground);
Cvar_Register (&pm_airstep);
Cvar_Register (&pm_rampjump);
@@ -3885,6 +3904,9 @@ void Host_Init (int argc, char **argv, int default_memsize)
Con_Printf ("%4.1f megabyte heap\n", (float)hunk_size / (1024 * 1024));
Con_Printf ("QuakeWorld Initialized\n");
+#ifndef WWW_INTEGRATION
+ Con_Printf ("www authentication disabled (no curl support)\n");
+#endif
Cbuf_InsertText ("exec server.cfg\n");
diff --git a/src/sv_move.c b/src/sv_move.c
index 76630af20..06911e04a 100644
--- a/src/sv_move.c
+++ b/src/sv_move.c
@@ -41,8 +41,8 @@ qbool SV_CheckBottom (edict_t *ent)
int x, y;
float mid, bottom;
- VectorAdd (ent->v.origin, ent->v.mins, mins);
- VectorAdd (ent->v.origin, ent->v.maxs, maxs);
+ VectorAdd (ent->v->origin, ent->v->mins, mins);
+ VectorAdd (ent->v->origin, ent->v->maxs, maxs);
// if all of the points under the corners are solid world, don't bother
// with the tougher checks
@@ -111,33 +111,33 @@ qbool SV_movestep (edict_t *ent, vec3_t move, qbool relink)
edict_t *enemy;
// try the move
- VectorCopy (ent->v.origin, oldorg);
- VectorAdd (ent->v.origin, move, neworg);
+ VectorCopy (ent->v->origin, oldorg);
+ VectorAdd (ent->v->origin, move, neworg);
// flying monsters don't step up
- if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )
+ if ( (int)ent->v->flags & (FL_SWIM | FL_FLY) )
{
// try one move with vertical motion, then one without
for (i=0 ; i<2 ; i++)
{
- VectorAdd (ent->v.origin, move, neworg);
- enemy = PROG_TO_EDICT(ent->v.enemy);
+ VectorAdd (ent->v->origin, move, neworg);
+ enemy = PROG_TO_EDICT(ent->v->enemy);
if (i == 0 && enemy != sv.edicts)
{
- dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];
+ dz = ent->v->origin[2] - PROG_TO_EDICT(ent->v->enemy)->v->origin[2];
if (dz > 40)
neworg[2] -= 8;
if (dz < 30)
neworg[2] += 8;
}
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
if (trace.fraction == 1)
{
- if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
+ if ( ((int)ent->v->flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )
return false; // swim monster left water
- VectorCopy (trace.endpos, ent->v.origin);
+ VectorCopy (trace.endpos, ent->v->origin);
if (relink)
SV_LinkEdict (ent, true);
return true;
@@ -155,7 +155,7 @@ qbool SV_movestep (edict_t *ent, vec3_t move, qbool relink)
VectorCopy (neworg, end);
end[2] -= STEPSIZE*2;
- trace = SV_Trace (neworg, ent->v.mins, ent->v.maxs, end, false, ent);
+ trace = SV_Trace (neworg, ent->v->mins, ent->v->maxs, end, false, ent);
if (trace.allsolid)
return false;
@@ -163,19 +163,19 @@ qbool SV_movestep (edict_t *ent, vec3_t move, qbool relink)
if (trace.startsolid)
{
neworg[2] -= STEPSIZE;
- trace = SV_Trace (neworg, ent->v.mins, ent->v.maxs, end, false, ent);
+ trace = SV_Trace (neworg, ent->v->mins, ent->v->maxs, end, false, ent);
if (trace.allsolid || trace.startsolid)
return false;
}
if (trace.fraction == 1)
{
// if monster had the ground pulled out, go ahead and fall
- if ( (int)ent->v.flags & FL_PARTIALGROUND )
+ if ( (int)ent->v->flags & FL_PARTIALGROUND )
{
- VectorAdd (ent->v.origin, move, ent->v.origin);
+ VectorAdd (ent->v->origin, move, ent->v->origin);
if (relink)
SV_LinkEdict (ent, true);
- ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
+ ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
// Con_Printf ("fall down\n");
return true;
}
@@ -184,27 +184,27 @@ qbool SV_movestep (edict_t *ent, vec3_t move, qbool relink)
}
// check point traces down for dangling corners
- VectorCopy (trace.endpos, ent->v.origin);
+ VectorCopy (trace.endpos, ent->v->origin);
if (!SV_CheckBottom (ent))
{
- if ( (int)ent->v.flags & FL_PARTIALGROUND )
+ if ( (int)ent->v->flags & FL_PARTIALGROUND )
{ // entity had floor mostly pulled out from underneath it
// and is trying to correct
if (relink)
SV_LinkEdict (ent, true);
return true;
}
- VectorCopy (oldorg, ent->v.origin);
+ VectorCopy (oldorg, ent->v->origin);
return false;
}
- if ( (int)ent->v.flags & FL_PARTIALGROUND )
+ if ( (int)ent->v->flags & FL_PARTIALGROUND )
{
// Con_Printf ("back on ground\n");
- ent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;
+ ent->v->flags = (int)ent->v->flags & ~FL_PARTIALGROUND;
}
- ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);
+ ent->v->groundentity = EDICT_TO_PROG(trace.e.ent);
// the move is ok
if (relink)
@@ -230,7 +230,7 @@ qbool SV_StepDirection (edict_t *ent, float yaw, float dist)
vec3_t move, oldorigin;
float delta;
- ent->v.ideal_yaw = yaw;
+ ent->v->ideal_yaw = yaw;
PF_changeyaw(); // OUCH OUCH: its relay on what ent == self ? I'm not even mention about PR2...
@@ -239,13 +239,13 @@ qbool SV_StepDirection (edict_t *ent, float yaw, float dist)
move[1] = sin(yaw)*dist;
move[2] = 0;
- VectorCopy (ent->v.origin, oldorigin);
+ VectorCopy (ent->v->origin, oldorigin);
if (SV_movestep (ent, move, false))
{
- delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
+ delta = ent->v->angles[YAW] - ent->v->ideal_yaw;
if (delta > 45 && delta < 315)
{ // not turned far enough, so don't take the step
- VectorCopy (oldorigin, ent->v.origin);
+ VectorCopy (oldorigin, ent->v->origin);
}
SV_LinkEdict (ent, true);
return true;
@@ -265,7 +265,7 @@ void SV_FixCheckBottom (edict_t *ent)
{
// Con_Printf ("SV_FixCheckBottom\n");
- ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
+ ent->v->flags = (int)ent->v->flags | FL_PARTIALGROUND;
}
@@ -283,11 +283,11 @@ void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
float d[3];
float tdir, olddir, turnaround;
- olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 );
+ olddir = anglemod( (int)(actor->v->ideal_yaw/45)*45 );
turnaround = anglemod(olddir - 180);
- deltax = enemy->v.origin[0] - actor->v.origin[0];
- deltay = enemy->v.origin[1] - actor->v.origin[1];
+ deltax = enemy->v->origin[0] - actor->v->origin[0];
+ deltay = enemy->v->origin[1] - actor->v->origin[1];
if (deltax>10)
d[1]= 0;
else if (deltax<-10)
@@ -348,7 +348,7 @@ void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
return;
- actor->v.ideal_yaw = olddir; // can't move
+ actor->v->ideal_yaw = olddir; // can't move
// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all
@@ -370,9 +370,9 @@ qbool SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
for (i=0 ; i<3 ; i++)
{
- if (goal->v.absmin[i] > ent->v.absmax[i] + dist)
+ if (goal->v->absmin[i] > ent->v->absmax[i] + dist)
return false;
- if (goal->v.absmax[i] < ent->v.absmin[i] - dist)
+ if (goal->v->absmax[i] < ent->v->absmin[i] - dist)
return false;
}
return true;
@@ -393,21 +393,21 @@ void SV_MoveToGoal (void)
float dist;
ent = PROG_TO_EDICT(pr_global_struct->self);
- goal = PROG_TO_EDICT(ent->v.goalentity);
+ goal = PROG_TO_EDICT(ent->v->goalentity);
dist = G_FLOAT(OFS_PARM0);
- if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+ if ( !( (int)ent->v->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
{
G_FLOAT(OFS_RETURN) = 0;
return;
}
// if the next step hits the enemy, return immediately
- if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
+ if ( PROG_TO_EDICT(ent->v->enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) )
return;
// bump around...
- if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->v.ideal_yaw, dist))
+ if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->v->ideal_yaw, dist))
{
SV_NewChaseDir (ent, goal, dist);
}
diff --git a/src/sv_nchan.c b/src/sv_nchan.c
index 177296515..aa50261bd 100644
--- a/src/sv_nchan.c
+++ b/src/sv_nchan.c
@@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void ClientReliableCheckBlock(client_t *cl, int maxsize)
{
if (cl->num_backbuf
- || cl->netchan.message.cursize > cl->netchan.message.maxsize - maxsize - 1)
+ || cl->netchan.message.cursize > cl->netchan.message.maxsize - maxsize - 1)
{
// we would probably overflow the buffer, save it for next
if (!cl->num_backbuf || cl->backbuf.cursize > cl->backbuf.maxsize - maxsize - 1)
diff --git a/src/sv_phys.c b/src/sv_phys.c
index c1c99a449..c65eae9cb 100644
--- a/src/sv_phys.c
+++ b/src/sv_phys.c
@@ -95,28 +95,28 @@ void SV_CheckVelocity (edict_t *ent)
//
for (i=0 ; i<3 ; i++)
{
- if (IS_NAN(ent->v.velocity[i]))
+ if (IS_NAN(ent->v->velocity[i]))
{
- Con_DPrintf ("Got a NaN velocity on %s\n", PR_GetEntityString(ent->v.classname));
- ent->v.velocity[i] = 0;
+ Con_DPrintf ("Got a NaN velocity on %s\n", PR_GetEntityString(ent->v->classname));
+ ent->v->velocity[i] = 0;
}
- if (IS_NAN(ent->v.origin[i]))
+ if (IS_NAN(ent->v->origin[i]))
{
- Con_DPrintf ("Got a NaN origin on %s\n", PR_GetEntityString(ent->v.classname));
- ent->v.origin[i] = 0;
+ Con_DPrintf ("Got a NaN origin on %s\n", PR_GetEntityString(ent->v->classname));
+ ent->v->origin[i] = 0;
}
-/* if (ent->v.velocity[i] > sv_maxvelocity.value)
- ent->v.velocity[i] = sv_maxvelocity.value;
- else if (ent->v.velocity[i] < -sv_maxvelocity.value)
- ent->v.velocity[i] = -sv_maxvelocity.value;
+/* if (ent->v->velocity[i] > sv_maxvelocity.value)
+ ent->v->velocity[i] = sv_maxvelocity.value;
+ else if (ent->v->velocity[i] < -sv_maxvelocity.value)
+ ent->v->velocity[i] = -sv_maxvelocity.value;
*/
}
// SV_MAXVELOCITY fix by Maddes
- wishspeed = VectorLength(ent->v.velocity);
+ wishspeed = VectorLength(ent->v->velocity);
if (wishspeed > sv_maxvelocity.value)
{
- VectorScale (ent->v.velocity, sv_maxvelocity.value/wishspeed, ent->v.velocity);
+ VectorScale (ent->v->velocity, sv_maxvelocity.value/wishspeed, ent->v->velocity);
wishspeed = sv_maxvelocity.value;
}
}
@@ -137,7 +137,7 @@ qbool SV_RunThink (edict_t *ent)
do
{
- thinktime = ent->v.nextthink;
+ thinktime = ent->v->nextthink;
if (thinktime <= 0)
return true;
if (thinktime > sv.time + sv_frametime)
@@ -147,13 +147,13 @@ qbool SV_RunThink (edict_t *ent)
thinktime = sv.time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
- ent->v.nextthink = 0;
+ ent->v->nextthink = 0;
pr_global_struct->time = thinktime;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
- PR_EdictThink(ent->v.think);
+ PR_EdictThink(ent->v->think);
- if (ent->e->free)
+ if (ent->e.free)
return false;
} while (1);
@@ -175,18 +175,18 @@ void SV_Impact (edict_t *e1, edict_t *e2)
old_other = pr_global_struct->other;
pr_global_struct->time = sv.time;
- if (e1->v.touch && e1->v.solid != SOLID_NOT)
+ if (e1->v->touch && e1->v->solid != SOLID_NOT)
{
pr_global_struct->self = EDICT_TO_PROG(e1);
pr_global_struct->other = EDICT_TO_PROG(e2);
- PR_EdictTouch(e1->v.touch);
+ PR_EdictTouch(e1->v->touch);
}
- if (e2->v.touch && e2->v.solid != SOLID_NOT)
+ if (e2->v->touch && e2->v->solid != SOLID_NOT)
{
pr_global_struct->self = EDICT_TO_PROG(e2);
pr_global_struct->other = EDICT_TO_PROG(e1);
- PR_EdictTouch(e2->v.touch);
+ PR_EdictTouch(e2->v->touch);
}
pr_global_struct->self = old_self;
@@ -252,8 +252,8 @@ int SV_FlyMove (edict_t *ent, float time1, trace_t *steptrace, int type)
numbumps = 4;
blocked = 0;
- VectorCopy (ent->v.velocity, original_velocity);
- VectorCopy (ent->v.velocity, primal_velocity);
+ VectorCopy (ent->v->velocity, original_velocity);
+ VectorCopy (ent->v->velocity, primal_velocity);
numplanes = 0;
time_left = time1;
@@ -261,20 +261,20 @@ int SV_FlyMove (edict_t *ent, float time1, trace_t *steptrace, int type)
for (bumpcount=0 ; bumpcountv.origin[i] + time_left * ent->v.velocity[i];
+ end[i] = ent->v->origin[i] + time_left * ent->v->velocity[i];
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent);
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent);
if (trace.allsolid)
{ // entity is trapped in another solid
- VectorClear (ent->v.velocity);
+ VectorClear (ent->v->velocity);
return 3;
}
if (trace.fraction > 0)
{ // actually covered some distance
- VectorCopy (trace.endpos, ent->v.origin);
- VectorCopy (ent->v.velocity, original_velocity);
+ VectorCopy (trace.endpos, ent->v->origin);
+ VectorCopy (ent->v->velocity, original_velocity);
numplanes = 0;
}
@@ -287,10 +287,10 @@ int SV_FlyMove (edict_t *ent, float time1, trace_t *steptrace, int type)
if (trace.plane.normal[2] > 0.7)
{
blocked |= 1; // floor
- if (trace.e.ent->v.solid == SOLID_BSP)
+ if (trace.e.ent->v->solid == SOLID_BSP)
{
- ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);
+ ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+ ent->v->groundentity = EDICT_TO_PROG(trace.e.ent);
}
}
if (!trace.plane.normal[2])
@@ -304,7 +304,7 @@ int SV_FlyMove (edict_t *ent, float time1, trace_t *steptrace, int type)
// run the impact function
//
SV_Impact (ent, trace.e.ent);
- if (ent->e->free)
+ if (ent->e.free)
break; // removed by the impact function
@@ -313,7 +313,7 @@ int SV_FlyMove (edict_t *ent, float time1, trace_t *steptrace, int type)
// cliped to another plane
if (numplanes >= MAX_CLIP_PLANES)
{ // this shouldn't really happen
- VectorClear (ent->v.velocity);
+ VectorClear (ent->v->velocity);
return 3;
}
@@ -338,28 +338,28 @@ int SV_FlyMove (edict_t *ent, float time1, trace_t *steptrace, int type)
if (i != numplanes)
{ // go along this plane
- VectorCopy (new_velocity, ent->v.velocity);
+ VectorCopy (new_velocity, ent->v->velocity);
}
else
{ // go along the crease
if (numplanes != 2)
{
// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
- VectorClear (ent->v.velocity);
+ VectorClear (ent->v->velocity);
return 7;
}
CrossProduct (planes[0], planes[1], dir);
- d = DotProduct (dir, ent->v.velocity);
- VectorScale (dir, d, ent->v.velocity);
+ d = DotProduct (dir, ent->v->velocity);
+ VectorScale (dir, d, ent->v->velocity);
}
//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
- if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
+ if (DotProduct (ent->v->velocity, primal_velocity) <= 0)
{
- VectorClear (ent->v.velocity);
+ VectorClear (ent->v->velocity);
return blocked;
}
}
@@ -375,7 +375,7 @@ SV_AddGravity
*/
void SV_AddGravity (edict_t *ent, float scale)
{
- ent->v.velocity[2] -= scale * movevars.gravity * sv_frametime;
+ ent->v->velocity[2] -= scale * movevars.gravity * sv_frametime;
}
/*
@@ -398,20 +398,20 @@ trace_t SV_PushEntity (edict_t *ent, vec3_t push, unsigned int traceflags)
trace_t trace;
vec3_t end;
- VectorAdd (ent->v.origin, push, end);
+ VectorAdd (ent->v->origin, push, end);
- if ((int)ent->v.flags&FL_LAGGEDMOVE)
+ if ((int)ent->v->flags&FL_LAGGEDMOVE)
traceflags |= MOVE_LAGGED;
- if (ent->v.movetype == MOVETYPE_FLYMISSILE)
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE|traceflags, ent);
- else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
+ if (ent->v->movetype == MOVETYPE_FLYMISSILE)
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE|traceflags, ent);
+ else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
// only clip against bmodels
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS|traceflags, ent);
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS|traceflags, ent);
else
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL|traceflags, ent);
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL|traceflags, ent);
- VectorCopy (trace.endpos, ent->v.origin);
+ VectorCopy (trace.endpos, ent->v->origin);
SV_LinkEdict (ent, true);
if (trace.e.ent)
@@ -440,15 +440,15 @@ qbool SV_Push (edict_t *pusher, vec3_t move)
for (i=0 ; i<3 ; i++)
{
- mins[i] = pusher->v.absmin[i] + move[i];
- maxs[i] = pusher->v.absmax[i] + move[i];
+ mins[i] = pusher->v->absmin[i] + move[i];
+ maxs[i] = pusher->v->absmax[i] + move[i];
}
- VectorCopy (pusher->v.origin, pushorig);
+ VectorCopy (pusher->v->origin, pushorig);
// move the pusher to its final position
- VectorAdd (pusher->v.origin, move, pusher->v.origin);
+ VectorAdd (pusher->v->origin, move, pusher->v->origin);
SV_LinkEdict (pusher, false);
// see if any solid entities are inside the final position
@@ -456,30 +456,30 @@ qbool SV_Push (edict_t *pusher, vec3_t move)
check = NEXT_EDICT(sv.edicts);
for (e=1 ; ee->free)
+ if (check->e.free)
continue;
- if (check->v.movetype == MOVETYPE_PUSH
- || check->v.movetype == MOVETYPE_NONE
- || check->v.movetype == MOVETYPE_NOCLIP)
+ if (check->v->movetype == MOVETYPE_PUSH
+ || check->v->movetype == MOVETYPE_NONE
+ || check->v->movetype == MOVETYPE_NOCLIP)
continue;
- solid_save = pusher->v.solid;
- pusher->v.solid = SOLID_NOT;
+ solid_save = pusher->v->solid;
+ pusher->v->solid = SOLID_NOT;
block = SV_TestEntityPosition (check);
- pusher->v.solid = solid_save;
+ pusher->v->solid = solid_save;
if (block)
continue;
// if the entity is standing on the pusher, it will definately be moved
- if ( ! ( ((int)check->v.flags & FL_ONGROUND)
- && PROG_TO_EDICT(check->v.groundentity) == pusher) )
+ if ( ! ( ((int)check->v->flags & FL_ONGROUND)
+ && PROG_TO_EDICT(check->v->groundentity) == pusher) )
{
- if ( check->v.absmin[0] >= maxs[0]
- || check->v.absmin[1] >= maxs[1]
- || check->v.absmin[2] >= maxs[2]
- || check->v.absmax[0] <= mins[0]
- || check->v.absmax[1] <= mins[1]
- || check->v.absmax[2] <= mins[2] )
+ if ( check->v->absmin[0] >= maxs[0]
+ || check->v->absmin[1] >= maxs[1]
+ || check->v->absmin[2] >= maxs[2]
+ || check->v->absmax[0] <= mins[0]
+ || check->v->absmax[1] <= mins[1]
+ || check->v->absmax[2] <= mins[2] )
continue;
// see if the ent's bbox is inside the pusher's final position
@@ -488,15 +488,15 @@ qbool SV_Push (edict_t *pusher, vec3_t move)
}
// remove the onground flag for non-players
- if (check->v.movetype != MOVETYPE_WALK)
- check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
+ if (check->v->movetype != MOVETYPE_WALK)
+ check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
- VectorCopy (check->v.origin, moved_from[num_moved]);
+ VectorCopy (check->v->origin, moved_from[num_moved]);
moved_edict[num_moved] = check;
num_moved++;
// try moving the contacted entity
- VectorAdd (check->v.origin, move, check->v.origin);
+ VectorAdd (check->v->origin, move, check->v->origin);
block = SV_TestEntityPosition (check);
if (!block)
{ // pushed ok
@@ -505,7 +505,7 @@ qbool SV_Push (edict_t *pusher, vec3_t move)
}
// if it is ok to leave in the old position, do it
- VectorSubtract (check->v.origin, move, check->v.origin);
+ VectorSubtract (check->v->origin, move, check->v->origin);
block = SV_TestEntityPosition (check);
if (!block)
{
@@ -517,35 +517,35 @@ qbool SV_Push (edict_t *pusher, vec3_t move)
}
// if it is still inside the pusher, block
- if (check->v.mins[0] == check->v.maxs[0])
+ if (check->v->mins[0] == check->v->maxs[0])
{
SV_LinkEdict (check, false);
continue;
}
- if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
+ if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
{ // corpse
- check->v.mins[0] = check->v.mins[1] = 0;
- VectorCopy (check->v.mins, check->v.maxs);
+ check->v->mins[0] = check->v->mins[1] = 0;
+ VectorCopy (check->v->mins, check->v->maxs);
SV_LinkEdict (check, false);
continue;
}
- VectorCopy (pushorig, pusher->v.origin);
+ VectorCopy (pushorig, pusher->v->origin);
SV_LinkEdict (pusher, false);
// if the pusher has a "blocked" function, call it
// otherwise, just stay in place until the obstacle is gone
- if (pusher->v.blocked)
+ if (pusher->v->blocked)
{
pr_global_struct->self = EDICT_TO_PROG(pusher);
pr_global_struct->other = EDICT_TO_PROG(check);
- PR_EdictBlocked (pusher->v.blocked);
+ PR_EdictBlocked (pusher->v->blocked);
}
// move back any entities we already moved
for (i=0 ; iv.origin);
+ VectorCopy (moved_from[i], moved_edict[i]->v->origin);
SV_LinkEdict (moved_edict[i], false);
}
return false;
@@ -565,17 +565,17 @@ void SV_PushMove (edict_t *pusher, float movetime)
int i;
vec3_t move;
- if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
+ if (!pusher->v->velocity[0] && !pusher->v->velocity[1] && !pusher->v->velocity[2])
{
- pusher->v.ltime += movetime;
+ pusher->v->ltime += movetime;
return;
}
for (i=0 ; i<3 ; i++)
- move[i] = pusher->v.velocity[i] * movetime;
+ move[i] = pusher->v->velocity[i] * movetime;
if (SV_Push (pusher, move))
- pusher->v.ltime += movetime;
+ pusher->v->ltime += movetime;
}
@@ -593,12 +593,12 @@ void SV_Physics_Pusher (edict_t *ent)
float l;
vec3_t oldorg, move;
- oldltime = ent->v.ltime;
+ oldltime = ent->v->ltime;
- thinktime = ent->v.nextthink;
- if (thinktime < ent->v.ltime + sv_frametime)
+ thinktime = ent->v->nextthink;
+ if (thinktime < ent->v->ltime + sv_frametime)
{
- movetime = thinktime - ent->v.ltime;
+ movetime = thinktime - ent->v->ltime;
if (movetime < 0)
movetime = 0;
}
@@ -607,27 +607,27 @@ void SV_Physics_Pusher (edict_t *ent)
if (movetime)
{
- SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
+ SV_PushMove (ent, movetime); // advances ent->v->ltime if not blocked
}
- if (thinktime > oldltime && thinktime <= ent->v.ltime)
+ if (thinktime > oldltime && thinktime <= ent->v->ltime)
{
- VectorCopy (ent->v.origin, oldorg);
- ent->v.nextthink = 0;
+ VectorCopy (ent->v->origin, oldorg);
+ ent->v->nextthink = 0;
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
- PR_EdictThink(ent->v.think);
+ PR_EdictThink(ent->v->think);
- if (ent->e->free)
+ if (ent->e.free)
return;
- VectorSubtract (ent->v.origin, oldorg, move);
+ VectorSubtract (ent->v->origin, oldorg, move);
l = VectorLength(move);
if (l > 1.0/64)
{
// Con_Printf ("**** snap: %f\n", VectorLength (l));
- VectorCopy (oldorg, ent->v.origin);
+ VectorCopy (oldorg, ent->v->origin);
SV_Push (ent, move);
}
}
@@ -659,8 +659,8 @@ void SV_Physics_Noclip (edict_t *ent)
if (!SV_RunThink (ent))
return;
- VectorMA (ent->v.angles, sv_frametime, ent->v.avelocity, ent->v.angles);
- VectorMA (ent->v.origin, sv_frametime, ent->v.velocity, ent->v.origin);
+ VectorMA (ent->v->angles, sv_frametime, ent->v->avelocity, ent->v->angles);
+ VectorMA (ent->v->origin, sv_frametime, ent->v->velocity, ent->v->origin);
SV_LinkEdict (ent, false);
}
@@ -683,31 +683,31 @@ void SV_CheckWaterTransition (edict_t *ent)
{
int cont;
- cont = SV_PointContents (ent->v.origin);
- if (!ent->v.watertype)
+ cont = SV_PointContents (ent->v->origin);
+ if (!ent->v->watertype)
{ // just spawned here
- ent->v.watertype = cont;
- ent->v.waterlevel = 1;
+ ent->v->watertype = cont;
+ ent->v->waterlevel = 1;
return;
}
if (cont <= CONTENTS_WATER)
{
- if (ent->v.watertype == CONTENTS_EMPTY)
+ if (ent->v->watertype == CONTENTS_EMPTY)
{ // just crossed into water
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
}
- ent->v.watertype = cont;
- ent->v.waterlevel = 1;
+ ent->v->watertype = cont;
+ ent->v->waterlevel = 1;
}
else
{
- if (ent->v.watertype != CONTENTS_EMPTY)
+ if (ent->v->watertype != CONTENTS_EMPTY)
{ // just crossed into water
SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
}
- ent->v.watertype = CONTENTS_EMPTY;
- ent->v.waterlevel = cont;
+ ent->v->watertype = CONTENTS_EMPTY;
+ ent->v->waterlevel = cont;
}
}
@@ -728,47 +728,47 @@ void SV_Physics_Toss (edict_t *ent)
if (!SV_RunThink (ent))
return;
- if (ent->v.velocity[2] > 0)
- ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
+ if (ent->v->velocity[2] > 0)
+ ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
// if onground, return without moving
- if ( ((int)ent->v.flags & FL_ONGROUND) )
+ if ( ((int)ent->v->flags & FL_ONGROUND) )
return;
SV_CheckVelocity (ent);
// add gravity
- if (ent->v.movetype != MOVETYPE_FLY
- && ent->v.movetype != MOVETYPE_FLYMISSILE)
+ if (ent->v->movetype != MOVETYPE_FLY
+ && ent->v->movetype != MOVETYPE_FLYMISSILE)
SV_AddGravity (ent, 1.0);
// move angles
- VectorMA (ent->v.angles, sv_frametime, ent->v.avelocity, ent->v.angles);
+ VectorMA (ent->v->angles, sv_frametime, ent->v->avelocity, ent->v->angles);
// move origin
- VectorScale (ent->v.velocity, sv_frametime, move);
+ VectorScale (ent->v->velocity, sv_frametime, move);
trace = SV_PushEntity (ent, move, (sv_antilag.value == 2 && sv_antilag_projectiles.value) ? MOVE_LAGGED:0);
if (trace.fraction == 1)
return;
- if (ent->e->free)
+ if (ent->e.free)
return;
- if (ent->v.movetype == MOVETYPE_BOUNCE)
+ if (ent->v->movetype == MOVETYPE_BOUNCE)
backoff = 1.5;
else
backoff = 1;
- ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
+ ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, backoff);
// stop if on ground
if (trace.plane.normal[2] > 0.7)
{
- if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE )
+ if (ent->v->velocity[2] < 60 || ent->v->movetype != MOVETYPE_BOUNCE )
{
- ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(trace.e.ent);
- VectorClear (ent->v.velocity);
- VectorClear (ent->v.avelocity);
+ ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+ ent->v->groundentity = EDICT_TO_PROG(trace.e.ent);
+ VectorClear (ent->v->velocity);
+ VectorClear (ent->v->avelocity);
}
}
@@ -801,9 +801,9 @@ void SV_Physics_Step (edict_t *ent)
qbool hitsound;
// frefall if not onground
- if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
+ if ( ! ((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
{
- if (ent->v.velocity[2] < movevars.gravity*-0.1)
+ if (ent->v->velocity[2] < movevars.gravity*-0.1)
hitsound = true;
else
hitsound = false;
@@ -813,13 +813,13 @@ void SV_Physics_Step (edict_t *ent)
// Tonik: the check for SOLID_NOT is to fix the way dead bodies and
// gibs behave (should not be blocked by players & monsters);
// The SOLID_TRIGGER check is disabled lest we break frikbots
- if (ent->v.solid == SOLID_NOT /* || ent->v.solid == SOLID_TRIGGER*/)
+ if (ent->v->solid == SOLID_NOT /* || ent->v->solid == SOLID_TRIGGER*/)
SV_FlyMove (ent, sv_frametime, NULL, MOVE_NOMONSTERS);
else
SV_FlyMove (ent, sv_frametime, NULL, MOVE_NORMAL);
SV_LinkEdict (ent, true);
- if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
+ if ( (int)ent->v->flags & FL_ONGROUND ) // just hit ground
{
if (hitsound)
SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
@@ -850,11 +850,11 @@ SV_RunEntity
*/
void SV_RunEntity (edict_t *ent)
{
- if (ent->e->lastruntime == sv.time)
+ if (ent->e.lastruntime == sv.time)
return;
- ent->e->lastruntime = sv.time;
+ ent->e.lastruntime = sv.time;
- switch ((int)ent->v.movetype)
+ switch ((int)ent->v->movetype)
{
case MOVETYPE_PUSH:
SV_Physics_Pusher (ent);
@@ -876,7 +876,7 @@ void SV_RunEntity (edict_t *ent)
SV_Physics_Toss (ent);
break;
default:
- SV_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
+ SV_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
}
}
@@ -895,15 +895,15 @@ void SV_RunNQNewmis (void)
ent = NEXT_EDICT(sv.edicts);
for (i=1 ; ie->free)
+ if (ent->e.free)
continue;
- if (ent->e->lastruntime || ent->v.owner != pl)
+ if (ent->e.lastruntime || ent->v->owner != pl)
continue;
- if (ent->v.movetype != MOVETYPE_FLY &&
- ent->v.movetype != MOVETYPE_FLYMISSILE &&
- ent->v.movetype != MOVETYPE_BOUNCE)
+ if (ent->v->movetype != MOVETYPE_FLY &&
+ ent->v->movetype != MOVETYPE_FLYMISSILE &&
+ ent->v->movetype != MOVETYPE_BOUNCE)
continue;
- if (ent->v.solid != SOLID_BBOX && ent->v.solid != SOLID_TRIGGER)
+ if (ent->v->solid != SOLID_BBOX && ent->v->solid != SOLID_TRIGGER)
continue;
save_frametime = sv_frametime;
@@ -985,7 +985,7 @@ void SV_Physics (void)
ent = sv.edicts;
for (i=0 ; ie->free)
+ if (ent->e.free)
continue;
if (PR_GLOBAL(force_retouch))
@@ -1014,7 +1014,7 @@ void SV_Physics (void)
sv_player = cl->edict;
if (sv_client->spectator && sv_client->spec_track > 0)
- sv_player->v.goalentity = EDICT_TO_PROG(svs.clients[sv_client->spec_track-1].edict);
+ sv_player->v->goalentity = EDICT_TO_PROG(svs.clients[sv_client->spec_track-1].edict);
}
sv_player = savesvpl;
@@ -1104,7 +1104,7 @@ void SV_RunBots(void)
if (sv_antilag.value) {
if (cl->antilag_position_next == 0 || cl->antilag_positions[(cl->antilag_position_next - 1) % MAX_ANTILAG_POSITIONS].localtime < cl->localtime) {
cl->antilag_positions[cl->antilag_position_next % MAX_ANTILAG_POSITIONS].localtime = cl->localtime;
- VectorCopy(cl->edict->v.origin, cl->antilag_positions[cl->antilag_position_next % MAX_ANTILAG_POSITIONS].origin);
+ VectorCopy(cl->edict->v->origin, cl->antilag_positions[cl->antilag_position_next % MAX_ANTILAG_POSITIONS].origin);
cl->antilag_position_next++;
}
}
diff --git a/src/sv_save.c b/src/sv_save.c
index 114918985..536c52f49 100644
--- a/src/sv_save.c
+++ b/src/sv_save.c
@@ -114,7 +114,7 @@ void SV_SaveGame_f(void)
if (svs.clients[0].state != cs_spawned) {
Con_Printf ("Can't save, client #0 not spawned.\n");
return;
- } else if (svs.clients[0].edict->v.health <= 0) {
+ } else if (svs.clients[0].edict->v->health <= 0) {
Con_Printf ("Can't save game with a dead player\n");
// in fact, we can, but does it make sense?
return;
@@ -297,7 +297,7 @@ void SV_LoadGame_f(void)
ED_ParseEdict (start, ent);
// link it into the bsp tree
- if (!ent->e->free)
+ if (!ent->e.free)
SV_LinkEdict (ent, false);
}
entnum++;
diff --git a/src/sv_send.c b/src/sv_send.c
index 636427c94..ce987e76b 100644
--- a/src/sv_send.c
+++ b/src/sv_send.c
@@ -458,18 +458,18 @@ void SV_MulticastEx (vec3_t origin, int to, const char *cl_reliable_key)
// in case of trackent we have to reflect his origin so PHS work right.
if (fofs_trackent)
{
- trackent = ((eval_t *)((byte *)&(client->edict)->v + fofs_trackent))->_int;
+ trackent = ((eval_t *)((byte *)(client->edict)->v + fofs_trackent))->_int;
if (trackent < 1 || trackent > MAX_CLIENTS || svs.clients[trackent - 1].state != cs_spawned)
trackent = 0;
}
if (trackent)
{
- VectorAdd (svs.clients[trackent - 1].edict->v.origin, svs.clients[trackent - 1].edict->v.view_ofs, vieworg);
+ VectorAdd (svs.clients[trackent - 1].edict->v->origin, svs.clients[trackent - 1].edict->v->view_ofs, vieworg);
}
else
{
- VectorAdd (client->edict->v.origin, client->edict->v.view_ofs, vieworg);
+ VectorAdd (client->edict->v->origin, client->edict->v->view_ofs, vieworg);
}
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
@@ -647,14 +647,14 @@ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, floa
channel |= SND_ATTENUATION;
// use the entity origin unless it is a bmodel or a trigger
- if (entity->v.solid == SOLID_BSP || (entity->v.solid == SOLID_TRIGGER && entity->v.modelindex == 0))
+ if (entity->v->solid == SOLID_BSP || (entity->v->solid == SOLID_TRIGGER && entity->v->modelindex == 0))
{
for (i=0 ; i<3 ; i++)
- origin[i] = entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]);
+ origin[i] = entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]);
}
else
{
- VectorCopy (entity->v.origin, origin);
+ VectorCopy (entity->v->origin, origin);
}
MSG_WriteByte (&sv.multicast, svc_sound);
@@ -731,17 +731,17 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
}
// send a damage message if the player got hit this frame
- if (ent->v.dmg_take || ent->v.dmg_save)
+ if (ent->v->dmg_take || ent->v->dmg_save)
{
- other = PROG_TO_EDICT(ent->v.dmg_inflictor);
+ other = PROG_TO_EDICT(ent->v->dmg_inflictor);
MSG_WriteByte (msg, svc_damage);
- MSG_WriteByte (msg, ent->v.dmg_save);
- MSG_WriteByte (msg, ent->v.dmg_take);
+ MSG_WriteByte (msg, ent->v->dmg_save);
+ MSG_WriteByte (msg, ent->v->dmg_take);
for (i=0 ; i<3 ; i++)
- MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
+ MSG_WriteCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]));
- ent->v.dmg_take = 0;
- ent->v.dmg_save = 0;
+ ent->v->dmg_take = 0;
+ ent->v->dmg_save = 0;
}
// add this to server demo
@@ -754,17 +754,17 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
}
// a fixangle might get lost in a dropped packet. Oh well.
- if (ent->v.fixangle)
+ if (ent->v->fixangle)
{
- ent->v.fixangle = 0;
+ ent->v->fixangle = 0;
demo.fixangle[clnum] = true;
- MSG_WriteByte (msg, svc_setangle);
+ MSG_WriteByte(msg, svc_setangle);
#ifdef MVD_PEXT1_HIGHLAGTELEPORT
if (client->mvdprotocolextensions1 & MVD_PEXT1_HIGHLAGTELEPORT) {
if (fofs_teleported) {
- client->lastteleport_teleport = ((eval_t *)((byte *)&(client->edict)->v + fofs_teleported))->_int;
+ client->lastteleport_teleport = ((eval_t *)((byte *)(client->edict)->v + fofs_teleported))->_int;
if (client->lastteleport_teleport) {
MSG_WriteByte(msg, 1); // signal a teleport
}
@@ -773,9 +773,9 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
}
client->lastteleport_outgoingseq = client->netchan.outgoing_sequence;
client->lastteleport_incomingseq = client->netchan.incoming_sequence;
- client->lastteleport_teleportyaw = (client->edict)->v.angles[YAW] - client->lastcmd.angles[YAW];
+ client->lastteleport_teleportyaw = (client->edict)->v->angles[YAW] - client->lastcmd.angles[YAW];
- ((eval_t *)((byte *)&(client->edict)->v + fofs_teleported))->_int = 0;
+ ((eval_t *)((byte *)(client->edict)->v + fofs_teleported))->_int = 0;
SV_RotateCmd(client, &client->lastcmd);
}
else {
@@ -785,14 +785,14 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
#endif
for (i=0 ; i < 3 ; i++)
- MSG_WriteAngle (msg, ent->v.angles[i] );
+ MSG_WriteAngle (msg, ent->v->angles[i] );
if (sv.mvdrecording)
{
MSG_WriteByte (&demo.datagram, svc_setangle);
MSG_WriteByte (&demo.datagram, clnum);
for (i=0 ; i < 3 ; i++)
- MSG_WriteAngle (&demo.datagram, ent->v.angles[i] );
+ MSG_WriteAngle (&demo.datagram, ent->v->angles[i] );
}
}
@@ -851,7 +851,7 @@ void SV_UpdateClientStats (client_t *client)
// in case of trackent we have to reflect his stats like for spectator.
if (fofs_trackent)
{
- int trackent = ((eval_t *)((byte *)&(client->edict)->v + fofs_trackent))->_int;
+ int trackent = ((eval_t *)((byte *)(client->edict)->v + fofs_trackent))->_int;
if (trackent < 1 || trackent > MAX_CLIENTS || svs.clients[trackent - 1].state != cs_spawned)
trackent = 0;
@@ -859,23 +859,23 @@ void SV_UpdateClientStats (client_t *client)
ent = svs.clients[trackent - 1].edict;
}
- stats[STAT_HEALTH] = ent->v.health;
- stats[STAT_WEAPON] = SV_ModelIndex(PR_GetEntityString(ent->v.weaponmodel));
- stats[STAT_AMMO] = ent->v.currentammo;
- stats[STAT_ARMOR] = ent->v.armorvalue;
- stats[STAT_SHELLS] = ent->v.ammo_shells;
- stats[STAT_NAILS] = ent->v.ammo_nails;
- stats[STAT_ROCKETS] = ent->v.ammo_rockets;
- stats[STAT_CELLS] = ent->v.ammo_cells;
+ stats[STAT_HEALTH] = ent->v->health;
+ stats[STAT_WEAPON] = SV_ModelIndex(PR_GetEntityString(ent->v->weaponmodel));
+ stats[STAT_AMMO] = ent->v->currentammo;
+ stats[STAT_ARMOR] = ent->v->armorvalue;
+ stats[STAT_SHELLS] = ent->v->ammo_shells;
+ stats[STAT_NAILS] = ent->v->ammo_nails;
+ stats[STAT_ROCKETS] = ent->v->ammo_rockets;
+ stats[STAT_CELLS] = ent->v->ammo_cells;
if (!client->spectator || client->spec_track > 0)
- stats[STAT_ACTIVEWEAPON] = ent->v.weapon;
+ stats[STAT_ACTIVEWEAPON] = ent->v->weapon;
// stuff the sigil bits into the high bits of items for sbar
- stats[STAT_ITEMS] = (int) ent->v.items | ((int) PR_GLOBAL(serverflags) << 28);
+ stats[STAT_ITEMS] = (int) ent->v->items | ((int) PR_GLOBAL(serverflags) << 28);
if (fofs_items2) // ZQ_ITEMS2 extension
stats[STAT_ITEMS] |= (int)EdictFieldFloat(ent, fofs_items2) << 23;
- if (ent->v.health > 0 || client->spectator) // viewheight for PF_DEAD & PF_GIB is hardwired
- stats[STAT_VIEWHEIGHT] = ent->v.view_ofs[2];
+ if (ent->v->health > 0 || client->spectator) // viewheight for PF_DEAD & PF_GIB is hardwired
+ stats[STAT_VIEWHEIGHT] = ent->v->view_ofs[2];
for (i=0 ; istats[i])
@@ -982,7 +982,7 @@ static void SV_UpdateToReliableMessages (void)
ent = sv_client->edict;
- if (sv_client->old_frags != (int)ent->v.frags)
+ if (sv_client->old_frags != (int)ent->v->frags)
{
for (j=0, client = svs.clients ; jv.frags);
+ ClientReliableWrite_Short(client, (int) ent->v->frags);
}
if (sv.mvdrecording)
@@ -999,11 +999,11 @@ static void SV_UpdateToReliableMessages (void)
{
MVD_MSG_WriteByte(svc_updatefrags);
MVD_MSG_WriteByte(i);
- MVD_MSG_WriteShort((int)ent->v.frags);
+ MVD_MSG_WriteShort((int)ent->v->frags);
}
}
- sv_client->old_frags = (int) ent->v.frags;
+ sv_client->old_frags = (int) ent->v->frags;
}
// maxspeed/entgravity changes
@@ -1096,7 +1096,7 @@ void SV_SendClientMessages (void)
if (fofs_visibility) {
for (i = 0; i < MAX_CLIENTS; ++i) {
- ((eval_t *)((byte *)&(svs.clients[i].edict)->v + fofs_visibility))->_int = 0;
+ ((eval_t *)((byte *)(svs.clients[i].edict)->v + fofs_visibility))->_int = 0;
}
}
@@ -1198,22 +1198,22 @@ static void SV_BotWriteDamage(client_t* c, int i)
{
edict_t* ent = c->edict;
- if (c->edict->v.dmg_take || c->edict->v.dmg_save) {
- if (ent->v.dmg_take || ent->v.dmg_save) {
+ if (c->edict->v->dmg_take || c->edict->v->dmg_save) {
+ if (ent->v->dmg_take || ent->v->dmg_save) {
int length = 3 + 3 * msg_coordsize;
if (MVDWrite_Begin(dem_single, i, length)) {
- edict_t* other = PROG_TO_EDICT(ent->v.dmg_inflictor);
+ edict_t* other = PROG_TO_EDICT(ent->v->dmg_inflictor);
MVD_MSG_WriteByte(svc_damage);
- MVD_MSG_WriteByte(ent->v.dmg_save);
- MVD_MSG_WriteByte(ent->v.dmg_take);
+ MVD_MSG_WriteByte(ent->v->dmg_save);
+ MVD_MSG_WriteByte(ent->v->dmg_take);
for (i = 0; i < 3; i++)
- MVD_MSG_WriteCoord(other->v.origin[i] + 0.5 * (other->v.mins[i] + other->v.maxs[i]));
+ MVD_MSG_WriteCoord(other->v->origin[i] + 0.5 * (other->v->mins[i] + other->v->maxs[i]));
}
- ent->v.dmg_take = 0;
- ent->v.dmg_save = 0;
+ ent->v->dmg_take = 0;
+ ent->v->dmg_save = 0;
}
}
}
@@ -1258,21 +1258,21 @@ void MVD_WriteStats(void)
ent = c->edict;
memset (stats, 0, sizeof(stats));
- stats[STAT_HEALTH] = ent->v.health;
- stats[STAT_WEAPON] = SV_ModelIndex(PR_GetEntityString(ent->v.weaponmodel));
- stats[STAT_AMMO] = ent->v.currentammo;
- stats[STAT_ARMOR] = ent->v.armorvalue;
- stats[STAT_SHELLS] = ent->v.ammo_shells;
- stats[STAT_NAILS] = ent->v.ammo_nails;
- stats[STAT_ROCKETS] = ent->v.ammo_rockets;
- stats[STAT_CELLS] = ent->v.ammo_cells;
- stats[STAT_ACTIVEWEAPON] = ent->v.weapon;
+ stats[STAT_HEALTH] = ent->v->health;
+ stats[STAT_WEAPON] = SV_ModelIndex(PR_GetEntityString(ent->v->weaponmodel));
+ stats[STAT_AMMO] = ent->v->currentammo;
+ stats[STAT_ARMOR] = ent->v->armorvalue;
+ stats[STAT_SHELLS] = ent->v->ammo_shells;
+ stats[STAT_NAILS] = ent->v->ammo_nails;
+ stats[STAT_ROCKETS] = ent->v->ammo_rockets;
+ stats[STAT_CELLS] = ent->v->ammo_cells;
+ stats[STAT_ACTIVEWEAPON] = ent->v->weapon;
- if (ent->v.health > 0) // viewheight for PF_DEAD & PF_GIB is hardwired
- stats[STAT_VIEWHEIGHT] = ent->v.view_ofs[2];
+ if (ent->v->health > 0) // viewheight for PF_DEAD & PF_GIB is hardwired
+ stats[STAT_VIEWHEIGHT] = ent->v->view_ofs[2];
// stuff the sigil bits into the high bits of items for sbar
- stats[STAT_ITEMS] = (int) ent->v.items | ((int) PR_GLOBAL(serverflags) << 28);
+ stats[STAT_ITEMS] = (int) ent->v->items | ((int) PR_GLOBAL(serverflags) << 28);
for (j = 0 ; j < MAX_CL_STATS; j++)
{
diff --git a/src/sv_user.c b/src/sv_user.c
index cdb832674..71f6d70d2 100644
--- a/src/sv_user.c
+++ b/src/sv_user.c
@@ -70,11 +70,8 @@ static struct {
antilag_client_info_t antilag_clients[MAX_CLIENTS];
} debug_info;
-#ifdef MVD_PEXT1_SERVERSIDEWEAPON
static void SV_DebugServerSideWeaponScript(client_t* cl, int best_impulse);
static void SV_DebugServerSideWeaponInstruction(client_t* cl);
-static void SV_UserSetWeaponRank(client_t* cl, const char* new_wrank);
-#endif
cvar_t sv_debug_weapons = { "sv_debug_weapons", "0" };
#endif
@@ -82,6 +79,7 @@ cvar_t sv_debug_weapons = { "sv_debug_weapons", "0" };
cvar_t sv_debug_usercmd = { "sv_debug_usercmd", "0" };
cvar_t sv_debug_antilag = { "sv_debug_antilag", "0" };
+static void SV_UserSetWeaponRank(client_t* cl, const char* new_wrank);
static void SV_DebugClientCommand(byte playernum, const usercmd_t* cmd, int dropnum_);
extern vec3_t player_mins;
@@ -177,6 +175,9 @@ Check that player's ping falls below sv_maxping value
*/
qbool PlayerCheckPing(void)
{
+
+ if (sv_client->maxping_met) return true;
+
int maxping = Q_atof(sv_maxping.string);
int playerping = sv_client->frames[sv_client->netchan.incoming_acknowledged & UPDATE_MASK].ping_time * 1000;
@@ -185,6 +186,7 @@ qbool PlayerCheckPing(void)
SV_ClientPrintf(sv_client, PRINT_HIGH, "\nYour ping is too high for this server! Maximum ping is set to %i, your ping is %i.\nForcing spectator.\n\n", maxping, playerping);
return false;
}
+ sv_client->maxping_met = true;
return true;
}
@@ -218,7 +220,7 @@ static void Cmd_New_f (void)
{
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
MSG_WriteString (&sv_client->netchan.message, "cmd pext\n");
- return;
+ return;
}
// do not proceed if realip is unknown
@@ -402,7 +404,7 @@ static void Cmd_New_f (void)
if (sv_client->rip_vip)
MSG_WriteString (&sv_client->netchan.message, "");
else
- MSG_WriteString (&sv_client->netchan.message, PR_GetEntityString(sv.edicts->v.message));
+ MSG_WriteString (&sv_client->netchan.message, PR_GetEntityString(sv.edicts->v->message));
// send the movevars
MSG_WriteFloat(&sv_client->netchan.message, movevars.gravity);
@@ -436,7 +438,7 @@ static void Cmd_New_f (void)
// send music
MSG_WriteByte (&sv_client->netchan.message, svc_cdtrack);
- MSG_WriteByte (&sv_client->netchan.message, sv.edicts->v.sounds);
+ MSG_WriteByte (&sv_client->netchan.message, sv.edicts->v->sounds);
// send server info string
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
@@ -722,7 +724,7 @@ static void Cmd_PreSpawn_f (void)
for (i = buf - sv.static_entity_count; i < sv.num_baseline_edicts; ++i) {
edict_t* svent = EDICT_NUM(i);
- entity_state_t* s = &svent->e->baseline;
+ entity_state_t* s = &svent->e.baseline;
if (sv_client->netchan.message.cursize >= (sv_client->netchan.message.maxsize / 2)) {
break;
@@ -740,13 +742,13 @@ static void Cmd_PreSpawn_f (void)
else if (s->modelindex < 256) {
MSG_WriteByte(&sv_client->netchan.message, svc_spawnbaseline);
MSG_WriteShort(&sv_client->netchan.message, i);
- MSG_WriteByte(&sv_client->netchan.message, svent->e->baseline.modelindex);
- MSG_WriteByte(&sv_client->netchan.message, svent->e->baseline.frame);
- MSG_WriteByte(&sv_client->netchan.message, svent->e->baseline.colormap);
- MSG_WriteByte(&sv_client->netchan.message, svent->e->baseline.skinnum);
+ MSG_WriteByte(&sv_client->netchan.message, svent->e.baseline.modelindex);
+ MSG_WriteByte(&sv_client->netchan.message, svent->e.baseline.frame);
+ MSG_WriteByte(&sv_client->netchan.message, svent->e.baseline.colormap);
+ MSG_WriteByte(&sv_client->netchan.message, svent->e.baseline.skinnum);
for (j = 0; j < 3; j++) {
- MSG_WriteCoord(&sv_client->netchan.message, svent->e->baseline.origin[j]);
- MSG_WriteAngle(&sv_client->netchan.message, svent->e->baseline.angles[j]);
+ MSG_WriteCoord(&sv_client->netchan.message, svent->e.baseline.origin[j]);
+ MSG_WriteAngle(&sv_client->netchan.message, svent->e.baseline.angles[j]);
}
}
++buf;
@@ -891,20 +893,20 @@ static void SV_SpawnSpectator (void)
int i;
edict_t *e;
- VectorClear (sv_player->v.origin);
- VectorClear (sv_player->v.view_ofs);
- sv_player->v.view_ofs[2] = 22;
- sv_player->v.fixangle = true;
- sv_player->v.movetype = MOVETYPE_NOCLIP; // progs can change this to MOVETYPE_FLY, for example
+ VectorClear (sv_player->v->origin);
+ VectorClear (sv_player->v->view_ofs);
+ sv_player->v->view_ofs[2] = 22;
+ sv_player->v->fixangle = true;
+ sv_player->v->movetype = MOVETYPE_NOCLIP; // progs can change this to MOVETYPE_FLY, for example
// search for an info_playerstart to spawn the spectator at
for (i=MAX_CLIENTS-1 ; iv.classname), "info_player_start"))
+ if (!strcmp(PR_GetEntityString(e->v->classname), "info_player_start"))
{
- VectorCopy (e->v.origin, sv_player->v.origin);
- VectorCopy (e->v.angles, sv_player->v.angles);
+ VectorCopy (e->v->origin, sv_player->v->origin);
+ VectorCopy (e->v->angles, sv_player->v->angles);
return;
}
}
@@ -997,7 +999,7 @@ static void Cmd_Begin_f (void)
ent = EDICT_NUM( 1 + (sv_client - svs.clients) );
MSG_WriteByte (&sv_client->netchan.message, svc_setangle);
for (i = 0; i < 2; i++)
- MSG_WriteAngle (&sv_client->netchan.message, ent->v.v_angle[i]);
+ MSG_WriteAngle (&sv_client->netchan.message, ent->v->v_angle[i]);
MSG_WriteAngle (&sv_client->netchan.message, 0);
}
@@ -1088,7 +1090,6 @@ void SV_CompleteDownoload(void)
}
}
-
/*
==================
Cmd_NextDownload_f
@@ -1890,7 +1891,6 @@ static void SV_Say (qbool team)
}
}
-
/*
==================
Cmd_Say_f
@@ -1949,7 +1949,7 @@ Cmd_Kill_f
*/
static void Cmd_Kill_f (void)
{
- if (sv_player->v.health <= 0)
+ if (sv_player->v->health <= 0)
{
SV_ClientPrintf (sv_client, PRINT_HIGH, "Can't suicide -- already dead!\n");
return;
@@ -2091,7 +2091,7 @@ static void Cmd_PTrack_f (void)
sv_client->spec_track = 0;
ent = EDICT_NUM(sv_client - svs.clients + 1);
tent = EDICT_NUM(0);
- ent->v.goalentity = EDICT_TO_PROG(tent);
+ ent->v->goalentity = EDICT_TO_PROG(tent);
return;
}
@@ -2102,14 +2102,14 @@ static void Cmd_PTrack_f (void)
sv_client->spec_track = 0;
ent = EDICT_NUM(sv_client - svs.clients + 1);
tent = EDICT_NUM(0);
- ent->v.goalentity = EDICT_TO_PROG(tent);
+ ent->v->goalentity = EDICT_TO_PROG(tent);
return;
}
sv_client->spec_track = i + 1; // now tracking
ent = EDICT_NUM(sv_client - svs.clients + 1);
tent = EDICT_NUM(i + 1);
- ent->v.goalentity = EDICT_TO_PROG(tent);
+ ent->v->goalentity = EDICT_TO_PROG(tent);
}
/*
@@ -2316,7 +2316,7 @@ static void Cmd_SetInfo_f (void)
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(sv_player);
- if (PR_UserInfoChanged())
+ if (PR_UserInfoChanged(0))
return; // does not allowed to be changed by mod.
Info_Set (&sv_client->_userinfo_ctx_, Cmd_Argv(1), Cmd_Argv(2));
@@ -2386,6 +2386,7 @@ static void Cmd_SetInfo_f (void)
//<-
ProcessUserInfoChange (sv_client, Cmd_Argv (1), oldval);
+ PR_UserInfoChanged(1);
}
void ProcessUserInfoChange (client_t* sv_client, const char* key, const char* old_value)
@@ -2561,14 +2562,14 @@ static void SetUpClientEdict (client_t *cl, edict_t *ent)
{
ED_ClearEdict(ent);
// restore client name.
- PR_SetEntityString(ent, ent->v.netname, cl->name);
+ PR_SetEntityString(ent, ent->v->netname, cl->name);
// so spec will have right goalentity - if speccing someone
if(cl->spectator && cl->spec_track > 0)
- ent->v.goalentity = EDICT_TO_PROG(svs.clients[cl->spec_track-1].edict);
+ ent->v->goalentity = EDICT_TO_PROG(svs.clients[cl->spec_track-1].edict);
- ent->v.colormap = NUM_FOR_EDICT(ent);
+ ent->v->colormap = NUM_FOR_EDICT(ent);
- ent->v.team = 0; // FIXME
+ ent->v->team = 0; // FIXME
cl->entgravity = 1.0;
if (fofs_gravity)
@@ -3383,18 +3384,18 @@ static void AddLinksToPmove ( areanode_t *node )
next = l->next;
check = EDICT_FROM_AREA(l);
- if (check->v.owner == pl)
+ if (check->v->owner == pl)
continue; // player's own missile
- if (check->v.solid == SOLID_BSP
- || check->v.solid == SOLID_BBOX
- || check->v.solid == SOLID_SLIDEBOX)
+ if (check->v->solid == SOLID_BSP
+ || check->v->solid == SOLID_BBOX
+ || check->v->solid == SOLID_SLIDEBOX)
{
if (check == sv_player)
continue;
for (i=0 ; i<3 ; i++)
- if (check->v.absmin[i] > pmove_maxs[i]
- || check->v.absmax[i] < pmove_mins[i])
+ if (check->v->absmin[i] > pmove_maxs[i]
+ || check->v->absmax[i] < pmove_mins[i])
break;
if (i != 3)
continue;
@@ -3403,20 +3404,20 @@ static void AddLinksToPmove ( areanode_t *node )
pe = &pmove.physents[pmove.numphysent];
pmove.numphysent++;
- VectorCopy (check->v.origin, pe->origin);
+ VectorCopy (check->v->origin, pe->origin);
pe->info = NUM_FOR_EDICT(check);
- if (check->v.solid == SOLID_BSP) {
- if ((unsigned)check->v.modelindex >= MAX_MODELS)
- SV_Error ("AddLinksToPmove: check->v.modelindex >= MAX_MODELS");
- pe->model = sv.models[(int)(check->v.modelindex)];
+ if (check->v->solid == SOLID_BSP) {
+ if ((unsigned)check->v->modelindex >= MAX_MODELS)
+ SV_Error ("AddLinksToPmove: check->v->modelindex >= MAX_MODELS");
+ pe->model = sv.models[(int)(check->v->modelindex)];
if (!pe->model)
SV_Error ("SOLID_BSP with a non-bsp model");
}
else
{
pe->model = NULL;
- VectorCopy (check->v.mins, pe->mins);
- VectorCopy (check->v.maxs, pe->maxs);
+ VectorCopy (check->v->mins, pe->mins);
+ VectorCopy (check->v->maxs, pe->maxs);
}
}
}
@@ -3433,22 +3434,22 @@ static void AddLinksToPmove ( areanode_t *node )
int SV_PMTypeForClient (client_t *cl)
{
- if (cl->edict->v.movetype == MOVETYPE_NOCLIP) {
+ if (cl->edict->v->movetype == MOVETYPE_NOCLIP) {
if (cl->extensions & Z_EXT_PM_TYPE_NEW)
return PM_SPECTATOR;
return PM_OLD_SPECTATOR;
}
- if (cl->edict->v.movetype == MOVETYPE_FLY)
+ if (cl->edict->v->movetype == MOVETYPE_FLY)
return PM_FLY;
- if (cl->edict->v.movetype == MOVETYPE_NONE)
+ if (cl->edict->v->movetype == MOVETYPE_NONE)
return PM_NONE;
- if (cl->edict->v.movetype == MOVETYPE_LOCK)
+ if (cl->edict->v->movetype == MOVETYPE_LOCK)
return PM_LOCK;
- if (cl->edict->v.health <= 0)
+ if (cl->edict->v->health <= 0)
return PM_DEAD;
return PM_NORMAL;
@@ -3536,36 +3537,36 @@ void SV_RunCmd (usercmd_t *ucmd, qbool inside, qbool second_attempt) //bliP: 24/
}
// copy humans' intentions to progs
- sv_player->v.button0 = ucmd->buttons & 1;
- sv_player->v.button2 = (ucmd->buttons & 2) >> 1;
- sv_player->v.button1 = (ucmd->buttons & 4) >> 2;
+ sv_player->v->button0 = ucmd->buttons & 1;
+ sv_player->v->button2 = (ucmd->buttons & 2) >> 1;
+ sv_player->v->button1 = (ucmd->buttons & 4) >> 2;
if (ucmd->impulse)
- sv_player->v.impulse = ucmd->impulse;
+ sv_player->v->impulse = ucmd->impulse;
if (fofs_movement) {
EdictFieldVector(sv_player, fofs_movement)[0] = ucmd->forwardmove;
EdictFieldVector(sv_player, fofs_movement)[1] = ucmd->sidemove;
EdictFieldVector(sv_player, fofs_movement)[2] = ucmd->upmove;
}
- //bliP: cuff
+ // bliP: cuff
if (sv_client->cuff_time > curtime)
- sv_player->v.button0 = sv_player->v.impulse = 0;
+ sv_player->v->button0 = sv_player->v->impulse = 0;
//<-
// clamp view angles
ucmd->angles[PITCH] = bound(sv_minpitch.value, ucmd->angles[PITCH], sv_maxpitch.value);
- if (!sv_player->v.fixangle && ! second_attempt)
- VectorCopy (ucmd->angles, sv_player->v.v_angle);
+ if (!sv_player->v->fixangle && ! second_attempt)
+ VectorCopy (ucmd->angles, sv_player->v->v_angle);
// model angles
// show 1/3 the pitch angle and all the roll angle
- if (sv_player->v.health > 0)
+ if (sv_player->v->health > 0)
{
- if (!sv_player->v.fixangle)
+ if (!sv_player->v->fixangle)
{
- sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
- sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
+ sv_player->v->angles[PITCH] = -sv_player->v->v_angle[PITCH]/3;
+ sv_player->v->angles[YAW] = sv_player->v->v_angle[YAW];
}
- sv_player->v.angles[ROLL] = 0;
+ sv_player->v->angles[ROLL] = 0;
}
sv_frametime = ucmd->msec * 0.001;
@@ -3578,11 +3579,11 @@ void SV_RunCmd (usercmd_t *ucmd, qbool inside, qbool second_attempt) //bliP: 24/
vec3_t oldvelocity;
float old_teleport_time;
- VectorCopy (sv_player->v.velocity, originalvel);
- onground = (int) sv_player->v.flags & FL_ONGROUND;
+ VectorCopy (sv_player->v->velocity, originalvel);
+ onground = (int) sv_player->v->flags & FL_ONGROUND;
- VectorCopy (sv_player->v.velocity, oldvelocity);
- old_teleport_time = sv_player->v.teleport_time;
+ VectorCopy (sv_player->v->velocity, oldvelocity);
+ old_teleport_time = sv_player->v->teleport_time;
PR_GLOBAL(frametime) = sv_frametime;
pr_global_struct->time = sv.time;
@@ -3591,30 +3592,30 @@ void SV_RunCmd (usercmd_t *ucmd, qbool inside, qbool second_attempt) //bliP: 24/
if (pr_nqprogs)
{
- sv_player->v.teleport_time = old_teleport_time;
- VectorCopy (oldvelocity, sv_player->v.velocity);
+ sv_player->v->teleport_time = old_teleport_time;
+ VectorCopy (oldvelocity, sv_player->v->velocity);
}
- if ( onground && originalvel[2] < 0 && sv_player->v.velocity[2] == 0 &&
- originalvel[0] == sv_player->v.velocity[0] &&
- originalvel[1] == sv_player->v.velocity[1] )
+ if ( onground && originalvel[2] < 0 && sv_player->v->velocity[2] == 0 &&
+ originalvel[0] == sv_player->v->velocity[0] &&
+ originalvel[1] == sv_player->v->velocity[1] )
{
// don't let KTeams mess with physics
- sv_player->v.velocity[2] = originalvel[2];
+ sv_player->v->velocity[2] = originalvel[2];
}
SV_RunThink (sv_player);
}
// copy player state to pmove
- VectorSubtract (sv_player->v.mins, player_mins, offset);
- VectorAdd (sv_player->v.origin, offset, pmove.origin);
- VectorCopy (sv_player->v.velocity, pmove.velocity);
- VectorCopy (sv_player->v.v_angle, pmove.angles);
- pmove.waterjumptime = sv_player->v.teleport_time;
+ VectorSubtract (sv_player->v->mins, player_mins, offset);
+ VectorAdd (sv_player->v->origin, offset, pmove.origin);
+ VectorCopy (sv_player->v->velocity, pmove.velocity);
+ VectorCopy (sv_player->v->v_angle, pmove.angles);
+ pmove.waterjumptime = sv_player->v->teleport_time;
pmove.cmd = *ucmd;
pmove.pm_type = SV_PMTypeForClient (sv_client);
- pmove.onground = ((int)sv_player->v.flags & FL_ONGROUND) != 0;
+ pmove.onground = ((int)sv_player->v->flags & FL_ONGROUND) != 0;
pmove.jump_held = sv_client->jump_held;
pmove.jump_msec = 0;
@@ -3649,7 +3650,7 @@ FIXME
#ifdef USE_PR2
// This is a temporary hack for Frogbots, who adjust after bumping into things
// Better would be to provide a way to simulate a move command, but at least this doesn't require API change
- if (blocked && !second_attempt && sv_client->isBot && sv_player->v.blocked)
+ if (blocked && !second_attempt && sv_client->isBot && sv_player->v->blocked)
{
pr_global_struct->self = EDICT_TO_PROG(sv_player);
@@ -3658,14 +3659,14 @@ FIXME
VectorCopy (pmove.velocity, pr_global_struct->trace_plane_normal);
if (pmove.onground)
{
- pr_global_struct->trace_allsolid = (int) sv_player->v.flags | FL_ONGROUND;
+ pr_global_struct->trace_allsolid = (int) sv_player->v->flags | FL_ONGROUND;
pr_global_struct->trace_ent = EDICT_TO_PROG(EDICT_NUM(pmove.physents[pmove.groundent].info));
} else {
- pr_global_struct->trace_allsolid = (int) sv_player->v.flags & ~FL_ONGROUND;
+ pr_global_struct->trace_allsolid = (int) sv_player->v->flags & ~FL_ONGROUND;
}
// Give the mod a chance to replace the command
- PR_EdictBlocked (sv_player->v.blocked);
+ PR_EdictBlocked (sv_player->v->blocked);
// Run the command again
SV_RunCmd (ucmd, false, true);
@@ -3675,25 +3676,25 @@ FIXME
// get player state back out of pmove
sv_client->jump_held = pmove.jump_held;
- sv_player->v.teleport_time = pmove.waterjumptime;
+ sv_player->v->teleport_time = pmove.waterjumptime;
if (pr_nqprogs)
- sv_player->v.flags = ((int)sv_player->v.flags & ~FL_WATERJUMP) | (pmove.waterjumptime ? FL_WATERJUMP : 0);
- sv_player->v.waterlevel = pmove.waterlevel;
- sv_player->v.watertype = pmove.watertype;
+ sv_player->v->flags = ((int)sv_player->v->flags & ~FL_WATERJUMP) | (pmove.waterjumptime ? FL_WATERJUMP : 0);
+ sv_player->v->waterlevel = pmove.waterlevel;
+ sv_player->v->watertype = pmove.watertype;
if (pmove.onground)
{
- sv_player->v.flags = (int) sv_player->v.flags | FL_ONGROUND;
- sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[pmove.groundent].info));
+ sv_player->v->flags = (int) sv_player->v->flags | FL_ONGROUND;
+ sv_player->v->groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[pmove.groundent].info));
} else {
- sv_player->v.flags = (int) sv_player->v.flags & ~FL_ONGROUND;
+ sv_player->v->flags = (int) sv_player->v->flags & ~FL_ONGROUND;
}
- VectorSubtract (pmove.origin, offset, sv_player->v.origin);
- VectorCopy (pmove.velocity, sv_player->v.velocity);
+ VectorSubtract (pmove.origin, offset, sv_player->v->origin);
+ VectorCopy (pmove.velocity, sv_player->v->velocity);
- VectorCopy (pmove.angles, sv_player->v.v_angle);
+ VectorCopy (pmove.angles, sv_player->v->v_angle);
- if (sv_player->v.solid != SOLID_NOT)
+ if (sv_player->v->solid != SOLID_NOT)
{
// link into place and touch triggers
SV_LinkEdict (sv_player, true);
@@ -3704,11 +3705,11 @@ FIXME
edict_t *ent;
n = pmove.physents[pmove.touchindex[i]].info;
ent = EDICT_NUM(n);
- if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
+ if (!ent->v->touch || (playertouch[n/8]&(1<<(n%8))))
continue;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv_player);
- PR_EdictTouch (ent->v.touch);
+ PR_EdictTouch (ent->v->touch);
playertouch[n/8] |= 1 << (n%8);
}
}
@@ -3726,7 +3727,7 @@ typedef struct ssw_info_s {
// Ranks best weapon for player
void SV_ServerSideWeaponRank(client_t* client, int* best_weapon, int* best_impulse, int* hide_weapon, int* hide_impulse)
{
- entvars_t* ent = &client->edict->v;
+ entvars_t* ent = client->edict->v;
int i;
int items = (int)ent->items;
int weapon = (int)ent->weapon;
@@ -3841,7 +3842,6 @@ static void SV_ExecuteServerSideWeaponForgetOrder(client_t* sv_client, int best_
if (Info_Get(&sv_client->_userinfo_ctx_, "dev")[0] == '1') {
SV_ClientPrintf(sv_client, PRINT_HIGH, "Best: %d, forgetorder enabled\n", best_impulse);
}
-
}
sv_client->weaponswitch_priority[0] = best_impulse;
sv_client->weaponswitch_priority[1] = (hide_impulse == 1 || best_impulse == 2 ? 1 : 2);
@@ -3867,7 +3867,7 @@ static void SV_ExecuteServerSideWeaponHideOnDeath(client_t* sv_client, int hide_
{
char new_wrank[16] = { 0 };
- if (sv_client->edict->v.health > 0.0f || !sv_client->weaponswitch_hide_on_death) {
+ if (sv_client->edict->v->health > 0.0f || !sv_client->weaponswitch_hide_on_death) {
return;
}
@@ -3884,14 +3884,14 @@ static void SV_ExecuteServerSideWeaponHideOnDeath(client_t* sv_client, int hide_
SV_NotifyUserOfBestWeapon(sv_client, hide_impulse);
SV_UserSetWeaponRank(sv_client, new_wrank);
- if (Info_Get(&sv_client->_userinfo_ctx_, "dev")[0] == '1' && sv_client->edict->v.weapon != hide_weapon) {
+ if (Info_Get(&sv_client->_userinfo_ctx_, "dev")[0] == '1' && sv_client->edict->v->weapon != hide_weapon) {
SV_ClientPrintf(sv_client, PRINT_HIGH, "Hiding on death: %d\n", hide_impulse);
}
}
static void SV_ServerSideWeaponLogic_PrePostThink(client_t* sv_client, ssw_info_t* ssw)
{
- entvars_t* ent = &sv_client->edict->v;
+ entvars_t* ent = sv_client->edict->v;
qbool dev_trace = (Info_Get(&sv_client->_userinfo_ctx_, "dev")[0] == '1');
ssw->firing = (ent->button0 != 0);
@@ -3906,10 +3906,7 @@ static void SV_ServerSideWeaponLogic_PrePostThink(client_t* sv_client, ssw_info_
if (mode == 2) {
mode = (ssw->firing ? 0 : 1);
}
-
- // by this point we should be down to 0 or 1
- switch_to_best_weapon = (mode == 0 && sv_client->weaponswitch_pending) || (ssw->firing && !sv_client->weaponswitch_wasfiring);
- switch_to_best_weapon &= (ent->health >= 1.0f); // Don't try and switch if dead
+ switch_to_best_weapon = sv_client->weaponswitch_pending && (mode == 0 || ssw->firing) && (ent->health >= 1.0f);
SV_ServerSideWeaponRank(sv_client, &ssw->best_weapon, &best_impulse, &ssw->hide_weapon, &hide_impulse);
@@ -3919,9 +3916,7 @@ static void SV_ServerSideWeaponLogic_PrePostThink(client_t* sv_client, ssw_info_
if (switch_to_best_weapon && sv_client->weaponswitch_forgetorder) {
SV_ExecuteServerSideWeaponForgetOrder(sv_client, best_impulse, hide_impulse);
}
- else {
- SV_ExecuteServerSideWeaponHideOnDeath(sv_client, hide_impulse, ssw->hide_weapon);
- }
+ SV_ExecuteServerSideWeaponHideOnDeath(sv_client, hide_impulse, ssw->hide_weapon);
if (!ent->impulse) {
if (switch_to_best_weapon) {
@@ -3963,20 +3958,26 @@ static void SV_ServerSideWeaponLogic_PrePostThink(client_t* sv_client, ssw_info_
static void SV_ServerSideWeaponLogic_PostPostThink(client_t* sv_client, ssw_info_t* ssw)
{
- entvars_t* ent = &sv_client->edict->v;
+ entvars_t* ent = sv_client->edict->v;
qbool dev_trace = (Info_Get(&sv_client->_userinfo_ctx_, "dev")[0] == '1');
if (ssw->impulse_set) {
qbool hide_failed = (ssw->impulse_set == 1 && ent->weapon != ssw->hide_weapon);
qbool pickbest_failed = (ssw->impulse_set == 2 && ent->weapon != ssw->best_weapon);
+ qbool failure = (hide_failed || pickbest_failed);
ent->impulse = 0;
if (dev_trace) {
- SV_ClientPrintf(sv_client, PRINT_HIGH, "... %s failed, will try again\n", ssw->impulse_set == 1 ? "hide" : "pickbest");
+ if (failure) {
+ SV_ClientPrintf(sv_client, PRINT_HIGH, "... %s failed, will try again\n", ssw->impulse_set == 1 ? "hide" : "pickbest");
+ }
+ else {
+ SV_ClientPrintf(sv_client, PRINT_HIGH, "... %s successful, stopping\n", ssw->impulse_set == 1 ? "hide" : "pickbest");
+ }
}
- sv_client->weaponswitch_pending &= (hide_failed || pickbest_failed);
+ sv_client->weaponswitch_pending &= failure;
}
if (ssw->hiding && ent->weapon == ssw->hide_weapon) {
if (dev_trace) {
@@ -4003,30 +4004,32 @@ void SV_PostRunCmd(void)
{
vec3_t originalvel;
qbool onground;
-
// run post-think
+#ifdef MVD_PEXT1_SERVERSIDEWEAPON
+ ssw_info_t ssw = { 0 };
+#endif
+
if (!sv_client->spectator)
{
#ifdef MVD_PEXT1_SERVERSIDEWEAPON
- ssw_info_t ssw = { 0 };
SV_ServerSideWeaponLogic_PrePostThink(sv_client, &ssw);
#endif
- onground = (int) sv_player->v.flags & FL_ONGROUND;
+ onground = (int) sv_player->v->flags & FL_ONGROUND;
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(sv_player);
- VectorCopy (sv_player->v.velocity, originalvel);
+ VectorCopy (sv_player->v->velocity, originalvel);
PR_GameClientPostThink(0);
- if ( onground && originalvel[2] < 0 && sv_player->v.velocity[2] == 0
- && originalvel[0] == sv_player->v.velocity[0]
- && originalvel[1] == sv_player->v.velocity[1] ) {
+ if ( onground && originalvel[2] < 0 && sv_player->v->velocity[2] == 0
+ && originalvel[0] == sv_player->v->velocity[0]
+ && originalvel[1] == sv_player->v->velocity[1] ) {
// don't let KTeams mess with physics
- sv_player->v.velocity[2] = originalvel[2];
+ sv_player->v->velocity[2] = originalvel[2];
}
if (pr_nqprogs)
- VectorCopy (originalvel, sv_player->v.velocity);
+ VectorCopy (originalvel, sv_player->v->velocity);
if (pr_nqprogs)
SV_RunNQNewmis ();
@@ -4045,7 +4048,6 @@ void SV_PostRunCmd(void)
}
}
-#ifdef MVD_PEXT1_SERVERSIDEWEAPON
/*
SV_UserSetWeaponRank
Sets wrank userinfo for mods to pick best weapon based on user's preferences
@@ -4063,7 +4065,6 @@ static void SV_UserSetWeaponRank(client_t* cl, const char* new_wrank)
}
}
}
-#endif
// SV_RotateCmd
// Rotates client command so a high-ping player can better control direction as they exit teleporters on high-ping
@@ -4080,7 +4081,7 @@ void SV_RotateCmd(client_t* cl, usercmd_t* cmd_)
cmd_->forwardmove = result[1];
}
else {
- cmd_->angles[YAW] = (cl->edict)->v.angles[YAW];
+ cmd_->angles[YAW] = (cl->edict)->v->angles[YAW];
}
}
@@ -4123,10 +4124,10 @@ static void SV_ExecuteClientMove(client_t* cl, usercmd_t oldest, usercmd_t oldcm
#ifdef MVD_PEXT1_SERVERSIDEWEAPON
{
// This is necessary to interrupt LG/SNG where the firing takes place inside animation frames
- if (sv_client->weaponswitch_enabled && sv_client->weaponswitch_pending && !sv_client->edict->v.impulse) {
- sv_client->edict->v.impulse = 255;
+ if (sv_client->weaponswitch_enabled && sv_client->weaponswitch_pending && !sv_client->edict->v->impulse) {
+ sv_client->edict->v->impulse = 255;
SV_RunCmd(&newcmd, false, false);
- sv_client->edict->v.impulse = 0;
+ sv_client->edict->v->impulse = 0;
}
else {
SV_RunCmd(&newcmd, false, false);
@@ -4276,6 +4277,7 @@ static void SV_DebugServerSideWeaponInstruction(client_t* cl)
}
}
}
+#endif
static void SV_DebugServerSideWeaponScript(client_t* cl, int best_impulse)
{
@@ -4284,7 +4286,7 @@ static void SV_DebugServerSideWeaponScript(client_t* cl, int best_impulse)
char encoded[128] = { 0 };
char* w;
char* o;
- entvars_t* ent = &cl->edict->v;
+ entvars_t* ent = cl->edict->v;
strlcpy(old_wrank, Info_Get(&cl->_userinfo_ctx_, "w_rank"), sizeof(old_wrank));
@@ -4299,8 +4301,7 @@ static void SV_DebugServerSideWeaponScript(client_t* cl, int best_impulse)
SV_DebugWriteWeaponScript(cl - svs.clients, true, ent->items, ent->ammo_shells, ent->ammo_nails, ent->ammo_rockets, ent->ammo_cells, best_impulse, encoded);
}
}
-#endif // #ifdef MVD_PEXT1_SERVERSIDEWEAPON
-#endif // #ifdef MVD_PEXT1_DEBUG_WEAPON
+#endif
/*
===================
@@ -4383,7 +4384,7 @@ void SV_ExecuteClientMessage (client_t *cl)
int j;
// don't hit dead players
- if (target_cl->state != cs_spawned || target_cl->antilag_position_next == 0 || (target_cl->spectator == 0 && target_cl->edict->v.health <= 0)) {
+ if (target_cl->state != cs_spawned || target_cl->antilag_position_next == 0 || (target_cl->spectator == 0 && target_cl->edict->v->health <= 0)) {
cl->laggedents[i].present = false;
continue;
}
@@ -4393,7 +4394,7 @@ void SV_ExecuteClientMessage (client_t *cl)
// target player's movement commands are late, extrapolate his position based on velocity
if (target_time > target_cl->localtime) {
- VectorMA(target_cl->edict->v.origin, min(target_time - target_cl->localtime, MAX_EXTRAPOLATE), target_cl->edict->v.velocity, cl->laggedents[i].laggedpos);
+ VectorMA(target_cl->edict->v->origin, min(target_time - target_cl->localtime, MAX_EXTRAPOLATE), target_cl->edict->v->velocity, cl->laggedents[i].laggedpos);
continue;
}
@@ -4603,7 +4604,7 @@ void SV_ExecuteClientMessage (client_t *cl)
if (sv_antilag.value) {
if (cl->antilag_position_next == 0 || cl->antilag_positions[(cl->antilag_position_next - 1) % MAX_ANTILAG_POSITIONS].localtime < cl->localtime) {
cl->antilag_positions[cl->antilag_position_next % MAX_ANTILAG_POSITIONS].localtime = cl->localtime;
- VectorCopy(cl->edict->v.origin, cl->antilag_positions[cl->antilag_position_next % MAX_ANTILAG_POSITIONS].origin);
+ VectorCopy(cl->edict->v->origin, cl->antilag_positions[cl->antilag_position_next % MAX_ANTILAG_POSITIONS].origin);
cl->antilag_position_next++;
}
} else {
@@ -4611,7 +4612,6 @@ void SV_ExecuteClientMessage (client_t *cl)
}
break;
-
case clc_stringcmd:
s = MSG_ReadString ();
s[1023] = 0;
@@ -4625,7 +4625,7 @@ void SV_ExecuteClientMessage (client_t *cl)
// only allowed by spectators
if (sv_client->spectator)
{
- VectorCopy(o, sv_player->v.origin);
+ VectorCopy(o, sv_player->v->origin);
SV_LinkEdict(sv_player, false);
}
break;
diff --git a/src/sv_world.c b/src/sv_world.c
index 89e79996f..f8f7b8703 100644
--- a/src/sv_world.c
+++ b/src/sv_world.c
@@ -61,15 +61,15 @@ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
// decide which clipping hull to use, based on the size
- if (ent->v.solid == SOLID_BSP)
+ if (ent->v->solid == SOLID_BSP)
{ // explicit hulls in the BSP model
- if (ent->v.movetype != MOVETYPE_PUSH)
+ if (ent->v->movetype != MOVETYPE_PUSH)
SV_Error ("SOLID_BSP without MOVETYPE_PUSH");
- if ((unsigned)ent->v.modelindex >= MAX_MODELS)
+ if ((unsigned)ent->v->modelindex >= MAX_MODELS)
SV_Error ("SV_HullForEntity: ent.modelindex >= MAX_MODELS");
- model = sv.models[(int)ent->v.modelindex];
+ model = sv.models[(int)ent->v->modelindex];
if (!model)
SV_Error ("SOLID_BSP with a non-bsp model");
@@ -83,16 +83,16 @@ hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
// calculate an offset value to center the origin
VectorSubtract (hull->clip_mins, mins, offset);
- VectorAdd (offset, ent->v.origin, offset);
+ VectorAdd (offset, ent->v->origin, offset);
}
else
{ // create a temp hull from bounding box sizes
- VectorSubtract (ent->v.mins, maxs, hullmins);
- VectorSubtract (ent->v.maxs, mins, hullmaxs);
+ VectorSubtract (ent->v->mins, maxs, hullmins);
+ VectorSubtract (ent->v->maxs, mins, hullmaxs);
hull = CM_HullForBox (hullmins, hullmaxs);
- VectorCopy (ent->v.origin, offset);
+ VectorCopy (ent->v->origin, offset);
}
@@ -215,10 +215,10 @@ SV_UnlinkEdict
*/
void SV_UnlinkEdict (edict_t *ent)
{
- if (!ent->e->area.prev)
+ if (!ent->e.area.prev)
return; // not linked in anywhere
- RemoveLink (&ent->e->area);
- ent->e->area.prev = ent->e->area.next = NULL;
+ RemoveLink (&ent->e.area);
+ ent->e.area.prev = ent->e.area.next = NULL;
}
/*
@@ -244,15 +244,15 @@ int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **edicts, int max_edicts, i
for (l = start->next ; l != start ; l = l->next)
{
touch = EDICT_FROM_AREA(l);
- if (touch->v.solid == SOLID_NOT)
+ if (touch->v->solid == SOLID_NOT)
continue;
- if (mins[0] > touch->v.absmax[0]
- || mins[1] > touch->v.absmax[1]
- || mins[2] > touch->v.absmax[2]
- || maxs[0] < touch->v.absmin[0]
- || maxs[1] < touch->v.absmin[1]
- || maxs[2] < touch->v.absmin[2])
+ if (mins[0] > touch->v->absmax[0]
+ || mins[1] > touch->v->absmax[1]
+ || mins[2] > touch->v->absmax[2]
+ || maxs[0] < touch->v->absmin[0]
+ || maxs[1] < touch->v->absmin[1]
+ || maxs[2] < touch->v->absmin[2])
continue;
if (count == max_edicts)
@@ -301,7 +301,7 @@ static void SV_TouchLinks ( edict_t *ent, areanode_t *node )
edict_t *touchlist[MAX_EDICTS], *touch;
int old_self, old_other;
- numtouch = SV_AreaEdicts (ent->v.absmin, ent->v.absmax, touchlist, sv.max_edicts, AREA_TRIGGERS);
+ numtouch = SV_AreaEdicts(ent->v->absmin, ent->v->absmax, touchlist, sv.max_edicts, AREA_TRIGGERS);
// touch linked edicts
for (i = 0; i < numtouch; i++)
@@ -309,7 +309,7 @@ static void SV_TouchLinks ( edict_t *ent, areanode_t *node )
touch = touchlist[i];
if (touch == ent)
continue;
- if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)
+ if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
continue;
old_self = pr_global_struct->self;
@@ -318,7 +318,7 @@ static void SV_TouchLinks ( edict_t *ent, areanode_t *node )
pr_global_struct->self = EDICT_TO_PROG(touch);
pr_global_struct->other = EDICT_TO_PROG(ent);
pr_global_struct->time = sv.time;
- PR_EdictTouch (touch->v.touch);
+ PR_EdictTouch (touch->v->touch);
pr_global_struct->self = old_self;
pr_global_struct->other = old_other;
@@ -334,11 +334,11 @@ void SV_LinkToLeafs (edict_t *ent)
{
int i, leafnums[MAX_ENT_LEAFS];
- ent->e->num_leafs = CM_FindTouchedLeafs (ent->v.absmin, ent->v.absmax, leafnums,
+ ent->e.num_leafs = CM_FindTouchedLeafs (ent->v->absmin, ent->v->absmax, leafnums,
MAX_ENT_LEAFS, 0, NULL);
- for (i = 0; i < ent->e->num_leafs; i++) {
- // ent->e->leafnums are real leafnum minus one (for pvs checks)
- ent->e->leafnums[i] = leafnums[i] - 1;
+ for (i = 0; i < ent->e.num_leafs; i++) {
+ // ent->e.leafnums are real leafnum minus one (for pvs checks)
+ ent->e.leafnums[i] = leafnums[i] - 1;
}
}
@@ -353,48 +353,48 @@ void SV_LinkEdict (edict_t *ent, qbool touch_triggers)
{
areanode_t *node;
- if (ent->e->area.prev)
+ if (ent->e.area.prev)
SV_UnlinkEdict (ent); // unlink from old position
-
+
if (ent == sv.edicts)
return; // don't add the world
- if (ent->e->free)
+ if (ent->e.free)
return;
// set the abs box
- VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);
- VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);
+ VectorAdd (ent->v->origin, ent->v->mins, ent->v->absmin);
+ VectorAdd (ent->v->origin, ent->v->maxs, ent->v->absmax);
//
// to make items easier to pick up and allow them to be grabbed off
// of shelves, the abs sizes are expanded
//
- if ((int)ent->v.flags & FL_ITEM)
+ if ((int)ent->v->flags & FL_ITEM)
{
- ent->v.absmin[0] -= 15;
- ent->v.absmin[1] -= 15;
- ent->v.absmax[0] += 15;
- ent->v.absmax[1] += 15;
+ ent->v->absmin[0] -= 15;
+ ent->v->absmin[1] -= 15;
+ ent->v->absmax[0] += 15;
+ ent->v->absmax[1] += 15;
}
else
{ // because movement is clipped an epsilon away from an actual edge,
// we must fully check even when bounding boxes don't quite touch
- ent->v.absmin[0] -= 1;
- ent->v.absmin[1] -= 1;
- ent->v.absmin[2] -= 1;
- ent->v.absmax[0] += 1;
- ent->v.absmax[1] += 1;
- ent->v.absmax[2] += 1;
+ ent->v->absmin[0] -= 1;
+ ent->v->absmin[1] -= 1;
+ ent->v->absmin[2] -= 1;
+ ent->v->absmax[0] += 1;
+ ent->v->absmax[1] += 1;
+ ent->v->absmax[2] += 1;
}
-
+
// link to PVS leafs
- if (ent->v.modelindex)
+ if (ent->v->modelindex)
SV_LinkToLeafs (ent);
else
- ent->e->num_leafs = 0;
+ ent->e.num_leafs = 0;
- if (ent->v.solid == SOLID_NOT)
+ if (ent->v->solid == SOLID_NOT)
return;
// find the first node that the ent's box crosses
@@ -403,20 +403,20 @@ void SV_LinkEdict (edict_t *ent, qbool touch_triggers)
{
if (node->axis == -1)
break;
- if (ent->v.absmin[node->axis] > node->dist)
+ if (ent->v->absmin[node->axis] > node->dist)
node = node->children[0];
- else if (ent->v.absmax[node->axis] < node->dist)
+ else if (ent->v->absmax[node->axis] < node->dist)
node = node->children[1];
else
- break; // crosses the node
+ break; // crosses the node
}
// link it in
- if (ent->v.solid == SOLID_TRIGGER)
- InsertLinkBefore (&ent->e->area, &node->trigger_edicts);
+ if (ent->v->solid == SOLID_TRIGGER)
+ InsertLinkBefore (&ent->e.area, &node->trigger_edicts);
else
- InsertLinkBefore (&ent->e->area, &node->solid_edicts);
+ InsertLinkBefore (&ent->e.area, &node->solid_edicts);
// if touch_triggers, touch all entities at this node and decend for more
if (touch_triggers)
@@ -458,11 +458,11 @@ edict_t *SV_TestEntityPosition (edict_t *ent)
{
trace_t trace;
- if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
+ if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
// only clip against bmodels
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NOMONSTERS, ent);
+ trace = SV_Trace (ent->v->origin, ent->v->mins, ent->v->maxs, ent->v->origin, MOVE_NOMONSTERS, ent);
else
- trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent);
+ trace = SV_Trace(ent->v->origin, ent->v->mins, ent->v->maxs, ent->v->origin, MOVE_NORMAL, ent);
if (trace.startsolid)
return sv.edicts;
@@ -536,32 +536,32 @@ void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
touch = touchlist[i];
if (touch == clip->passedict)
continue;
- if (touch->v.solid == SOLID_TRIGGER)
+ if (touch->v->solid == SOLID_TRIGGER)
SV_Error ("Trigger in clipping list");
- if ((clip->type & MOVE_NOMONSTERS) && touch->v.solid != SOLID_BSP)
+ if ((clip->type & MOVE_NOMONSTERS) && touch->v->solid != SOLID_BSP)
continue;
- if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
+ if (clip->passedict && clip->passedict->v->size[0] && !touch->v->size[0])
continue; // points never interact
if (clip->type & MOVE_LAGGED)
{
//can't touch lagged ents - we do an explicit test for them later in SV_AntilagClipCheck.
- if (touch->e->entnum - 1 < w.maxlagents)
- if (w.lagents[touch->e->entnum - 1].present)
+ if (touch->e.entnum - 1 < w.maxlagents)
+ if (w.lagents[touch->e.entnum - 1].present)
continue;
}
if (clip->passedict)
{
- if (PROG_TO_EDICT(touch->v.owner) == clip->passedict)
+ if (PROG_TO_EDICT(touch->v->owner) == clip->passedict)
continue; // don't clip against own missiles
- if (PROG_TO_EDICT(clip->passedict->v.owner) == touch)
+ if (PROG_TO_EDICT(clip->passedict->v->owner) == touch)
continue; // don't clip against owner
}
- if ((int)touch->v.flags & FL_MONSTER)
+ if ((int)touch->v->flags & FL_MONSTER)
trace = SV_ClipMoveToEntity (touch, NULL, clip->start, clip->mins2, clip->maxs2, clip->end);
else
trace = SV_ClipMoveToEntity (touch, NULL, clip->start, clip->mins, clip->maxs, clip->end);
@@ -618,16 +618,16 @@ void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t b
void SV_AntilagReset (edict_t *ent)
{
- if (ent->e->entnum == 0 || ent->e->entnum > MAX_CLIENTS)
+ if (ent->e.entnum == 0 || ent->e.entnum > MAX_CLIENTS)
return;
- svs.clients[ent->e->entnum - 1].antilag_position_next = 0;
+ svs.clients[ent->e.entnum - 1].antilag_position_next = 0;
}
void SV_AntilagClipSetUp ( areanode_t *node, moveclip_t *clip )
{
edict_t *passedict = clip->passedict;
- int entnum = passedict->e->entnum;
+ int entnum = passedict->e.entnum;
clip->type &= ~MOVE_LAGGED;
@@ -638,9 +638,9 @@ void SV_AntilagClipSetUp ( areanode_t *node, moveclip_t *clip )
w.maxlagents = svs.clients[entnum - 1].laggedents_count;
w.lagentsfrac = svs.clients[entnum - 1].laggedents_frac;
}
- else if (passedict->v.owner)
+ else if (passedict->v->owner)
{
- int owner = PROG_TO_EDICT(passedict->v.owner)->e->entnum;
+ int owner = PROG_TO_EDICT(passedict->v->owner)->e.entnum;
if (owner && owner <= MAX_CLIENTS && !svs.clients[owner - 1].isBot)
{
@@ -668,38 +668,38 @@ void SV_AntilagClipCheck ( areanode_t *node, moveclip_t *clip )
continue;
touch = EDICT_NUM(i + 1);
- if (touch->v.solid == SOLID_NOT)
+ if (touch->v->solid == SOLID_NOT)
continue;
if (touch == clip->passedict)
continue;
- if (touch->v.solid == SOLID_TRIGGER)
- SV_Error ("Trigger (%s) in clipping list", PR_GetEntityString(touch->v.classname));
+ if (touch->v->solid == SOLID_TRIGGER)
+ SV_Error ("Trigger (%s) in clipping list", PR_GetEntityString(touch->v->classname));
- if ((clip->type & MOVE_NOMONSTERS) && touch->v.solid != SOLID_BSP)
+ if ((clip->type & MOVE_NOMONSTERS) && touch->v->solid != SOLID_BSP)
continue;
- VectorInterpolate(touch->v.origin, w.lagentsfrac, w.lagents[i].laggedpos, lp);
+ VectorInterpolate(touch->v->origin, w.lagentsfrac, w.lagents[i].laggedpos, lp);
- if ( clip->boxmins[0] > lp[0]+touch->v.maxs[0]
- || clip->boxmins[1] > lp[1]+touch->v.maxs[1]
- || clip->boxmins[2] > lp[2]+touch->v.maxs[2]
- || clip->boxmaxs[0] < lp[0]+touch->v.mins[0]
- || clip->boxmaxs[1] < lp[1]+touch->v.mins[1]
- || clip->boxmaxs[2] < lp[2]+touch->v.mins[2] )
+ if ( clip->boxmins[0] > lp[0]+touch->v->maxs[0]
+ || clip->boxmins[1] > lp[1]+touch->v->maxs[1]
+ || clip->boxmins[2] > lp[2]+touch->v->maxs[2]
+ || clip->boxmaxs[0] < lp[0]+touch->v->mins[0]
+ || clip->boxmaxs[1] < lp[1]+touch->v->mins[1]
+ || clip->boxmaxs[2] < lp[2]+touch->v->mins[2] )
continue;
- if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
+ if (clip->passedict && clip->passedict->v->size[0] && !touch->v->size[0])
continue; // points never interact
if (clip->passedict)
{
- if (PROG_TO_EDICT(touch->v.owner) == clip->passedict)
+ if (PROG_TO_EDICT(touch->v->owner) == clip->passedict)
continue; // don't clip against own missiles
- if (PROG_TO_EDICT(clip->passedict->v.owner) == touch)
+ if (PROG_TO_EDICT(clip->passedict->v->owner) == touch)
continue; // don't clip against owner
}
- if ((int)touch->v.flags & FL_MONSTER)
+ if ((int)touch->v->flags & FL_MONSTER)
trace = SV_ClipMoveToEntity (touch, &lp, clip->start, clip->mins2, clip->maxs2, clip->end);
else
trace = SV_ClipMoveToEntity (touch, &lp, clip->start, clip->mins, clip->maxs, clip->end);
diff --git a/src/sv_world.h b/src/sv_world.h
index 18d59093d..3aa47e6c0 100644
--- a/src/sv_world.h
+++ b/src/sv_world.h
@@ -51,12 +51,12 @@ void SV_ClearWorld (void);
void SV_UnlinkEdict (edict_t *ent);
// call before removing an entity, and before trying to move one,
// so it doesn't clip against itself
-// flags ent->v.modified
+// flags ent->v->modified
void SV_LinkEdict (edict_t *ent, qbool touch_triggers);
// Needs to be called any time an entity changes origin, mins, maxs, or solid
-// flags ent->v.modified
-// sets ent->v.absmin and ent->v.absmax
+// flags ent->v->modified
+// sets ent->v->absmin and ent->v->absmax
// if touchtriggers, calls prog functions for the intersected triggers
int SV_PointContents (vec3_t p);
diff --git a/src/sys.h b/src/sys.h
index 4963ce131..b2c4334b4 100644
--- a/src/sys.h
+++ b/src/sys.h
@@ -19,11 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// sys.h -- non-portable functions
-#ifdef _WIN32
-#define PATH_SEPARATOR "\\"
-#else
-#define PATH_SEPARATOR "/"
-#endif
+#include "q_platform.h"
#ifdef _WIN32
#define Sys_MSleep(x) Sleep(x)
@@ -42,10 +38,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define _MAX_DIR 1024
typedef void *DL_t;
-#define DLEXT "so"
#else
typedef HMODULE DL_t;
-#define DLEXT "dll"
#endif
DL_t Sys_DLOpen(const char *path);
@@ -199,6 +193,7 @@ int Sys_compare_by_name (const void *a, const void *b);
#define SORT_BY_DATE 1
#define SORT_BY_NAME 2
+#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x)))
// library loading.
diff --git a/src/vm.c b/src/vm.c
new file mode 100644
index 000000000..6a4929db9
--- /dev/null
+++ b/src/vm.c
@@ -0,0 +1,1617 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+// vm.c -- virtual machine
+/*
+
+
+intermix code and data
+symbol table
+
+a dll has one imported function: VM_SystemCall
+and one exported function: Perform
+
+
+*/
+#ifdef USE_PR2
+#include "qwsvdef.h"
+#include "vm_local.h"
+
+opcode_info_t ops[ OP_MAX ] =
+{
+ { 0, 0, 0, 0 }, // undef
+ { 0, 0, 0, 0 }, // ignore
+ { 0, 0, 0, 0 }, // break
+
+ { 4, 0, 0, 0 }, // enter
+ { 4,-4, 0, 0 }, // leave
+ { 0, 0, 1, 0 }, // call
+ { 0, 4, 0, 0 }, // push
+ { 0,-4, 1, 0 }, // pop
+
+ { 4, 4, 0, 0 }, // const
+ { 4, 4, 0, 0 }, // local
+ { 0,-4, 1, 0 }, // jump
+
+ { 4,-8, 2, JUMP }, // eq
+ { 4,-8, 2, JUMP }, // ne
+
+ { 4,-8, 2, JUMP }, // lti
+ { 4,-8, 2, JUMP }, // lei
+ { 4,-8, 2, JUMP }, // gti
+ { 4,-8, 2, JUMP }, // gei
+
+ { 4,-8, 2, JUMP }, // ltu
+ { 4,-8, 2, JUMP }, // leu
+ { 4,-8, 2, JUMP }, // gtu
+ { 4,-8, 2, JUMP }, // geu
+
+ { 4,-8, 2, JUMP }, // eqf
+ { 4,-8, 2, JUMP }, // nef
+
+ { 4,-8, 2, JUMP }, // ltf
+ { 4,-8, 2, JUMP }, // lef
+ { 4,-8, 2, JUMP }, // gtf
+ { 4,-8, 2, JUMP }, // gef
+
+ { 0, 0, 1, 0 }, // load1
+ { 0, 0, 1, 0 }, // load2
+ { 0, 0, 1, 0 }, // load4
+ { 0,-8, 2, 0 }, // store1
+ { 0,-8, 2, 0 }, // store2
+ { 0,-8, 2, 0 }, // store4
+ { 1,-4, 1, 0 }, // arg
+ { 4,-8, 2, 0 }, // bcopy
+
+ { 0, 0, 1, 0 }, // sex8
+ { 0, 0, 1, 0 }, // sex16
+
+ { 0, 0, 1, 0 }, // negi
+ { 0,-4, 3, 0 }, // add
+ { 0,-4, 3, 0 }, // sub
+ { 0,-4, 3, 0 }, // divi
+ { 0,-4, 3, 0 }, // divu
+ { 0,-4, 3, 0 }, // modi
+ { 0,-4, 3, 0 }, // modu
+ { 0,-4, 3, 0 }, // muli
+ { 0,-4, 3, 0 }, // mulu
+
+ { 0,-4, 3, 0 }, // band
+ { 0,-4, 3, 0 }, // bor
+ { 0,-4, 3, 0 }, // bxor
+ { 0, 0, 1, 0 }, // bcom
+
+ { 0,-4, 3, 0 }, // lsh
+ { 0,-4, 3, 0 }, // rshi
+ { 0,-4, 3, 0 }, // rshu
+
+ { 0, 0, 1, 0 }, // negf
+ { 0,-4, 3, 0 }, // addf
+ { 0,-4, 3, 0 }, // subf
+ { 0,-4, 3, 0 }, // divf
+ { 0,-4, 3, 0 }, // mulf
+
+ { 0, 0, 1, 0 }, // cvif
+ { 0, 0, 1, 0 } // cvfi
+};
+
+const char *opname[ 256 ] = {
+ "OP_UNDEF",
+
+ "OP_IGNORE",
+
+ "OP_BREAK",
+
+ "OP_ENTER",
+ "OP_LEAVE",
+ "OP_CALL",
+ "OP_PUSH",
+ "OP_POP",
+
+ "OP_CONST",
+
+ "OP_LOCAL",
+
+ "OP_JUMP",
+
+ //-------------------
+
+ "OP_EQ",
+ "OP_NE",
+
+ "OP_LTI",
+ "OP_LEI",
+ "OP_GTI",
+ "OP_GEI",
+
+ "OP_LTU",
+ "OP_LEU",
+ "OP_GTU",
+ "OP_GEU",
+
+ "OP_EQF",
+ "OP_NEF",
+
+ "OP_LTF",
+ "OP_LEF",
+ "OP_GTF",
+ "OP_GEF",
+
+ //-------------------
+
+ "OP_LOAD1",
+ "OP_LOAD2",
+ "OP_LOAD4",
+ "OP_STORE1",
+ "OP_STORE2",
+ "OP_STORE4",
+ "OP_ARG",
+
+ "OP_BLOCK_COPY",
+
+ //-------------------
+
+ "OP_SEX8",
+ "OP_SEX16",
+
+ "OP_NEGI",
+ "OP_ADD",
+ "OP_SUB",
+ "OP_DIVI",
+ "OP_DIVU",
+ "OP_MODI",
+ "OP_MODU",
+ "OP_MULI",
+ "OP_MULU",
+
+ "OP_BAND",
+ "OP_BOR",
+ "OP_BXOR",
+ "OP_BCOM",
+
+ "OP_LSH",
+ "OP_RSHI",
+ "OP_RSHU",
+
+ "OP_NEGF",
+ "OP_ADDF",
+ "OP_SUBF",
+ "OP_DIVF",
+ "OP_MULF",
+
+ "OP_CVIF",
+ "OP_CVFI"
+};
+
+cvar_t vm_rtChecks = { "vm_rtChecks", "1"};
+
+int vm_debugLevel;
+
+// used by SV_Error to get rid of running vm's before longjmp
+static int forced_unload;
+
+struct vm_s vmTable[ VM_COUNT ];
+void VM_VmInfo_f( void );
+void VM_VmProfile_f( void );
+
+
+void VM_Debug( int level ) {
+ vm_debugLevel = level;
+}
+
+
+/*
+==============
+VM_CheckBounds
+==============
+*/
+void VM_CheckBounds( const vm_t *vm, unsigned int address, unsigned int length )
+{
+ //if ( !vm->entryPoint )
+ {
+ if ( (address | length) > vm->dataMask || (address + length) > vm->dataMask )
+ {
+ SV_Error( "program tried to bypass data segment bounds" );
+ }
+ }
+}
+
+/*
+==============
+VM_CheckBounds2
+==============
+*/
+void VM_CheckBounds2( const vm_t *vm, unsigned int addr1, unsigned int addr2, unsigned int length )
+{
+ //if ( !vm->entryPoint )
+ {
+ if ( (addr1 | addr2 | length) > vm->dataMask || (addr1 + length) > vm->dataMask || (addr2+length) > vm->dataMask )
+ {
+ SV_Error( "program tried to bypass data segment bounds" );
+ }
+ }
+}
+
+/*
+==============
+VM_Init
+==============
+*/
+
+void ED2_PrintEdicts (void);
+void PR2_Profile_f (void);
+void ED2_PrintEdict_f (void);
+void ED_Count (void);
+void PR_CleanLogText_Init(void);
+vm_t *currentVM = NULL; // bk001212
+vm_t *lastVM = NULL; // bk001212
+int vm_debugLevel;
+
+
+void *VM_ArgPtr( intptr_t intValue ) {
+ if ( !intValue ) {
+ return NULL;
+ }
+ // bk001220 - currentVM is missing on reconnect
+ if ( currentVM==NULL )
+ return NULL;
+
+ if ( currentVM->entryPoint ) {
+ return (void *)(currentVM->dataBase + intValue);
+ }
+ else {
+ return (void *)(currentVM->dataBase + (intValue & currentVM->dataMask));
+ }
+}
+
+void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) {
+ if ( !intValue ) {
+ return NULL;
+ }
+
+ // bk010124 - currentVM is missing on reconnect here as well?
+ if ( vm==NULL )
+ return NULL;
+
+ //
+ if ( vm->entryPoint ) {
+ return (void *)(vm->dataBase + intValue);
+ }
+ else {
+ return (void *)(vm->dataBase + (intValue & vm->dataMask));
+ }
+}
+
+intptr_t VM_Ptr2VM( void* ptr ) {
+ if ( !ptr ) {
+ return 0;
+ }
+ // bk001220 - currentVM is missing on reconnect
+ if ( currentVM==NULL )
+ return 0;
+
+ if ( currentVM->entryPoint ) {
+ return (intptr_t)ptr;
+ } else {
+ return (((byte*)ptr - currentVM->dataBase )) & currentVM->dataMask;
+ }
+}
+
+
+intptr_t VM_ExplicitPtr2VM( vm_t *vm, void* ptr ) {
+ if ( !ptr ) {
+ return 0;
+ }
+ // bk001220 - currentVM is missing on reconnect
+ if ( vm==NULL )
+ return 0;
+
+ if ( vm->entryPoint ) {
+ return (intptr_t)ptr;
+ } else {
+ return (((byte*)ptr - vm->dataBase )) & vm->dataMask;
+ }
+}
+
+/*
+===============
+VM_ValueToSymbol
+
+Assumes a program counter value
+===============
+*/
+const char *VM_ValueToSymbol( vm_t *vm, int value ) {
+ vmSymbol_t *sym;
+ static char text[MAX_COM_TOKEN];
+
+ sym = vm->symbols;
+ if ( !sym ) {
+ return "NO SYMBOLS";
+ }
+
+ // find the symbol
+ while ( sym->next && sym->next->symValue <= value ) {
+ sym = sym->next;
+ }
+
+ if ( value == sym->symValue ) {
+ return sym->symName;
+ }
+
+ snprintf( text, sizeof( text ), "%s+%i", sym->symName, value - sym->symValue );
+
+ return text;
+}
+
+/*
+===============
+VM_ValueToFunctionSymbol
+
+For profiling, find the symbol behind this value
+===============
+*/
+vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ) {
+ vmSymbol_t *sym;
+ static vmSymbol_t nullSym;
+
+ sym = vm->symbols;
+ if ( !sym ) {
+ return &nullSym;
+ }
+
+ while ( sym->next && sym->next->symValue <= value ) {
+ sym = sym->next;
+ }
+
+ return sym;
+}
+
+/*
+===============
+VM_SymbolToValue
+===============
+*/
+int VM_SymbolToValue( vm_t *vm, const char *symbol ) {
+ vmSymbol_t *sym;
+
+ for ( sym = vm->symbols ; sym ; sym = sym->next ) {
+ if ( !strcmp( symbol, sym->symName ) ) {
+ return sym->symValue;
+ }
+ }
+ return 0;
+}
+
+/*
+===============
+ParseHex
+===============
+*/
+int ParseHex( const char *text ) {
+ int value;
+ int c;
+
+ value = 0;
+ while ( ( c = *text++ ) != 0 ) {
+ if ( c >= '0' && c <= '9' ) {
+ value = value * 16 + c - '0';
+ continue;
+ }
+ if ( c >= 'a' && c <= 'f' ) {
+ value = value * 16 + 10 + c - 'a';
+ continue;
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ value = value * 16 + 10 + c - 'A';
+ continue;
+ }
+ }
+
+ return value;
+}
+
+/*
+===============
+VM_LoadSymbols
+===============
+*/
+void VM_LoadSymbols( vm_t *vm ) {
+ union {
+ char *c;
+ void *v;
+ } mapfile;
+ char *text_p;
+ //char name[MAX_QPATH];
+ char symbols[MAX_QPATH];
+ vmSymbol_t **prev, *sym;
+ int count;
+ int value;
+ int chars;
+ int segment;
+ int numInstructions;
+
+ // don't load symbols if not developer
+ //if ( !com_developer->integer ) { return; }
+
+ //COM_StripExtension((char*)vm->name, name);
+ snprintf( symbols, sizeof( symbols ), "%s.map", vm->name );
+ mapfile.v = FS_LoadTempFile( symbols, NULL );
+ if ( !mapfile.c ) {
+ Con_Printf( "Couldn't load symbol file: %s\n", symbols );
+ return;
+ }
+
+ numInstructions = vm->instructionCount;
+
+ // parse the symbols
+ text_p = mapfile.c;
+ prev = &vm->symbols;
+ count = 0;
+
+ while ( 1 ) {
+ text_p = COM_Parse( text_p );
+ if ( !text_p ) {
+ break;
+ }
+ segment = ParseHex( com_token );
+ if ( segment ) {
+ COM_Parse( text_p );
+ COM_Parse( text_p );
+ continue; // only load code segment values
+ }
+
+ text_p = COM_Parse( text_p );
+ if ( !text_p ) {
+ Con_Printf( "WARNING: incomplete line at end of file\n" );
+ break;
+ }
+ value = ParseHex( com_token );
+
+ text_p = COM_Parse( text_p );
+ if ( !text_p ) {
+ Con_Printf( "WARNING: incomplete line at end of file\n" );
+ break;
+ }
+ chars = strlen( com_token );
+ sym = Hunk_Alloc( sizeof( *sym ) + chars);
+ *prev = sym;
+ prev = &sym->next;
+ sym->next = NULL;
+
+ // convert value from an instruction number to a code offset
+ if ( vm->instructionPointers && value >= 0 && value < numInstructions ) {
+ value = vm->instructionPointers[value];
+ }
+
+ sym->symValue = value;
+ strlcpy( sym->symName, com_token, chars + 1 );
+
+ count++;
+ }
+
+ vm->numSymbols = count;
+ Con_Printf( "%i symbols parsed from %s\n", count, symbols );
+
+}
+
+static void VM_SwapLongs( void *data, int length )
+{
+ int i, *ptr;
+ ptr = (int *) data;
+ length /= sizeof( int );
+ for ( i = 0; i < length; i++ ) {
+ ptr[ i ] = LittleLong( ptr[ i ] );
+ }
+}
+
+/*
+============
+VM_DllSyscall
+
+Dlls will call this directly
+
+ rcg010206 The horror; the horror.
+
+ The syscall mechanism relies on stack manipulation to get its args.
+ This is likely due to C's inability to pass "..." parameters to
+ a function in one clean chunk. On PowerPC Linux, these parameters
+ are not necessarily passed on the stack, so while (&arg[0] == arg)
+ is true, (&arg[1] == 2nd function parameter) is not necessarily
+ accurate, as arg's value might have been stored to the stack or
+ other piece of scratch memory to give it a valid address, but the
+ next parameter might still be sitting in a register.
+
+ Quake's syscall system also assumes that the stack grows downward,
+ and that any needed types can be squeezed, safely, into a signed int.
+
+ This hack below copies all needed values for an argument to a
+ array in memory, so that Quake can get the correct values. This can
+ also be used on systems where the stack grows upwards, as the
+ presumably standard and safe stdargs.h macros are used.
+
+ As for having enough space in a signed int for your datatypes, well,
+ it might be better to wait for DOOM 3 before you start porting. :)
+
+ The original code, while probably still inherently dangerous, seems
+ to work well enough for the platforms it already works on. Rather
+ than add the performance hit for those platforms, the original code
+ is still in use there.
+
+ For speed, we just grab 15 arguments, and don't worry about exactly
+ how many the syscall actually needs; the extra is thrown away.
+
+============
+*/
+#if 1 // - disabled because now is different for each module
+intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {
+#if !idx386 || defined __clang__
+ // rcg010206 - see commentary above
+ intptr_t args[16];
+ va_list ap;
+ int i;
+
+ args[0] = arg;
+
+ va_start( ap, arg );
+ for (i = 1; i < ARRAY_LEN( args ); i++ )
+ args[ i ] = va_arg( ap, intptr_t );
+ va_end( ap );
+
+ return currentVM->systemCall( args );
+#else // original id code
+ return currentVM->systemCall( &arg );
+#endif
+}
+#endif
+
+/*
+=================
+VM_ValidateHeader
+=================
+*/
+static char *VM_ValidateHeader( vmHeader_t *header, int fileSize )
+{
+ static char errMsg[128];
+ int n;
+
+ // truncated
+ if ( fileSize < ( sizeof( vmHeader_t ) - sizeof( int ) ) ) {
+ sprintf( errMsg, "truncated image header (%i bytes long)", fileSize );
+ return errMsg;
+ }
+
+ // bad magic
+ if ( LittleLong( header->vmMagic ) != VM_MAGIC && LittleLong( header->vmMagic ) != VM_MAGIC_VER2 ) {
+ sprintf( errMsg, "bad file magic %08x", LittleLong( header->vmMagic ) );
+ return errMsg;
+ }
+
+ // truncated
+ if ( fileSize < sizeof( vmHeader_t ) && LittleLong( header->vmMagic ) != VM_MAGIC_VER2 ) {
+ sprintf( errMsg, "truncated image header (%i bytes long)", fileSize );
+ return errMsg;
+ }
+
+ if ( LittleLong( header->vmMagic ) == VM_MAGIC_VER2 )
+ n = sizeof( vmHeader_t );
+ else
+ n = ( sizeof( vmHeader_t ) - sizeof( int ) );
+
+ // byte swap the header
+ VM_SwapLongs( header, n );
+
+ // bad code offset
+ if ( header->codeOffset >= fileSize ) {
+ sprintf( errMsg, "bad code segment offset %i", header->codeOffset );
+ return errMsg;
+ }
+
+ // bad code length
+ if ( header->codeLength <= 0 || header->codeOffset + header->codeLength > fileSize ) {
+ sprintf( errMsg, "bad code segment length %i", header->codeLength );
+ return errMsg;
+ }
+
+ // bad data offset
+ if ( header->dataOffset >= fileSize || header->dataOffset != header->codeOffset + header->codeLength ) {
+ sprintf( errMsg, "bad data segment offset %i", header->dataOffset );
+ return errMsg;
+ }
+
+ // bad data length
+ if ( header->dataOffset + header->dataLength > fileSize ) {
+ sprintf( errMsg, "bad data segment length %i", header->dataLength );
+ return errMsg;
+ }
+
+ if ( header->vmMagic == VM_MAGIC_VER2 )
+ {
+ // bad lit/jtrg length
+ if ( header->dataOffset + header->dataLength + header->litLength + header->jtrgLength != fileSize ) {
+ sprintf( errMsg, "bad lit/jtrg segment length" );
+ return errMsg;
+ }
+ }
+ // bad lit length
+ else if ( header->dataOffset + header->dataLength + header->litLength != fileSize )
+ {
+ sprintf( errMsg, "bad lit segment length %i", header->litLength );
+ return errMsg;
+ }
+
+ return NULL;
+}
+
+/*
+=================
+VM_LoadQVM
+
+Load a .qvm file
+
+if ( alloc )
+ - Validate header, swap data
+ - Alloc memory for data/instructions
+ - Alloc memory for instructionPointers - NOT NEEDED
+ - Load instructions
+ - Clear/load data
+else
+ - Check for header changes
+ - Clear/load data
+
+=================
+*/
+static vmHeader_t *VM_LoadQVM( vm_t *vm, qbool alloc ) {
+ int length;
+ unsigned int dataLength;
+ unsigned int dataAlloc;
+ int i;
+ char filename[MAX_QPATH], *errorMsg;
+ unsigned int crc32sum;
+ //qbool tryjts;
+ vmHeader_t *header;
+ char num[32];
+
+ // load the image
+ snprintf( filename, sizeof( filename ), "%s.qvm", vm->name );
+ Con_Printf( "Loading vm file %s...\n", filename );
+ header = ( vmHeader_t*)FS_LoadTempFile( filename, &length );
+ if ( !header ) {
+ Con_Printf( "Failed.\n" );
+ VM_Free( vm );
+ return NULL;
+ }
+
+ crc32sum = CRC_Block( ( byte * ) header, length );
+ sprintf( num, "%i", crc32sum );
+ Info_SetValueForStarKey( svs.info, "*progs", num, MAX_SERVERINFO_STRING );
+
+ // will also swap header
+ errorMsg = VM_ValidateHeader( header, length );
+ if ( errorMsg ) {
+ VM_Free( vm );
+ Con_Printf( "%s\n", errorMsg );
+ return NULL;
+ }
+
+ vm->crc32sum = crc32sum;
+ //tryjts = false;
+
+ if( header->vmMagic == VM_MAGIC_VER2 ) {
+ Con_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
+ } else {
+ // tryjts = true;
+ }
+
+ vm->exactDataLength = header->dataLength + header->litLength + header->bssLength;
+ dataLength = vm->exactDataLength + PROGRAM_STACK_EXTRA;
+ vm->dataLength = dataLength;
+
+ // round up to next power of 2 so all data operations can
+ // be mask protected
+ for ( i = 0 ; dataLength > ( 1 << i ) ; i++ )
+ ;
+ dataLength = 1 << i;
+
+ // reserve some space for effective LOCAL+LOAD* checks
+ dataAlloc = dataLength + 1024;
+
+ if ( dataLength >= (1U<<31) || dataAlloc >= (1U<<31) ) {
+ VM_Free( vm );
+ Con_Printf( "%s: data segment is too large\n", __func__ );
+ return NULL;
+ }
+
+ if ( alloc ) {
+ // allocate zero filled space for initialized and uninitialized data
+ vm->dataBase = Hunk_Alloc( dataAlloc);
+ vm->dataMask = dataLength - 1;
+ vm->dataAlloc = dataAlloc;
+ } else {
+ // clear the data, but make sure we're not clearing more than allocated
+ if ( vm->dataAlloc != dataAlloc ) {
+ VM_Free( vm );
+ Con_Printf( "Warning: Data region size of %s not matching after"
+ "VM_Restart()\n", filename );
+ return NULL;
+ }
+ memset( vm->dataBase, 0, vm->dataAlloc );
+ }
+
+ // copy the intialized data
+ memcpy( vm->dataBase, (byte *)header + header->dataOffset, header->dataLength + header->litLength );
+
+ // byte swap the longs
+ VM_SwapLongs( vm->dataBase, header->dataLength );
+
+ if( header->vmMagic == VM_MAGIC_VER2 ) {
+ int previousNumJumpTableTargets = vm->numJumpTableTargets;
+
+ header->jtrgLength &= ~0x03;
+
+ vm->numJumpTableTargets = header->jtrgLength >> 2;
+ Con_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets );
+
+ if ( alloc ) {
+ vm->jumpTableTargets = Hunk_Alloc( header->jtrgLength);
+ } else {
+ if ( vm->numJumpTableTargets != previousNumJumpTableTargets ) {
+ VM_Free( vm );
+
+ Con_Printf( "Warning: Jump table size of %s not matching after "
+ "VM_Restart()\n", filename );
+ return NULL;
+ }
+
+ memset( vm->jumpTableTargets, 0, header->jtrgLength );
+ }
+
+ memcpy( vm->jumpTableTargets, (byte *)header + header->dataOffset +
+ header->dataLength + header->litLength, header->jtrgLength );
+
+ // byte swap the longs
+ VM_SwapLongs( vm->jumpTableTargets, header->jtrgLength );
+ }
+
+ /*if ( tryjts == true && (length = Load_JTS( vm, crc32sum, NULL, vmPakIndex )) >= 0 ) {
+ // we are trying to load newer file?
+ if ( vm->jumpTableTargets && vm->numJumpTableTargets != length >> 2 ) {
+ Con_Printf( "Reload jts file\n" );
+ vm->jumpTableTargets = NULL;
+ alloc = true;
+ }
+ vm->numJumpTableTargets = length >> 2;
+ Con_Printf( "Loading %d external jump table targets\n", vm->numJumpTableTargets );
+ if ( alloc == true ) {
+ vm->jumpTableTargets = Hunk_Alloc( length);
+ } else {
+ memset( vm->jumpTableTargets, 0, length );
+ }
+ Load_JTS( vm, crc32sum, vm->jumpTableTargets, vmPakIndex );
+ }*/
+
+ return header;
+}
+
+/*
+=================
+VM_LoadInstructions
+
+loads instructions in structured format
+=================
+*/
+const char *VM_LoadInstructions( const byte *code_pos, int codeLength, int instructionCount, instruction_t *buf )
+{
+ static char errBuf[ 128 ];
+ const byte *code_start, *code_end;
+ int i, n, op0, op1, opStack;
+ instruction_t *ci;
+
+ code_start = code_pos; // for printing
+ code_end = code_pos + codeLength;
+
+ ci = buf;
+ opStack = 0;
+ op1 = OP_UNDEF;
+
+ // load instructions and perform some initial calculations/checks
+ for ( i = 0; i < instructionCount; i++, ci++, op1 = op0 ) {
+ op0 = *code_pos;
+ if ( op0 < 0 || op0 >= OP_MAX ) {
+ sprintf( errBuf, "bad opcode %02X at offset %d", op0, (int)(code_pos - code_start) );
+ return errBuf;
+ }
+ n = ops[ op0 ].size;
+ if ( code_pos + 1 + n > code_end ) {
+ sprintf( errBuf, "code_pos > code_end" );
+ return errBuf;
+ }
+ code_pos++;
+ ci->op = op0;
+ if ( n == 4 ) {
+ ci->value = LittleLong( *((int*)code_pos) );
+ code_pos += 4;
+ } else if ( n == 1 ) {
+ ci->value = *((unsigned char*)code_pos);
+ code_pos += 1;
+ } else {
+ ci->value = 0;
+ }
+
+ // setup jump value from previous const
+ if ( op0 == OP_JUMP && op1 == OP_CONST ) {
+ ci->value = (ci-1)->value;
+ }
+
+ ci->opStack = opStack;
+ opStack += ops[ op0 ].stack;
+ }
+
+ return NULL;
+}
+
+/*
+===============================
+VM_CheckInstructions
+
+performs additional consistency and security checks
+===============================
+*/
+const char *VM_CheckInstructions( instruction_t *buf,
+ int instructionCount,
+ const byte *jumpTableTargets,
+ int numJumpTableTargets,
+ int dataLength )
+{
+ static char errBuf[ 128 ];
+ int i, n, v, op0, op1, opStack, pstack;
+ instruction_t *ci, *proc;
+ int startp, endp;
+
+ ci = buf;
+ opStack = 0;
+
+ // opstack checks
+ for ( i = 0; i < instructionCount; i++, ci++ ) {
+ opStack += ops[ ci->op ].stack;
+ if ( opStack < 0 ) {
+ sprintf( errBuf, "opStack underflow at %i", i );
+ return errBuf;
+ }
+ if ( opStack >= PROC_OPSTACK_SIZE * 4 ) {
+ sprintf( errBuf, "opStack overflow at %i", i );
+ return errBuf;
+ }
+ }
+
+ ci = buf;
+ pstack = 0;
+ op1 = OP_UNDEF;
+ proc = NULL;
+
+ startp = 0;
+ endp = instructionCount - 1;
+
+ // Additional security checks
+
+ for ( i = 0; i < instructionCount; i++, ci++, op1 = op0 ) {
+ op0 = ci->op;
+
+ // function entry
+ if ( op0 == OP_ENTER ) {
+ // missing block end
+ if ( proc || ( pstack && op1 != OP_LEAVE ) ) {
+ sprintf( errBuf, "missing proc end before %i", i );
+ return errBuf;
+ }
+ if ( ci->opStack != 0 ) {
+ v = ci->opStack;
+ sprintf( errBuf, "bad entry opstack %i at %i", v, i );
+ return errBuf;
+ }
+ v = ci->value;
+ if ( v < 0 || v >= PROGRAM_STACK_SIZE || (v & 3) ) {
+ sprintf( errBuf, "bad entry programStack %i at %i", v, i );
+ return errBuf;
+ }
+
+ pstack = ci->value;
+
+ // mark jump target
+ ci->jused = 1;
+ proc = ci;
+ startp = i + 1;
+
+ // locate endproc
+ for ( endp = 0, n = i+1 ; n < instructionCount; n++ ) {
+ if ( buf[n].op == OP_PUSH && buf[n+1].op == OP_LEAVE ) {
+ endp = n;
+ break;
+ }
+ }
+
+ if ( endp == 0 ) {
+ sprintf( errBuf, "missing end proc for %i", i );
+ return errBuf;
+ }
+
+ continue;
+ }
+
+ // proc opstack will carry max.possible opstack value
+ if ( proc && ci->opStack > proc->opStack )
+ proc->opStack = ci->opStack;
+
+ // function return
+ if ( op0 == OP_LEAVE ) {
+ // bad return programStack
+ if ( pstack != ci->value ) {
+ v = ci->value;
+ sprintf( errBuf, "bad programStack %i at %i", v, i );
+ return errBuf;
+ }
+ // bad opStack before return
+ if ( ci->opStack != 4 ) {
+ v = ci->opStack;
+ sprintf( errBuf, "bad opStack %i at %i", v, i );
+ return errBuf;
+ }
+ v = ci->value;
+ if ( v < 0 || v >= PROGRAM_STACK_SIZE || (v & 3) ) {
+ sprintf( errBuf, "bad return programStack %i at %i", v, i );
+ return errBuf;
+ }
+ if ( op1 == OP_PUSH ) {
+ if ( proc == NULL ) {
+ sprintf( errBuf, "unexpected proc end at %i", i );
+ return errBuf;
+ }
+ proc = NULL;
+ startp = i + 1; // next instruction
+ endp = instructionCount - 1; // end of the image
+ }
+ continue;
+ }
+
+ // conditional jumps
+ if ( ops[ ci->op ].flags & JUMP ) {
+ v = ci->value;
+ // conditional jumps should have opStack == 8
+ if ( ci->opStack != 8 ) {
+ sprintf( errBuf, "bad jump opStack %i at %i", ci->opStack, i );
+ return errBuf;
+ }
+ //if ( v >= header->instructionCount ) {
+ // allow only local proc jumps
+ if ( v < startp || v > endp ) {
+ sprintf( errBuf, "jump target %i at %i is out of range (%i,%i)", v, i-1, startp, endp );
+ return errBuf;
+ }
+ if ( buf[v].opStack != 0 ) {
+ n = buf[v].opStack;
+ sprintf( errBuf, "jump target %i has bad opStack %i", v, n );
+ return errBuf;
+ }
+ // mark jump target
+ buf[v].jused = 1;
+ continue;
+ }
+
+ // unconditional jumps
+ if ( op0 == OP_JUMP ) {
+ // jumps should have opStack == 4
+ if ( ci->opStack != 4 ) {
+ sprintf( errBuf, "bad jump opStack %i at %i", ci->opStack, i );
+ return errBuf;
+ }
+ if ( op1 == OP_CONST ) {
+ v = buf[i-1].value;
+ // allow only local jumps
+ if ( v < startp || v > endp ) {
+ sprintf( errBuf, "jump target %i at %i is out of range (%i,%i)", v, i-1, startp, endp );
+ return errBuf;
+ }
+ if ( buf[v].opStack != 0 ) {
+ n = buf[v].opStack;
+ sprintf( errBuf, "jump target %i has bad opStack %i", v, n );
+ return errBuf;
+ }
+ if ( buf[v].op == OP_ENTER ) {
+ n = buf[v].op;
+ sprintf( errBuf, "jump target %i has bad opcode %i", v, n );
+ return errBuf;
+ }
+ if ( v == (i-1) ) {
+ sprintf( errBuf, "self loop at %i", v );
+ return errBuf;
+ }
+ // mark jump target
+ buf[v].jused = 1;
+ } else {
+ if ( proc )
+ proc->swtch = 1;
+ else
+ ci->swtch = 1;
+ }
+ continue;
+ }
+
+ if ( op0 == OP_CALL ) {
+ if ( ci->opStack < 4 ) {
+ sprintf( errBuf, "bad call opStack at %i", i );
+ return errBuf;
+ }
+ if ( op1 == OP_CONST ) {
+ v = buf[i-1].value;
+ // analyse only local function calls
+ if ( v >= 0 ) {
+ if ( v >= instructionCount ) {
+ sprintf( errBuf, "call target %i is out of range", v );
+ return errBuf;
+ }
+ if ( buf[v].op != OP_ENTER ) {
+ n = buf[v].op;
+ sprintf( errBuf, "call target %i has bad opcode %i", v, n );
+ return errBuf;
+ }
+ if ( v == 0 ) {
+ sprintf( errBuf, "explicit vmMain call inside VM" );
+ return errBuf;
+ }
+ // mark jump target
+ buf[v].jused = 1;
+ }
+ }
+ continue;
+ }
+
+ if ( ci->op == OP_ARG ) {
+ v = ci->value & 255;
+ // argument can't exceed programStack frame
+ if ( v < 8 || v > pstack - 4 || (v & 3) ) {
+ sprintf( errBuf, "bad argument address %i at %i", v, i );
+ return errBuf;
+ }
+ continue;
+ }
+
+ if ( ci->op == OP_LOCAL ) {
+ v = ci->value;
+ if ( proc == NULL ) {
+ sprintf( errBuf, "missing proc frame for local %i at %i", v, i );
+ return errBuf;
+ }
+ if ( (ci+1)->op == OP_LOAD1 || (ci+1)->op == OP_LOAD2 || (ci+1)->op == OP_LOAD4 || (ci+1)->op == OP_ARG ) {
+ // FIXME: alloc 256 bytes of programStack in VM_CallCompiled()?
+ if ( v < 8 || v >= proc->value + 256 ) {
+ sprintf( errBuf, "bad local address %i at %i", v, i );
+ return errBuf;
+ }
+ }
+ }
+
+ if ( ci->op == OP_LOAD4 && op1 == OP_CONST ) {
+ v = (ci-1)->value;
+ if ( v < 0 || v > dataLength - 4 ) {
+ sprintf( errBuf, "bad load4 address %i at %i", v, i - 1 );
+ return errBuf;
+ }
+ }
+
+ if ( ci->op == OP_LOAD2 && op1 == OP_CONST ) {
+ v = (ci-1)->value;
+ if ( v < 0 || v > dataLength - 2 ) {
+ sprintf( errBuf, "bad load2 address %i at %i", v, i - 1 );
+ return errBuf;
+ }
+ }
+
+ if ( ci->op == OP_LOAD1 && op1 == OP_CONST ) {
+ v = (ci-1)->value;
+ if ( v < 0 || v > dataLength - 1 ) {
+ sprintf( errBuf, "bad load1 address %i at %i", v, i - 1 );
+ return errBuf;
+ }
+ }
+
+ if ( ci->op == OP_BLOCK_COPY ) {
+ v = ci->value;
+ if ( v >= dataLength ) {
+ sprintf( errBuf, "bad count %i for block copy at %i", v, i - 1 );
+ return errBuf;
+ }
+ }
+
+// op1 = op0;
+// ci++;
+ }
+
+ if ( op1 != OP_UNDEF && op1 != OP_LEAVE ) {
+ sprintf( errBuf, "missing return instruction at the end of the image" );
+ return errBuf;
+ }
+
+ // ensure that the optimization pass knows about all the jump table targets
+ if ( jumpTableTargets ) {
+ // first pass - validate
+ for( i = 0; i < numJumpTableTargets; i++ ) {
+ n = *(int *)(jumpTableTargets + ( i * sizeof( int ) ) );
+ if ( n < 0 || n >= instructionCount ) {
+ Con_Printf( "jump target %i set on instruction %i that is out of range [0..%i]",
+ i, n, instructionCount - 1 );
+ break;
+ }
+ if ( buf[n].opStack != 0 ) {
+ Con_Printf( "jump target %i set on instruction %i (%s) with bad opStack %i\n",
+ i, n, opname[ buf[n].op ], buf[n].opStack );
+ break;
+ }
+ }
+ if ( i != numJumpTableTargets ) {
+ // we may trap this on buggy VM_MAGIC_VER2 images
+ // but we can safely optimize code even without JTRGSEG
+ // so just switch to VM_MAGIC path here
+ goto __noJTS;
+ }
+ // second pass - apply
+ for( i = 0; i < numJumpTableTargets; i++ ) {
+ n = *(int *)(jumpTableTargets + ( i * sizeof( int ) ) );
+ buf[n].jused = 1;
+ }
+ } else {
+__noJTS:
+ v = 0;
+ // instructions with opStack > 0 can't be jump labels so its safe to optimize/merge
+ for ( i = 0, ci = buf; i < instructionCount; i++, ci++ ) {
+ if ( ci->op == OP_ENTER ) {
+ v = ci->swtch;
+ continue;
+ }
+ // if there is a switch statement in function -
+ // mark all potential jump labels
+ if ( ci->swtch )
+ v = ci->swtch;
+ if ( ci->opStack > 0 )
+ ci->jused = 0;
+ else if ( v )
+ ci->jused = 1;
+ }
+ }
+
+ return NULL;
+}
+qbool VM_LoadNative( vm_t * vm)
+{
+ char name[MAX_OSPATH];
+ char *gpath = NULL;
+ void ( *dllEntry ) ( void * );
+
+ while ( ( gpath = FS_NextPath( gpath ) ) )
+ {
+ snprintf( name, sizeof( name ), "%s/%s." DLEXT, gpath, vm->name );
+ vm->dllHandle = Sys_DLOpen( name );
+ if ( vm->dllHandle )
+ {
+ Con_Printf( "LoadLibrary (%s)\n", name );
+ break;
+ }
+ }
+ if ( !vm->dllHandle )
+ return false;
+
+ dllEntry = Sys_DLProc( vm->dllHandle, "dllEntry" );
+ vm->entryPoint = Sys_DLProc( vm->dllHandle, "vmMain" );
+ if ( !dllEntry || !vm->entryPoint )
+ {
+ Sys_DLClose( vm->dllHandle );
+ SV_Error( "VM_LoadNative: couldn't initialize module %s", name );
+ }
+ dllEntry( vm->dllSyscall );
+
+ Info_SetValueForStarKey( svs.info, "*qvm", DLEXT, MAX_SERVERINFO_STRING );
+ Info_SetValueForStarKey( svs.info, "*progs", DLEXT, MAX_SERVERINFO_STRING );
+ vm->type = VMI_NATIVE;
+ return true;
+}
+
+/*
+================
+VM_Create
+
+If image ends in .qvm it will be interpreted, otherwise
+it will attempt to load as a system dll
+================
+*/
+vm_t *VM_Create( vmIndex_t index, const char *name, syscall_t systemCalls, /*dllSyscall_t dllSyscalls,*/ vmInterpret_t interpret ) {
+ //int remaining;
+ vmHeader_t *header;
+ vm_t *vm;
+
+ if ( !systemCalls ) {
+ SV_Error( "VM_Create: bad parms" );
+ }
+
+ if ( (unsigned)index >= VM_COUNT ) {
+ SV_Error( "VM_Create: bad vm index %i", index );
+ }
+
+ //remaining = Hunk_MemoryRemaining();
+
+ vm = &vmTable[ index ];
+
+ // see if we already have the VM
+ if ( vm->name ) {
+ if ( vm->index != index ) {
+ SV_Error( "VM_Create: bad allocated vm index %i", vm->index );
+ return NULL;
+ }
+ return vm;
+ }
+
+ vm->name = name;
+ vm->index = index;
+ vm->systemCall = systemCalls;
+ vm->dllSyscall = VM_DllSyscall;//dllSyscalls;
+ //vm->privateFlag = CVAR_PRIVATE;
+
+ // never allow dll loading with a demo
+ /*if ( interpret == VMI_NATIVE ) {
+ if ( Cvar_VariableIntegerValue( "fs_restrict" ) ) {
+ interpret = VMI_COMPILED;
+ }
+ }*/
+
+ if ( interpret == VMI_NATIVE ) {
+ // try to load as a system dll
+ //Con_Printf( "Loading dll file %s.\n", name );
+ if ( VM_LoadNative( vm ) ) {
+ //vm->privateFlag = 0; // allow reading private cvars
+ vm->dataAlloc = ~0U;
+ vm->dataMask = ~0U;
+ vm->dataBase = 0;
+ return vm;
+ }
+
+ Con_Printf( "Failed to load dll, looking for qvm.\n" );
+ interpret = VMI_COMPILED;
+ }
+
+ // load the image
+ if( ( header = VM_LoadQVM( vm, true ) ) == NULL ) {
+ return NULL;
+ }
+
+ // allocate space for the jump targets, which will be filled in by the compile/prep functions
+ vm->instructionCount = header->instructionCount;
+ //vm->instructionPointers = Hunk_Alloc(vm->instructionCount * sizeof(*vm->instructionPointers), h_high);
+ vm->instructionPointers = NULL;
+
+ // copy or compile the instructions
+ vm->codeLength = header->codeLength;
+
+ // the stack is implicitly at the end of the image
+ vm->programStack = vm->dataMask + 1;
+ vm->stackBottom = vm->programStack - PROGRAM_STACK_SIZE - PROGRAM_STACK_EXTRA;
+
+ vm->compiled = false;
+
+
+#ifdef NO_VM_COMPILED
+ if(interpret >= VMI_COMPILED) {
+ Con_Printf("Architecture doesn't have a bytecode compiler, using interpreter\n");
+ interpret = VMI_BYTECODE;
+ }
+#else
+ if ( interpret >= VMI_COMPILED ) {
+ if ( VM_Compile( vm, header ) ) {
+ vm->compiled = true;
+ }
+ }
+#endif
+ // VM_Compile may have reset vm->compiled if compilation failed
+ if ( !vm->compiled ) {
+ if ( !VM_PrepareInterpreter2( vm, header ) ) {
+ //FS_FreeFile( header ); // free the original file
+ VM_Free( vm );
+ return NULL;
+ }
+ }
+ vm->type = interpret;
+
+ // free the original file
+ //FS_FreeFile( header );
+
+ // load the map file
+ VM_LoadSymbols( vm );
+
+ //Con_Printf( "%s loaded in %d bytes on the hunk\n", vm->name, remaining - Hunk_MemoryRemaining() );
+
+ return vm;
+}
+
+/*
+==============
+VM_Free
+==============
+*/
+void VM_Free( vm_t *vm ) {
+
+ if( !vm ) {
+ return;
+ }
+
+/* if ( vm->callLevel ) {
+ if ( !forced_unload ) {
+ SV_Error( ERR_FATAL, "VM_Free(%s) on running vm", vm->name );
+ return;
+ } else {
+ Con_Printf( "forcefully unloading %s vm\n", vm->name );
+ }
+ }*/
+
+ if ( vm->destroy )
+ vm->destroy( vm );
+
+ if ( vm->dllHandle )
+ Sys_DLClose( vm->dllHandle );
+
+#if 0 // now automatically freed by hunk
+ if ( vm->codeBase.ptr ) {
+ Z_Free( vm->codeBase.ptr );
+ }
+ if ( vm->dataBase ) {
+ Z_Free( vm->dataBase );
+ }
+ if ( vm->instructionPointers ) {
+ Z_Free( vm->instructionPointers );
+ }
+#endif
+ currentVM = NULL;
+ lastVM = NULL;
+ memset( vm, 0, sizeof( *vm ) );
+}
+
+
+void VM_Clear( void ) {
+ int i;
+ for ( i = 0; i < VM_COUNT; i++ ) {
+ VM_Free( &vmTable[ i ] );
+ }
+ currentVM = NULL;
+ lastVM = NULL;
+}
+
+/*
+==============
+VM_Call
+
+
+Upon a system call, the stack will look like:
+
+sp+32 parm1
+sp+28 parm0
+sp+24 return value
+sp+20 return address
+sp+16 local1
+sp+14 local0
+sp+12 arg1
+sp+8 arg0
+sp+4 return stack
+sp return address
+
+An interpreted function will immediately execute
+an OP_ENTER instruction, which will subtract space for
+locals from sp
+==============
+*/
+
+intptr_t QDECL VM_Call( vm_t *vm, int nargs, int callnum, ... )
+{
+ vm_t *oldVM;
+ intptr_t r;
+ int i;
+
+ if ( !vm ) {
+ SV_Error( "VM_Call with NULL vm" );
+ }
+
+
+ oldVM = currentVM;
+ currentVM = vm;
+ lastVM = vm;
+
+ if ( vm_debugLevel ) {
+ Con_Printf( "VM_Call( %d )\n", callnum );
+ }
+
+#ifdef DEBUG
+ if ( nargs >= MAX_VMMAIN_CALL_ARGS ) {
+ SV_Error( "VM_Call: nargs >= MAX_VMMAIN_CALL_ARGS" );
+ }
+#endif
+
+ ++vm->callLevel;
+ // if we have a dll loaded, call it directly
+ if ( vm->entryPoint )
+ {
+ //rcg010207 - see dissertation at top of VM_DllSyscall() in this file.
+ int args[MAX_VMMAIN_CALL_ARGS-1];
+ va_list ap;
+ va_start( ap, callnum );
+ for ( i = 0; i < nargs; i++ ) {
+ args[i] = va_arg( ap, int );
+ }
+ va_end(ap);
+
+ // add more agruments if you're changed MAX_VMMAIN_CALL_ARGS:
+ r = vm->entryPoint( callnum, args[0], args[1], args[2] );
+ } else {
+#if idx386 && !defined __clang__ // calling convention doesn't need conversion in some cases
+#ifndef NO_VM_COMPILED
+ if ( vm->compiled )
+ r = VM_CallCompiled( vm, nargs+1, (int*)&callnum );
+ else
+#endif
+ r = VM_CallInterpreted2( vm, nargs+1, (int*)&callnum );
+#else
+ int args[MAX_VMMAIN_CALL_ARGS];
+ va_list ap;
+
+ args[0] = callnum;
+ va_start( ap, callnum );
+ for ( i = 0; i < nargs; i++ ) {
+ args[i+1] = va_arg( ap, int );
+ }
+ va_end(ap);
+#ifndef NO_VM_COMPILED
+ if ( vm->compiled )
+ r = VM_CallCompiled( vm, nargs+1, &args[0] );
+ else
+#endif
+ r = VM_CallInterpreted2( vm, nargs+1, &args[0] );
+#endif
+ }
+ --vm->callLevel;
+ if ( oldVM != NULL ) // bk001220 - assert(currentVM!=NULL) for oldVM==NULL
+ currentVM = oldVM;
+
+ return r;
+}
+
+
+//=================================================================
+
+static int QDECL VM_ProfileSort( const void *a, const void *b ) {
+ vmSymbol_t *sa, *sb;
+
+ sa = *(vmSymbol_t **)a;
+ sb = *(vmSymbol_t **)b;
+
+ if ( sa->profileCount < sb->profileCount ) {
+ return -1;
+ }
+ if ( sa->profileCount > sb->profileCount ) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+==============
+VM_VmProfile_f
+
+==============
+*/
+void VM_VmProfile_f( void ) {
+ vm_t *vm;
+ vmSymbol_t **sorted, *sym;
+ int i;
+ double total;
+
+ vm = &vmTable[VM_GAME];
+
+ if ( !vm->name ) {
+ Con_Printf( " VM is not running.\n" );
+ return;
+ }
+ if ( vm == NULL ) {
+ return;
+ }
+
+ if ( !vm->numSymbols ) {
+ return;
+ }
+
+ sorted = Q_malloc( vm->numSymbols * sizeof( *sorted ) );
+ sorted[0] = vm->symbols;
+ total = sorted[0]->profileCount;
+ for ( i = 1 ; i < vm->numSymbols ; i++ ) {
+ sorted[i] = sorted[i-1]->next;
+ total += sorted[i]->profileCount;
+ }
+
+ qsort( sorted, vm->numSymbols, sizeof( *sorted ), VM_ProfileSort );
+
+ for ( i = 0 ; i < vm->numSymbols ; i++ ) {
+ int perc;
+
+ sym = sorted[i];
+
+ perc = 100 * (float) sym->profileCount / total;
+ Con_Printf( "%2i%% %9i %s\n", perc, sym->profileCount, sym->symName );
+ sym->profileCount = 0;
+ }
+
+ Con_Printf(" %9.0f total\n", total );
+
+ Q_free( sorted );
+}
+
+/*
+==============
+VM_VmInfo_f
+==============
+*/
+void VM_VmInfo_f( void ) {
+ vm_t *vm;
+ int i;
+
+ Con_Printf( "Registered virtual machines:\n" );
+ for ( i = 0 ; i < VM_COUNT ; i++ ) {
+ vm = &vmTable[i];
+ if ( !vm->name ) {
+ continue;
+ }
+ Con_Printf( "%s : ", vm->name );
+ if ( vm->dllHandle ) {
+ Con_Printf( "native\n" );
+ continue;
+ }
+ if ( vm->compiled ) {
+ Con_Printf( "compiled on load\n" );
+ } else {
+ Con_Printf( "interpreted\n" );
+ }
+ Con_Printf( " code length : %7i\n", vm->codeLength );
+ Con_Printf( " table length: %7i\n", vm->instructionCount*4 );
+ Con_Printf( " data length : %7i\n", vm->dataMask + 1 );
+ }
+}
+
+/*
+===============
+VM_LogSyscalls
+
+Insert calls to this while debugging the vm compiler
+===============
+*/
+void VM_LogSyscalls(int *args) {
+#if 1
+ static int callnum;
+ static FILE *f;
+
+ if (!f) {
+ f = fopen("syscalls.log", "w");
+ if (!f) {
+ return;
+ }
+ }
+ callnum++;
+ fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase),
+ args[0], args[1], args[2], args[3], args[4]);
+#endif
+}
+#endif /* USE_PR2 */
diff --git a/src/vm.h b/src/vm.h
new file mode 100644
index 000000000..9fedfb547
--- /dev/null
+++ b/src/vm.h
@@ -0,0 +1,90 @@
+#ifndef VM_H
+#define VM_H
+
+/*
+==============================================================
+
+VIRTUAL MACHINE
+
+==============================================================
+*/
+
+#ifdef _WIN32
+#define QDECL __cdecl
+#else
+#define QDECL
+#endif
+
+typedef struct vm_s vm_t;
+
+typedef enum {
+ VMI_NONE,
+ VMI_NATIVE,
+ VMI_BYTECODE,
+ VMI_COMPILED
+} vmInterpret_t;
+
+
+typedef enum {
+ VM_BAD = -1,
+ VM_GAME = 0,
+ VM_COUNT
+} vmIndex_t;
+
+extern vm_t *currentVM;
+typedef intptr_t (*syscall_t)( intptr_t *parms );
+typedef intptr_t (QDECL *dllSyscall_t)( intptr_t callNum, ... );
+typedef void (QDECL *dllEntry_t)( dllSyscall_t syscallptr );
+
+
+void VM_Init( void );
+vm_t *VM_Create( vmIndex_t index, const char* name, syscall_t systemCalls, /*dllSyscall_t dllSyscalls,*/ vmInterpret_t interpret );
+
+extern vm_t *currentVM;
+
+// module should be bare: "cgame", not "cgame.dll" or "vm/cgame.qvm"
+
+void VM_Free( vm_t *vm );
+void VM_Clear(void);
+void VM_Forced_Unload_Start(void);
+void VM_Forced_Unload_Done(void);
+vm_t *VM_Restart( vm_t *vm );
+
+intptr_t QDECL VM_Call( vm_t *vm, int nargs, int callNum, ... );
+
+void VM_Debug( int level );
+void VM_CheckBounds( const vm_t *vm, unsigned int address, unsigned int length );
+void VM_CheckBounds2( const vm_t *vm, unsigned int addr1, unsigned int addr2, unsigned int length );
+
+#if 1
+#define VM_CHECKBOUNDS VM_CheckBounds
+#define VM_CHECKBOUNDS2 VM_CheckBounds2
+#else // for performance evaluation purposes
+#define VM_CHECKBOUNDS(vm,a,b)
+#define VM_CHECKBOUNDS2(vm,a,b,c)
+#endif
+
+void *VM_ArgPtr( intptr_t intValue );
+void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue );
+intptr_t VM_Ptr2VM( void* ptr ) ;
+intptr_t VM_ExplicitPtr2VM( vm_t *vm, void* ptr );
+
+typedef union floatint_u
+{
+ int i;
+ unsigned int u;
+ float f;
+ byte b[4];
+}
+floatint_t;
+
+#define VMA(x) VM_ArgPtr(args[x])
+static inline float _vmf(intptr_t x)
+{
+ floatint_t v;
+ v.i = (int)x;
+ return v.f;
+}
+#define VMF(x) _vmf(args[x])
+
+#endif
diff --git a/src/vm_interpreted.c b/src/vm_interpreted.c
new file mode 100644
index 000000000..615d1dae6
--- /dev/null
+++ b/src/vm_interpreted.c
@@ -0,0 +1,636 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#ifdef USE_PR2
+#ifdef SERVERONLY
+#include "qwsvdef.h"
+#else
+#include "quakedef.h"
+#endif
+#include "vm_local.h"
+
+
+char *VM_Indent( vm_t *vm ) {
+ static char *string = " ";
+ if ( vm->callLevel > 20 ) {
+ return string;
+ }
+ return string + 2 * ( 20 - vm->callLevel );
+}
+
+
+void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) {
+ int count;
+
+ count = 0;
+ do {
+ Con_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) );
+ programStack = *(int *)&vm->dataBase[programStack+4];
+ programCounter = *(int *)&vm->dataBase[programStack];
+ } while ( programCounter != -1 && ++count < 32 );
+
+}
+
+// macro opcode sequences
+typedef enum {
+ MOP_LOCAL_LOAD4 = OP_MAX,
+ MOP_LOCAL_LOAD4_CONST,
+ MOP_LOCAL_LOCAL,
+ MOP_LOCAL_LOCAL_LOAD4,
+} macro_op_t;
+
+
+/*
+=================
+VM_FindMOps
+
+Search for known macro-op sequences
+=================
+*/
+static void VM_FindMOps( instruction_t *buf, int instructionCount )
+{
+ int i, op0;
+ instruction_t *ci;
+
+ ci = buf;
+ i = 0;
+
+ while ( i < instructionCount )
+ {
+ op0 = ci->op;
+
+ if ( op0 == OP_LOCAL && (ci+1)->op == OP_LOAD4 && (ci+2)->op == OP_CONST ) {
+ ci->op = MOP_LOCAL_LOAD4_CONST;
+ ci += 3; i += 3;
+ continue;
+ }
+
+ if ( op0 == OP_LOCAL && (ci+1)->op == OP_LOAD4 ) {
+ ci->op = MOP_LOCAL_LOAD4;
+ ci += 2; i += 2;
+ continue;
+ }
+
+ if ( op0 == OP_LOCAL && (ci+1)->op == OP_LOCAL && (ci+2)->op == OP_LOAD4 ) {
+ ci->op = MOP_LOCAL_LOCAL_LOAD4;
+ ci += 3; i += 3;
+ continue;
+ }
+
+ if ( op0 == OP_LOCAL && (ci+1)->op == OP_LOCAL ) {
+ ci->op = MOP_LOCAL_LOCAL;
+ ci += 2; i += 2;
+ continue;
+ }
+
+ ci++;
+ i++;
+ }
+}
+
+
+/*
+====================
+VM_PrepareInterpreter2
+====================
+*/
+qbool VM_PrepareInterpreter2( vm_t *vm, vmHeader_t *header )
+{
+ const char *errMsg;
+ instruction_t *buf;
+ buf = ( instruction_t *) Hunk_Alloc( (vm->instructionCount + 8) * sizeof( instruction_t ));
+
+ errMsg = VM_LoadInstructions( (byte *) header + header->codeOffset, header->codeLength, header->instructionCount, buf );
+ if ( !errMsg ) {
+ errMsg = VM_CheckInstructions( buf, vm->instructionCount, vm->jumpTableTargets, vm->numJumpTableTargets, vm->exactDataLength );
+ }
+ if ( errMsg ) {
+ Con_Printf( "VM_PrepareInterpreter2 error: %s\n", errMsg );
+ return false;
+ }
+
+ //VM_ReplaceInstructions( vm, buf );
+
+ VM_FindMOps( buf, vm->instructionCount );
+
+ vm->codeBase.ptr = (void*)buf;
+ return true;
+}
+
+
+/*
+==============
+VM_CallInterpreted2
+
+
+Upon a system call, the stack will look like:
+
+sp+32 parm1
+sp+28 parm0
+sp+24 return stack
+sp+20 return address
+sp+16 local1
+sp+14 local0
+sp+12 arg1
+sp+8 arg0
+sp+4 return stack
+sp return address
+
+An interpreted function will immediately execute
+an OP_ENTER instruction, which will subtract space for
+locals from sp
+==============
+*/
+int VM_CallInterpreted2( vm_t *vm, int nargs, int *args ) {
+ int stack[MAX_OPSTACK_SIZE];
+ int *opStack, *opStackTop;
+ unsigned int programStack;
+ unsigned int stackOnEntry;
+ byte *image;
+ int v1, v0;
+ int dataMask;
+ instruction_t *inst, *ci;
+ floatint_t r0, r1;
+ int opcode;
+ int *img;
+ int i;
+
+ // interpret the code
+ //vm->currentlyInterpreting = true;
+
+ // we might be called recursively, so this might not be the very top
+ programStack = stackOnEntry = vm->programStack;
+
+ // set up the stack frame
+ image = vm->dataBase;
+ inst = (instruction_t *)vm->codeBase.ptr;
+ dataMask = vm->dataMask;
+
+ // leave a free spot at start of stack so
+ // that as long as opStack is valid, opStack-1 will
+ // not corrupt anything
+ opStack = &stack[1];
+ opStackTop = stack + ARRAY_LEN( stack ) - 1;
+
+ programStack -= (MAX_VMMAIN_CALL_ARGS+2)*4;
+ img = (int*)&image[ programStack ];
+ for ( i = 0; i < nargs; i++ ) {
+ img[ i + 2 ] = args[ i ];
+ }
+ img[ 1 ] = 0; // return stack
+ img[ 0 ] = -1; // will terminate the loop on return
+
+ ci = inst;
+
+ // main interpreter loop, will exit when a LEAVE instruction
+ // grabs the -1 program counter
+
+ while ( 1 ) {
+
+ r0.i = opStack[0];
+ r1.i = opStack[-1];
+
+nextInstruction2:
+
+ v0 = ci->value;
+ opcode = ci->op;
+ ci++;
+
+ switch ( opcode ) {
+
+ case OP_BREAK:
+ vm->breakCount++;
+ goto nextInstruction2;
+
+ case OP_ENTER:
+ // get size of stack frame
+ programStack -= v0;
+ if ( programStack <= vm->stackBottom ) {
+ VM_StackTrace(vm, ci - (instruction_t *)vm->codeBase.ptr, programStack);
+ SV_Error( "VM programStack overflow" );
+ }
+ if ( opStack + ((ci-1)->opStack/4) >= opStackTop ) {
+ VM_StackTrace(vm, ci - (instruction_t *)vm->codeBase.ptr, programStack);
+ SV_Error( "VM opStack overflow" );
+ }
+ break;
+
+ case OP_LEAVE:
+ // remove our stack frame
+ programStack += v0;
+
+ // grab the saved program counter
+ v1 = *(int *)&image[ programStack ];
+ // check for leaving the VM
+ if ( v1 == -1 ) {
+ goto done;
+ } else if ( (unsigned)v1 >= vm->instructionCount ) {
+ VM_StackTrace(vm, ci - (instruction_t *)vm->codeBase.ptr, programStack);
+ SV_Error( "VM program counter out of range in OP_LEAVE" );
+ }
+ ci = inst + v1;
+ break;
+
+ case OP_CALL:
+ // save current program counter
+ *(int *)&image[ programStack ] = ci - inst;
+
+ // jump to the location on the stack
+ if ( r0.i < 0 ) {
+ // system call
+ // save the stack to allow recursive VM entry
+ //vm->programStack = programStack - 4;
+ vm->programStack = programStack - 8;
+ *(int *)&image[ programStack + 4 ] = ~r0.i;
+ {
+#if idx64 //__WORDSIZE == 64
+ // the vm has ints on the stack, we expect
+ // longs so we have to convert it
+ intptr_t argarr[16];
+ int argn;
+ for ( argn = 0; argn < ARRAY_LEN( argarr ); ++argn ) {
+ argarr[ argn ] = *(int*)&image[ programStack + 4 + 4*argn ];
+ }
+ v0 = vm->systemCall( &argarr[0] );
+#else
+ //VM_LogSyscalls( (int *)&image[ programStack + 4 ] );
+ v0 = vm->systemCall( (intptr_t *)&image[ programStack + 4 ] );
+#endif
+ }
+
+ // save return value
+ //opStack++;
+ ci = inst + *(int *)&image[ programStack ];
+ *opStack = v0;
+ } else if ( r0.u < vm->instructionCount ) {
+ // vm call
+ ci = inst + r0.i;
+ opStack--;
+ } else {
+ VM_StackTrace(vm, ci - (instruction_t *)vm->codeBase.ptr, programStack);
+ SV_Error( "VM program counter out of range in OP_CALL" );
+ }
+ break;
+
+ // push and pop are only needed for discarded or bad function return values
+ case OP_PUSH:
+ opStack++;
+ break;
+
+ case OP_POP:
+ opStack--;
+ break;
+
+ case OP_CONST:
+ opStack++;
+ r1.i = r0.i;
+ r0.i = *opStack = v0;
+ goto nextInstruction2;
+
+ case OP_LOCAL:
+ opStack++;
+ r1.i = r0.i;
+ r0.i = *opStack = v0 + programStack;
+ goto nextInstruction2;
+
+ case OP_JUMP:
+ if ( r0.u >= vm->instructionCount ) {
+ VM_StackTrace(vm, ci - (instruction_t *)vm->codeBase.ptr, programStack);
+ SV_Error( "VM program counter out of range in OP_JUMP" );
+ }
+ ci = inst + r0.i;
+ opStack--;
+ break;
+
+ /*
+ ===================================================================
+ BRANCHES
+ ===================================================================
+ */
+
+ case OP_EQ:
+ opStack -= 2;
+ if ( r1.i == r0.i )
+ ci = inst + v0;
+ break;
+
+ case OP_NE:
+ opStack -= 2;
+ if ( r1.i != r0.i )
+ ci = inst + v0;
+ break;
+
+ case OP_LTI:
+ opStack -= 2;
+ if ( r1.i < r0.i )
+ ci = inst + v0;
+ break;
+
+ case OP_LEI:
+ opStack -= 2;
+ if ( r1.i <= r0.i )
+ ci = inst + v0;
+ break;
+
+ case OP_GTI:
+ opStack -= 2;
+ if ( r1.i > r0.i )
+ ci = inst + v0;
+ break;
+
+ case OP_GEI:
+ opStack -= 2;
+ if ( r1.i >= r0.i )
+ ci = inst + v0;
+ break;
+
+ case OP_LTU:
+ opStack -= 2;
+ if ( r1.u < r0.u )
+ ci = inst + v0;
+ break;
+
+ case OP_LEU:
+ opStack -= 2;
+ if ( r1.u <= r0.u )
+ ci = inst + v0;
+ break;
+
+ case OP_GTU:
+ opStack -= 2;
+ if ( r1.u > r0.u )
+ ci = inst + v0;
+ break;
+
+ case OP_GEU:
+ opStack -= 2;
+ if ( r1.u >= r0.u )
+ ci = inst + v0;
+ break;
+
+ case OP_EQF:
+ opStack -= 2;
+ if ( r1.f == r0.f )
+ ci = inst + v0;
+ break;
+
+ case OP_NEF:
+ opStack -= 2;
+ if ( r1.f != r0.f )
+ ci = inst + v0;
+ break;
+
+ case OP_LTF:
+ opStack -= 2;
+ if ( r1.f < r0.f )
+ ci = inst + v0;
+ break;
+
+ case OP_LEF:
+ opStack -= 2;
+ if ( r1.f <= r0.f )
+ ci = inst + v0;
+ break;
+
+ case OP_GTF:
+ opStack -= 2;
+ if ( r1.f > r0.f )
+ ci = inst + v0;
+ break;
+
+ case OP_GEF:
+ opStack -= 2;
+ if ( r1.f >= r0.f )
+ ci = inst + v0;
+ break;
+
+ //===================================================================
+
+ case OP_LOAD1:
+ r0.i = *opStack = image[ r0.i & dataMask ];
+ goto nextInstruction2;
+
+ case OP_LOAD2:
+ r0.i = *opStack = *(unsigned short *)&image[ r0.i & dataMask ];
+ goto nextInstruction2;
+
+ case OP_LOAD4:
+ r0.i = *opStack = *(int *)&image[ r0.i & dataMask ];
+ goto nextInstruction2;
+
+ case OP_STORE1:
+ image[ r1.i & dataMask ] = r0.i;
+ opStack -= 2;
+ break;
+
+ case OP_STORE2:
+ *(short *)&image[ r1.i & dataMask ] = r0.i;
+ opStack -= 2;
+ break;
+
+ case OP_STORE4:
+ *(int *)&image[ r1.i & dataMask ] = r0.i;
+ opStack -= 2;
+ break;
+
+ case OP_ARG:
+ // single byte offset from programStack
+ *(int *)&image[ ( v0 + programStack ) /*& ( dataMask & ~3 ) */ ] = r0.i;
+ opStack--;
+ break;
+
+ case OP_BLOCK_COPY:
+ {
+ int *src, *dest;
+ int count, srci, desti;
+
+ count = v0;
+ // MrE: copy range check
+ srci = r0.i & dataMask;
+ desti = r1.i & dataMask;
+ count = ((srci + count) & dataMask) - srci;
+ count = ((desti + count) & dataMask) - desti;
+
+ src = (int *)&image[ srci ];
+ dest = (int *)&image[ desti ];
+
+ memcpy( dest, src, count );
+ opStack -= 2;
+ }
+ break;
+
+ case OP_SEX8:
+ *opStack = (signed char)*opStack;
+ break;
+
+ case OP_SEX16:
+ *opStack = (short)*opStack;
+ break;
+
+ case OP_NEGI:
+ *opStack = -r0.i;
+ break;
+
+ case OP_ADD:
+ opStack[-1] = r1.i + r0.i;
+ opStack--;
+ break;
+
+ case OP_SUB:
+ opStack[-1] = r1.i - r0.i;
+ opStack--;
+ break;
+
+ case OP_DIVI:
+ opStack[-1] = r1.i / r0.i;
+ opStack--;
+ break;
+
+ case OP_DIVU:
+ opStack[-1] = r1.u / r0.u;
+ opStack--;
+ break;
+
+ case OP_MODI:
+ opStack[-1] = r1.i % r0.i;
+ opStack--;
+ break;
+
+ case OP_MODU:
+ opStack[-1] = r1.u % r0.u;
+ opStack--;
+ break;
+
+ case OP_MULI:
+ opStack[-1] = r1.i * r0.i;
+ opStack--;
+ break;
+
+ case OP_MULU:
+ opStack[-1] = r1.u * r0.u;
+ opStack--;
+ break;
+
+ case OP_BAND:
+ opStack[-1] = r1.u & r0.u;
+ opStack--;
+ break;
+
+ case OP_BOR:
+ opStack[-1] = r1.u | r0.u;
+ opStack--;
+ break;
+
+ case OP_BXOR:
+ opStack[-1] = r1.u ^ r0.u;
+ opStack--;
+ break;
+
+ case OP_BCOM:
+ *opStack = ~ r0.u;
+ break;
+
+ case OP_LSH:
+ opStack[-1] = r1.i << r0.i;
+ opStack--;
+ break;
+
+ case OP_RSHI:
+ opStack[-1] = r1.i >> r0.i;
+ opStack--;
+ break;
+
+ case OP_RSHU:
+ opStack[-1] = r1.u >> r0.i;
+ opStack--;
+ break;
+
+ case OP_NEGF:
+ *(float *)opStack = - r0.f;
+ break;
+
+ case OP_ADDF:
+ *(float *)(opStack-1) = r1.f + r0.f;
+ opStack--;
+ break;
+
+ case OP_SUBF:
+ *(float *)(opStack-1) = r1.f - r0.f;
+ opStack--;
+ break;
+
+ case OP_DIVF:
+ *(float *)(opStack-1) = r1.f / r0.f;
+ opStack--;
+ break;
+
+ case OP_MULF:
+ *(float *)(opStack-1) = r1.f * r0.f;
+ opStack--;
+ break;
+
+ case OP_CVIF:
+ *(float *)opStack = (float) r0.i;
+ break;
+
+ case OP_CVFI:
+ *opStack = (int) r0.f;
+ break;
+
+ case MOP_LOCAL_LOAD4:
+ ci++;
+ opStack++;
+ r1.i = r0.i;
+ r0.i = *opStack = *(int *)&image[ v0 + programStack ];
+ goto nextInstruction2;
+
+ case MOP_LOCAL_LOAD4_CONST:
+ r1.i = opStack[1] = *(int *)&image[ v0 + programStack ];
+ r0.i = opStack[2] = (ci+1)->value;
+ opStack += 2;
+ ci += 2;
+ goto nextInstruction2;
+
+ case MOP_LOCAL_LOCAL:
+ r1.i = opStack[1] = v0 + programStack;
+ r0.i = opStack[2] = ci->value + programStack;
+ opStack += 2;
+ ci++;
+ goto nextInstruction2;
+
+ case MOP_LOCAL_LOCAL_LOAD4:
+ r1.i = opStack[1] = v0 + programStack;
+ r0.i /*= opStack[2]*/ = ci->value + programStack;
+ r0.i = opStack[2] = *(int *)&image[ r0.i /*& dataMask*/ ];
+ opStack += 2;
+ ci += 2;
+ goto nextInstruction2;
+ }
+ }
+
+done:
+ //vm->currentlyInterpreting = false;
+
+ if ( opStack != &stack[2] ) {
+ VM_StackTrace(vm, ci - (instruction_t *)vm->codeBase.ptr, programStack);
+ SV_Error( "Interpreter error: opStack = %ld", (long int) (opStack - stack) );
+ }
+
+ vm->programStack = stackOnEntry;
+
+ // return the result
+ return *opStack;
+}
+#endif /* USE_PR2 */
diff --git a/src/vm_local.h b/src/vm_local.h
new file mode 100644
index 000000000..315ea63d6
--- /dev/null
+++ b/src/vm_local.h
@@ -0,0 +1,293 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+
+#ifndef VM_LOCAL_H
+#define VM_LOCAL_H
+
+#include "vm.h"
+#define MAX_OPSTACK_SIZE 512
+#define PROC_OPSTACK_SIZE 30
+#define STACK_MASK (MAX_OPSTACK_SIZE-1)
+#define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack )
+
+// we don't need more than 4 arguments (counting callnum) for vmMain, at least in Quake3
+#define MAX_VMMAIN_CALL_ARGS 4
+
+// don't change
+// Hardcoded in q3asm an reserved at end of bss
+#define PROGRAM_STACK_SIZE 0x10000
+
+// for some buggy mods
+#define PROGRAM_STACK_EXTRA (32*1024)
+
+#define PAD(base, alignment) (((base)+(alignment)-1) & ~((alignment)-1))
+#define PADLEN(base, alignment) (PAD((base), (alignment)) - (base))
+
+typedef enum {
+ OP_UNDEF,
+
+ OP_IGNORE,
+
+ OP_BREAK,
+
+ OP_ENTER,
+ OP_LEAVE,
+ OP_CALL,
+ OP_PUSH,
+ OP_POP,
+
+ OP_CONST,
+ OP_LOCAL,
+
+ OP_JUMP,
+
+ //-------------------
+
+ OP_EQ,
+ OP_NE,
+
+ OP_LTI,
+ OP_LEI,
+ OP_GTI,
+ OP_GEI,
+
+ OP_LTU,
+ OP_LEU,
+ OP_GTU,
+ OP_GEU,
+
+ OP_EQF,
+ OP_NEF,
+
+ OP_LTF,
+ OP_LEF,
+ OP_GTF,
+ OP_GEF,
+
+ //-------------------
+
+ OP_LOAD1,
+ OP_LOAD2,
+ OP_LOAD4,
+ OP_STORE1,
+ OP_STORE2,
+ OP_STORE4, // *(stack[top-1]) = stack[top]
+ OP_ARG,
+
+ OP_BLOCK_COPY,
+
+ //-------------------
+
+ OP_SEX8,
+ OP_SEX16,
+
+ OP_NEGI,
+ OP_ADD,
+ OP_SUB,
+ OP_DIVI,
+ OP_DIVU,
+ OP_MODI,
+ OP_MODU,
+ OP_MULI,
+ OP_MULU,
+
+ OP_BAND,
+ OP_BOR,
+ OP_BXOR,
+ OP_BCOM,
+
+ OP_LSH,
+ OP_RSHI,
+ OP_RSHU,
+
+ OP_NEGF,
+ OP_ADDF,
+ OP_SUBF,
+ OP_DIVF,
+ OP_MULF,
+
+ OP_CVIF,
+ OP_CVFI,
+
+ OP_MAX
+} opcode_t;
+
+typedef struct {
+ int value; // 32
+ byte op; // 8
+ byte opStack; // 8
+ unsigned jused:1;
+ unsigned swtch:1;
+} instruction_t;
+
+typedef struct vmSymbol_s {
+ struct vmSymbol_s *next;
+ int symValue;
+ int profileCount;
+ char symName[1]; // variable sized
+} vmSymbol_t;
+
+
+//typedef void(*vmfunc_t)(void);
+
+typedef union vmFunc_u {
+ byte *ptr;
+ void (*func)(void);
+} vmFunc_t;
+
+#define VM_MAGIC 0x12721444
+#define VM_MAGIC_VER2 0x12721445
+typedef struct
+{
+ int vmMagic;
+
+ int instructionCount;
+
+ int codeOffset;
+ int codeLength;
+
+ int dataOffset;
+ int dataLength;
+ int litLength; // ( dataLength - litLength ) should be byteswapped on load
+ int bssLength; // zero filled memory appended to datalength
+ //!!! below here is VM_MAGIC_VER2 !!!
+ int jtrgLength; // number of jump table targets
+} vmHeader_t;
+
+
+typedef struct vm_s vm_t;
+
+struct vm_s {
+
+ unsigned int programStack; // the vm may be recursively entered
+ syscall_t systemCall;
+ byte *dataBase;
+ int *opStack; // pointer to local function stack
+
+ int instructionCount;
+ intptr_t *instructionPointers;
+
+ //------------------------------------
+
+ const char *name;
+ vmIndex_t index;
+
+ // for dynamic linked modules
+ void *dllHandle;
+ dllSyscall_t entryPoint;
+ dllSyscall_t dllSyscall;
+ void (*destroy)(vm_t* self);
+
+ // for interpreted modules
+ //qbool currentlyInterpreting;
+
+ qbool compiled;
+
+ vmFunc_t codeBase;
+ unsigned int codeSize; // code + jump targets, needed for proper munmap()
+ unsigned int codeLength; // just for information
+
+ unsigned int dataMask;
+ unsigned int dataLength; // data segment length
+ unsigned int exactDataLength; // from qvm header
+ unsigned int dataAlloc; // actually allocated
+
+ unsigned int stackBottom; // if programStack < stackBottom, error
+ int *opStackTop;
+
+ int numSymbols;
+ vmSymbol_t *symbols;
+
+ int callLevel; // counts recursive VM_Call
+ int breakFunction; // increment breakCount on function entry to this
+ int breakCount;
+
+ byte *jumpTableTargets;
+ int numJumpTableTargets;
+
+ uint32_t crc32sum;
+
+ qbool forceDataMask;
+ vmInterpret_t type;
+ qbool pr2_references;
+ //int privateFlag;
+};
+
+extern int vm_debugLevel;
+
+extern cvar_t vm_rtChecks;
+qbool VM_Compile( vm_t *vm, vmHeader_t *header );
+int VM_CallCompiled( vm_t *vm, int nargs, int *args );
+
+qbool VM_PrepareInterpreter2( vm_t *vm, vmHeader_t *header );
+int VM_CallInterpreted2( vm_t *vm, int nargs, int *args );
+
+vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value );
+int VM_SymbolToValue( vm_t *vm, const char *symbol );
+const char *VM_ValueToSymbol( vm_t *vm, int value );
+void VM_LogSyscalls( int *args );
+
+const char *VM_LoadInstructions( const byte *code_pos, int codeLength, int instructionCount, instruction_t *buf );
+const char *VM_CheckInstructions( instruction_t *buf, int instructionCount,
+ const byte *jumpTableTargets,
+ int numJumpTableTargets,
+ int dataLength );
+
+//void VM_ReplaceInstructions( vm_t *vm, instruction_t *buf );
+
+#define JUMP (1<<0)
+
+typedef struct opcode_info_s
+{
+ int size;
+ int stack;
+ int nargs;
+ int flags;
+} opcode_info_t ;
+
+extern opcode_info_t ops[ OP_MAX ];
+
+void VM_Init( void );
+vm_t *VM_Create( vmIndex_t index, const char* name, syscall_t systemCalls, /*dllSyscall_t dllSyscalls,*/ vmInterpret_t interpret );
+
+// module should be bare: "cgame", not "cgame.dll" or "vm/cgame.qvm"
+
+void VM_Free( vm_t *vm );
+void VM_Clear(void);
+void VM_Forced_Unload_Start(void);
+void VM_Forced_Unload_Done(void);
+vm_t *VM_Restart( vm_t *vm );
+
+intptr_t QDECL VM_Call( vm_t *vm, int nargs, int callNum, ... );
+
+void VM_Debug( int level );
+void VM_CheckBounds( const vm_t *vm, unsigned int address, unsigned int length );
+void VM_CheckBounds2( const vm_t *vm, unsigned int addr1, unsigned int addr2, unsigned int length );
+
+#if 1
+#define VM_CHECKBOUNDS VM_CheckBounds
+#define VM_CHECKBOUNDS2 VM_CheckBounds2
+#else // for performance evaluation purposes
+#define VM_CHECKBOUNDS(vm,a,b)
+#define VM_CHECKBOUNDS2(vm,a,b,c)
+#endif
+
+
+
+#endif // VM_LOCAL_H
+
diff --git a/src/vm_x86.c b/src/vm_x86.c
new file mode 100644
index 000000000..bdd384a97
--- /dev/null
+++ b/src/vm_x86.c
@@ -0,0 +1,2968 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+
+#ifdef USE_PR2
+#ifdef SERVERONLY
+#include "qwsvdef.h"
+#else
+#include "quakedef.h"
+#include "pr_comp.h"
+#include "g_public.h"
+#endif
+#include "vm_local.h"
+
+#if ( idx386) || (idx64)
+#ifdef _WIN32
+#include
+#endif
+
+#ifdef __FreeBSD__
+#include
+#endif
+
+#ifndef _WIN32
+#include // for PROT_ stuff
+#endif
+
+/* need this on NX enabled systems (i386 with PAE kernel or
+ * noexec32=on x86_64) */
+#if defined(__linux__) || defined(__FreeBSD__)
+#define VM_X86_MMAP
+#endif
+
+//#define VM_LOG_SYSCALLS
+#define JUMP_OPTIMIZE 0
+
+#if JUMP_OPTIMIZE
+#define NUM_PASSES 7
+#else
+#define NUM_PASSES 3
+#endif
+
+/*
+** --------------------------------------------------------------------------------
+**
+** PROCESSOR STUFF
+**
+** --------------------------------------------------------------------------------
+*/
+
+#define CPU_FCOM 0x01
+#define CPU_MMX 0x02
+#define CPU_SSE 0x04
+#define CPU_SSE2 0x08
+#define CPU_SSE3 0x10
+
+int CPU_Flags = 0;
+#if defined _MSC_VER
+
+static void CPUID( int func, unsigned int *regs )
+{
+#if _MSC_VER >= 1400
+ __cpuid( regs, func );
+#else
+ __asm {
+ mov edi,regs
+ mov eax,[edi]
+ cpuid
+ mov [edi], eax
+ mov [edi+4], ebx
+ mov [edi+8], ecx
+ mov [edi+12], edx
+ }
+#endif
+}
+
+#else
+
+static void CPUID( int func, unsigned int *regs )
+{
+ __asm__ __volatile__( "cpuid" :
+ "=a"(regs[0]),
+ "=b"(regs[1]),
+ "=c"(regs[2]),
+ "=d"(regs[3]) :
+ "a"(func) );
+}
+#endif
+
+int Sys_GetProcessorId( char *vendor )
+{
+ unsigned int regs[4];
+
+ // setup initial features
+#if idx64
+ CPU_Flags |= CPU_SSE | CPU_SSE2 | CPU_FCOM;
+#else
+ CPU_Flags = 0;
+#endif
+
+ // get CPU feature bits
+ CPUID( 1, regs );
+
+ // bit 15 of EDX denotes CMOV/FCMOV/FCOMI existence
+ if ( regs[3] & ( 1 << 15 ) )
+ CPU_Flags |= CPU_FCOM;
+
+ // bit 23 of EDX denotes MMX existence
+ if ( regs[3] & ( 1 << 23 ) )
+ CPU_Flags |= CPU_MMX;
+
+ // bit 25 of EDX denotes SSE existence
+ if ( regs[3] & ( 1 << 25 ) )
+ CPU_Flags |= CPU_SSE;
+
+ // bit 26 of EDX denotes SSE2 existence
+ if ( regs[3] & ( 1 << 26 ) )
+ CPU_Flags |= CPU_SSE2;
+
+ // bit 0 of ECX denotes SSE3 existence
+ if ( regs[2] & ( 1 << 0 ) )
+ CPU_Flags |= CPU_SSE3;
+
+ if ( vendor ) {
+#if idx64
+ strcpy( vendor, "64-bit " );
+ vendor += strlen( vendor );
+#else
+ vendor[0] = '\0';
+#endif
+ // get CPU vendor string
+ CPUID( 0, regs );
+ memcpy( vendor+0, (char*) ®s[1], 4 );
+ memcpy( vendor+4, (char*) ®s[3], 4 );
+ memcpy( vendor+8, (char*) ®s[2], 4 );
+ vendor[12] = '\0'; vendor += 12;
+ if ( CPU_Flags ) {
+ // print features
+#if !idx64 // do not print default 64-bit features in 32-bit mode
+ strcat( vendor, " w/" );
+ if ( CPU_Flags & CPU_FCOM )
+ strcat( vendor, " CMOV" );
+ if ( CPU_Flags & CPU_MMX )
+ strcat( vendor, " MMX" );
+ if ( CPU_Flags & CPU_SSE )
+ strcat( vendor, " SSE" );
+ if ( CPU_Flags & CPU_SSE2 )
+ strcat( vendor, " SSE2" );
+#endif
+ //if ( CPU_Flags & CPU_SSE3 )
+ // strcat( vendor, " SSE3" );
+ }
+ }
+ return 1;
+}
+
+static void *VM_Alloc_Compiled( vm_t *vm, int codeLength, int tableLength );
+static void VM_Destroy_Compiled( vm_t *vm );
+
+/*
+ -------------
+ eax scratch
+ ebx* dataBase
+ ecx scratch (required for shifts)
+ edx scratch (required for divisions)
+ esi* program stack
+ edi* opstack
+ ebp* current proc stack ( dataBase + program stack )
+ -------------
+ rax scratch
+ rbx* dataBase
+ rcx scratch (required for shifts)
+ rdx scratch (required for divisions)
+ rsi* programStack
+ rdi* opstack
+ rbp* current proc stack ( dataBase + program stack )
+ r8 instructionPointers
+ r9 dataMask
+ r12* systemCall
+ r13* stackBottom
+ r14* opStackTop
+ xmm0 scratch
+ xmm1 scratch
+ xmm2 scratch
+ xmm3 scratch
+ xmm4 scratch
+ xmm5 scratch
+
+ Windows ABI: you are required to preserve the XMM6-XMM15 registers
+ System V ABI: you don't have to preserve any of the XMM registers
+
+ Example how data segment will look like during vmMain execution:
+ | .... |
+ |------| vm->programStack -=36 (8+12+16) // set by vmMain
+ | ???? | +0 - unused, reserved for interpreter
+ | ???? | +4 - unused, reserved for interpreter
+ |-------
+ | arg0 | +8 \
+ | arg4 | +12 | - passed arguments, accessible from subroutines
+ | arg8 | +16 /
+ |------|
+ | loc0 | +20 \
+ | loc4 | +24 \ - locals, accessible only from local scope
+ | loc8 | +28 /
+ | lc12 | +32 /
+ |------| vm->programStack -= 24 ( 8 + MAX_VMMAIN_CALL_ARGS*4 ) // set by VM_CallCompiled()
+ | ???? | +0 - unused, reserved for interpreter
+ | ???? | +4 - unused, reserved for interpreter
+ | arg0 | +8 \
+ | arg1 | +12 \ - passed arguments, accessible from vmMain
+ | arg2 | +16 /
+ | arg3 | +20 /
+ |------| vm->programStack = vm->dataMask + 1 // set by VM_Create()
+
+ jump/call opStack rules:
+
+ 1) opStack must be 8 before conditional jump
+ 2) opStack must be 4 before unconditional jump
+ 3) opStack must be >=4 before OP_CALL
+ 4) opStack must remain the same after OP_CALL
+ 5) you may not jump in/call locations with opStack != 0
+
+*/
+
+#define ISS8(V) ( (V) >= -128 && (V) <= 127 )
+#define ISU8(V) ( (V) >= 0 && (V) <= 127 )
+
+#define REWIND(N) { compiledOfs -= (N); instructionOffsets[ ip-1 ] = compiledOfs; };
+
+typedef enum
+{
+ REG_EAX = 0,
+ REG_ECX
+} reg_t;
+
+
+typedef enum
+{
+ LAST_COMMAND_NONE = 0,
+ LAST_COMMAND_MOV_EDI_EAX,
+ LAST_COMMAND_MOV_EDI_CONST,
+ LAST_COMMAND_MOV_EAX_EDI,
+ LAST_COMMAND_MOV_EAX_EDI_CALL,
+ LAST_COMMAND_SUB_DI_4,
+ LAST_COMMAND_SUB_DI_8,
+ LAST_COMMAND_SUB_DI_12,
+ LAST_COMMAND_STORE_FLOAT_EDI,
+ LAST_COMMAND_STORE_FLOAT_EDI_X87,
+ LAST_COMMAND_STORE_FLOAT_EDI_SSE
+} ELastCommand;
+
+typedef enum
+{
+ FUNC_ENTR = 0,
+ FUNC_CALL,
+ FUNC_SYSC,
+ FUNC_FTOL,
+ FUNC_BCPY,
+ FUNC_NCPY,
+ FUNC_PSOF,
+ FUNC_OSOF,
+ FUNC_BADJ,
+ FUNC_ERRJ,
+ FUNC_DATA,
+ FUNC_LAST
+} funcx86_t;
+
+// macro opcode sequences
+typedef enum {
+ MOP_UNDEF = OP_MAX,
+ MOP_IGNORE4,
+ MOP_ADD4,
+ MOP_SUB4,
+ MOP_BAND4,
+ MOP_BOR4,
+ MOP_NCPY,
+} macro_op_t;
+
+static byte *code;
+static int compiledOfs;
+static int *instructionOffsets;
+static intptr_t *instructionPointers;
+
+static instruction_t *inst = NULL;
+static instruction_t *ci;
+static instruction_t *ni;
+
+static int fp_cw[2] = { 0x0000, 0x0F7F }; // [0] - current value, [1] - round towards zero
+
+static int ip, pass;
+static int lastConst;
+static opcode_t pop1;
+
+static ELastCommand LastCommand;
+
+int funcOffset[FUNC_LAST];
+
+#ifdef DEBUG_VM
+static int errParam = 0;
+#endif
+
+static void ErrJump( void )
+{
+ SV_Error( "program tried to execute code outside VM" );
+}
+
+
+static void BadJump( void )
+{
+ SV_Error( "program tried to execute code at bad location inside VM" );
+}
+
+
+static void BadStack( void )
+{
+ SV_Error( "program tried to overflow program stack" );
+}
+
+
+static void BadOpStack( void )
+{
+ SV_Error( "program tried to overflow opcode stack" );
+}
+
+
+static void BadData( void )
+{
+#ifdef DEBUG_VM
+ SV_Error( "program tried to read/write out of data segment at %i", errParam );
+#else
+ SV_Error( "program tried to read/write out of data segment" );
+#endif
+}
+
+
+static void (*const errJumpPtr)(void) = ErrJump;
+static void (*const badJumpPtr)(void) = BadJump;
+static void (*const badStackPtr)(void) = BadStack;
+static void (*const badOpStackPtr)(void) = BadOpStack;
+static void (*const badDataPtr)(void) = BadData;
+
+static void VM_FreeBuffers( void )
+{
+ // should be freed in reversed allocation order
+ Q_free( instructionOffsets );
+ Q_free( inst );
+}
+
+static const inline qbool HasFCOM( void )
+{
+#if idx386
+ return ( CPU_Flags & CPU_FCOM );
+#else
+ return true; // assume idx64
+#endif
+}
+
+
+static const inline qbool HasSSEFP( void )
+{
+#if idx386
+ return ( CPU_Flags & CPU_SSE ) && ( CPU_Flags & CPU_SSE2 );
+#else
+ return true; // assume idx64
+#endif
+}
+
+static void Emit1( int v )
+{
+ if ( code )
+ {
+ code[ compiledOfs ] = v;
+ }
+ compiledOfs++;
+
+ LastCommand = LAST_COMMAND_NONE;
+}
+
+static void Emit4( int v )
+{
+ Emit1( v & 255 );
+ Emit1( ( v >> 8 ) & 255 );
+ Emit1( ( v >> 16 ) & 255 );
+ Emit1( ( v >> 24 ) & 255 );
+}
+
+
+#if idx64
+static void Emit8( int64_t v )
+{
+ Emit1( ( v >> 0 ) & 255 );
+ Emit1( ( v >> 8 ) & 255 );
+ Emit1( ( v >> 16 ) & 255 );
+ Emit1( ( v >> 24 ) & 255 );
+ Emit1( ( v >> 32 ) & 255 );
+ Emit1( ( v >> 40 ) & 255 );
+ Emit1( ( v >> 48 ) & 255 );
+ Emit1( ( v >> 56 ) & 255 );
+}
+#endif
+
+
+static void EmitPtr( const void *ptr )
+{
+#if idx64
+ Emit8( (intptr_t)ptr );
+#else
+ Emit4( (intptr_t)ptr );
+#endif
+}
+
+
+static int Hex( int c )
+{
+ if ( c >= '0' && c <= '9' ) {
+ return c - '0';
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ return 10 + c - 'A';
+ }
+ if ( c >= 'a' && c <= 'f' ) {
+ return 10 + c - 'a';
+ }
+
+ VM_FreeBuffers();
+ SV_Error( "Hex: bad char '%c'", c );
+
+ return 0;
+}
+
+
+static void EmitString( const char *string )
+{
+ int c1, c2;
+ int v;
+
+ while ( 1 ) {
+ c1 = string[0];
+ c2 = string[1];
+
+ v = ( Hex( c1 ) << 4 ) | Hex( c2 );
+ Emit1( v );
+
+ if ( !string[2] ) {
+ break;
+ }
+ string += 3;
+ }
+}
+
+
+static void EmitRexString( const char *string )
+{
+#if idx64
+ Emit1( 0x48 );
+#endif
+ EmitString( string );
+}
+
+
+static void EmitAlign( int align )
+{
+ int i, n;
+
+ n = compiledOfs & ( align - 1 );
+
+ for ( i = 0; i < n ; i++ )
+ EmitString( "90" ); // nop
+}
+
+
+static void EmitCommand( ELastCommand command )
+{
+ switch( command )
+ {
+ case LAST_COMMAND_MOV_EDI_EAX:
+ EmitString( "89 07" ); // mov dword ptr [edi], eax
+ break;
+
+ case LAST_COMMAND_MOV_EAX_EDI:
+ EmitString( "8B 07" ); // mov eax, dword ptr [edi]
+ break;
+
+ case LAST_COMMAND_SUB_DI_4:
+ EmitRexString( "83 EF 04" ); // sub edi, 4
+ break;
+
+ case LAST_COMMAND_SUB_DI_8:
+ EmitRexString( "83 EF 08" ); // sub edi, 8
+ break;
+
+ case LAST_COMMAND_SUB_DI_12:
+ EmitRexString( "83 EF 0C" ); // sub edi, 12
+ break;
+
+ case LAST_COMMAND_STORE_FLOAT_EDI_SSE:
+ EmitString( "F3 0F 11 07" ); // movss dword ptr [edi], xmm0
+ break;
+
+ case LAST_COMMAND_STORE_FLOAT_EDI_X87:
+ EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ break;
+
+ case LAST_COMMAND_STORE_FLOAT_EDI: // meta command
+ if ( HasSSEFP() ) {
+ EmitString( "F3 0F 11 07" );// movss dword ptr [edi], xmm0
+ command = LAST_COMMAND_STORE_FLOAT_EDI_SSE;
+ } else {
+ EmitString( "D9 1F" ); // fstp dword ptr [edi]
+ command = LAST_COMMAND_STORE_FLOAT_EDI_X87;
+ }
+ break;
+
+ default:
+ break;
+ }
+ LastCommand = command;
+}
+
+static void EmitAddEDI4( vm_t *vm )
+{
+ if ( LastCommand == LAST_COMMAND_NONE )
+ {
+ EmitRexString( "83 C7 04" ); // add edi,4
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_SUB_DI_4 ) // sub edi, 4
+ {
+#if idx64
+ REWIND( 4 );
+#else
+ REWIND( 3 );
+#endif
+ LastCommand = LAST_COMMAND_NONE;
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_SUB_DI_8 ) // sub edi, 8
+ {
+#if idx64
+ REWIND( 4 );
+#else
+ REWIND( 3 );
+#endif
+ EmitCommand( LAST_COMMAND_SUB_DI_4 );
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_SUB_DI_12 ) // sub edi, 12
+ {
+#if idx64
+ REWIND( 4 );
+#else
+ REWIND( 3 );
+#endif
+ EmitCommand( LAST_COMMAND_SUB_DI_8 );
+ return;
+ }
+
+ EmitRexString( "83 C7 04" ); // add edi,4
+}
+
+
+static void EmitMovEAXEDI( vm_t *vm )
+{
+ opcode_t pop = pop1;
+ pop1 = OP_UNDEF;
+
+ if ( LastCommand == LAST_COMMAND_NONE )
+ {
+ EmitString( "8B 07" ); // mov eax, dword ptr [edi]
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_MOV_EAX_EDI )
+ return;
+
+ if ( LastCommand == LAST_COMMAND_MOV_EAX_EDI_CALL )
+ return;
+
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) // mov dword ptr [edi], eax
+ {
+ REWIND( 2 );
+ LastCommand = LAST_COMMAND_NONE;
+ return;
+ }
+
+ if ( pop == OP_DIVI || pop == OP_DIVU || pop == OP_MULI || pop == OP_MULU ||
+ pop == OP_STORE4 || pop == OP_STORE2 || pop == OP_STORE1 )
+ {
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_CONST ) // mov dword ptr [edi], 0x12345678
+ {
+ REWIND( 6 );
+ if ( lastConst == 0 ) {
+ EmitString( "31 C0" ); // xor eax, eax
+ } else {
+ EmitString( "B8" ); // mov eax, 0x12345678
+ Emit4( lastConst );
+ }
+ return;
+ }
+
+ EmitString( "8B 07" ); // mov eax, dword ptr [edi]
+}
+
+
+void EmitMovECXEDI( vm_t *vm )
+{
+ opcode_t pop = pop1;
+ pop1 = OP_UNDEF;
+
+ if ( LastCommand == LAST_COMMAND_NONE )
+ {
+ EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_MOV_EAX_EDI_CALL )
+ {
+ EmitString( "89 C1" ); // mov ecx, eax
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_MOV_EAX_EDI ) // mov eax, dword ptr [edi]
+ {
+ REWIND( 2 );
+ EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) // mov dword ptr [edi], eax
+ {
+ REWIND( 2 );
+ EmitString( "89 C1" ); // mov ecx, eax
+ return;
+ }
+
+ if (pop == OP_DIVI || pop == OP_DIVU || pop == OP_MULI || pop == OP_MULU ||
+ pop == OP_STORE4 || pop == OP_STORE2 || pop == OP_STORE1 )
+ {
+ EmitString( "89 C1" ); // mov ecx, eax
+ return;
+ }
+
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_CONST ) // mov dword ptr [edi], 0x12345678
+ {
+ REWIND( 6 );
+ EmitString( "B9" ); // mov ecx, 0x12345678
+ Emit4( lastConst );
+ return;
+ }
+
+ EmitString( "8B 0F" ); // mov ecx, dword ptr [edi]
+}
+
+
+static void EmitCheckReg( vm_t *vm, int reg, int size )
+{
+ int n;
+
+ if ( !( (int)vm_rtChecks.value & 8 ) || vm->forceDataMask ) {
+ if ( vm->forceDataMask ) {
+ if ( reg == REG_EAX )
+ EmitString( "25" ); // and eax, 0x12345678
+ else
+ EmitString( "81 E1" ); // and ecx, 0x12345678
+ Emit4( vm->dataMask );
+ }
+ return;
+ }
+
+#ifdef DEBUG_VM
+ EmitString( "50" ); // push eax
+ EmitRexString( "B8" ); // mov eax, &errParam
+ EmitPtr( &errParam );
+ EmitString( "C7 00" ); // mov [rax], ip-1
+ Emit4( ip-1 );
+ EmitString( "58" ); // pop eax
+#endif
+
+#if idx64
+ if ( reg == REG_EAX )
+ EmitString( "44 39 C8" );// cmp eax, r9d // vm->dataMask
+ else
+ EmitString( "44 39 C9" );// cmp ecx, r9d // vm->dataMask
+#else
+ if ( reg == REG_EAX )
+ EmitString( "3D" ); // cmp eax, 0x12345678
+ else
+ EmitString( "81 F9" ); // cmp ecx, 0x12345678
+
+ Emit4( vm->dataMask - (size - 1) );
+#endif
+
+ // error reporting
+ EmitString( "0F 87" ); // ja +errorFunction
+ n = funcOffset[FUNC_DATA] - compiledOfs;
+ Emit4( n - 6 );
+}
+
+
+static int EmitLoadFloatEDI_SSE( vm_t *vm )
+{
+ // movss dword ptr [edi], xmm0
+ if ( LastCommand == LAST_COMMAND_STORE_FLOAT_EDI_SSE )
+ {
+ if ( !vm )
+ return 1;
+ REWIND( 4 );
+ LastCommand = LAST_COMMAND_NONE;
+ return 1;
+ }
+ EmitString( "F3 0F 10 07" ); // movss xmm0, dword ptr [edi]
+ return 0;
+}
+
+
+static int EmitLoadFloatEDI_X87( vm_t *vm )
+{
+ // fstp dword ptr [edi]
+ if ( LastCommand == LAST_COMMAND_STORE_FLOAT_EDI_X87 )
+ {
+ if ( !vm )
+ return 1;
+ REWIND( 2 );
+ LastCommand = LAST_COMMAND_NONE;
+ return 1;
+ }
+
+ EmitString( "D9 07" ); // fld dword ptr [edi]
+ return 0;
+}
+
+
+static int EmitLoadFloatEDI( vm_t *vm )
+{
+ if ( HasSSEFP() )
+ return EmitLoadFloatEDI_SSE( vm );
+ else
+ return EmitLoadFloatEDI_X87( vm );
+}
+
+#if JUMP_OPTIMIZE
+const char *NearJumpStr( int op )
+{
+ switch ( op )
+ {
+ case OP_EQF:
+ case OP_EQ: return "74"; // je
+
+ case OP_NEF:
+ case OP_NE: return "75"; // jne
+
+ case OP_LTI: return "7C"; // jl
+ case OP_LEI: return "7E"; // jle
+ case OP_GTI: return "7F"; // jg
+ case OP_GEI: return "7D"; // jge
+
+ case OP_LTF:
+ case OP_LTU: return "72"; // jb
+
+ case OP_LEF:
+ case OP_LEU: return "76"; // jbe
+
+ case OP_GTF:
+ case OP_GTU: return "77"; // ja
+
+ case OP_GEF:
+ case OP_GEU: return "73"; // jae
+
+ case OP_JUMP: return "EB"; // jmp
+
+ //default:
+ // SV_Error( "Bad opcode %i", op );
+ };
+ return NULL;
+}
+#endif
+
+
+const char *FarJumpStr( int op, int *n )
+{
+ switch ( op )
+ {
+ case OP_EQF:
+ case OP_EQ: *n = 2; return "0F 84"; // je
+
+ case OP_NEF:
+ case OP_NE: *n = 2; return "0F 85"; // jne
+
+ case OP_LTI: *n = 2; return "0F 8C"; // jl
+ case OP_LEI: *n = 2; return "0F 8E"; // jle
+ case OP_GTI: *n = 2; return "0F 8F"; // jg
+ case OP_GEI: *n = 2; return "0F 8D"; // jge
+
+ case OP_LTF:
+ case OP_LTU: *n = 2; return "0F 82"; // jb
+
+ case OP_LEF:
+ case OP_LEU: *n = 2; return "0F 86"; // jbe
+
+ case OP_GTF:
+ case OP_GTU: *n = 2; return "0F 87"; // ja
+
+ case OP_GEF:
+ case OP_GEU: *n = 2; return "0F 83"; // jae
+
+ case OP_JUMP: *n = 1; return "E9"; // jmp
+ };
+ return NULL;
+}
+
+
+void EmitJump( vm_t *vm, instruction_t *i, int op, int addr )
+{
+ const char *str;
+ int v, jump_size = 0;
+
+ v = instructionOffsets[ addr ] - compiledOfs;
+
+#if JUMP_OPTIMIZE
+ if ( i->njump ) {
+ // can happen
+ if ( v < -126 || v > 129 ) {
+ str = FarJumpStr( op, &jump_size );
+ EmitString( str );
+ Emit4( v - 4 - jump_size );
+ i->njump = 0;
+ return;
+ }
+ EmitString( NearJumpStr( op ) );
+ Emit1( v - 2 );
+ return;
+ }
+
+ if ( pass >= 2 && pass < NUM_PASSES-2 ) {
+ if ( v >= -126 && v <= 129 ) {
+ EmitString( NearJumpStr( op ) );
+ Emit1( v - 2 );
+ i->njump = 1;
+ return;
+ }
+ }
+#endif
+
+ str = FarJumpStr( op, &jump_size );
+ if ( jump_size == 0 ) {
+ SV_Error( "VM_CompileX86 error: %s\n", "bad jump size" );
+ } else {
+ EmitString( str );
+ Emit4( v - 4 - jump_size );
+ }
+}
+
+
+void EmitFloatJump( vm_t *vm, instruction_t *i, int op, int addr )
+{
+ switch ( op ) {
+ case OP_EQF:
+ EmitString( "80 E4 40" ); // and ah,0x40
+ EmitJump( vm, i, OP_NE, addr );
+ break;
+
+ case OP_NEF:
+ EmitString( "80 E4 40" ); // and ah,0x40
+ EmitJump( vm, i, OP_EQ, addr );
+ break;
+
+ case OP_LTF:
+ EmitString( "80 E4 01" ); // and ah,0x01
+ EmitJump( vm, i, OP_NE, addr );
+ break;
+
+ case OP_LEF:
+ EmitString( "80 E4 41" ); // and ah,0x41
+ EmitJump( vm, i, OP_NE, addr );
+ break;
+
+ case OP_GTF:
+ EmitString( "80 E4 41" ); // and ah,0x41
+ EmitJump( vm, i, OP_EQ, addr );
+ break;
+
+ case OP_GEF:
+ EmitString( "80 E4 01" ); // and ah,0x01
+ EmitJump( vm, i, OP_EQ, addr );
+ break;
+ };
+
+}
+
+
+static void EmitCallAddr( vm_t *vm, int addr )
+{
+ int v;
+ v = instructionOffsets[ addr ] - compiledOfs;
+ EmitString( "E8" );
+ Emit4( v - 5 );
+}
+
+
+static void EmitCallOffset( funcx86_t Func )
+{
+ int v;
+ v = funcOffset[ Func ] - compiledOfs;
+ EmitString( "E8" ); // call +funcOffset[ Func ]
+ Emit4( v - 5 );
+}
+
+
+#ifdef _WIN32
+#define SHADOW_BASE 40
+#else // linux/*BSD ABI
+#define SHADOW_BASE 8
+#endif
+
+#define PUSH_STACK 32
+#define PARAM_STACK 128
+
+static void EmitCallFunc( vm_t *vm )
+{
+ static int sysCallOffset = 0;
+ int n;
+
+ EmitString( "85 C0" ); // test eax, eax
+ EmitString( "7C" ); // jl +offset (SystemCall)
+ Emit1( sysCallOffset ); // will be valid after first pass
+sysCallOffset = compiledOfs;
+
+ // jump target range check
+ if ( (int)vm_rtChecks.value & 4 ) {
+ EmitString( "3D" ); // cmp eax, vm->instructionCount
+ Emit4( vm->instructionCount );
+ EmitString( "0F 83" ); // jae +funcOffset[FUNC_ERRJ]
+ n = funcOffset[FUNC_ERRJ] - compiledOfs;
+ Emit4( n - 6 );
+ }
+
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+
+ // save proc base and programStack
+ EmitString( "55" ); // push ebp
+ EmitString( "56" ); // push esi
+
+ // calling another vm function
+#if idx64
+ EmitString( "41 FF 14 C0" ); // call dword ptr [r8+rax*8]
+#else
+ EmitString( "8D 0C 85" ); // lea ecx, [vm->instructionPointers+eax*4]
+ EmitPtr( instructionPointers );
+ EmitString( "FF 11" ); // call dword ptr [ecx]
+#endif
+
+ // restore proc base and programStack so there is
+ // no need to validate programStack anymore
+ EmitString( "5E" ); // pop esi
+ EmitString( "5D" ); // pop ebp
+
+ EmitString( "C3" ); // ret
+
+sysCallOffset = compiledOfs - sysCallOffset;
+
+ // systemCall:
+ // convert negative num to system call number
+ // and store right before the first arg
+ EmitString( "F7 D0" ); // not eax
+
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+
+ // we may jump here from ConstOptimize() also
+funcOffset[FUNC_SYSC] = compiledOfs;
+
+#if idx64
+ // allocate stack for shadow(win32)+parameters
+ EmitString( "48 81 EC" ); // sub rsp, 200
+ Emit4( SHADOW_BASE + PUSH_STACK + PARAM_STACK );
+
+ // save scratch registers
+ EmitString( "48 8D 54 24" ); // lea rdx, [rsp+SHADOW_BASE]
+ Emit1( SHADOW_BASE );
+ EmitString( "48 89 32" ); // mov [rdx+00], rsi
+ EmitString( "48 89 7A 08" ); // mov [rdx+08], rdi
+ EmitString( "4C 89 42 10" ); // mov [rdx+16], r8
+ EmitString( "4C 89 4A 18" ); // mov [rdx+24], r9
+
+ // ecx = &int64_params[0]
+ EmitString( "48 8D 4C 24" ); // lea rcx, [rsp+SHADOW_BASE+PUSH_STACK]
+ Emit1( SHADOW_BASE + PUSH_STACK );
+
+ // save syscallNum
+ EmitString( "48 89 01" ); // mov [rcx], rax
+
+ // vm->programStack = programStack - 4;
+ EmitString( "48 BA" ); // mov rdx, &vm->programStack
+ EmitPtr( &vm->programStack );
+ //EmitString( "8D 46 FC" ); // lea eax, [esi-4]
+ EmitString( "8D 46 F8" ); // lea eax, [esi-8]
+ EmitString( "89 02" ); // mov [rdx], eax
+ //EmitString( "89 32" ); // mov dword ptr [rdx], esi
+
+ // params = (vm->dataBase + programStack + 8);
+ EmitString( "48 8D 74 33 08" ); // lea rsi, [rbx+rsi+8]
+
+ // rcx = &int64_params[1]
+ EmitString( "48 83 C1 08" ); // add rcx, 8
+
+ // dest_params[1-15] = params[1-15];
+ EmitString( "31 D2" ); // xor edx, edx
+ // loop
+ EmitString( "48 63 04 96" ); // movsxd rax, dword [rsi+rdx*4]
+ EmitString( "48 89 04 D1" ); // mov qword ptr[rcx+rdx*8], rax
+ EmitString( "48 83 C2 01" ); // add rdx, 1
+ EmitString( "48 83 FA" ); // cmp rdx, 15
+ Emit1( (PARAM_STACK/8) - 1 );
+ EmitString( "7C EE" ); // jl -18
+
+#ifdef _WIN32
+ // rcx = &int64_params[0]
+ EmitString( "48 83 E9 08" ); // sub rcx, 8
+#else // linux/*BSD ABI
+ // rdi = &int64_params[0]
+ EmitString( "48 8D 79 F8" ); // lea rdi, [rcx-8]
+#endif
+
+ // currentVm->systemCall( param );
+ EmitString( "41 FF 14 24" ); // call qword [r12]
+
+ // restore registers
+ EmitString( "48 8D 54 24" ); // lea rdx, [rsp+SHADOW_BASE]
+ Emit1( SHADOW_BASE );
+ EmitString( "48 8B 32" ); // mov rsi, [rdx+00]
+ EmitString( "48 8B 7A 08" ); // mov rdi, [rdx+08]
+ EmitString( "4C 8B 42 10" ); // mov r8, [rdx+16]
+ EmitString( "4C 8B 4A 18" ); // mov r9, [rdx+24]
+
+ // we added the return value: *(opstack+1) = eax
+ EmitAddEDI4( vm ); // add edi, 4
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+
+ // return stack
+ EmitString( "48 81 C4" ); // add rsp, 200
+ Emit4( SHADOW_BASE + PUSH_STACK + PARAM_STACK );
+
+ EmitRexString( "8D 2C 33" ); // lea rbp, [rbx+rsi]
+
+ EmitString( "C3" ); // ret
+
+#else // i386
+
+ // params = (int *)((byte *)currentVM->dataBase + programStack + 4);
+ EmitString( "8D 4D 04" ); // lea ecx, [ebp+4]
+
+ // function prologue
+ EmitString( "55" ); // push ebp
+ EmitRexString( "89 E5" ); // mov ebp, esp
+ EmitRexString( "83 EC 04" ); // sub esp, 4
+ // align stack before call
+ EmitRexString( "83 E4 F0" ); // and esp, -16
+
+ // ABI note: esi/edi must not change during call!
+
+ // currentVM->programStack = programStack - 4;
+ EmitString( "8D 56 FC" ); // lea edx, [esi-4]
+ EmitString( "89 15" ); // mov [&vm->programStack], edx
+ EmitPtr( &vm->programStack );
+
+ // params[0] = syscallNum
+ EmitString( "89 01" ); // mov [ecx], eax
+
+ // cdecl - set params
+ EmitString( "89 0C 24" ); // mov [esp], ecx
+
+ // currentVm->systemCall( param );
+ EmitString( "FF 15" ); // call dword ptr [¤tVM->systemCall]
+ EmitPtr( &vm->systemCall );
+
+ // we added the return value: *(opstack+1) = eax
+#if 0
+ EmitAddEDI4( vm ); // add edi, 4
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov [edi], eax
+#else // break dependency from edi value?
+ EmitString( "89 47 04" ); // mov [edi+4], eax
+ EmitAddEDI4( vm ); // add edi, 4
+#endif
+
+ // function epilogue
+ EmitRexString( "89 EC" ); // mov esp, ebp
+ EmitString( "5D" ); // pop ebp
+ EmitString( "C3" ); // ret
+#endif
+}
+
+
+static void EmitFTOLFunc( vm_t *vm )
+{
+ EmitRexString( "B8" ); // mov eax, &fp_cw[0]
+ EmitPtr( &fp_cw[0] );
+ EmitString( "9B D9 38" ); // fnstcw word ptr [eax]
+ EmitString( "D9 68 04" ); // fldcw word ptr [eax+4]
+ EmitString( "DB 1F" ); // fistp dword ptr [edi]
+ EmitString( "D9 28" ); // fldcw word ptr [eax]
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitBCPYFunc( vm_t *vm )
+{
+ // FIXME: range check
+ EmitString( "56" ); // push esi
+ EmitString( "57" ); // push edi
+ EmitString( "8B 37" ); // mov esi,[edi]
+ EmitString( "8B 7F FC" ); // mov edi,[edi-4]
+ EmitString( "B8" ); // mov eax, datamask
+ Emit4( vm->dataMask );
+ EmitString( "21 C6" ); // and esi, eax
+ EmitString( "21 C7" ); // and edi, eax
+#if idx64
+ EmitString( "48 01 DE" ); // add rsi, rbx
+ EmitString( "48 01 DF" ); // add rdi, rbx
+#else
+ EmitString( "03 F3" ); // add esi, ebx
+ EmitString( "03 FB" ); // add edi, ebx
+#endif
+ EmitString( "F3 A5" ); // rep movsd
+ EmitString( "5F" ); // pop edi
+ EmitString( "5E" ); // pop esi
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitPSOFFunc( vm_t *vm )
+{
+ EmitRexString( "B8" ); // mov eax, badStackPtr
+ EmitPtr( &badStackPtr );
+ EmitString( "FF 10" ); // call [eax]
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitOSOFFunc( vm_t *vm )
+{
+ EmitRexString( "B8" ); // mov eax, badOptackPtr
+ EmitPtr( &badOpStackPtr );
+ EmitString( "FF 10" ); // call [eax]
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitBADJFunc( vm_t *vm )
+{
+ EmitRexString( "B8" ); // mov eax, badJumpPtr
+ EmitPtr( &badJumpPtr );
+ EmitString( "FF 10" ); // call [eax]
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitERRJFunc( vm_t *vm )
+{
+ EmitRexString( "B8" ); // mov eax, errJumpPtr
+ EmitPtr( &errJumpPtr );
+ EmitString( "FF 10" ); // call [eax]
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitDATAFunc( vm_t *vm )
+{
+ EmitRexString( "B8" ); // mov eax, badDataPtr
+ EmitPtr( &badDataPtr );
+ EmitString( "FF 10" ); // call [eax]
+ EmitString( "C3" ); // ret
+}
+
+
+static void EmitNCPYFunc( vm_t *vm )
+{
+ static int Lend, Lcopy, Lpadz, Lpop0, Lpop1; // jump labels
+ int n;
+
+ //EmitString( "8B 4D 10" ); // mov ecx, dword ptr [ebp+16] // counter
+ EmitString( "89 C1" ); // mov ecx, eax // get cached value from previous OP_ARG instruction
+ EmitString( "85 C9" ); // test ecx, ecx
+ EmitString( "74" ); // je +Lend
+ Emit1( Lend ); Lend = compiledOfs;
+ EmitString( "57" ); // push edi
+ EmitString( "8B 55 0C" ); // mov edx, dword ptr [ebp+12] // source
+ EmitString( "8B 7D 08" ); // mov edi, dword ptr [ebp+08] // destination
+ EmitRexString( "01 DA" ); // add edx, ebx // + vm->dataBase
+
+#if 0
+ if ( vm->forceDataMask )
+ {
+#ifdef idx64
+ EmitString( "44 21 CF" ); // and edi, r9d
+#else
+ EmitString( "81 E7" ); // and edi, vm->dataMask
+ Emit4( vm->dataMask );
+#endif
+ EmitRexString( "01 DF" ); // add edi, ebx // + vm->dataBase
+ }
+ else
+#endif
+ if ( (int)vm_rtChecks.value & 8 ) // security checks
+ {
+ EmitString( "89 F8" ); // mov eax, edi
+ EmitString( "09 C8" ); // or eax, ecx
+ EmitString( "3D" ); // cmp eax, vm->dataMask
+ Emit4( vm->dataMask );
+ EmitString( "0F 87" ); // ja +errorFunction
+ n = funcOffset[FUNC_DATA] - compiledOfs;
+ Emit4( n - 6 );
+ EmitString( "8D 04 0F" ); // lea eax, dword ptr [edi + ecx]
+ EmitRexString( "01 DF" ); // add edi, ebx // + vm->dataBase
+ EmitString( "3D" ); // cmp eax, vm->dataMask
+ Emit4( vm->dataMask );
+ EmitString( "0F 87" ); // ja +errorFunction
+ n = funcOffset[FUNC_DATA] - compiledOfs;
+ Emit4( n - 6 );
+ }
+ else
+ {
+ EmitRexString( "01 DF" ); // add edi, ebx // + vm->dataBase
+ }
+
+Lcopy = compiledOfs - Lcopy;
+ EmitString( "8A 02" ); // mov al, dword ptr [edx]
+ EmitString( "88 07" ); // mov dword ptr [edi], al
+ EmitRexString( "83 C2 01" );// add edx, 1
+ EmitRexString( "83 C7 01" );// add edi, 1
+ EmitRexString( "84 C0" ); // test al, al
+ EmitString( "74" ); // je +Lpadz
+ Emit1( Lpadz ); Lpadz = compiledOfs;
+ EmitString( "83 E9 01" ); // sub ecx, 1
+ EmitString( "75" ); // jne +Lcopy
+ Emit1( Lcopy ); Lcopy = compiledOfs;
+ EmitString( "5F" ); // pop edi
+ EmitString( "C3" ); // ret
+Lpadz = compiledOfs - Lpadz;
+ EmitString( "85 C9" ); // test ecx, ecx
+ EmitString( "74" ); // je +Lpop0
+ Emit1( Lpop0 ); Lpop0 = compiledOfs;
+#if 0
+ // zero only one char
+ EmitString( "31 C0" ); // xor eax, eax
+ EmitString( "88 07" ); // mov dword ptr [edi], al
+#else
+ // zero all remaining chars
+ EmitString( "83 E9 01" ); // sub ecx, 1
+ EmitString( "74" ); // je +Lpop1
+ Emit1( Lpop1 ); Lpop1 = compiledOfs;
+ EmitString( "89 CA" ); // mov edx, ecx
+ EmitString( "C1 E9 02" ); // shr ecx, 2
+ EmitString( "31 C0" ); // xor eax, eax
+ EmitString( "83 E2 03" ); // and edx, 3
+ EmitString( "F3 AB" ); // rep stosd
+ EmitString( "89 D1" ); // mov ecx, edx
+ //EmitString( "83 E1 03" ); // and ecx, 3
+ EmitString( "F3 AA" ); // rep stosb
+Lpop1 = compiledOfs - Lpop1;
+#endif
+Lpop0 = compiledOfs - Lpop0;
+ EmitString( "5F" ); // pop edi
+Lend = compiledOfs - Lend;
+ EmitString( "C3" ); // ret
+}
+
+
+/*
+=================
+EmitFCalcEDI
+=================
+*/
+static void EmitFCalcEDI( int op )
+{
+ switch ( op )
+ {
+ case OP_ADDF: EmitString( "D8 07" ); break; // fadd dword ptr [edi]
+ case OP_SUBF: EmitString( "D8 27" ); break; // fsub dword ptr [edi]
+ case OP_MULF: EmitString( "D8 0F" ); break; // fmul dword ptr [edi]
+ case OP_DIVF: EmitString( "D8 37" ); break; // fdiv dword ptr [edi]
+ default: SV_Error( "bad float op" ); break;
+ };
+}
+
+
+/*
+=================
+EmitFCalcPop
+=================
+*/
+static void EmitFCalcPop( int op )
+{
+ switch ( op )
+ {
+ case OP_ADDF: EmitString( "DE C1" ); break; // faddp
+ case OP_SUBF: EmitString( "DE E9" ); break; // fsubp
+ case OP_MULF: EmitString( "DE C9" ); break; // fmulp
+ case OP_DIVF: EmitString( "DE F9" ); break; // fdivp
+ default: SV_Error( "bad opcode %02x", op ); break;
+ };
+}
+
+
+/*
+=================
+CommuteFloatOp
+=================
+*/
+static int CommuteFloatOp( int op )
+{
+ switch ( op ) {
+ case OP_LEF: return OP_GEF;
+ case OP_LTF: return OP_GTF;
+ case OP_GEF: return OP_LEF;
+ case OP_GTF: return OP_LTF;
+ default: return op;
+ }
+}
+
+
+/*
+=================
+ConstOptimize
+=================
+*/
+static qbool ConstOptimize( vm_t *vm )
+{
+ int v;
+ int op1;
+ qbool sign_extend;
+
+ op1 = ni->op;
+
+ switch ( op1 ) {
+
+ case OP_LOAD4:
+ EmitAddEDI4( vm );
+ if ( ISS8( ci->value ) ) {
+ EmitString( "8B 43" ); // mov eax, dword ptr [ebx+0x7F]
+ Emit1( ci->value );
+ } else {
+ EmitString( "8B 83" ); // mov eax, dword ptr [ebx+0x12345678]
+ Emit4( ci->value );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ ip += 1;
+ return true;
+
+ case OP_LOAD2:
+ EmitAddEDI4( vm );
+ sign_extend = ( (ci+2)->op == OP_SEX16 );
+ if ( ISS8( ci->value ) ) {
+ if ( sign_extend ) {
+ EmitString( "0F BF 43" ); // movsx eax, word ptr [ebx+0x7F]
+ ip += 1;
+ } else {
+ EmitString( "0F B7 43" ); // movzx eax, word ptr [ebx+0x7F]
+ }
+ Emit1( ci->value );
+ } else {
+ if ( sign_extend ) {
+ EmitString( "0F BF 83" ); // movsx eax, word ptr [ebx+0x12345678]
+ ip += 1;
+ } else {
+ EmitString( "0F B7 83" ); // movzx eax, word ptr [ebx+0x12345678]
+ }
+ Emit4( ci->value );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ ip += 1;
+ return true;
+
+ case OP_LOAD1:
+ EmitAddEDI4( vm );
+ sign_extend = ( (ci+2)->op == OP_SEX8 );
+ if ( ISS8( ci->value ) ) {
+ if ( sign_extend ) {
+ EmitString( "0F BE 43" ); // movsx eax, byte ptr [ebx+0x7F]
+ ip += 1;
+ } else {
+ EmitString( "0F B6 43" ); // movzx eax, byte ptr [ebx+0x7F]
+ }
+ Emit1( ci->value );
+ } else {
+ if ( sign_extend ) {
+ EmitString( "0F BE 83" ); // movsx eax, word ptr [ebx+0x12345678]
+ ip += 1;
+ } else {
+ EmitString( "0F B6 83" ); // movzx eax, word ptr [ebx+0x12345678]
+ }
+ Emit4( ci->value );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ ip += 1;
+ return true;
+
+ case OP_STORE4:
+ EmitMovEAXEDI( vm );
+ if ( !ci->value ) {
+ EmitString( "31 C9" ); // xor ecx, ecx
+ } else {
+ EmitString( "B9" ); // mov ecx, 0x12345678
+ Emit4( ci->value );
+ }
+ EmitCheckReg( vm, REG_EAX, 4 );
+ EmitString( "89 0C 03" ); // mov dword ptr [ebx + eax], ecx
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ ip += 1;
+ return true;
+
+ case OP_STORE2:
+ EmitMovEAXEDI( vm );
+ if ( !ci->value ) {
+ EmitString( "31 C9" ); // xor ecx, ecx
+ } else {
+ EmitString( "B9" ); // mov ecx, 0x12345678
+ Emit4( ci->value );
+ }
+ EmitCheckReg( vm, REG_EAX, 2 );
+ EmitString( "66 89 0C 03" ); // mov word ptr [ebx + eax], cx
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ ip += 1;
+ return true;
+
+ case OP_STORE1:
+ EmitMovEAXEDI( vm );
+ if ( !ci->value ) {
+ EmitString( "31 C9" ); // xor ecx, ecx
+ } else {
+ EmitString( "B9" ); // mov ecx, 0x12345678
+ Emit4( ci->value );
+ }
+ EmitCheckReg( vm, REG_EAX, 1 );
+ EmitString( "88 0C 03" ); // mov byte ptr [ebx + eax], cl
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ ip += 1;
+ return true;
+
+ case OP_ADD:
+ v = ci->value;
+ EmitMovEAXEDI( vm );
+ if ( ISS8( v ) ) {
+ EmitString( "83 C0" ); // add eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "05" ); // add eax, 0x12345678
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1; // OP_ADD
+ return true;
+
+ case OP_SUB:
+ v = ci->value;
+ EmitMovEAXEDI( vm );
+ if ( ISS8( v ) ) {
+ EmitString( "83 E8" ); // sub eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "2D" ); // sub eax, 0x12345678
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_MULI:
+ v = ci->value;
+ EmitMovEAXEDI( vm );
+ if ( ISS8( v ) ) {
+ EmitString( "6B C0" ); // imul eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "69 C0" ); // imul eax, 0x12345678
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_MULF:
+ case OP_DIVF:
+ case OP_ADDF:
+ case OP_SUBF:
+ v = ci->value;
+ EmitLoadFloatEDI( vm );
+ if ( HasSSEFP() ) {
+ EmitString( "C7 45 00" ); // mov dword ptr [ebp], v
+ Emit4( v );
+ EmitString( "F3 0F 10 4D 00" ); // movss xmm1, dword ptr [ebp]
+ switch( op1 ) {
+ case OP_ADDF: EmitString( "0F 58 C1" ); break; // addps xmm0, xmm1
+ case OP_SUBF: EmitString( "0F 5C C1" ); break; // subps xmm0, xmm1
+ case OP_MULF: EmitString( "0F 59 C1" ); break; // mulps xmm0, xmm1
+ case OP_DIVF: EmitString( "0F 5E C1" ); break; // divps xmm0, xmm1
+ }
+ } else {
+ EmitString( "C7 45 00" ); // mov dword ptr [ebp], 0x12345678
+ Emit4( v );
+ EmitString( "D9 45 00" ); // fld dword ptr [ebp]
+ EmitFCalcPop( op1 ); // fmulp/fdivp/faddp/fsubp
+ }
+ EmitCommand( LAST_COMMAND_STORE_FLOAT_EDI );
+ ip +=1;
+ return true;
+
+ case OP_LSH:
+ v = ci->value;
+ if ( v < 0 || v > 31 )
+ break;
+ EmitMovEAXEDI( vm );
+ EmitString( "C1 E0" ); // shl eax, 0x12
+ Emit1( v );
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1; // OP_LSH
+ return true;
+
+ case OP_RSHI:
+ v = ci->value;
+ if ( v < 0 || v > 31 )
+ break;
+ EmitMovEAXEDI( vm );
+ EmitString( "C1 F8" ); // sar eax, 0x12
+ Emit1( v );
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_RSHU:
+ v = ci->value;
+ if ( v < 0 || v > 31 )
+ break;
+ EmitMovEAXEDI( vm );
+ EmitString( "C1 E8" ); // shr eax, 0x12
+ Emit1( v );
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_BAND:
+ v = ci->value;
+ EmitMovEAXEDI( vm );
+ if ( ISU8( v ) ) {
+ EmitString( "83 E0" ); // and eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "25" ); // and eax, 0x12345678
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_BOR:
+ v = ci->value;
+ EmitMovEAXEDI( vm );
+ if ( ISU8( v ) ) {
+ EmitString( "83 C8" ); // or eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "0D" ); // or eax, 0x12345678
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_BXOR:
+ v = ci->value;
+ EmitMovEAXEDI( vm );
+ if ( ISU8( v ) ) {
+ EmitString( "83 F0" ); // xor eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "35" ); // xor eax, 0x12345678
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );
+ ip += 1;
+ return true;
+
+ case OP_JUMP:
+ EmitJump( vm, ni, ni->op, ci->value );
+ ip += 1; // OP_JUMP
+ return true;
+
+ case OP_CALL:
+#ifdef VM_LOG_SYSCALLS
+ // [dataBase + programStack + 0] = ip;
+ EmitString( "C7 45 00" ); // mov dword ptr [ebp], 0x12345678
+ Emit4( ip );
+#endif
+ v = ci->value;
+ // try to inline some syscalls
+ if ( HasSSEFP() && v == ~g_sqrt ) {
+ // inline SSE implementation of sin/cos is too problematic...
+ EmitString( "F3 0F 10 45 08" ); // movss xmm0, dword ptr [ebp + 8]
+ EmitAddEDI4( vm );
+ EmitString( "F3 0F 51 C0" ); // sqrtss xmm0, xmm0
+ EmitCommand( LAST_COMMAND_STORE_FLOAT_EDI );
+ ip += 1;
+ return true;
+ } else if ( v == ~g_sin || v == ~g_cos || v == ~g_sqrt ) {
+ EmitString( "D9 45 08" ); // fld dword ptr [ebp + 8]
+ switch ( v ) {
+ case ~g_sqrt: EmitString( "D9 FA" ); break; // fsqrt
+ case ~g_sin: EmitString( "D9 FE" ); break; // fsin
+ case ~g_cos: EmitString( "D9 FF" ); break; // fcos
+ }
+ EmitAddEDI4( vm ); // add edi, 4
+ EmitCommand( LAST_COMMAND_STORE_FLOAT_EDI_X87 );// fstp dword ptr[edi]
+ ip += 1;
+ return true;
+ }
+
+ if ( v < 0 ) // syscall
+ {
+ EmitString( "B8" ); // mov eax, 0x12345678
+ Emit4( ~v );
+ EmitCallOffset( FUNC_SYSC );
+ LastCommand = LAST_COMMAND_MOV_EAX_EDI_CALL;
+ ip += 1; // OP_CALL
+ return true;
+ }
+ EmitString( "55" ); // push ebp
+ EmitString( "56" ); // push rsi
+ EmitString( "53" ); // push rbx
+ EmitCallAddr( vm, v ); // call +addr
+ EmitString( "5B" ); // pop rbx
+ EmitString( "5E" ); // pop rsi
+ EmitString( "5D" ); // pop ebp
+ ip += 1; // OP_CALL
+ return true;
+
+ case OP_EQF:
+ case OP_NEF:
+ case OP_LTF:
+ case OP_LEF:
+ case OP_GTF:
+ case OP_GEF:
+ if ( !HasFCOM() )
+ return false;
+ EmitLoadFloatEDI( vm );
+ EmitCommand( LAST_COMMAND_SUB_DI_4 );
+ v = ci->value;
+ if ( HasSSEFP() ) {
+ if ( v == 0 ) {
+ EmitString( "0F 57 C9" ); // xorps xmm1, xmm1
+ } else {
+ EmitString( "C7 45 00" ); // mov dword ptr [ebp], v
+ Emit4( v );
+ EmitString( "F3 0F 10 4D 00" ); // movss xmm1, dword ptr [ebp]
+ }
+ EmitString( "0F 2F C1" ); // comiss xmm0, xmm1
+ EmitJump( vm, ni, ni->op, ni->value );
+ } else {
+ if ( v == 0 ) {
+ EmitString( "D9 EE" ); // fldz
+ } else {
+ EmitString( "C7 45 00" ); // mov [ebp], 0x12345678
+ Emit4( v );
+ EmitString( "D9 45 00" ); // fld dword ptr [ebp]
+ }
+ EmitString( "DF E9" ); // fucomip
+ EmitString( "DD D8" ); // fstp st(0)
+ EmitJump( vm, ni, CommuteFloatOp( ni->op ), ni->value );
+ }
+ ip +=1;
+ return true;
+
+ case OP_EQ:
+ case OP_NE:
+ case OP_GEI:
+ case OP_GTI:
+ case OP_GTU:
+ case OP_GEU:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_LEI:
+ case OP_LTI:
+ EmitMovEAXEDI( vm );
+ EmitCommand( LAST_COMMAND_SUB_DI_4 );
+ v = ci->value;
+ if ( v == 0 && ( op1 == OP_EQ || op1 == OP_NE ) ) {
+ EmitString( "85 C0" ); // test eax, eax
+ } else {
+ if ( ISS8( v ) ) {
+ EmitString( "83 F8" ); // cmp eax, 0x7F
+ Emit1( v );
+ } else {
+ EmitString( "3D" ); // cmp eax, 0xFFFFFFFF
+ Emit4( v );
+ }
+ }
+ EmitJump( vm, ni, ni->op, ni->value );
+ ip += 1;
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/*
+=================
+VM_FindMOps
+
+Search for known macro-op sequences
+=================
+*/
+static void VM_FindMOps( instruction_t *buf, int instructionCount )
+{
+ int n, v, op0;
+ instruction_t *i;
+
+ i = buf;
+ n = 0;
+
+ while ( n < instructionCount )
+ {
+ op0 = i->op;
+ if ( op0 == OP_LOCAL ) {
+ // OP_LOCAL + OP_LOCAL + OP_LOAD4 + OP_CONST + OP_XXX + OP_STORE4
+ if ( (i+1)->op == OP_LOCAL && i->value == (i+1)->value && (i+2)->op == OP_LOAD4 && (i+3)->op == OP_CONST && (i+4)->op != OP_UNDEF && (i+5)->op == OP_STORE4 ) {
+ v = (i+4)->op;
+ if ( v == OP_ADD ) {
+ i->op = MOP_ADD4;
+ i += 6; n += 6;
+ continue;
+ }
+ if ( v == OP_SUB ) {
+ i->op = MOP_SUB4;
+ i += 6; n += 6;
+ continue;
+ }
+ if ( v == OP_BAND ) {
+ i->op = MOP_BAND4;
+ i += 6; n += 6;
+ continue;
+ }
+ if ( v == OP_BOR ) {
+ i->op = MOP_BOR4;
+ i += 6; n += 6;
+ continue;
+ }
+ }
+
+ // skip useless sequences
+ if ( (i+1)->op == OP_LOCAL && (i+0)->value == (i+1)->value && (i+2)->op == OP_LOAD4 && (i+3)->op == OP_STORE4 ) {
+ i->op = MOP_IGNORE4;
+ i += 4; n += 4;
+ continue;
+ }
+ } else if ( op0 == OP_CONST && (i+1)->op == OP_CALL && (i+2)->op == OP_POP && i >= buf+6 && (i-1)->op == OP_ARG && !i->jused ) {
+ // some void function( arg1, arg2, arg3 )
+ if ( i->value == ~g_strlcpy ) {
+ i->op = MOP_NCPY;
+ i += 3; n += 3;
+ continue;
+ }
+ }
+
+ i++;
+ n++;
+ }
+}
+
+
+/*
+=================
+EmitMOPs
+=================
+*/
+static qbool EmitMOPs( vm_t *vm, int op )
+{
+ int v, n;
+ switch ( op )
+ {
+ //[local] += CONST
+ case MOP_ADD4:
+ n = inst[ip+2].value;
+ v = ci->value; // local variable address
+ if ( ISS8( n ) ) {
+ if ( ISS8( v ) ) {
+ EmitString( "83 45" ); // add dword ptr [ebp + 0x7F], 0x12
+ Emit1( v );
+ Emit1( n );
+ } else {
+ EmitString( "83 85" ); // add dword ptr [ebp + 0x12345678], 0x12
+ Emit4( v );
+ Emit1( n );
+ }
+ } else {
+ if ( ISS8( v ) ) {
+ EmitString( "81 45" ); // add dword ptr [ebp + 0x7F], 0x12345678
+ Emit1( v );
+ Emit4( n );
+ } else {
+ EmitString( "81 85" ); // add dword ptr [ebp + 0x12345678], 0x12345678
+ Emit4( v );
+ Emit4( n );
+ }
+ }
+ ip += 5;
+ return true;
+
+ //[local] -= CONST
+ case MOP_SUB4:
+ n = inst[ip+2].value;
+ v = ci->value; // local variable address
+ if ( ISS8( n ) ) {
+ if ( ISS8( v ) ) {
+ EmitString( "83 6D" ); // sub dword ptr [ebp + 0x7F], 0x12
+ Emit1( v );
+ Emit1( n );
+ } else {
+ EmitString( "83 AD" ); // sub dword ptr [ebp + 0x12345678], 0x12
+ Emit4( v );
+ Emit1( n );
+ }
+ } else {
+ if ( ISS8( v ) ) {
+ EmitString( "81 6D" ); // sub dword ptr [ebp + 0x7F], 0x12345678
+ Emit1( v );
+ Emit4( n );
+ } else {
+ EmitString( "81 AD" ); // sub dword ptr[esi+0x12345678], 0x12345678
+ Emit4( v );
+ Emit4( n );
+ }
+ }
+ ip += 5;
+ return true;
+
+ //[local] &= CONST
+ case MOP_BAND4:
+ n = inst[ip+2].value;
+ v = ci->value; // local variable address
+ if ( ISS8( n ) ) {
+ if ( ISS8( v ) ) {
+ EmitString( "83 65" ); // and dword ptr [ebp + 0x7F], 0x12
+ Emit1( v );
+ Emit1( n );
+ } else {
+ EmitString( "83 A5" ); // and dword ptr [ebp + 0x12345678], 0x12
+ Emit4( v );
+ Emit1( n );
+ }
+ } else {
+ if ( ISS8( v ) ) {
+ EmitString( "81 65" ); // and dword ptr [ebp + 0x7F], 0x12345678
+ Emit1( v );
+ Emit4( n );
+ } else {
+ EmitString( "81 A5" ); // and dword ptr [ebp + 0x12345678], 0x12345678
+ Emit4( v );
+ Emit4( n );
+ }
+ }
+ ip += 5;
+ return true;
+
+ //[local] |= CONST
+ case MOP_BOR4:
+ n = inst[ip+2].value;
+ v = ci->value; // local variable address
+ if ( ISS8( n ) ) {
+ if ( ISS8( v ) ) {
+ EmitString( "83 4D" ); // or dword ptr [ebp + 0x7F], 0x12
+ Emit1( v );
+ Emit1( n );
+ } else {
+ EmitString( "83 8D" ); // or dword ptr [ebp + 0x12345678], 0x12
+ Emit4( v );
+ Emit1( n );
+ }
+ } else {
+ if ( ISS8( v ) ) {
+ EmitString( "81 4D" ); // or dword ptr [ebp + 0x7F], 0x12345678
+ Emit1( v );
+ Emit4( n );
+ } else {
+ EmitString( "81 8D" ); // or dword ptr [ebp + 0x12345678], 0x12345678
+ Emit4( v );
+ Emit4( n );
+ }
+ }
+ ip += 5;
+ return true;
+
+ // [local] = [local]
+ case MOP_IGNORE4:
+ ip += 3;
+ return true;
+
+ // const + call + pop
+ case MOP_NCPY:
+ EmitCallOffset( FUNC_NCPY );
+ ip += 2;
+ return true;
+
+ };
+ return false;
+}
+
+/*
+=================
+VM_Compile
+=================
+*/
+qbool VM_Compile( vm_t *vm, vmHeader_t *header ) {
+ const char *errMsg;
+ int instructionCount;
+ int proc_base;
+ int proc_len;
+ int i, n, v;
+ qbool wantres;
+
+ Sys_GetProcessorId(NULL);
+ inst = (instruction_t*)Q_malloc( (header->instructionCount + 8 ) * sizeof( instruction_t ) );
+ instructionOffsets = (int*)Q_malloc( header->instructionCount * sizeof( int ) );
+
+ errMsg = VM_LoadInstructions( (byte *) header + header->codeOffset, header->codeLength, header->instructionCount, inst );
+ if ( !errMsg ) {
+ errMsg = VM_CheckInstructions( inst, vm->instructionCount, vm->jumpTableTargets, vm->numJumpTableTargets, vm->exactDataLength );
+ }
+ if ( errMsg ) {
+ VM_FreeBuffers();
+ Con_Printf( "VM_CompileX86 error: %s\n", errMsg );
+ return false;
+ }
+
+ //VM_ReplaceInstructions( vm, inst );
+
+ VM_FindMOps( inst, vm->instructionCount );
+
+ code = NULL; // we will allocate memory later, after last defined pass
+ instructionPointers = NULL;
+
+ memset( funcOffset, 0, sizeof( funcOffset ) );
+
+ instructionCount = header->instructionCount;
+
+ for( pass = 0; pass < NUM_PASSES; pass++ )
+ {
+__compile:
+ pop1 = OP_UNDEF;
+ lastConst = 0;
+
+ // translate all instructions
+ ip = 0;
+ compiledOfs = 0;
+ LastCommand = LAST_COMMAND_NONE;
+
+ proc_base = -1;
+ proc_len = 0;
+
+#if idx64
+ EmitString( "53" ); // push rbx
+ EmitString( "56" ); // push rsi
+ EmitString( "57" ); // push rdi
+ EmitString( "55" ); // push rbp
+ EmitString( "41 54" ); // push r12
+ EmitString( "41 55" ); // push r13
+ EmitString( "41 56" ); // push r14
+ EmitString( "41 57" ); // push r15
+
+ EmitRexString( "BB" ); // mov rbx, vm->dataBase
+ EmitPtr( vm->dataBase );
+
+ EmitString( "49 B8" ); // mov r8, vm->instructionPointers
+ EmitPtr( instructionPointers );
+
+ EmitString( "49 C7 C1" ); // mov r9, vm->dataMask
+ Emit4( vm->dataMask );
+
+ EmitString( "49 BC" ); // mov r12, vm->systemCall
+ EmitPtr( &vm->systemCall );
+
+ EmitString( "49 C7 C5" ); // mov r13, vm->stackBottom
+ Emit4( vm->stackBottom );
+
+ EmitRexString( "B8" ); // mov rax, &vm->programStack
+ EmitPtr( &vm->programStack );
+ EmitString( "8B 30" ); // mov esi, [rax]
+
+ EmitRexString( "B8" ); // mov rax, &vm->opStack
+ EmitPtr( &vm->opStack );
+ EmitRexString( "8B 38" ); // mov rdi, [rax]
+
+ EmitRexString( "B8" ); // mov rax, &vm->opStackTop
+ EmitPtr( &vm->opStackTop );
+ EmitString( "4C 8B 30" ); // mov r14, [rax]
+
+#else
+ EmitString( "60" ); // pushad
+
+ EmitRexString( "BB" ); // mov ebx, vm->dataBase
+ EmitPtr( vm->dataBase );
+
+ EmitString( "8B 35" ); // mov esi, [vm->programStack]
+ EmitPtr( &vm->programStack );
+
+ EmitString( "8B 3D" ); // mov edi, [vm->opStack]
+ EmitPtr( &vm->opStack );
+#endif
+
+ EmitCallOffset( FUNC_ENTR );
+
+#if idx64
+
+#ifdef DEBUG_VM
+ EmitRexString( "B8" ); // mov rax, &vm->programStack
+ EmitPtr( &vm->programStack );
+ EmitString( "89 30" ); // mov [rax], esi
+#endif
+
+ EmitRexString( "B8" ); // mov rax, &vm->opStack
+ EmitPtr( &vm->opStack );
+ EmitRexString( "89 38" ); // mov [rax], rdi
+
+ EmitString( "41 5F" ); // pop r15
+ EmitString( "41 5E" ); // pop r14
+ EmitString( "41 5D" ); // pop r13
+ EmitString( "41 5C" ); // pop r12
+ EmitString( "5D" ); // pop rbp
+ EmitString( "5F" ); // pop rdi
+ EmitString( "5E" ); // pop rsi
+ EmitString( "5B" ); // pop rbx
+#else
+
+#ifdef DEBUG_VM
+ EmitString( "89 35" ); // [vm->programStack], esi
+ EmitPtr( &vm->programStack );
+#endif
+
+ EmitString( "89 3D" ); // [vm->opStack], edi
+ EmitPtr( &vm->opStack );
+
+ EmitString( "61" ); // popad
+#endif
+
+ EmitString( "C3" ); // ret
+
+ EmitAlign( 4 );
+
+ // main function entry offset
+ funcOffset[FUNC_ENTR] = compiledOfs;
+
+ while ( ip < instructionCount )
+ {
+ instructionOffsets[ ip ] = compiledOfs;
+
+ ci = &inst[ ip ];
+ ni = &inst[ ip + 1 ];
+ ip++;
+
+ if ( ci->jused ) {
+ LastCommand = LAST_COMMAND_NONE;
+ pop1 = OP_UNDEF;
+ }
+
+ switch ( ci->op ) {
+
+ case OP_UNDEF:
+ case OP_IGNORE:
+ break;
+
+ case OP_BREAK:
+ EmitString( "CC" ); // int 3
+ break;
+
+ case OP_ENTER:
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "83 EE" ); // sub esi, 0x12
+ Emit1( v );
+ } else {
+ EmitString( "81 EE" ); // sub esi, 0x12345678
+ Emit4( v );
+ }
+
+ // locate endproc
+ for ( n = -1, i = ip + 1; i < instructionCount; i++ ) {
+ if ( inst[ i ].op == OP_PUSH && inst[ i + 1 ].op == OP_LEAVE ) {
+ n = i;
+ break;
+ }
+ }
+
+ // should never happen because equal check in VM_LoadInstructions() but anyway
+ if ( n == -1 ) {
+ VM_FreeBuffers();
+ Con_Printf( "VM_CompileX86 error: %s\n", "missing proc end" );
+ return false;
+ }
+
+ proc_base = ip + 1;
+ proc_len = n - proc_base + 1 ;
+
+ // programStack overflow check
+ if ( (int)vm_rtChecks.value & 1 ) {
+#if idx64
+ EmitString( "4C 39 EE" ); // cmp rsi, r13
+#else
+ EmitString( "81 FE" ); // cmp esi, vm->stackBottom
+ Emit4( vm->stackBottom );
+#endif
+ EmitString( "0F 82" ); // jb +funcOffset[FUNC_PSOF]
+ n = funcOffset[FUNC_PSOF] - compiledOfs;
+ Emit4( n - 6 );
+ }
+
+ // opStack overflow check
+ if ( (int)vm_rtChecks.value & 2 ) {
+ if ( ISU8( ci->opStack ) ) {
+ EmitRexString( "8D 47" ); // lea eax, [edi+0x7F]
+ Emit1( ci->opStack );
+ } else {
+ EmitRexString( "8D 87" ); // lea eax, [edi+0x12345678]
+ Emit4( ci->opStack );
+ }
+#if idx64
+ EmitString( "4C 39 F0" ); // cmp rax, r14
+#else
+ EmitString( "3B 05" ); // cmp eax, [&vm->opStackTop]
+ EmitPtr( &vm->opStackTop );
+#endif
+ EmitString( "0F 87" ); // ja +funcOffset[FUNC_OSOF]
+ n = funcOffset[FUNC_OSOF] - compiledOfs;
+ Emit4( n - 6 );
+ }
+
+ EmitRexString( "8D 2C 33" ); // lea ebp, [ebx+esi]
+ break;
+
+ case OP_CONST:
+
+ // we can safely perform optimizations only in case if
+ // we are 100% sure that next instruction is not a jump label
+ if ( !ni->jused && ConstOptimize( vm ) )
+ break;
+
+ EmitAddEDI4( vm ); // add edi, 4
+ EmitString( "C7 07" ); // mov dword ptr [edi], 0x12345678
+ lastConst = ci->value;
+ Emit4( lastConst );
+ LastCommand = LAST_COMMAND_MOV_EDI_CONST;
+ break;
+
+ case OP_LOCAL:
+ // optimization: merge OP_LOCAL + OP_LOAD4
+ if ( ni->op == OP_LOAD4 ) {
+ EmitAddEDI4( vm ); // add edi, 4
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "8B 45" ); // mov eax, dword ptr [ebp + 0x7F]
+ Emit1( v );
+ } else {
+ EmitString( "8B 85" ); // mov eax, dword ptr [ebp + 0x12345678]
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ ip++;
+ break;
+ }
+
+ // optimization: merge OP_LOCAL + OP_LOAD2
+ if ( ni->op == OP_LOAD2 ) {
+ EmitAddEDI4( vm ); // add edi, 4
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "0F B7 45" ); // movzx eax, word ptr [ebp + 0x7F]
+ Emit1( v );
+ } else {
+ EmitString( "0F B7 85" ); // movzx eax, word ptr [ebp + 0x12345678]
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ ip++;
+ break;
+ }
+
+ // optimization: merge OP_LOCAL + OP_LOAD1
+ if ( ni->op == OP_LOAD1 ) {
+ EmitAddEDI4( vm ); // add edi, 4
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "0F B6 45" ); // movzx eax, byte ptr [ebp + 0x7F]
+ Emit1( v );
+ } else {
+ EmitString( "0F B6 85" ); // movzx eax, byte ptr [ebp + 0x12345678]
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ ip++;
+ break;
+ }
+
+ // TODO: i = j + k;
+ // TODO: i = j - k;
+
+ EmitAddEDI4( vm ); // add edi, 4
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "8D 46" ); // lea eax, [esi + 0x7F]
+ Emit1( v );
+ } else {
+ EmitString( "8D 86" ); // lea eax, [esi + 0x12345678]
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+
+ case OP_ARG:
+ if ( LastCommand == LAST_COMMAND_STORE_FLOAT_EDI_SSE ) {
+ REWIND(4);
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "F3 0F 11 45" ); // movss dword ptr [ebp + 0x7F], xmm0
+ Emit1( v );
+ } else {
+ EmitString( "F3 0F 11 85" ); // movss dword ptr [ebp + 0x12345678], xmm0
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+ }
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ if ( (ci+1)->op == MOP_NCPY && !(ci+1)->jused ) {
+ // we will read counter from eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+ }
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "89 45" ); // mov dword ptr [ebp + 0x7F], eax
+ Emit1( v );
+ } else {
+ EmitString( "89 85" ); // mov dword ptr [ebp + 0x12345678], eax
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_CALL:
+#ifdef VM_LOG_SYSCALLS
+ // [dataBase + programStack + 0] = ip-1;
+ EmitString( "C7 45 00" ); // mov dword ptr [ebp], 0x12345678
+ Emit4( ip-1 );
+#endif
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitCallOffset( FUNC_CALL ); // call +FUNC_CALL
+ break;
+
+ case OP_PUSH:
+ EmitAddEDI4( vm ); // add edi, 4
+ break;
+
+ case OP_POP:
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_LEAVE:
+#ifdef DEBUG_VM
+ v = ci->value;
+ if ( ISU8( v ) ) {
+ EmitString( "83 C6" ); // add esi, 0x12
+ Emit1( v );
+ } else {
+ EmitString( "81 C6" ); // add esi, 0x12345678
+ Emit4( v );
+ }
+#endif
+ EmitString( "C3" ); // ret
+ break;
+
+ case OP_LOAD4:
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) {
+ REWIND( 2 );
+ EmitCheckReg( vm, REG_EAX, 4 ); // range check eax
+ EmitString( "8B 04 03" ); // mov eax, dword ptr [ebx + eax]
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+ }
+ EmitMovECXEDI( vm ); // mov ecx, dword ptr [edi]
+ EmitCheckReg( vm, REG_ECX, 4 ); // range check ecx
+ EmitString( "8B 04 0B" ); // mov eax, dword ptr [ebx + ecx]
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ break;
+
+ case OP_LOAD2:
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) {
+ REWIND( 2 );
+ EmitCheckReg( vm, REG_EAX, 2 ); // range check eax
+ if ( ni->op == OP_SEX16 ) {
+ EmitString( "0F BF 04 03" ); // movsx eax, word ptr [ebx + eax]
+ ip++;
+ } else {
+ EmitString( "0F B7 04 03" ); // movzx eax, word ptr [ebx + eax]
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+ }
+ EmitMovECXEDI( vm ); // mov ecx, dword ptr [edi]
+ EmitCheckReg( vm, REG_ECX, 2 ); // range check ecx
+ if ( ni->op == OP_SEX16 ) {
+ EmitString( "0F BF 04 0B" ); // movsx eax, word ptr [ebx + ecx]
+ ip++;
+ } else {
+ EmitString( "0F B7 04 0B" ); // movzx eax, word ptr [ebx + ecx]
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ break;
+
+ case OP_LOAD1:
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) {
+ REWIND( 2 );
+ EmitCheckReg( vm, REG_EAX, 1 ); // range check eax
+ if ( ni->op == OP_SEX8 ) {
+ EmitString( "0F BE 04 03" ); // movsx eax, byte ptr [ebx + eax]
+ ip++;
+ } else {
+ EmitString( "0F B6 04 03" ); // movzx eax, byte ptr [ebx + eax]
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+ }
+ EmitMovECXEDI( vm ); // mov ecx, dword ptr [edi]
+ EmitCheckReg( vm, REG_ECX, 1 ); // range check ecx
+ if ( ni->op == OP_SEX8 ) {
+ EmitString( "0F BE 04 0B" ); // movsx eax, byte ptr [ebx + ecx]
+ ip++;
+ } else {
+ EmitString( "0F B6 04 0B" ); // movzx eax, byte ptr [ebx + ecx]
+ }
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX ); // mov dword ptr [edi], eax
+ break;
+
+ case OP_STORE4:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "8B 4F FC" ); // mov ecx, dword ptr [edi-4]
+ EmitCheckReg( vm, REG_ECX, 4 ); // range check
+ EmitString( "89 04 0B" ); // mov dword ptr [ebx + ecx], eax
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ break;
+
+ case OP_STORE2:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "8B 4F FC" ); // mov ecx, dword ptr [edi-4]
+ EmitCheckReg( vm, REG_ECX, 2 ); // range check
+ EmitString( "66 89 04 0B" ); // mov word ptr [ebx + ecx], ax
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ break;
+
+ case OP_STORE1:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "8B 4F FC" ); // mov ecx, dword ptr [edi-4]
+ EmitCheckReg( vm, REG_ECX, 1 ); // range check
+ EmitString( "88 04 0B" ); // mov byte ptr [ebx + ecx], al
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ break;
+
+ case OP_EQ:
+ case OP_NE:
+ case OP_LTI:
+ case OP_LEI:
+ case OP_GTI:
+ case OP_GEI:
+ case OP_LTU:
+ case OP_LEU:
+ case OP_GTU:
+ case OP_GEU:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ EmitString( "39 47 04" ); // cmp dword ptr [edi+4], eax
+ EmitJump( vm, ci, ci->op, ci->value );
+ break;
+
+ case OP_EQF:
+ case OP_NEF:
+ case OP_LTF:
+ case OP_LEF:
+ case OP_GTF:
+ case OP_GEF:
+ if ( HasFCOM() ) {
+ EmitLoadFloatEDI( vm );
+ if ( HasSSEFP() ) {
+ EmitString( "F3 0F 10 4F FC" ); // movss xmm1, dword ptr [edi-4]
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ EmitString( "0F 2F C8" ); // comiss xmm1, xmm0
+ } else {
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ //EmitString( "D9 47 08" ); // fld dword ptr [edi+8]
+ EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
+ EmitString( "DF E9" ); // fucomip
+ EmitString( "DD D8" ); // fstp st(0)
+ }
+ EmitJump( vm, ci, ci->op, ci->value );
+ } else {
+ EmitCommand( LAST_COMMAND_SUB_DI_8 ); // sub edi, 8
+ EmitString( "D9 47 04" ); // fld dword ptr [edi+4]
+ EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8]
+ EmitString( "DF E0" ); // fnstsw ax
+ EmitFloatJump( vm, ci, ci->op, ci->value );
+ }
+ pop1 = OP_UNDEF;
+ break;
+
+ case OP_NEGI:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "F7 D8" ); // neg eax
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+
+ case OP_ADD:
+ wantres = ( ops[ ni->op ].stack <= 0 );
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ if ( wantres ) {
+ EmitString( "03 47 FC" ); // add eax, dword ptr [edi-4]
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ } else {
+ EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ break;
+
+ case OP_SUB:
+ wantres = ( ops[ ni->op ].stack <= 0 );
+ if ( wantres ) {
+ EmitMovECXEDI( vm ); // mov ecx,dword ptr [edi]
+ EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ EmitString( "29 C8" ); // sub eax, ecx
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ } else {
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ break;
+
+ case OP_DIVI:
+ wantres = ( ops[ ni->op ].stack <= 0 );
+ EmitMovECXEDI( vm ); // mov ecx,dword ptr [edi]
+ EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ if ( wantres ) {
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ EmitString( "99" ); // cdq
+ EmitString( "F7 F9" ); // idiv ecx
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ } else{
+ EmitString( "99" ); // cdq
+ EmitString( "F7 F9" ); // idiv ecx
+ EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ break;
+
+ case OP_DIVU:
+ EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ EmitString( "33 D2" ); // xor edx, edx
+ EmitString( "F7 37" ); // div dword ptr [edi]
+ EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_MODI:
+ EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ EmitString( "99" ); // cdq
+ EmitString( "F7 3F" ); // idiv dword ptr [edi]
+ EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_MODU:
+ EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ EmitString( "33 D2" ); // xor edx, edx
+ EmitString( "F7 37" ); // div dword ptr [edi]
+ EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_MULI:
+ wantres = ( ops[ ni->op ].stack <= 0 );
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "F7 6F FC" ); // imul eax, dword ptr [edi-4]
+ if ( wantres ) {
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ } else {
+ EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ break;
+
+ case OP_MULU:
+ EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4]
+ EmitString( "F7 27" ); // mul dword ptr [edi]
+ EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_BAND:
+ wantres = ( ops[ ni->op ].stack <= 0 );
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ if ( wantres ) {
+ EmitString( "23 47 FC" ); // and eax, dword ptr [edi-4]
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ } else {
+ EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ break;
+
+ case OP_BOR:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_BXOR:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_BCOM:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitString( "F7 D0" ); // not eax
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+
+ case OP_LSH:
+ EmitMovECXEDI( vm ); // mov ecx, dword ptr [edi]
+ EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_RSHI:
+ EmitMovECXEDI( vm ); // mov ecx, dword ptr [edi]
+ EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_RSHU:
+ EmitMovECXEDI( vm ); // mov ecx, dword ptr [edi]
+ EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ break;
+
+ case OP_NEGF:
+ //if ( !ci->fpu )
+ EmitLoadFloatEDI( vm ); // fld dword ptr [edi] | movss xmm0, dword ptr [edi]
+ if ( HasSSEFP() ) {
+ EmitString( "0F 57 C9" ); // xorps xmm1, xmm1
+ EmitString( "0F 5C C8" ); // subps xmm1, xmm0
+ EmitString( "0F 28 C1" ); // movaps xmm0, xmm1
+ } else {
+ EmitString( "D9 E0" ); // fchs
+ }
+ //if ( !ci->fpu || ci->store )
+ EmitCommand( LAST_COMMAND_STORE_FLOAT_EDI ); // fstp dword ptr [edi]
+ break;
+
+ case OP_ADDF:
+ case OP_SUBF:
+ case OP_DIVF:
+ case OP_MULF:
+ wantres = ( ops[ ni->op ].stack <= 0 );
+ if ( HasSSEFP() ) {
+ if ( LastCommand == LAST_COMMAND_STORE_FLOAT_EDI_SSE ) {
+ REWIND(4);
+ EmitString( "0F 28 C8" ); // movaps xmm1, xmm0
+ } else {
+ EmitString( "F3 0F 10 0F" ); // movss xmm1, dword ptr [edi]
+ }
+ EmitString( "F3 0F 10 47 FC" ); // movss xmm0, dword ptr [edi-4]
+ if ( wantres ) {
+ if ( ni->op == OP_STORE4 ) {
+ EmitString( "8B 47 F8" ); // mov eax, dword ptr [edi-8]
+ EmitCheckReg( vm, REG_EAX, 4 );
+ } else if ( ni->op == OP_ARG ) {
+ //
+ } else {
+ EmitCommand( LAST_COMMAND_SUB_DI_4 );
+ }
+ }
+ switch( ci->op ) {
+ case OP_ADDF: EmitString( "0F 58 C1" ); break; // addps xmm0, xmm1
+ case OP_SUBF: EmitString( "0F 5C C1" ); break; // subps xmm0, xmm1
+ case OP_MULF: EmitString( "0F 59 C1" ); break; // mulps xmm0, xmm1
+ case OP_DIVF: EmitString( "0F 5E C1" ); break; // divps xmm0, xmm1
+ }
+ if ( wantres ) {
+ if ( ni->op == OP_STORE4 ) {
+ EmitString( "F3 0F 11 04 03" ); // movss dword ptr [ebx + eax], xmm0
+ EmitCommand( LAST_COMMAND_SUB_DI_12 );
+ pop1 = OP_UNDEF;
+ ip++; // OP_STORE4
+ } else if ( ni->op == OP_ARG ) {
+ v = ni->value;
+ if ( ISU8( v ) ) {
+ EmitString( "F3 0F 11 45" ); // movss dword ptr [ebp + 0x7F], xmm0
+ Emit1( v );
+ } else {
+ EmitString( "F3 0F 11 85" ); // movss dword ptr [ebp + 0x12345678], xmm0
+ Emit4( v );
+ }
+ EmitCommand( LAST_COMMAND_SUB_DI_8 );
+ pop1 = OP_UNDEF;
+ ip++; // OP_ARG
+ } else {
+ EmitCommand( LAST_COMMAND_STORE_FLOAT_EDI );
+ }
+ } else {
+ EmitString( "F3 0F 11 47 FC" ); // movss dword ptr [edi-4], xmm0
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ } else {
+ EmitString( "D9 47 FC" ); // fld dword ptr [edi-4]
+ EmitFCalcEDI( ci->op ); // fadd|fsub|fmul|fdiv dword ptr [edi]
+ EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4]
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+ }
+ break;
+
+ case OP_CVIF:
+ if ( HasSSEFP() ) {
+ if ( LastCommand == LAST_COMMAND_MOV_EDI_EAX ) {
+ REWIND(2);
+ EmitString( "F3 0F 2A C0" ); // cvtsi2ss xmm0, eax
+ } else {
+ EmitString( "F3 0F 2A 07" ); // cvtsi2ss xmm0, dword ptr [edi]
+ }
+ } else {
+ EmitString( "DB 07" ); // fild dword ptr [edi]
+ }
+ //if ( !ci->fpu )
+ EmitCommand( LAST_COMMAND_STORE_FLOAT_EDI );
+ break;
+
+ case OP_CVFI:
+ if ( HasSSEFP() ) {
+ // assume that rounding mode in MXCSR is correctly set in 64-bit environment
+ EmitLoadFloatEDI_SSE( vm ); // movss xmm0, dword ptr [edi]
+ EmitString( "F3 0F 2C C0" ); // cvttss2si eax, xmm0
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ } else {
+ EmitLoadFloatEDI_X87( vm ); // fld dword ptr [edi]
+ // call the library conversion function
+ EmitCallOffset( FUNC_FTOL ); // call +FUNC_FTOL
+ }
+ break;
+
+ case OP_SEX8:
+ EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi]
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+
+ case OP_SEX16:
+ EmitString( "0F BF 07" ); // movsx eax, word ptr [edi]
+ EmitCommand( LAST_COMMAND_MOV_EDI_EAX );// mov dword ptr [edi], eax
+ break;
+
+ case OP_BLOCK_COPY:
+ EmitString( "B9" ); // mov ecx, 0x12345678
+ Emit4( ci->value >> 2 );
+ EmitCallOffset( FUNC_BCPY );
+ break;
+
+ case OP_JUMP:
+ EmitMovEAXEDI( vm ); // mov eax, dword ptr [edi]
+ EmitCommand( LAST_COMMAND_SUB_DI_4 ); // sub edi, 4
+
+ // jump target range check
+ if ( (int)vm_rtChecks.value & 4 ) {
+ if ( proc_base != -1 ) {
+ // allow jump within local function scope only
+ EmitString( "89 C2" ); // mov edx, eax
+ if ( ISU8( proc_base ) ) {
+ EmitString( "83 EA" ); // sub edx, 0x7F
+ Emit1( proc_base );
+ } else {
+ EmitString( "81 EA" ); // sub edx, 0x12345678
+ Emit4( proc_base );
+ }
+ if ( ISU8( proc_len ) ) {
+ EmitString( "83 FA" ); // cmp edx, 0x7F
+ Emit1( proc_len );
+ } else {
+ EmitString( "81 FA" ); // cmp edx, 0x12345678
+ Emit4( proc_len );
+ }
+ } else {
+ EmitString( "3D" ); // cmp eax, 0x12345678
+ Emit4( vm->instructionCount );
+ }
+ EmitString( "0F 83" ); // jae +funcOffset[FUNC_BADJ]
+ n = funcOffset[FUNC_BADJ] - compiledOfs;
+ Emit4( n - 6 );
+ }
+#if idx64
+ EmitString( "41 FF 24 C0" ); // jmp dword ptr [r8 + rax*8]
+#else
+ EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4]
+ EmitPtr( instructionPointers );
+#endif
+ break;
+
+ case MOP_IGNORE4:
+ case MOP_ADD4:
+ case MOP_SUB4:
+ case MOP_BAND4:
+ case MOP_BOR4:
+ case MOP_NCPY:
+ if ( !EmitMOPs( vm, ci->op ) )
+ SV_Error( "VM_CompileX86: bad opcode %02X", ci->op );
+ break;
+
+ default:
+ SV_Error( "VM_CompileX86: bad opcode %02X", ci->op );
+ VM_FreeBuffers();
+ return false;
+ }
+
+ pop1 = (opcode_t)ci->op;
+ } // while( ip < header->instructionCount )
+
+ // ****************
+ // system functions
+ // ****************
+ EmitAlign( 8 );
+ funcOffset[FUNC_CALL] = compiledOfs;
+ EmitCallFunc( vm );
+
+ EmitAlign( 8 );
+ funcOffset[FUNC_FTOL] = compiledOfs;
+ EmitFTOLFunc( vm );
+
+ EmitAlign( 8 );
+ funcOffset[FUNC_BCPY] = compiledOfs;
+ EmitBCPYFunc( vm );
+
+ EmitAlign( 8 );
+ funcOffset[FUNC_NCPY] = compiledOfs;
+ EmitNCPYFunc( vm );
+
+ // ***************
+ // error functions
+ // ***************
+
+ // bad jump
+ EmitAlign( 8 );
+ funcOffset[FUNC_BADJ] = compiledOfs;
+ EmitBADJFunc( vm );
+
+ // error jump
+ EmitAlign( 8 );
+ funcOffset[FUNC_ERRJ] = compiledOfs;
+ EmitERRJFunc( vm );
+
+ // programStack overflow
+ EmitAlign( 8 );
+ funcOffset[FUNC_PSOF] = compiledOfs;
+ EmitPSOFFunc( vm );
+
+ // opStack overflow
+ EmitAlign( 8 );
+ funcOffset[FUNC_OSOF] = compiledOfs;
+ EmitOSOFFunc( vm );
+
+ // read/write access violation
+ EmitAlign( 8 );
+ funcOffset[FUNC_DATA] = compiledOfs;
+ EmitDATAFunc( vm );
+
+ EmitAlign( sizeof( intptr_t ) ); // for instructionPointers
+
+ } // for( pass = 0; pass < n; pass++ )
+
+ n = header->instructionCount * sizeof( intptr_t );
+
+ if ( code == NULL ) {
+ code = (byte*)VM_Alloc_Compiled( vm, PAD(compiledOfs,8), n );
+ if ( code == NULL ) {
+ return false;
+ }
+ instructionPointers = (intptr_t*)(byte*)(code + PAD(compiledOfs,8));
+ //vm->instructionPointers = instructionPointers; // for debug purposes?
+ pass = NUM_PASSES-1; // repeat last pass
+ goto __compile;
+ }
+
+ // offset all the instruction pointers for the new location
+ for ( i = 0 ; i < header->instructionCount ; i++ ) {
+ if ( !inst[i].jused ) {
+ instructionPointers[ i ] = (intptr_t)badJumpPtr;
+ continue;
+ }
+ instructionPointers[ i ] = (intptr_t)vm->codeBase.ptr + instructionOffsets[ i ];
+ }
+
+ VM_FreeBuffers();
+
+#ifdef VM_X86_MMAP
+ if ( mprotect( vm->codeBase.ptr, vm->codeSize, PROT_READ|PROT_EXEC ) ) {
+ VM_Destroy_Compiled( vm );
+ Con_Printf( "VM_CompileX86: mprotect failed\n" );
+ return false;
+ }
+#elif _WIN32
+ {
+ DWORD oldProtect = 0;
+
+ // remove write permissions.
+ if ( !VirtualProtect( vm->codeBase.ptr, vm->codeSize, PAGE_EXECUTE_READ, &oldProtect ) ) {
+ VM_Destroy_Compiled( vm );
+ Con_Printf( "VM_CompileX86: VirtualProtect failed\n" );
+ return false;
+ }
+ }
+#endif
+
+ vm->destroy = VM_Destroy_Compiled;
+
+ Con_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
+
+ return true;
+}
+/*
+=================
+VM_Alloc_Compiled
+=================
+*/
+static void *VM_Alloc_Compiled( vm_t *vm, int codeLength, int tableLength )
+{
+ void *ptr;
+ int length;
+
+ length = codeLength + tableLength;
+#ifdef VM_X86_MMAP
+ ptr = mmap( NULL, length, PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0 );
+ if ( ptr == MAP_FAILED ) {
+ SV_Error( "VM_CompileX86: mmap failed" );
+ return NULL;
+ }
+#elif _WIN32
+ // allocate memory with EXECUTE permissions under windows.
+ ptr = VirtualAlloc( NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+ if ( !ptr ) {
+ SV_Error( "VM_CompileX86: VirtualAlloc failed" );
+ return NULL;
+ }
+#else
+ ptr = malloc( length );
+ if ( !ptr ) {
+ SV_Error( "VM_CompileX86: malloc failed" );
+ return NULL;
+ }
+#endif
+ vm->codeBase.ptr = (byte*)ptr;
+ vm->codeLength = codeLength;
+ vm->codeSize = length;
+
+ return vm->codeBase.ptr;
+}
+
+
+/*
+==============
+VM_Destroy_Compiled
+==============
+*/
+static void VM_Destroy_Compiled( vm_t* vm )
+{
+#ifdef VM_X86_MMAP
+ munmap( vm->codeBase.ptr, vm->codeSize );
+#elif _WIN32
+ VirtualFree( vm->codeBase.ptr, 0, MEM_RELEASE );
+#else
+ free( vm->codeBase.ptr );
+#endif
+ vm->codeBase.ptr = NULL;
+}
+
+/*
+==============
+VM_CallCompiled
+
+This function is called directly by the generated code
+==============
+*/
+int VM_CallCompiled( vm_t *vm, int nargs, int *args )
+{
+ int opStack[MAX_OPSTACK_SIZE];
+ unsigned int stackOnEntry;
+ int *image;
+ int *oldOpTop;
+ int i;
+
+ // we might be called recursively, so this might not be the very top
+ stackOnEntry = vm->programStack;
+ oldOpTop = vm->opStackTop;
+
+ vm->programStack -= (MAX_VMMAIN_CALL_ARGS+2)*4;
+
+ // set up the stack frame
+ image = (int*)( vm->dataBase + vm->programStack );
+ for ( i = 0; i < nargs; i++ ) {
+ image[ i + 2 ] = args[ i ];
+ }
+
+ image[1] = 0; // return stack
+ image[0] = -1; // will terminate loop on return
+
+ opStack[1] = 0;
+
+ vm->opStack = opStack;
+ vm->opStackTop = opStack + ARRAY_LEN( opStack ) - 1;
+
+ vm->codeBase.func(); // go into generated code
+
+ if ( vm->opStack != &opStack[1] ) {
+ SV_Error( "opStack corrupted in compiled code" );
+ }
+
+#ifdef DEBUG_VM
+ if ( vm->programStack != stackOnEntry - CALL_PSTACK ) {
+ SV_Error( "programStack corrupted in compiled code" );
+ }
+#endif
+
+ vm->programStack = stackOnEntry;
+ vm->opStackTop = oldOpTop;
+
+ return vm->opStack[0];
+}
+#else
+int VM_CallCompiled( vm_t *vm, int nargs, int *args ) { return 0;}
+qbool VM_Compile( vm_t *vm, vmHeader_t *header ) { return false; }
+#endif
+#endif /* USE_PR2 */
+
diff --git a/src/zone.c b/src/zone.c
index 00fcbb229..1cf2c7f54 100644
--- a/src/zone.c
+++ b/src/zone.c
@@ -224,22 +224,13 @@ void Hunk_FreeToLowMark(int mark)
hunk_low_used = mark;
}
-int Hunk_HighMark(void)
+static int Hunk_HighMark(void)
{
- if (hunk_tempactive) {
- hunk_tempactive = false;
- Hunk_FreeToHighMark(hunk_tempmark);
- }
-
return hunk_high_used;
}
-void Hunk_FreeToHighMark(int mark)
+static void Hunk_FreeToHighMark(int mark)
{
- if (hunk_tempactive) {
- hunk_tempactive = false;
- Hunk_FreeToHighMark(hunk_tempmark);
- }
if (mark < 0 || mark > hunk_high_used) {
Sys_Error("Hunk_FreeToHighMark: bad mark %i", mark);
}
@@ -252,7 +243,7 @@ void Hunk_FreeToHighMark(int mark)
Hunk_HighAllocName
===================
*/
-void *Hunk_HighAllocName(int size, char *name)
+static void *Hunk_HighAllocName(int size, char *name)
{
hunk_t *h;
@@ -260,11 +251,6 @@ void *Hunk_HighAllocName(int size, char *name)
Sys_Error("Hunk_HighAllocName: bad size: %i", size);
}
- if (hunk_tempactive) {
- Hunk_FreeToHighMark(hunk_tempmark);
- hunk_tempactive = false;
- }
-
#ifdef PARANOID
Hunk_Check();
#endif
@@ -294,23 +280,33 @@ void *Hunk_HighAllocName(int size, char *name)
/*
=================
-Hunk_TempAlloc
+Hunk_TempFlush
-Return space from the top of the hunk
+Free the temporary memory zone to baseline.
=================
*/
-void *Hunk_TempAlloc(int size)
+void Hunk_TempFlush(void)
{
- void *buf;
-
- size = (size + 15) & ~15;
-
if (hunk_tempactive) {
Hunk_FreeToHighMark(hunk_tempmark);
hunk_tempactive = false;
}
hunk_tempmark = Hunk_HighMark();
+}
+
+/*
+=================
+Hunk_TempAlloc
+
+Return space from the top of the hunk
+=================
+*/
+void *Hunk_TempAlloc(int size)
+{
+ void *buf;
+
+ Hunk_TempFlush();
buf = Hunk_HighAllocName(size, "temp");
@@ -319,6 +315,21 @@ void *Hunk_TempAlloc(int size)
return buf;
}
+/*
+=================
+Hunk_TempAllocMore
+
+Return space after any previous temporary allocation without clearing first.
+=================
+*/
+void *Hunk_TempAllocMore(int size)
+{
+ if (!hunk_tempactive)
+ return Hunk_TempAlloc(size);
+
+ return Hunk_HighAllocName(size, "temp+");
+}
+
#ifdef SERVERONLY
/*
===============================================================================
diff --git a/src/zone.h b/src/zone.h
index 62f865672..056d9ca51 100644
--- a/src/zone.h
+++ b/src/zone.h
@@ -85,15 +85,12 @@ void Memory_Init (void *buf, int size);
void *Hunk_Alloc (int size); // returns 0 filled memory
void *Hunk_AllocName (int size, const char *name);
-void *Hunk_HighAllocName (int size, char *name);
-
int Hunk_LowMark (void);
void Hunk_FreeToLowMark (int mark);
-int Hunk_HighMark (void);
-void Hunk_FreeToHighMark (int mark);
-
+void Hunk_TempFlush(void);
void *Hunk_TempAlloc (int size);
+void *Hunk_TempAllocMore(int size);
void Hunk_Check (void);