Protocol 666/large map support from FitzQuake.

Alpha and lerping aren't implemented yet, but things seem to be working. I
can load and play oms2.bsp (Conflagrant Rodent).
This commit is contained in:
Bill Currie 2010-08-24 09:53:54 +09:00
parent 8c4fe2f844
commit 31c13d92a2
25 changed files with 758 additions and 228 deletions

View file

@ -41,11 +41,9 @@
#define MAX_MAP_ENTSTRING 65536
#define MAX_MAP_PLANES 32767
//#define MAX_MAP_PLANES 8192
#define MAX_MAP_NODES 32767 // because negative shorts are contents
#define MAX_MAP_CLIPNODES 32767 //
#define MAX_MAP_LEAFS 32767 //
//#define MAX_MAP_LEAFS 8192
#define MAX_MAP_VERTS 65535
#define MAX_MAP_FACES 65535
#define MAX_MAP_MARKSURFACES 65535
@ -181,6 +179,7 @@ typedef struct texinfo_s {
int32_t flags;
} texinfo_t;
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
#define TEX_MISSING 2 // this texinfo does not have a texture
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face

View file

@ -46,7 +46,8 @@ void MSG_WriteCoordAngleV (sizebuf_t *sb, const vec3_t coord,
const vec3_t angles);
void MSG_WriteAngle (sizebuf_t *sb, float angle);
void MSG_WriteAngleV (sizebuf_t *sb, const vec3_t angles);
void MSG_WriteAngle16 (sizebuf_t *sb, float angle16);
void MSG_WriteAngle16 (sizebuf_t *sb, float angle);
void MSG_WriteAngle16V (sizebuf_t *sb, const vec3_t angle);
void MSG_WriteUTF8 (sizebuf_t *sb, unsigned utf8);
typedef struct msg_s {
@ -72,6 +73,7 @@ float MSG_ReadAngle (qmsg_t *msg);
void MSG_ReadCoordAngleV (qmsg_t *msg, vec3_t coord, vec3_t angles);
void MSG_ReadAngleV (qmsg_t *msg, vec3_t angles);
float MSG_ReadAngle16 (qmsg_t *msg);
void MSG_ReadAngle16V (qmsg_t *msg, vec3_t angles);
int MSG_ReadUTF8 (qmsg_t *msg);
//@}

View file

@ -34,12 +34,9 @@
#define MAX_QPATH 64
#define MAX_CL_STATS 32
#define NUM_CSHIFTS 4
#define MAX_MODELS 256
#define MAX_SOUNDS 256
#define MAX_SCOREBOARD 16
#define MAX_SCOREBOARDNAME 32
#define MAX_STYLESTRING 64
#define MAX_EDICTS 768
#define MAX_LIGHTSTYLES 64
#define clc_stringcmd 4

View file

@ -41,7 +41,7 @@ struct qsockaddr
#define NET_NAMELEN 64
#define NET_MAXMESSAGE 8192
#define NET_MAXMESSAGE 32000
#define NET_HEADERSIZE (2 * sizeof(unsigned int))
#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE)

View file

@ -297,7 +297,7 @@ void SND_SFX_Init (void);
*/
//@{
#define MAX_CHANNELS 512 //!< number of available mixing channels
#define MAX_DYNAMIC_CHANNELS 8 //!< number of dynamic channels
#define MAX_DYNAMIC_CHANNELS 128 //!< number of dynamic channels
#define MAX_STATIC_CHANNELS 256 //!< number of static channels
extern channel_t snd_channels[MAX_CHANNELS]; //!< pool of available channels
extern int snd_total_channels; //!< number of active channels

View file

@ -357,6 +357,18 @@ Mod_LoadSubmodels (bsp_t *bsp)
out->firstface = LittleLong (in->firstface);
out->numfaces = LittleLong (in->numfaces);
}
out = loadmodel->submodels;
if (out->visleafs > MAX_MAP_LEAFS) {
Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s",
out->visleafs, MAX_MAP_LEAFS, loadmodel->name);
}
if (out->visleafs > 8192)
Sys_MaskPrintf (SYS_WARN,
"%i visleafs exceeds standard limit of 8192.\n",
out->visleafs);
}
static void
@ -473,8 +485,8 @@ CalcSurfaceExtents (msurface_t *s)
s->texturemins[i] = bmins[i] * 16;
s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
// FIXME even 512 is really too small, need a saner test
if (!(tex->flags & TEX_SPECIAL) && s->extents[i] > 512)
// FIXME even 2000 is really too small, need a saner test
if (!(tex->flags & TEX_SPECIAL) && s->extents[i] > 2000)
Sys_Error ("Bad surface extents: %d %x %d %d", i, tex->flags,
s->extents[i], LongSwap (s->extents[i]));
}
@ -491,6 +503,11 @@ Mod_LoadFaces (bsp_t *bsp)
count = bsp->numfaces;
out = Hunk_AllocName (count * sizeof (*out), loadname);
if (count > 32767) {
Sys_MaskPrintf (SYS_WARN,
"%i faces exceeds standard limit of 32767.\n", count);
}
loadmodel->surfaces = out;
loadmodel->numsurfaces = count;
@ -566,6 +583,11 @@ Mod_LoadNodes (bsp_t *bsp)
count = bsp->numnodes;
out = Hunk_AllocName (count * sizeof (*out), loadname);
if (count > 32767) {
Sys_MaskPrintf (SYS_WARN,
"%i nodes exceeds standard limit of 32767.\n", count);
}
loadmodel->nodes = out;
loadmodel->numnodes = count;
@ -582,11 +604,22 @@ Mod_LoadNodes (bsp_t *bsp)
out->numsurfaces = LittleShort (in->numfaces);
for (j = 0; j < 2; j++) {
p = LittleShort (in->children[j]);
if (p >= 0)
// handle > 32k nodes. From darkplaces via fitzquake
p = (unsigned short) LittleShort (in->children[j]);
if (p < count) {
out->children[j] = loadmodel->nodes + p;
else
out->children[j] = (mnode_t *) (loadmodel->leafs + (-1 - p));
} else {
p = 65535 - p; //NOTE this uses 65535 intentionally, -1 is leaf
if (p < loadmodel->numleafs) {
out->children[j] = (mnode_t *) (loadmodel->leafs + p);
} else {
Sys_Printf ("Mod_LoadNodes: invalid leaf index %i "
"(file has only %i leafs)\n", p,
loadmodel->numleafs);
//map it to the solid leaf
out->children[j] = (mnode_t *)(loadmodel->leafs);
}
}
}
}
@ -605,6 +638,9 @@ Mod_LoadLeafs (bsp_t *bsp)
count = bsp->numleafs;
out = Hunk_AllocName (count * sizeof (*out), loadname);
if (count > 32767)
Sys_Error ("%i leafs exceeds limit of 32767.\n", count);
loadmodel->leafs = out;
loadmodel->numleafs = count;
// snprintf(s, sizeof (s), "maps/%s.bsp",
@ -621,8 +657,8 @@ Mod_LoadLeafs (bsp_t *bsp)
out->contents = p;
out->firstmarksurface = loadmodel->marksurfaces +
LittleShort (in->firstmarksurface);
out->nummarksurfaces = LittleShort (in->nummarksurfaces);
(uint16_t) LittleShort (in->firstmarksurface);
out->nummarksurfaces = (uint16_t) LittleShort (in->nummarksurfaces);
p = LittleLong (in->visofs);
if (p == -1)
@ -657,6 +693,12 @@ Mod_LoadClipnodes (bsp_t *bsp)
count = bsp->numclipnodes;
out = Hunk_AllocName (count * sizeof (*out), loadname);
if (count > 32767) {
Sys_MaskPrintf (SYS_WARN,
"%i clilpnodes exceeds standard limit of 32767.\n",
count);
}
loadmodel->clipnodes = out;
loadmodel->numclipnodes = count;
@ -688,8 +730,14 @@ Mod_LoadClipnodes (bsp_t *bsp)
for (i = 0; i < count; i++, out++, in++) {
out->planenum = LittleLong (in->planenum);
out->children[0] = LittleShort (in->children[0]);
out->children[1] = LittleShort (in->children[1]);
if (out->planenum < 0 || out->planenum >= loadmodel->numplanes)
Sys_Error ("Mod_LoadClipnodes: planenum out of bounds");
out->children[0] = (uint16_t) LittleShort (in->children[0]);
out->children[1] = (uint16_t) LittleShort (in->children[1]);
if (out->children[0] >= count)
out->children[0] -= 65536;
if (out->children[1] >= count)
out->children[1] -= 65536;
if ((out->children[0] >= 0
&& (out->children[0] < hull->firstclipnode
|| out->children[0] > hull->lastclipnode))
@ -748,11 +796,17 @@ Mod_LoadMarksurfaces (bsp_t *bsp)
count = bsp->nummarksurfaces;
out = Hunk_AllocName (count * sizeof (*out), loadname);
if (count > 32767) {
Sys_MaskPrintf (SYS_WARN,
"%i marksurfaces exceeds standard limit of 32767.\n",
count);
}
loadmodel->marksurfaces = out;
loadmodel->nummarksurfaces = count;
for (i = 0; i < count; i++) {
j = LittleShort (in[i]);
j = (uint16_t) LittleShort (in[i]);
if (j >= loadmodel->numsurfaces)
Sys_Error ("Mod_ParseMarksurfaces: bad surface number");
out[i] = loadmodel->surfaces + j;

View file

@ -160,9 +160,24 @@ MSG_WriteAngleV (sizebuf_t *sb, const vec3_t angles)
}
VISIBLE void
MSG_WriteAngle16 (sizebuf_t *sb, float angle16)
MSG_WriteAngle16 (sizebuf_t *sb, float angle)
{
MSG_WriteShort (sb, (int) (angle16 * (65536.0 / 360.0)) & 65535);
MSG_WriteShort (sb, (int) (angle * (65536.0 / 360.0)) & 65535);
}
VISIBLE void
MSG_WriteAngle16V (sizebuf_t *sb, const vec3_t angles)
{
byte *buf;
int i;
unsigned short ang;
buf = SZ_GetSpace (sb, 6);
for (i = 0; i < 3; i++) {
ang = (int) (angles[i] * (65536.0 / 360.0)) & 65535;
*buf++ = ang & 0xff;
*buf++ = ang >> 8;
}
}
VISIBLE void
@ -383,6 +398,19 @@ MSG_ReadAngle16 (qmsg_t *msg)
return MSG_ReadShort (msg) * (360.0 / 65536.0);
}
VISIBLE void
MSG_ReadAngle16V (qmsg_t *msg, vec3_t angles)
{
int i;
short ang;
for (i = 0; i < 3; i++) {
ang = MSG_ReadByte (msg);
ang |= MSG_ReadByte (msg) << 8;
angles[i] = ang * (360.0 / 65536.0);
}
}
VISIBLE int
MSG_ReadUTF8 (qmsg_t *msg)
{

View file

@ -110,7 +110,7 @@ vec5_t skyvec[6][4] = {
}
};
void
VISIBLE void
R_LoadSkys (const char *skyname)
{
const char *name;

View file

@ -215,12 +215,10 @@ R_SetSkyFrame (void)
/*
R_LoadSkys
Stub function for loading a skybox. Currently we have support for
skyboxes only in GL targets, so we just do nothing here. --KB
*/
void
VISIBLE void
R_LoadSkys (const char *name)
{
}

View file

@ -216,12 +216,10 @@ R_SetSkyFrame (void)
/*
R_LoadSkys
Stub function for loading a skybox. Currently we have support for
skyboxes only in GL targets, so we just do nothing here. --KB
*/
void
VISIBLE void
R_LoadSkys (const char *name)
{
}

View file

@ -215,6 +215,8 @@ typedef struct
// frag scoreboard
scoreboard_t *scores; // [cl.maxclients]
unsigned protocol;
} client_state_t;
@ -278,8 +280,7 @@ extern struct cvar_s *cl_cshift_powerup;
extern struct cvar_s *noskins;
#define MAX_TEMP_ENTITIES 64 // lightning bolts, etc
#define MAX_STATIC_ENTITIES 128 // torches, etc
#define MAX_STATIC_ENTITIES 512 // torches, etc
extern client_state_t cl;
@ -290,6 +291,7 @@ extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
extern int fps_count;
extern void (*write_angles) (sizebuf_t *sb, const vec3_t angles);
// cl_main
void CL_Init (void);

View file

@ -34,11 +34,14 @@
#include "QF/qtypes.h"
#include "QF/qdefs.h"
#undef MAX_DATAGRAM
#define MAX_DATAGRAM 1024 // max length of unreliable message
#undef MAX_MSGLEN
#define MAX_MSGLEN 8000 // max length of a reliable message
#define MIN_EDICTS 256 // lowest allowed value for max_edicts
#define MAX_EDICTS 32000 // highest allowed value for max_edicts
#define MAX_DATAGRAM 32000 // max length of unreliable message
#define MAX_MSGLEN 32000 // max length of a reliable message
#define DATAGRAM_MTU 1400 // actual limit for unreliable messages
// to nonlocal clients
#define MAX_MODELS 2048
#define MAX_SOUNDS 2048
#include <math.h>
#include <string.h>

View file

@ -31,7 +31,8 @@
#include "QF/qtypes.h"
#define PROTOCOL_VERSION 15
#define PROTOCOL_NETQUAKE 15
#define PROTOCOL_FITZQUAKE 666
// if the high bit of the servercmd is set, the low bits are fast update flags:
#define U_MOREBITS (1<<0)
@ -39,7 +40,7 @@
#define U_ORIGIN2 (1<<2)
#define U_ORIGIN3 (1<<3)
#define U_ANGLE2 (1<<4)
#define U_NOLERP (1<<5) // don't interpolate movement
#define U_STEP (1<<5) // don't interpolate movement
#define U_FRAME (1<<6)
#define U_SIGNAL (1<<7) // just differentiates from other updates
@ -51,30 +52,16 @@
#define U_SKIN (1<<12)
#define U_EFFECTS (1<<13)
#define U_LONGENTITY (1<<14)
// QSG Protocol Extensions (Version 2) ========================================
// Network definitions for the engine
#define U_EXTEND1 (1<<15)
#define U_DELTA (1<<16) // no data, while this is set the entity is delta compressed (uses previous frame as a baseline, meaning only things that have changed from the previous frame are sent, except for the forced full update every half second)
#define U_ALPHA (1<<17) // 1 byte, 0.0-1.0 = 0-255 (Unsent if 1)
#define U_SCALE (1<<18) // 1 byte, scale / 16 positive, (Unsent if 1)
#define U_EFFECTS2 (1<<19) // 1 byte, .effects & 0xFF00
#define U_GLOWSIZE (1<<20) // 1 byte, float/8.0, signed. Unsent if 1
#define U_GLOWCOLOR (1<<21) // 1 byte, palette index, default, 254.
#define U_COLORMOD (1<<22) // 1 byte, rrrgggbb. Model tinting
#define U_EXTEND2 (1<<23) // Another byte to follow
#define U_GLOWTRAIL (1<<24) // Leave U_GLOW* trail
#define U_VIEWMODEL (1<<25) // Attach model to view (relative). Owner only
#define U_FRAME2 (1<<26) // 1 byte .frame & 0xFF00 (second byte)
#define U_UNUSED27 (1<<27) // future expansion
#define U_UNUSED28 (1<<28) // future expansion
#define U_UNUSED29 (1<<29) // future expansion
#define U_UNUSED30 (1<<30) // future expansion
#define U_EXTEND3 (1<<31) // another byte to follow, future expansion
// QSG 2 End ==================================================================
//PROTOCOL_FITZQUAKE -- new bits
#define U_EXTEND1 (1<<15)
#define U_ALPHA (1<<16) // 1 byte, uses ENTALPHA_ENCODE, not sent if equal to baseline
#define U_FRAME2 (1<<17) // 1 byte, this is .frame & 0xFF00 (second byte)
#define U_MODEL2 (1<<18) // 1 byte, this is .modelindex & 0xFF00 (second byte)
#define U_LERPFINISH (1<<19) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 0.1, this is ent->v.nextthink - sv.time, used for lerping
#define U_UNUSED20 (1<<20)
#define U_UNUSED21 (1<<21)
#define U_UNUSED22 (1<<22)
#define U_EXTEND2 (1<<23) // another byte to follow, future expansion
#define SU_VIEWHEIGHT (1<<0)
#define SU_IDEALPITCH (1<<1)
@ -84,21 +71,55 @@
#define SU_VELOCITY1 (1<<5)
#define SU_VELOCITY2 (1<<6)
#define SU_VELOCITY3 (1<<7)
//#define SU_AIMENT (1<<8) AVAILABLE BIT
#define SU_UNUSED8 (1<<8) //AVAILABLE BIT
#define SU_ITEMS (1<<9)
#define SU_ONGROUND (1<<10) // no data follows, the bit is it
#define SU_INWATER (1<<11) // no data follows, the bit is it
#define SU_WEAPONFRAME (1<<12)
#define SU_ARMOR (1<<13)
#define SU_WEAPON (1<<14)
// PROTOCOL_FITZQUAKE -- new bits
#define SU_EXTEND1 (1<<15) // another byte to follow
#define SU_WEAPON2 (1<<16) // 1 byte, this is .weaponmodel & 0xFF00 (second byte)
#define SU_ARMOR2 (1<<17) // 1 byte, this is .armorvalue & 0xFF00 (second byte)
#define SU_AMMO2 (1<<18) // 1 byte, this is .currentammo & 0xFF00 (second byte)
#define SU_SHELLS2 (1<<19) // 1 byte, this is .ammo_shells & 0xFF00 (second byte)
#define SU_NAILS2 (1<<20) // 1 byte, this is .ammo_nails & 0xFF00 (second byte)
#define SU_ROCKETS2 (1<<21) // 1 byte, this is .ammo_rockets & 0xFF00 (second byte)
#define SU_CELLS2 (1<<22) // 1 byte, this is .ammo_cells & 0xFF00 (second byte)
#define SU_EXTEND2 (1<<23) // another byte to follow
#define SU_WEAPONFRAME2 (1<<24) // 1 byte, this is .weaponframe & 0xFF00 (second byte)
#define SU_WEAPONALPHA (1<<25) // 1 byte, this is alpha for weaponmodel, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT
#define SU_UNUSED26 (1<<26)
#define SU_UNUSED27 (1<<27)
#define SU_UNUSED28 (1<<28)
#define SU_UNUSED29 (1<<29)
#define SU_UNUSED30 (1<<30)
#define SU_EXTEND3 (1<<31) // another byte to follow, future expansion
// a sound with no channel is a local-only sound
#define SND_VOLUME (1<<0) // a byte
#define SND_ATTENUATION (1<<1) // a byte
#define SND_LOOPING (1<<2) // a long
// PROTOCOL_FITZQUAKE -- new bits
#define SND_LARGEENTITY (1<<3) // a short + byte (instead of just a short)
#define SND_LARGESOUND (1<<4) // a short soundindex (instead of a byte)
#define DEFAULT_SOUND_PACKET_VOLUME 255
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
// PROTOCOL_FITZQUAKE -- flags for entity baseline messages
#define B_LARGEMODEL (1<<0) // modelindex is short instead of byte
#define B_LARGEFRAME (1<<1) // frame is short instead of byte
#define B_ALPHA (1<<2) // 1 byte, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT
// PROTOCOL_FITZQUAKE -- alpha encoding
#define ENTALPHA_DEFAULT 0 //entity's alpha is "default" (i.e. water obeys r_wateralpha) -- must be zero so zeroed out memory works
#define ENTALPHA_ZERO 1 //entity is invisible (lowest possible alpha)
#define ENTALPHA_ONE 255 //entity is fully opaque (highest possible alpha)
#define ENTALPHA_ENCODE(a) (((a)==0)?ENTALPHA_DEFAULT:RINT(CLAMP(1,(a)*254.0f+1,255))) //server convert to byte to send to client
#define ENTALPHA_DECODE(a) (((a)==ENTALPHA_DEFAULT)?1.0f:((float)(a)-1)/(254)) //client convert to float for rendering
#define ENTALPHA_TOSAVE(a) (((a)==ENTALPHA_DEFAULT)?0.0f:(((a)==ENTALPHA_ZERO)?-1.0f:((float)(a)-1)/(254))) //server convert to float for savegame
// defaults for clientinfo messages
#define DEFAULT_VIEWHEIGHT 22
@ -156,13 +177,21 @@
#define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten
#define svc_intermission 30 // [string] music
#define svc_finale 31 // [string] music [string] text
#define svc_intermission 30 // [string] music
#define svc_finale 31 // [string] music [string] text
#define svc_cdtrack 32 // [byte] track [byte] looptrack
#define svc_sellscreen 33
#define svc_cdtrack 32 // [byte] track [byte] looptrack
#define svc_sellscreen 33
#define svc_cutscene 34
#define svc_cutscene 34
// PROTOCOL_FITZQUAKE -- new server messages
#define svc_skybox 37 // [string] name
#define svc_bf 40
#define svc_fog 41 // [byte] density [byte] red [byte] green [byte] blue [float] time
#define svc_spawnbaseline2 42 // support for large modelindex, large framenum, alpha, using flags
#define svc_spawnstatic2 43 // support for large modelindex, large framenum, alpha, using flags
#define svc_spawnstaticsound2 44 // [coord3] [short] samp [byte] vol [byte] aten
// client to server ===========================================================
@ -199,13 +228,11 @@ typedef struct entity_state_s
{
vec3_t origin;
vec3_t angles;
int modelindex;
int frame;
int colormap;
int skin;
unsigned short modelindex;
unsigned short frame;
int effects;
// LordHavoc: Endy neglected to mark this as a QSG version 2 thingy...
byte colormap;
byte skin;
byte alpha;
byte scale;
byte glow_size;

View file

@ -89,7 +89,9 @@ typedef struct
byte reliable_datagram_buf[MAX_DATAGRAM];
sizebuf_t signon;
byte signon_buf[8192];
byte signon_buf[MAX_MSGLEN-2];
unsigned protocol;
} server_t;
@ -213,6 +215,8 @@ extern struct cvar_s *sv_aim;
extern struct cvar_s *sv_friction;
extern struct cvar_s *sv_stopspeed;
extern struct cvar_s *max_edicts;
extern server_static_t svs; // persistant server info
extern server_t sv; // local server

View file

@ -75,6 +75,7 @@ kbutton_t in_up, in_down;
int in_impulse;
void (*write_angles) (sizebuf_t *sb, const vec3_t angles);
static void
KeyPress (kbutton_t *b)
@ -555,7 +556,7 @@ CL_SendMove (usercmd_t *cmd)
MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
MSG_WriteAngleV (&buf, cl.viewangles);
write_angles (&buf, cl.viewangles);
MSG_WriteShort (&buf, cmd->forwardmove);
MSG_WriteShort (&buf, cmd->sidemove);

View file

@ -608,7 +608,7 @@ CL_RelinkEntities (void)
CL_NewDlight (i, ent->origin, state->effects);
if (VectorDistance_fast (state->msg_origins[1], ent->origin)
> (256 * 256))
VectorCopy (ent ->origin, state->msg_origins[1]);
VectorCopy (ent->origin, state->msg_origins[1]);
if (ent->model->flags & EF_ROCKET) {
dl = R_AllocDlight (i);
if (dl) {
@ -729,6 +729,10 @@ CL_SetState (cactive_t state)
key_dest = key_console;
VID_SetCaption ("Disconnected");
}
if (state == ca_connected)
S_AmbientOn ();
else
S_AmbientOff ();
}
if (con_module)
con_module->data->console->force_commandline = (state != ca_active);

View file

@ -43,6 +43,7 @@ static __attribute__ ((used)) const char rcsid[] =
#include "QF/cmd.h"
#include "QF/console.h"
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/idparse.h"
#include "QF/input.h"
#include "QF/msg.h"
@ -50,8 +51,10 @@ static __attribute__ ((used)) const char rcsid[] =
#include "QF/screen.h"
#include "QF/skin.h"
#include "QF/sound.h" // FIXME: DEFAULT_SOUND_PACKET_*
#include "QF/va.h"
#include "client.h"
#include "compat.h"
#include "host.h"
#include "sbar.h"
#include "server.h"
@ -100,11 +103,24 @@ const char *svc_strings[] = {
"svc_finale", // [string] music [string] text
"svc_cdtrack", // [byte] track [byte] looptrack
"svc_sellscreen",
"svc_cutscene"
"svc_cutscene",
// end of iD svc
// FIXME switchable extensions?
// protocol 666
"",
"",
"svc_skybox",
"",
"",
"svc_bf",
"svc_fog",
"svc_spawnbaseline2",
"svc_spawnstatic2",
"svc_spawnstaticsound2",
};
float r_gravity;
dstring_t *centerprint;
/*
CL_EntityNum
@ -114,9 +130,9 @@ float r_gravity;
static cl_entity_state_t *
CL_EntityNum (int num)
{
if (num < 0 || num >= MAX_EDICTS)
Host_Error ("CL_EntityNum: %i is an invalid number", num);
if (num >= cl.num_entities) {
if (num >= MAX_EDICTS)
Host_Error ("CL_EntityNum: %i is an invalid number", num);
while (cl.num_entities <= num) {
cl_baselines[cl.num_entities].ent =
&cl_entities[cl.num_entities];
@ -147,12 +163,22 @@ CL_ParseStartSoundPacket (void)
else
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
channel = MSG_ReadShort (net_message);
sound_num = MSG_ReadByte (net_message);
if (field_mask & SND_LARGEENTITY) {
ent = (uint16_t) MSG_ReadShort (net_message);
channel = MSG_ReadByte (net_message);
} else {
channel = (uint16_t) MSG_ReadShort (net_message);
ent = channel >> 3;
channel &= 7;
}
ent = channel >> 3;
channel &= 7;
if (field_mask & SND_LARGESOUND)
sound_num = (uint16_t) MSG_ReadShort (net_message);
else
sound_num = MSG_ReadByte (net_message);
if (sound_num >= MAX_SOUNDS)
Host_Error ("CL_ParseStartSoundPacket: %i > MAX_SOUNDS", sound_num);
if (ent > MAX_EDICTS)
Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
@ -275,10 +301,16 @@ CL_ParseServerInfo (void)
// parse protocol version number
i = MSG_ReadLong (net_message);
if (i != PROTOCOL_VERSION) {
Sys_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION);
if (i != PROTOCOL_NETQUAKE && i!= PROTOCOL_FITZQUAKE) {
Sys_Printf ("Server returned version %i, not %i or %i\n", i,
PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE);
goto done;
}
cl.protocol = i;
if (cl.protocol == PROTOCOL_FITZQUAKE)
write_angles = MSG_WriteAngle16V;
else
write_angles = MSG_WriteAngleV;
// parse maxclients
cl.maxclients = MSG_ReadByte (net_message);
if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) {
@ -351,6 +383,10 @@ CL_ParseServerInfo (void)
// local state
cl_entities[0].model = cl.worldmodel = cl.model_precache[1];
if (!centerprint)
centerprint = dstring_newstr ();
else
dstring_clearstr (centerprint);
CL_NewMap (model_precache[1]);
Hunk_Check (); // make sure nothing is hurt
@ -389,6 +425,13 @@ CL_ParseUpdate (int bits)
i = MSG_ReadByte (net_message);
bits |= (i << 8);
}
if (cl.protocol == PROTOCOL_FITZQUAKE) {
if (bits & U_EXTEND1)
bits |= MSG_ReadByte(net_message) << 16;
if (bits & U_EXTEND2)
bits |= MSG_ReadByte(net_message) << 24;
}
if (bits & U_LONGENTITY)
num = MSG_ReadShort (net_message);
@ -422,26 +465,6 @@ CL_ParseUpdate (int bits)
} else
modnum = state->baseline.modelindex;
model = cl.model_precache[modnum];
if (model != ent->model) {
ent->model = model;
// automatic animation (torches, etc) can be either all together
// or randomized
if (model) {
if (model->synctype == ST_RAND)
ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff;
else
ent->syncbase = 0.0;
} else
forcelink = true; // hack to make null model players work
if (num > 0 && num <= cl.maxclients) {
if (!ent->skin)
ent->skin = Skin_NewTempSkin ();
if (ent->skin)
CL_NewTranslation (num - 1, ent->skin);
}
}
if (bits & U_FRAME)
ent->frame = MSG_ReadByte (net_message);
else
@ -509,50 +532,49 @@ CL_ParseUpdate (int bits)
else
state->msg_angles[0][2] = state->baseline.angles[2];
if (bits & U_NOLERP)
if (bits & U_STEP) //FIXME lerping (see fitzquake)
forcelink = true;
// QSG Start
if (bits & U_ALPHA)
state->alpha = MSG_ReadByte (net_message);
else
if (cl.protocol == PROTOCOL_FITZQUAKE) {
if (bits & U_ALPHA)
state->alpha = MSG_ReadByte(net_message);
else
state->alpha = state->baseline.alpha;
if (bits & U_FRAME2)
ent->frame |= MSG_ReadByte(net_message) << 8;
if (bits & U_MODEL2)
modnum |= MSG_ReadByte(net_message) << 8;
if (bits & U_LERPFINISH) {
MSG_ReadByte (net_message); //FIXME ignored for now. see fitzquake
}
} else {
state->alpha = state->baseline.alpha;
if (bits & U_SCALE)
state->scale = MSG_ReadByte (net_message);
else
state->scale = state->baseline.scale;
if (bits & U_EFFECTS2)
state->effects = (state->effects & 0xFF) |
(MSG_ReadByte (net_message) << 8);
if (bits & U_GLOWSIZE)
state->glow_size = MSG_ReadByte (net_message);
else
state->glow_size = state->baseline.glow_size;
if (bits & U_GLOWCOLOR)
state->glow_color = MSG_ReadByte (net_message);
else
state->glow_color = state->baseline.glow_color;
if (bits & U_COLORMOD)
state->colormod = MSG_ReadByte (net_message);
else
state->colormod = state->baseline.colormod;
}
if (!(bits & U_EXTEND2))
goto link;
model = cl.model_precache[modnum];
if (model != ent->model) {
ent->model = model;
// automatic animation (torches, etc) can be either all together
// or randomized
if (model) {
if (model->synctype == ST_RAND)
ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff;
else
ent->syncbase = 0.0;
} else
forcelink = true; // hack to make null model players work
if (num > 0 && num <= cl.maxclients) {
if (!ent->skin)
ent->skin = Skin_NewTempSkin ();
if (ent->skin)
CL_NewTranslation (num - 1, ent->skin);
}
}
if (bits & U_GLOWTRAIL)
state->effects |= EF_GLOWTRAIL;
if (bits & U_FRAME2)
ent->frame = (ent->frame & 0xFF) | (MSG_ReadByte (net_message) << 8);
// QSG End
link:
if (forcelink) { // didn't have an update last message
VectorCopy (state->msg_origins[0], state->msg_origins[1]);
VectorCopy (state->msg_origins[0], ent->origin);
@ -563,18 +585,33 @@ link:
}
static void
CL_ParseBaseline (cl_entity_state_t *state)
CL_ParseBaseline (cl_entity_state_t *state, int version)
{
state->baseline.modelindex = MSG_ReadByte (net_message);
state->baseline.frame = MSG_ReadByte (net_message);
int bits = 0;
if (version == 2)
bits = MSG_ReadByte (net_message);
if (bits & B_LARGEMODEL)
state->baseline.modelindex = MSG_ReadShort (net_message);
else
state->baseline.modelindex = MSG_ReadByte (net_message);
if (bits & B_LARGEFRAME)
state->baseline.frame = MSG_ReadShort (net_message);
else
state->baseline.frame = MSG_ReadByte (net_message);
state->baseline.colormap = MSG_ReadByte (net_message);
state->baseline.skin = MSG_ReadByte (net_message);
MSG_ReadCoordAngleV (net_message, state->baseline.origin,
state->baseline.angles);
// LordHavoc: set up baseline for new effects (alpha, colormod, etc)
state->baseline.alpha = 255;
if (bits & B_ALPHA)
state->baseline.alpha = MSG_ReadByte (net_message);
else
state->baseline.alpha = 255;//FIXME alpha
state->baseline.scale = 16;
state->baseline.glow_size = 0;
state->baseline.glow_color = 254;
@ -587,9 +624,16 @@ CL_ParseBaseline (cl_entity_state_t *state)
Server information pertaining to only this client
*/
static void
CL_ParseClientdata (int bits)
CL_ParseClientdata (void)
{
int i, j;
int bits;
bits = (uint16_t) MSG_ReadShort (net_message);
if (bits & SU_EXTEND1)
bits |= MSG_ReadByte (net_message) << 16;
if (bits & SU_EXTEND2)
bits |= MSG_ReadByte (net_message) << 24;
if (bits & SU_VIEWHEIGHT)
cl.viewheight = ((signed char) MSG_ReadByte (net_message));
@ -614,6 +658,12 @@ CL_ParseClientdata (int bits)
cl.mvelocity[0][i] = 0;
}
//FIXME
//if (!VectorCompare (v_punchangles[0], cl.punchangle[0])) {
// VectorCopy (v_punchangles[0], v_punchangles[1]);
// VectorCopy (cl.punchangle, v_punchangles[0]);
//}
// [always sent] if (bits & SU_ITEMS)
i = MSG_ReadLong (net_message);
@ -684,10 +734,33 @@ CL_ParseClientdata (int bits)
Sbar_Changed ();
}
}
if (bits & SU_WEAPON2)
cl.stats[STAT_WEAPON] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_ARMOR2)
cl.stats[STAT_ARMOR] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_AMMO2)
cl.stats[STAT_AMMO] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_SHELLS2)
cl.stats[STAT_SHELLS] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_NAILS2)
cl.stats[STAT_NAILS] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_ROCKETS2)
cl.stats[STAT_ROCKETS] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_CELLS2)
cl.stats[STAT_CELLS] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_WEAPONFRAME2)
cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte (net_message) << 8;
if (bits & SU_WEAPONALPHA) {
byte alpha = MSG_ReadByte (net_message);
cl.viewent.colormod[3] = ENTALPHA_DECODE (alpha);
} else {
cl.viewent.colormod[3] = 1.0;
}
}
static void
CL_ParseStatic (void)
CL_ParseStatic (int version)
{
cl_entity_state_t state;
entity_t *ent;
@ -698,11 +771,12 @@ CL_ParseStatic (void)
Host_Error ("Too many static entities");
ent = &cl_static_entities[i];
cl.num_statics++;
CL_ParseBaseline (&state);
CL_ParseBaseline (&state, version);
// copy it to the current state
VectorCopy (state.baseline.origin, ent->origin);
VectorCopy (state.baseline.angles, ent->angles);
//FIXME alpha & lerp
ent->model = cl.model_precache[state.baseline.modelindex];
ent->frame = state.baseline.frame;
ent->colormap = vid.colormap8;
@ -717,20 +791,23 @@ CL_ParseStatic (void)
ent->colormod[2] = ((float) (state.baseline.colormod & 3)) *
(1.0 / 3.0);
}
ent->colormod[3] = state.baseline.alpha / 255.0;
ent->colormod[3] = ENTALPHA_DECODE (state.baseline.alpha);
ent->scale = state.baseline.scale / 16.0;
R_AddEfrags (ent);
}
static void
CL_ParseStaticSound (void)
CL_ParseStaticSound (int version)
{
int sound_num, vol, atten;
vec3_t org;
MSG_ReadCoordV (net_message, org);
sound_num = MSG_ReadByte (net_message);
if (version == 2)
sound_num = MSG_ReadShort (net_message);
else
sound_num = MSG_ReadByte (net_message);
vol = MSG_ReadByte (net_message);
atten = MSG_ReadByte (net_message);
@ -747,6 +824,7 @@ void
CL_ParseServerMessage (void)
{
int cmd, i;
const char *str;
// if recording demos, copy the message out
if (cl_shownet->int_val == 1)
@ -770,13 +848,13 @@ CL_ParseServerMessage (void)
return; // end of message
}
// if the high bit of the command byte is set, it is a fast update
if (cmd & 128) {
if (cmd & U_SIGNAL) {
SHOWNET ("fast update");
CL_ParseUpdate (cmd & 127);
CL_ParseUpdate (cmd & ~U_SIGNAL);
continue;
}
SHOWNET (svc_strings[cmd]);
SHOWNET (va ("%s(%d)", svc_strings[cmd], cmd));
// other commands
switch (cmd) {
@ -794,15 +872,16 @@ CL_ParseServerMessage (void)
break;
case svc_clientdata:
i = MSG_ReadShort (net_message);
CL_ParseClientdata (i);
CL_ParseClientdata ();
break;
case svc_version:
i = MSG_ReadLong (net_message);
if (i != PROTOCOL_VERSION)
if (i != PROTOCOL_NETQUAKE && i!= PROTOCOL_FITZQUAKE)
Host_Error ("CL_ParseServerMessage: Server is protocol %i "
"instead of %i\n", i, PROTOCOL_VERSION);
"instead of %i or %i\n", i, PROTOCOL_NETQUAKE,
PROTOCOL_FITZQUAKE);
cl.protocol = i;
break;
case svc_disconnect:
@ -813,7 +892,12 @@ CL_ParseServerMessage (void)
break;
case svc_centerprint:
Sbar_CenterPrint (MSG_ReadString (net_message));
str = MSG_ReadString (net_message);
if (strcmp (str, centerprint->str)) {
dstring_copystr (centerprint, str);
//FIXME logging
}
Sbar_CenterPrint (str);
break;
case svc_stufftext:
@ -844,6 +928,7 @@ CL_ParseServerMessage (void)
Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
strcpy (r_lightstyle[i].map, MSG_ReadString (net_message));
r_lightstyle[i].length = strlen (r_lightstyle[i].map);
// FIXME extra info
break;
case svc_sound:
@ -896,10 +981,10 @@ CL_ParseServerMessage (void)
case svc_spawnbaseline:
i = MSG_ReadShort (net_message);
// must use CL_EntityNum () to force cl.num_entities up
CL_ParseBaseline (CL_EntityNum (i));
CL_ParseBaseline (CL_EntityNum (i), 1);
break;
case svc_spawnstatic:
CL_ParseStatic ();
CL_ParseStatic (1);
break;
case svc_temp_entity:
CL_ParseTEnt ();
@ -942,7 +1027,7 @@ CL_ParseServerMessage (void)
break;
case svc_spawnstaticsound:
CL_ParseStaticSound ();
CL_ParseStaticSound (1);
break;
case svc_cdtrack:
@ -967,7 +1052,12 @@ CL_ParseServerMessage (void)
r_force_fullscreen = 1;
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
Sbar_CenterPrint (MSG_ReadString (net_message));
str = MSG_ReadString (net_message);
if (strcmp (str, centerprint->str)) {
dstring_copystr (centerprint, str);
//FIXME logging
}
Sbar_CenterPrint (str);
break;
case svc_cutscene:
@ -975,12 +1065,47 @@ CL_ParseServerMessage (void)
r_force_fullscreen = 1;
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
Sbar_CenterPrint (MSG_ReadString (net_message));
str = MSG_ReadString (net_message);
if (strcmp (str, centerprint->str)) {
dstring_copystr (centerprint, str);
//FIXME logging
}
Sbar_CenterPrint (str);
break;
case svc_sellscreen:
Cmd_ExecuteString ("help", src_command);
break;
// PROTOCOL_FITZQUAKE
case svc_skybox:
R_LoadSkys (MSG_ReadString(net_message));
break;
case svc_bf:
Cmd_ExecuteString ("bf", src_command);
break;
case svc_fog:
{ //FIXME implement
float density, red, green, blue, time;
density = MSG_ReadByte (net_message) / 255.0;
red = MSG_ReadByte (net_message) / 255.0;
green = MSG_ReadByte (net_message) / 255.0;
blue = MSG_ReadByte (net_message) / 255.0;
time = MSG_ReadShort (net_message) / 100.0;
time = max (0.0, time);
}
break;
case svc_spawnbaseline2:
i = MSG_ReadShort (net_message);
// must use CL_EntityNum() to force cl.num_entities up
CL_ParseBaseline (CL_EntityNum(i), 2);
break;
case svc_spawnstatic2:
CL_ParseStatic (2);
break;
case svc_spawnstaticsound2:
CL_ParseStaticSound (2);
break;
}
}
}

View file

@ -112,6 +112,7 @@ cvar_t *host_mem_size;
cvar_t *host_framerate;
cvar_t *host_speeds;
cvar_t *max_edicts;
cvar_t *sys_ticrate;
cvar_t *serverprofile;
@ -258,6 +259,8 @@ Host_InitLocal (void)
host_speeds =
Cvar_Get ("host_speeds", "0", CVAR_NONE, NULL,
"set for running times");
max_edicts = Cvar_Get ("max_edicts", "1024", CVAR_NONE, NULL,
"maximum server edicts");
sys_ticrate = Cvar_Get ("sys_ticrate", "0.05", CVAR_NONE, NULL, "None");
serverprofile = Cvar_Get ("serverprofile", "0", CVAR_NONE, NULL, "None");

View file

@ -49,8 +49,36 @@ server_static_t svs;
char localmodels[MAX_MODELS][5]; // inline model names for precache
int sv_protocol = PROTOCOL_FITZQUAKE;
entity_state_t baselines[MAX_EDICTS];
static void
SV_Protocol_f (void)
{
int i;
switch (Cmd_Argc ()) {
case 1:
Sys_Printf ("\"sv_protocol\" is \"%i\"\n", sv_protocol);
break;
case 2:
i = atoi (Cmd_Argv (1));
if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) {
Sys_Printf ("sv_protocol must be %i or %i\n",
PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE);
} else {
sv_protocol = i;
if (sv.active)
Sys_Printf ("changes will not take effect until the next "
"level load.\n");
}
break;
default:
Sys_Printf ("usage: sv_protocol <protocol>\n");
break;
}
}
void
SV_Init (void)
@ -73,6 +101,9 @@ SV_Init (void)
sv_aim = Cvar_Get ("sv_aim", "0.93", CVAR_NONE, NULL, "None");
sv_nostep = Cvar_Get ("sv_nostep", "0", CVAR_NONE, NULL, "None");
Cmd_AddCommand ("sv_protocol", SV_Protocol_f, "set the protocol to be "
"used after the next map load");
for (i = 0; i < MAX_MODELS; i++)
snprintf (localmodels[i], sizeof (localmodels[i]), "*%i", i);
}
@ -149,14 +180,25 @@ SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
ent = NUM_FOR_EDICT (&sv_pr_state, entity);
channel = (ent << 3) | channel;
field_mask = 0;
if (volume != DEFAULT_SOUND_PACKET_VOLUME)
field_mask |= SND_VOLUME;
if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
field_mask |= SND_ATTENUATION;
if (ent >= 8192) {
if (sv.protocol == PROTOCOL_NETQUAKE)
return; //don't send any info protocol can't support
else
field_mask |= SND_LARGEENTITY;
}
if (sound_num >= 256 || channel >= 8) {
if (sv.protocol == PROTOCOL_NETQUAKE)
return; //don't send any info protocol can't support
else
field_mask |= SND_LARGESOUND;
}
// directed messages go to only the entity on which they are targeted
MSG_WriteByte (&sv.datagram, svc_sound);
MSG_WriteByte (&sv.datagram, field_mask);
@ -164,8 +206,18 @@ SV_StartSound (edict_t *entity, int channel, const char *sample, int volume,
MSG_WriteByte (&sv.datagram, volume);
if (field_mask & SND_ATTENUATION)
MSG_WriteByte (&sv.datagram, attenuation * 64);
MSG_WriteShort (&sv.datagram, channel);
MSG_WriteByte (&sv.datagram, sound_num);
if (field_mask & SND_LARGEENTITY) {
MSG_WriteShort (&sv.datagram, ent);
MSG_WriteByte (&sv.datagram, channel);
} else {
MSG_WriteShort (&sv.datagram, (ent << 3 | channel));
}
if (field_mask & SND_LARGESOUND)
MSG_WriteShort (&sv.datagram, sound_num);
else
MSG_WriteByte (&sv.datagram, sound_num);
VectorBlend (SVvector (entity, mins), SVvector (entity, maxs), 0.5, v);
VectorAdd (v, SVvector (entity, origin), v);
MSG_WriteCoordV (&sv.datagram, v);
@ -184,6 +236,7 @@ SV_SendServerinfo (client_t *client)
{
const char **s;
char message[2048];
int i;
MSG_WriteByte (&client->message, svc_print);
snprintf (message, sizeof (message), "%c\nVersion %s server (%i CRC)", 2,
@ -191,7 +244,7 @@ SV_SendServerinfo (client_t *client)
MSG_WriteString (&client->message, message);
MSG_WriteByte (&client->message, svc_serverinfo);
MSG_WriteLong (&client->message, PROTOCOL_VERSION);
MSG_WriteLong (&client->message, sv.protocol);
MSG_WriteByte (&client->message, svs.maxclients);
if (!coop->int_val && deathmatch->int_val)
@ -201,15 +254,19 @@ SV_SendServerinfo (client_t *client)
snprintf (message, sizeof (message), "%s",
PR_GetString (&sv_pr_state, SVstring (sv.edicts, message)));
message[sizeof (message) - 1] = 0;
MSG_WriteString (&client->message, message);
for (s = sv.model_precache + 1; *s; s++)
MSG_WriteString (&client->message, *s);
// send only the first 256 model and sound precaches if protocol 15
for (i = 0, s = sv.model_precache + 1; *s; s++, i++)
if (sv.protocol != PROTOCOL_NETQUAKE || i < 256)
MSG_WriteString (&client->message, *s);
MSG_WriteByte (&client->message, 0);
for (s = sv.sound_precache + 1; *s; s++)
MSG_WriteString (&client->message, *s);
for (i = 0, s = sv.sound_precache + 1; *s; s++, i++)
if (sv.protocol != PROTOCOL_NETQUAKE || i < 256)
MSG_WriteString (&client->message, *s);
MSG_WriteByte (&client->message, 0);
// send music
@ -385,6 +442,7 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
float miss;
vec3_t org;
edict_t *ent;
entity_state_t *baseline;
// find the client's PVS
VectorAdd (SVvector (clent, origin), SVvector (clent, view_ofs), org);
@ -393,6 +451,8 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
// send over all entities (excpet the client) that touch the pvs
ent = NEXT_EDICT (&sv_pr_state, sv.edicts);
for (e = 1; e < sv.num_edicts; e++, ent = NEXT_EDICT (&sv_pr_state, ent)) {
baseline = (entity_state_t*) ent->data;
// ignore if not touching a PV leaf
if (ent != clent) { // clent is ALWAYS sent
// ignore ents without visible models
@ -400,6 +460,11 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
!*PR_GetString (&sv_pr_state, SVstring (ent, model)))
continue;
// don't send model > 255 for protocol 15
if (sv.protocol == PROTOCOL_NETQUAKE
&& (int) SVfloat (ent, modelindex) & 0xFF00)
continue;
for (i = 0; i < ent->num_leafs; i++)
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7)))
break;
@ -408,51 +473,79 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
continue; // not visible
}
if (msg->maxsize - msg->cursize < 16) {
if (msg->cursize + 24 > msg->maxsize) {
Sys_Printf ("packet overflow\n");
return;
}
// send an update
bits = 0;
for (i = 0; i < 3; i++) {
miss = SVvector (ent, origin)[i] -
((entity_state_t*)ent->data)->origin[i];
miss = SVvector (ent, origin)[i] - baseline->origin[i];
if (miss < -0.1 || miss > 0.1)
bits |= U_ORIGIN1 << i;
}
if (SVvector (ent, angles)[0] !=
((entity_state_t*)ent->data)->angles[0])
if (SVvector (ent, angles)[0] != baseline->angles[0])
bits |= U_ANGLE1;
if (SVvector (ent, angles)[1] !=
((entity_state_t*)ent->data)->angles[1])
if (SVvector (ent, angles)[1] != baseline->angles[1])
bits |= U_ANGLE2;
if (SVvector (ent, angles)[2] !=
((entity_state_t*)ent->data)->angles[2])
if (SVvector (ent, angles)[2] != baseline->angles[2])
bits |= U_ANGLE3;
if (SVfloat (ent, movetype) == MOVETYPE_STEP)
bits |= U_NOLERP; // don't mess up the step animation
bits |= U_STEP; // don't mess up the step animation
if (((entity_state_t*)ent->data)->colormap != SVfloat (ent, colormap))
if (baseline->colormap != SVfloat (ent, colormap))
bits |= U_COLORMAP;
if (((entity_state_t*)ent->data)->skin != SVfloat (ent, skin))
if (baseline->skin != SVfloat (ent, skin))
bits |= U_SKIN;
if (((entity_state_t*)ent->data)->frame != SVfloat (ent, frame))
if (baseline->frame != SVfloat (ent, frame))
bits |= U_FRAME;
if (((entity_state_t*)ent->data)->effects != SVfloat (ent, effects))
if (baseline->effects != SVfloat (ent, effects))
bits |= U_EFFECTS;
if (((entity_state_t*)ent->data)->modelindex != SVfloat (ent,
modelindex))
if (baseline->modelindex != SVfloat (ent, modelindex))
bits |= U_MODEL;
#if 0
//FIXME finish porting to QF
if (pr_alpha_supported) {
// TODO: find a cleaner place to put this code
eval_t *val;
val = GetEdictFieldValue(ent, "alpha");
if (val)
ent->alpha = ENTALPHA_ENCODE(val->_float);
}
//don't send invisible entities unless they have effects
if (ent->alpha == ENTALPHA_ZERO && !ent->v.effects)
continue;
#endif
if (sv.protocol != PROTOCOL_NETQUAKE) {
//FIXME
//if (ent->baseline.alpha != ent->alpha)
// bits |= U_ALPHA;
if (bits & U_FRAME && (int) SVfloat (ent, frame) & 0xFF00)
bits |= U_FRAME2;
if (bits & U_MODEL && (int) SVfloat (ent, modelindex) & 0xFF00)
bits |= U_MODEL2;
//if (ent->sendinterval) FIXME
// bits |= U_LERPFINISH;
if (bits >= 65536)
bits |= U_EXTEND1;
if (bits >= 16777216)
bits |= U_EXTEND2;
}
if (e >= 256)
bits |= U_LONGENTITY;
@ -464,6 +557,11 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
if (bits & U_MOREBITS)
MSG_WriteByte (msg, bits >> 8);
if (bits & U_EXTEND1)
MSG_WriteByte (msg, bits >> 16);
if (bits & U_EXTEND2)
MSG_WriteByte (msg, bits >> 24);
if (bits & U_LONGENTITY)
MSG_WriteShort (msg, e);
else
@ -491,6 +589,16 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
MSG_WriteCoord (msg, SVvector (ent, origin)[2]);
if (bits & U_ANGLE3)
MSG_WriteAngle (msg, SVvector (ent, angles)[2]);
//FIXME
//if (bits & U_ALPHA)
// MSG_WriteByte(msg, ent->alpha);
if (bits & U_FRAME2)
MSG_WriteByte(msg, (int) SVfloat (ent, frame) >> 8);
if (bits & U_MODEL2)
MSG_WriteByte(msg, (int) SVfloat (ent, modelindex) >> 8);
if (bits & U_LERPFINISH)
MSG_WriteByte(msg, rint ((SVfloat (ent, nextthink) - sv.time) * 255));
}
}
@ -512,6 +620,9 @@ SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
int bits, items, i;
vec3_t v;
edict_t *other;
const char *weaponmodel;
weaponmodel = PR_GetString (&sv_pr_state, SVstring (ent, weaponmodel));
// send a damage message
if (SVfloat (ent, dmg_take) || SVfloat (ent, dmg_save)) {
@ -577,11 +688,42 @@ SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
// if (SVfloat (ent, weapon))
bits |= SU_WEAPON;
if (sv.protocol != PROTOCOL_NETQUAKE) {
if (bits & SU_WEAPON && SV_ModelIndex(weaponmodel) & 0xFF00)
bits |= SU_WEAPON2;
if ((int) SVfloat (ent, armorvalue) & 0xFF00)
bits |= SU_ARMOR2;
if ((int) SVfloat (ent, currentammo) & 0xFF00)
bits |= SU_AMMO2;
if ((int) SVfloat (ent, ammo_shells) & 0xFF00)
bits |= SU_SHELLS2;
if ((int) SVfloat (ent, ammo_nails) & 0xFF00)
bits |= SU_NAILS2;
if ((int) SVfloat (ent, ammo_rockets) & 0xFF00)
bits |= SU_ROCKETS2;
if ((int) SVfloat (ent, ammo_cells) & 0xFF00)
bits |= SU_CELLS2;
if (bits & SU_WEAPONFRAME && (int) SVfloat (ent, weaponframe) & 0xFF00)
bits |= SU_WEAPONFRAME2;
//FIXME
//if (bits & SU_WEAPON && ent->alpha != ENTALPHA_DEFAULT)
// bits |= SU_WEAPONALPHA; //for now, weaponalpha = client entity alpha
if (bits >= 65536)
bits |= SU_EXTEND1;
if (bits >= 16777216)
bits |= SU_EXTEND2;
}
// send the data
MSG_WriteByte (msg, svc_clientdata);
MSG_WriteShort (msg, bits);
if (bits & SU_EXTEND1)
MSG_WriteByte(msg, bits>>16);
if (bits & SU_EXTEND2)
MSG_WriteByte(msg, bits>>24);
if (bits & SU_VIEWHEIGHT)
MSG_WriteByte (msg, SVvector (ent, view_ofs)[2]);
@ -603,8 +745,7 @@ SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
if (bits & SU_ARMOR)
MSG_WriteByte (msg, SVfloat (ent, armorvalue));
if (bits & SU_WEAPON)
MSG_WriteByte (msg, SV_ModelIndex (PR_GetString (&sv_pr_state, SVstring
(ent, weaponmodel))));
MSG_WriteByte (msg, SV_ModelIndex (weaponmodel));
MSG_WriteShort (msg, SVfloat (ent, health));
MSG_WriteByte (msg, SVfloat (ent, currentammo));
@ -623,6 +764,26 @@ SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
}
}
}
if (bits & SU_WEAPON2)
MSG_WriteByte (msg, SV_ModelIndex(weaponmodel) >> 8);
if (bits & SU_ARMOR2)
MSG_WriteByte (msg, (int) SVfloat (ent, armorvalue) >> 8);
if (bits & SU_AMMO2)
MSG_WriteByte (msg, (int) SVfloat (ent, currentammo) >> 8);
if (bits & SU_SHELLS2)
MSG_WriteByte (msg, (int) SVfloat (ent, ammo_shells) >> 8);
if (bits & SU_NAILS2)
MSG_WriteByte (msg, (int) SVfloat (ent, ammo_nails) >> 8);
if (bits & SU_ROCKETS2)
MSG_WriteByte (msg, (int) SVfloat (ent, ammo_rockets) >> 8);
if (bits & SU_CELLS2)
MSG_WriteByte (msg, (int) SVfloat (ent, ammo_cells) >> 8);
if (bits & SU_WEAPONFRAME2)
MSG_WriteByte (msg, (int) SVfloat (ent, weaponframe) >> 8);
// FIXME
//if (bits & SU_WEAPONALPHA)
// MSG_WriteByte (msg, ent->alpha); //for now, weaponalpha = client entity alpha
}
static qboolean
@ -635,6 +796,9 @@ SV_SendClientDatagram (client_t *client)
msg.maxsize = sizeof (buf);
msg.cursize = 0;
if (strcmp (client->netconnection->address, "LOCAL") != 0)
msg.maxsize = DATAGRAM_MTU;
MSG_WriteByte (&msg, svc_time);
MSG_WriteFloat (&msg, sv.time);
@ -799,46 +963,81 @@ SV_CreateBaseline (void)
{
int entnum;
edict_t *svent;
entity_state_t *baseline;
int bits;
for (entnum = 0; entnum < sv.num_edicts; entnum++) {
// get the current server version
svent = EDICT_NUM (&sv_pr_state, entnum);
baseline = (entity_state_t *) svent->data;
if (svent->free)
continue;
if (entnum > svs.maxclients && !SVfloat (svent, modelindex))
continue;
// create entity baseline
VectorCopy (SVvector (svent, origin),
((entity_state_t *) svent->data)->origin);
VectorCopy (SVvector (svent, angles),
((entity_state_t *) svent->data)->angles);
((entity_state_t *) svent->data)->frame = SVfloat (svent, frame);
((entity_state_t *) svent->data)->skin = SVfloat (svent, skin);
VectorCopy (SVvector (svent, origin), baseline->origin);
VectorCopy (SVvector (svent, angles), baseline->angles);
baseline->frame = SVfloat (svent, frame);
baseline->skin = SVfloat (svent, skin);
if (entnum > 0 && entnum <= svs.maxclients) {
((entity_state_t *) svent->data)->colormap = entnum;
((entity_state_t *) svent->data)->modelindex = SV_ModelIndex
("progs/player.mdl");
baseline->colormap = entnum;
baseline->modelindex = SV_ModelIndex ("progs/player.mdl");
baseline->alpha = ENTALPHA_DEFAULT;
} else {
((entity_state_t *) svent->data)->colormap = 0;
((entity_state_t *) svent->data)->modelindex =
SV_ModelIndex (PR_GetString (&sv_pr_state, SVstring (svent,
model)));
const char *model;
model = PR_GetString (&sv_pr_state, SVstring (svent, model));
baseline->colormap = 0;
baseline->modelindex = SV_ModelIndex (model);
baseline->alpha = ENTALPHA_DEFAULT;
}
bits = 0;
if (sv.protocol == PROTOCOL_NETQUAKE) {
//still want to send baseline in PROTOCOL_NETQUAKE, so reset
//these values
if (baseline->modelindex & 0xFF00)
baseline->modelindex = 0;
if (baseline->frame & 0xFF00)
baseline->frame = 0;
baseline->alpha = ENTALPHA_DEFAULT;
} else {
if (baseline->modelindex & 0xFF00)
bits |= B_LARGEMODEL;
if (baseline->frame & 0xFF00)
bits |= B_LARGEFRAME;
if (baseline->alpha != ENTALPHA_DEFAULT)
bits |= B_ALPHA;
}
// add to the message
MSG_WriteByte (&sv.signon, svc_spawnbaseline);
if (bits)
MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
else
MSG_WriteByte (&sv.signon, svc_spawnbaseline);
MSG_WriteShort (&sv.signon, entnum);
MSG_WriteByte (&sv.signon,
((entity_state_t *) svent->data)->modelindex);
MSG_WriteByte (&sv.signon, ((entity_state_t *) svent->data)->frame);
MSG_WriteByte (&sv.signon, ((entity_state_t *) svent->data)->colormap);
MSG_WriteByte (&sv.signon, ((entity_state_t *) svent->data)->skin);
if (bits)
MSG_WriteByte (&sv.signon, bits);
MSG_WriteCoordAngleV (&sv.signon,
((entity_state_t *) svent->data)->origin,
((entity_state_t *) svent->data)->angles);
if (bits & B_LARGEMODEL)
MSG_WriteShort (&sv.signon, baseline->modelindex);
else
MSG_WriteByte (&sv.signon, baseline->modelindex);
if (bits & B_LARGEFRAME)
MSG_WriteShort (&sv.signon, baseline->frame);
else
MSG_WriteByte (&sv.signon, baseline->frame);
MSG_WriteByte (&sv.signon, baseline->colormap);
MSG_WriteByte (&sv.signon, baseline->skin);
MSG_WriteCoordAngleV (&sv.signon, baseline->origin, baseline->angles);
if (bits & B_ALPHA)
MSG_WriteByte (&sv.signon, baseline->alpha);
}
}
@ -935,12 +1134,14 @@ SV_SpawnServer (const char *server)
strcpy (sv.name, server);
sv.protocol = sv_protocol;
// load progs to get entity field count
sv.max_edicts = MAX_EDICTS;
sv.max_edicts = bound (MIN_EDICTS, max_edicts->int_val, MAX_EDICTS);
SV_LoadProgs ();
// init the data field of the edicts
for (i = 0; i < MAX_EDICTS; i++) {
for (i = 0; i < sv.max_edicts; i++) {
ent = EDICT_NUM (&sv_pr_state, i);
ent->data = &baselines[i];
}
@ -1034,6 +1235,10 @@ SV_SpawnServer (const char *server)
// create a baseline for more efficient communications
SV_CreateBaseline ();
if (sv.signon.cursize > 8000-2)
Sys_Printf ("%i byte signon buffer exceeds standard limit of 7998.\n",
sv.signon.cursize);
// send serverinfo to all connected clients
for (i = 0, host_client = svs.clients; i < svs.maxclients; i++,
host_client++)

View file

@ -128,6 +128,7 @@ qboolean
SV_RunThink (edict_t *ent)
{
float thinktime;
float oldframe;
do {
thinktime = SVfloat (ent, nextthink);
@ -138,12 +139,27 @@ 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.
oldframe = SVfloat (ent, frame);
SVfloat (ent, nextthink) = 0;
*sv_globals.time = thinktime;
sv_pr_think (ent);
if (ent->free)
return false;
#if 0 //FIXME
ent->sendinterval = false;
if (SVfloat (ent, nextthink)
&& (SVfloat (ent, movetype) == MOVETYPE_STEP
|| SVfloat (ent, frame) != oldframe)) {
int i;
i = rint ((SVfloat (ent, nextthink) - thinktime) * 255);
if (i >= 0 && i < 256 && i != 25 && i != 26) {
//25 and 26 are close enough to 0.1 to not send
ent->sendinterval = true;
}
}
#endif
} while (0);
return true;
@ -383,10 +399,11 @@ SV_Push (edict_t *pusher, vec3_t move)
float solid_save;
int num_moved, i, e;
edict_t *check, *block;
edict_t *moved_edict[MAX_EDICTS];
edict_t **moved_edict;
vec3_t entorig;
vec3_t mins, maxs, pushorig;
vec3_t moved_from[MAX_EDICTS];
vec3_t *moved_from;
int mark;
VectorAdd (SVvector (pusher, absmin), move, mins);
VectorAdd (SVvector (pusher, absmax), move, maxs);
@ -397,6 +414,10 @@ SV_Push (edict_t *pusher, vec3_t move)
VectorAdd (SVvector (pusher, origin), move, SVvector (pusher, origin));
SV_LinkEdict (pusher, false);
mark = Hunk_LowMark ();
moved_edict = Hunk_Alloc (sv.num_edicts * sizeof (edict_t *));
moved_from = Hunk_Alloc (sv.num_edicts * sizeof (vec_t));
// see if any solid entities are inside the final position
num_moved = 0;
check = NEXT_EDICT (&sv_pr_state, sv.edicts);
@ -473,8 +494,10 @@ SV_Push (edict_t *pusher, vec3_t move)
VectorCopy (moved_from[i], SVvector (moved_edict[i], origin));
SV_LinkEdict (moved_edict[i], false);
}
Hunk_FreeToLowMark (mark);
return false;
}
Hunk_FreeToLowMark (mark);
return true;
}

View file

@ -262,10 +262,16 @@ PF_setmodel (progs_t *pr)
mod = sv.models[(int) SVfloat (e, modelindex)]; // Mod_ForName (m, true);
if (mod)
SetMinMaxSize (pr, e, mod->mins, mod->maxs, true);
else
if (mod) {
// FIXME disabled for now as setting clipmins/maxs is currently
// too messy
//if (mod->type == mod_brush)
// SetMinMaxSize (pr, e, mod->clipmins, mod->clipmaxs, true);
//else
SetMinMaxSize (pr, e, mod->mins, mod->maxs, true);
} else {
SetMinMaxSize (pr, e, vec3_origin, vec3_origin, true);
}
}
/*
@ -370,6 +376,7 @@ PF_ambientsound (progs_t *pr)
float *pos;
float vol, attenuation;
int soundnum;
int large = false;
pos = P_VECTOR (pr, 0);
samp = P_GSTRING (pr, 1);
@ -385,11 +392,20 @@ PF_ambientsound (progs_t *pr)
Sys_Printf ("no precache: %s\n", samp);
return;
}
if (soundnum > 255) {
if (sv.protocol == PROTOCOL_NETQUAKE)
return;
large = true;
}
// add an svc_spawnambient command to the level signon packet
MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
MSG_WriteByte (&sv.signon,
large ? svc_spawnstaticsound2 : svc_spawnstaticsound);
MSG_WriteCoordV (&sv.signon, pos);
MSG_WriteByte (&sv.signon, soundnum);
if (large)
MSG_WriteShort (&sv.signon, soundnum);
else
MSG_WriteByte (&sv.signon, soundnum);
MSG_WriteByte (&sv.signon, vol * 255);
MSG_WriteByte (&sv.signon, attenuation * 64);
@ -1141,22 +1157,57 @@ PF_makestatic (progs_t *pr)
{
const char *model;
edict_t *ent;
int bits = 0;
ent = P_EDICT (pr, 0);
MSG_WriteByte (&sv.signon, svc_spawnstatic);
//if (ent->alpha == ENTALPHA_ZERO) { //FIXME
// //johnfitz -- don't send invisible static entities
// goto nosend;
//}
model = PR_GetString (pr, SVstring (ent, model));
MSG_WriteByte (&sv.signon, SV_ModelIndex (model));
if (sv.protocol == PROTOCOL_NETQUAKE) {
if (SV_ModelIndex (model) & 0xff00
|| (int) SVfloat (ent, frame) & 0xff00)
goto nosend;
} else {
if (SV_ModelIndex (model) & 0xff00)
bits |= B_LARGEMODEL;
if ((int) SVfloat (ent, frame) & 0xff00)
bits |= B_LARGEFRAME;
//FIXME
//if (ent->alpha != ENTALPHA_DEFAULT)
// bits |= B_ALPHA;
}
if (bits) {
MSG_WriteByte (&sv.signon, svc_spawnstatic2);
MSG_WriteByte (&sv.signon, bits);
} else {
MSG_WriteByte (&sv.signon, svc_spawnstatic);
}
if (bits & B_LARGEMODEL)
MSG_WriteShort (&sv.signon, SV_ModelIndex (model));
else
MSG_WriteByte (&sv.signon, SV_ModelIndex (model));
if (bits & B_LARGEFRAME)
MSG_WriteShort (&sv.signon, SVfloat (ent, frame));
else
MSG_WriteByte (&sv.signon, SVfloat (ent, frame));
MSG_WriteByte (&sv.signon, SVfloat (ent, frame));
MSG_WriteByte (&sv.signon, SVfloat (ent, colormap));
MSG_WriteByte (&sv.signon, SVfloat (ent, skin));
MSG_WriteCoordAngleV (&sv.signon, SVvector (ent, origin),
SVvector (ent, angles));
//FIXME
//if (bits & B_ALPHA)
// MSG_WriteByte (&sv.signon, ent->alpha);
// throw the entity away now
nosend:
ED_Free (pr, ent);
}

View file

@ -427,7 +427,10 @@ SV_ReadClientMove (usercmd_t *move)
host_client->num_pings++;
// read current angles
MSG_ReadAngleV (net_message, angle);
if (sv.protocol == PROTOCOL_NETQUAKE)
MSG_ReadAngleV (net_message, angle);
else
MSG_ReadAngle16V (net_message, angle);
VectorCopy (angle, SVvector (host_client->edict, v_angle));

View file

@ -33,6 +33,7 @@
#define __server_h
#include "netchan.h"
#include "qw/bothdefs.h"
#include "qw/pmove.h"
struct client_s;

View file

@ -35,6 +35,7 @@
#include "QF/zone.h"
#include "netchan.h"
#include "qw/bothdefs.h"
#include "qw/protocol.h"
#include "r_local.h"
#include "QF/render.h"

View file

@ -39,6 +39,7 @@
#include "host.h"
#include "netchan.h"
#include "qw/bothdefs.h"
#include "qw/msg_backbuf.h"
#include "qw/protocol.h"