my attempt at android multitouch (csqc can also distinguish separate mice in windows too).

playing around with fragmentation and mtus. added net_mtu to negotiate some mtu size for smaller (or larger) network messages. setting a custom mtu allows for message fragmentation too.
trying to add a reworked deltaing protocol, including all sorts of fun stuff like bbox sizes, and higher ent limits.
added support for content override entities. set the skin field to some (negative) contents value, and you get movable water with prediction and waterwarp and everything, though you likely want a custom qbsp or a shader to get backface culling.
removed some madness with model skins, fixing some weird q3 bugs.
fixed forced-pause-on-start for q2
fixed q3 server to actually accept client packets again.
fixed strftime builtin

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3979 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2012-02-12 05:18:31 +00:00
parent fb35b91e01
commit 9ee7301d32
74 changed files with 3175 additions and 1276 deletions

View file

@ -1577,6 +1577,10 @@ void Q_InitProgs(void)
sv.world.max_edicts = MAX_EDICTS;
sv.world.edict_size = PR_InitEnts(svprogfuncs, sv.world.max_edicts);
if (progstype == PROG_QW)
sv.world.defaultgravityscale = 0;
else
sv.world.defaultgravityscale = 1;
SV_RegisterH2CustomTents();
@ -5607,18 +5611,7 @@ lh_extension_t *checkfteextensioncl(int mask, char *name) //true if the cient ex
lh_extension_t *checkfteextensionsv(char *name) //true if the server supports an protocol extension.
{
int i;
for (i = 0; i < 32; i++)
{
if (svs.fteprotocolextensions & (1<<i))
{
if (QSG_Extensions[i].name) //some were removed
if (!stricmp(name, QSG_Extensions[i].name)) //name matches
return &QSG_Extensions[i];
}
}
return NULL;
return checkfteextensioncl(Net_PextMask(1), name);
}
lh_extension_t *checkextension(char *name)
@ -8326,7 +8319,6 @@ static void QCBUILTIN PF_runclientphys(progfuncs_t *prinst, struct globalvars_s
VectorCopy(ent->v->velocity, pmove.velocity);
VectorCopy(ent->v->maxs, player_maxs);
VectorCopy(ent->v->mins, player_mins);
pmove.hullnum = SV_HullNumForPlayer(ent->xv->hull, ent->v->mins, ent->v->maxs);
pmove.numphysent = 1;
pmove.physents[0].model = sv.world.worldmodel;
@ -9262,7 +9254,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//VM_SV_getextresponse, // #624 string getextresponse(void)
{"sprintf", PF_sprintf, 0, 0, 0, 627, "string(...)" STUB},
{"sprintf", PF_sprintf, 0, 0, 0, 627, "string(...)"},
// {"getsurfacenumpoints",VM_getsurfacenumtriangles,0,0, 0, 628, "float(entity e, float s)" STUB},
// {"getsurfacepoint",VM_getsurfacenumtriangles,0,0, 0, 629, "vector(entity e, float s, float n)" STUB},
@ -9369,10 +9361,10 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any
if (pr_builtin[BuiltinList[i].ebfsnum] == PF_Fixme && builtincount[BuiltinList[i].ebfsnum] == (BuiltinList[i].obsolete?0:1))
{
pr_builtin[BuiltinList[i].ebfsnum] = BuiltinList[i].bifunc;
Con_DPrintf("Enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum);
// Con_DPrintf("Enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum);
}
else if (pr_builtin[i] != BuiltinList[i].bifunc)
Con_DPrintf("Not enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum);
// else if (pr_builtin[i] != BuiltinList[i].bifunc)
// Con_DPrintf("Not enabled %s (%i)\n", BuiltinList[i].name, BuiltinList[i].ebfsnum);
}
}
}
@ -9486,7 +9478,7 @@ void PR_SVExtensionList_f(void)
if (i < 32)
{
if (!(svs.fteprotocolextensions & (1<<i)))
if (!(Net_PextMask(1) & (1<<i)))
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf("^4protocol %s is not supported\n", extlist[i].name);
@ -9955,6 +9947,12 @@ void PR_DumpPlatform_f(void)
{"RF_FRAMETIMESARESTARTTIMES","const float", CS, CSQCRF_FRAMETIMESARESTARTTIMES},
{"RF_NOAUTOADD", "const float", CS, CSQCRF_NOAUTOADD},
{"IE_KEYDOWN", "const float", CS, CSIE_KEYDOWN},
{"IE_KEYUP", "const float", CS, CSIE_KEYUP},
{"IE_MOUSEDELTA", "const float", CS, CSIE_MOUSEDELTA},
{"IE_MOUSEABS", "const float", CS, CSIE_MOUSEABS},
{"IE_ACCELEROMETER", "const float", CS, CSIE_ACCELEROMETER},
{"FILE_READ", "const float", QW|NQ|CS, FRIK_FILE_READ},
{"FILE_APPEND", "const float", QW|NQ|CS, FRIK_FILE_APPEND},
{"FILE_WRITE", "const float", QW|NQ|CS, FRIK_FILE_WRITE},

View file

@ -199,6 +199,7 @@ and the extension fields are added on the end and can have extra vm-specific stu
comfieldentity(tag_entity)\
comfieldfloat(skeletonindex) /*FTE_CSQC_SKELETONOBJECTS*/\
comfieldvector(colormod)\
comfieldvector(glowmod)\
comfieldfloat(pmove_flags)/*EXT_CSQC_1*/\
comfieldfloat(friction)/*DP_...PHYSICS*/\
comfieldfloat(erp)/*DP_...PHYSICS*/\
@ -277,7 +278,6 @@ and the extension fields are added on the end and can have extra vm-specific stu
\
comfieldfloat(drawmask) /*So that the qc can specify all rockets at once or all bannanas at once*/ \
comfieldfunction(predraw, ".void()") /*If present, is called just before it's drawn.*/ \
comfieldvector(glowmod) \
\
comfieldfloat(ideal_pitch)\
comfieldfloat(pitch_speed)

View file

@ -581,7 +581,7 @@ qboolean SV_LoadLevelCache(char *savename, char *level, char *startspot, qboolea
f = FS_OpenVFS(name, "rb", FS_GAME);
if (!f)
{
Con_TPrintf (STL_ERRORCOULDNTOPEN);
Con_Printf ("ERROR: Couldn't load \"%s\"\n", name);
return false;
}
@ -790,35 +790,37 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame)
vfsfile_t *f;
int i;
char comment[SAVEGAME_COMMENT_LENGTH+1];
levelcache_t *cache;
if (!sv.state)
return;
cache = svs.levcache;
while(cache)
if (!dontharmgame)
{
if (!strcmp(cache->mapname, sv.name))
break;
cache = svs.levcache;
while(cache)
{
if (!strcmp(cache->mapname, sv.name))
break;
cache = cache->next;
cache = cache->next;
}
if (!cache) //not visited yet. Let us know that we went there.
{
cache = Z_Malloc(sizeof(levelcache_t)+strlen(sv.name)+1);
cache->mapname = (char *)(cache+1);
strcpy(cache->mapname, sv.name);
cache->gametype = svs.gametype;
cache->next = svs.levcache;
svs.levcache = cache;
}
}
if (!cache) //not visited yet. Let us know that we went there.
{
cache = Z_Malloc(sizeof(levelcache_t)+strlen(sv.name)+1);
cache->mapname = (char *)(cache+1);
strcpy(cache->mapname, sv.name);
cache->gametype = svs.gametype;
cache->next = svs.levcache;
svs.levcache = cache;
}
if (savedir)
Q_snprintfz (name, sizeof(name), "saves/%s/%s", savedir, cache->mapname);
Q_snprintfz (name, sizeof(name), "saves/%s/%s", savedir, sv.name);
else
Q_snprintfz (name, sizeof(name), "saves/%s", cache->mapname);
Q_snprintfz (name, sizeof(name), "saves/%s", sv.name);
COM_DefaultExtension (name, ".lvc", sizeof(name));
FS_CreatePath(name, FS_GAMEONLY);
@ -859,7 +861,7 @@ void SV_SaveLevelCache(char *savedir, qboolean dontharmgame)
VFS_PRINTF (f, "%s\n", comment);
if (!dontharmgame)
{
for (cl = svs.clients, clnum=0; clnum < MAX_CLIENTS; cl++,clnum++)//fake dropping
for (cl = svs.clients, clnum=0; clnum < sv.allocated_client_slots; cl++,clnum++)//fake dropping
{
if (cl->state < cs_spawned && !cl->istobeloaded) //don't drop if they are still connecting
{

View file

@ -76,7 +76,7 @@ typedef struct laggedpacket_s
double time;
struct laggedpacket_s *next;
int length;
unsigned char data[MAX_QWMSGLEN];
unsigned char data[MAX_QWMSGLEN+10];
} laggedpacket_t;
typedef struct
@ -284,14 +284,16 @@ typedef struct
// received from client
// reply
double senttime;
float ping_time;
int move_msecs;
int packetsizein;
int packetsizeout;
vec3_t playerpositions[MAX_CLIENTS];
qboolean playerpresent[MAX_CLIENTS];
packet_entities_t entities; //must come last (mvd states are bigger)
double senttime; //time we sent this frame to the client, for ping calcs
int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale
float ping_time; //how long it took for the client to ack it, may be negativ
int move_msecs; //
int packetsizein; //amount of data received for this frame
int packetsizeout; //amount of data that was sent in the frame
vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag
qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present
packet_entities_t entities; //package containing entity states that were sent in this frame, for deltaing
unsigned int *resendentbits; //the bits of each entity that were sent in this frame
} client_frame_t;
#ifdef Q2SERVER
@ -351,6 +353,7 @@ typedef struct client_s
usercmd_t lastcmd; // for filling in big drops and partial predictions
double localtime; // of last message
qboolean jump_held;
qboolean lockangles; //mod is spamming angle changes, don't do relative changes
float maxspeed; // localized maxspeed
float entgravity; // localized ent gravity
@ -417,6 +420,8 @@ typedef struct client_s
q3client_frame_t *q3frames;
#endif
} frameunion;
packet_entities_t sentents;
unsigned int *pendingentbits;
char downloadfn[MAX_QPATH];
vfsfile_t *download; // file being downloaded
@ -469,7 +474,7 @@ typedef struct client_s
netchan_t netchan;
qboolean isindependant;
int lastsequence_acknoledged;
int lastsequence_acknowledged;
#ifdef VOICECHAT
unsigned int voice_read; /*place in ring*/
@ -507,7 +512,7 @@ typedef struct client_s
unsigned long fteprotocolextensions2;
#endif
unsigned long zquake_extensions;
unsigned int max_net_ents;
unsigned int max_net_ents; /*highest entity number the client can receive (limited by either protocol or client's buffer size)*/
unsigned int maxmodels; /*max models supported by whatever the protocol is*/
enum {
@ -760,10 +765,6 @@ typedef struct
progsnum_t progsnum[MAX_PROGS];
int numprogs;
#ifdef PROTOCOLEXTENSIONS
unsigned long fteprotocolextensions;
unsigned long fteprotocolextensions2;
#endif
struct netprim_s netprim;
qboolean demoplayback;
@ -772,6 +773,7 @@ typedef struct
int language; //the server operators language
laggedpacket_t *free_lagged_packet;
packet_entities_t entstatebuffer; /*just a temp buffer*/
levelcache_t *levcache;
} server_static_t;
@ -917,7 +919,7 @@ void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf);
int SV_ModelIndex (char *name);
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext);
void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext);
void SV_SaveSpawnparms (qboolean);
void SV_SaveLevelCache(char *savename, qboolean dontharmgame);
@ -955,8 +957,8 @@ qboolean SVQ2_InitGameProgs(void);
void VARGS SVQ2_ShutdownGameProgs (void);
//svq2_ents.c
void SV_BuildClientFrame (client_t *client);
void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg);
void SVQ2_BuildClientFrame (client_t *client);
void SVQ2_WriteFrameToClient (client_t *client, sizebuf_t *msg);
#ifdef Q2SERVER
void MSGQ2_WriteDeltaEntity (q2entity_state_t *from, q2entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity);
void SVQ2_BuildBaselines(void);
@ -967,7 +969,7 @@ void SVQ2_BuildBaselines(void);
void SVQ3_ShutdownGame(void);
qboolean SVQ3_InitGame(void);
qboolean SVQ3_ConsoleCommand(void);
void SVQ3_HandleClient(void);
qboolean SVQ3_HandleClient(void);
void SVQ3_DirectConnect(void);
void SVQ3_DropClient(client_t *cl);
int SVQ3_AddBot(void);

View file

@ -393,10 +393,33 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg)
#endif
}
#ifdef PEXT_CSQC
void SV_CSQC_DroppedPacket(client_t *client, int sequence)
{
int i;
//skip it if we never generated that frame, to avoid pulling in stale data
if (client->frameunion.frames[sequence & UPDATE_MASK].sequence != sequence)
{
Con_Printf("SV: Stale %i\n", sequence);
return;
}
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
unsigned int *f = client->frameunion.frames[sequence & UPDATE_MASK].resendentbits;
Con_Printf("SV: Resend %i\n", sequence);
i = client->max_net_ents;
if (i > sv.world.num_edicts)
i = sv.world.num_edicts;
while (i > 0)
{
if (f[i])
{
client->pendingentbits[i] |= f[i];
f[i] = 0;
}
i--;
}
}
if (!(client->csqcactive)) //we don't need this, but it might be a little faster.
return;
@ -408,13 +431,19 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence)
void SV_CSQC_DropAll(client_t *client)
{
int i;
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
Con_Printf("Reset all\n");
client->pendingentbits[0] = UF_REMOVE;
}
if (!(client->csqcactive)) //we don't need this, but it might be a little faster.
return;
for (i = 0; i < sv.world.num_edicts; i++)
client->csqcentversions[i]--; //do that update thang (but later).
}
#endif
//=============================================================================
@ -427,7 +456,7 @@ Writes part of a packetentities message.
Can delta from either a baseline or a previous packet_entity
==================
*/
void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext)
void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext)
{
#ifdef PROTOCOLEXTENSIONS
int evenmorebits=0;
@ -554,8 +583,8 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb
evenmorebits |= U_LIGHT;
#endif
if (to->flags & U_SOLID)
bits |= U_SOLID;
// if (to->solid)
// bits |= U_SOLID;
if (msg->cursize + 40 > msg->maxsize)
{ //not enough space in the buffer, don't send the entity this frame. (not sending means nothing changes, and it takes no bytes!!)
@ -684,15 +713,382 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb
MSG_WriteByte (msg, (to->effects&0xff00)>>8);
}
/*special flags which are slightly more compact. these are 'wasted' as part of the delta itself*/
#define UF_REMOVE UF_16BIT /*special flag, slightly more compact (we can reuse the 16bit flag as its not important)*/
#define UF_MOVETYPE UF_EFFECTS2
//#define UF_WASTED3 UF_EXTEND1
//#define UF_WASTED2 UF_EXTEND2
//#define UF_WASTED1 UF_EXTEND3
static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to)
{
unsigned int bits = 0;
if (to->u.q1.pmovetype)
{
bits |= UF_PREDINFO;
/*if we've got player movement then always resend this extra stuff to avoid any weird loss*/
bits |= UF_ORIGINXY | UF_ORIGINZ | UF_ANGLESXZ | UF_ANGLESY;
if (from->u.q1.pmovetype != to->u.q1.pmovetype)
bits |= UF_MOVETYPE;
}
if (to->origin[0] != from->origin[0])
bits |= UF_ORIGINXY;
if (to->origin[1] != from->origin[1])
bits |= UF_ORIGINXY;
if (to->origin[2] != from->origin[2])
bits |= UF_ORIGINZ;
if (to->angles[0] != from->angles[0])
bits |= UF_ANGLESXZ;
if (to->angles[1] != from->angles[1])
bits |= UF_ANGLESY;
if (to->angles[2] != from->angles[2])
bits |= UF_ANGLESXZ;
if (to->modelindex != from->modelindex)
bits |= UF_MODEL;
if (to->frame != from->frame)
bits |= UF_FRAME;
if (to->skinnum != from->skinnum)
bits |= UF_SKIN;
if (to->colormap != from->colormap)
bits |= UF_COLORMAP;
if (to->effects != from->effects)
bits |= UF_EFFECTS;
if (to->dpflags != from->dpflags)
bits |= UF_FLAGS;
if (to->solid != from->solid)
bits |= UF_SOLID;
if (to->scale != from->scale)
bits |= UF_SCALE;
if (to->trans != from->trans)
bits |= UF_ALPHA;
if (to->fatness != from->fatness)
bits |= UF_FATNESS;
if (to->hexen2flags != from->hexen2flags)
bits |= UF_DRAWFLAGS;
if (to->abslight != from->abslight)
bits |= UF_ABSLIGHT;
if (to->colormod[0]!=from->colormod[0]||to->colormod[1]!=from->colormod[1]||to->colormod[2]!=from->colormod[2])
bits |= UF_COLORMOD;
if (to->glowmod[0]!=from->glowmod[0]||to->glowmod[1]!=from->glowmod[1]||to->glowmod[2]!=from->glowmod[2])
bits |= UF_GLOWMOD;
if (to->tagentity != from->tagentity || to->tagindex != from->tagindex)
bits |= UF_TAGINFO;
if (to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightstyle)
bits |= UF_LIGHT;
return bits;
}
static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg)
{
unsigned int predbits = 0;
if (bits & UF_MOVETYPE)
{
bits &= ~UF_MOVETYPE;
predbits |= UFP_MOVETYPE;
}
/*check if we need more precision*/
if ((bits & UF_MODEL) && state->modelindex > 255)
bits |= UF_16BIT;
if ((bits & UF_SKIN) && state->skinnum > 255)
bits |= UF_16BIT;
if ((bits & UF_FRAME) && state->frame > 255)
bits |= UF_16BIT;
/*convert effects bits to higher lengths if needed*/
if (bits & UF_EFFECTS)
{
if (state->effects & 0xffff0000) /*both*/
bits |= UF_EFFECTS | UF_EFFECTS2;
else if (state->effects & 0x0000ff00) /*2 only*/
bits = (bits & ~UF_EFFECTS) | UF_EFFECTS2;
}
if (bits & 0xff000000)
bits |= UF_EXTEND3;
if (bits & 0x00ff0000)
bits |= UF_EXTEND2;
if (bits & 0x0000ff00)
bits |= UF_EXTEND1;
MSG_WriteByte(msg, bits>>0);
if (bits & UF_EXTEND1)
MSG_WriteByte(msg, bits>>8);
if (bits & UF_EXTEND2)
MSG_WriteByte(msg, bits>>16);
if (bits & UF_EXTEND3)
MSG_WriteByte(msg, bits>>24);
if (bits & UF_FRAME)
{
if (bits & UF_16BIT)
MSG_WriteShort(msg, state->frame);
else
MSG_WriteByte(msg, state->frame);
}
if (bits & UF_ORIGINXY)
{
MSG_WriteCoord(msg, state->origin[0]);
MSG_WriteCoord(msg, state->origin[1]);
}
if (bits & UF_ORIGINZ)
MSG_WriteCoord(msg, state->origin[2]);
if (bits & UF_PREDINFO)
{ /*if we have pred info, use more precise angles*/
if (bits & UF_ANGLESXZ)
{
MSG_WriteAngle16(msg, state->angles[0]);
MSG_WriteAngle16(msg, state->angles[2]);
}
if (bits & UF_ANGLESY)
MSG_WriteAngle16(msg, state->angles[1]);
}
else
{
if (bits & UF_ANGLESXZ)
{
MSG_WriteAngle(msg, state->angles[0]);
MSG_WriteAngle(msg, state->angles[2]);
}
if (bits & UF_ANGLESY)
MSG_WriteAngle(msg, state->angles[1]);
}
if ((bits & (UF_EFFECTS|UF_EFFECTS2)) == (UF_EFFECTS|UF_EFFECTS2))
MSG_WriteLong(msg, state->effects);
else if (bits & UF_EFFECTS2)
MSG_WriteShort(msg, state->effects);
else if (bits & UF_EFFECTS)
MSG_WriteByte(msg, state->effects);
if (bits & UF_PREDINFO)
{
/*movetype is set above somewhere*/
if (state->u.q1.movement[0])
predbits |= UFP_FORWARD;
if (state->u.q1.movement[1])
predbits |= UFP_SIDE;
if (state->u.q1.movement[2])
predbits |= UFP_UP;
if (state->u.q1.velocity[0])
predbits |= UFP_VELOCITYXY;
if (state->u.q1.velocity[1])
predbits |= UFP_VELOCITYXY;
if (state->u.q1.velocity[2])
predbits |= UFP_VELOCITYZ;
if (state->u.q1.msec)
predbits |= UFP_MSEC;
MSG_WriteByte(msg, predbits);
if (predbits & UFP_FORWARD)
MSG_WriteShort(msg, state->u.q1.movement[0]);
if (predbits & UFP_SIDE)
MSG_WriteShort(msg, state->u.q1.movement[1]);
if (predbits & UFP_UP)
MSG_WriteShort(msg, state->u.q1.movement[2]);
if (predbits & UFP_MOVETYPE)
MSG_WriteByte(msg, state->u.q1.pmovetype);
if (predbits & UFP_VELOCITYXY)
{
MSG_WriteShort(msg, state->u.q1.velocity[0]);
MSG_WriteShort(msg, state->u.q1.velocity[1]);
}
if (predbits & UFP_VELOCITYZ)
MSG_WriteShort(msg, state->u.q1.velocity[2]);
if (predbits & UFP_MSEC)
MSG_WriteByte(msg, state->u.q1.msec);
}
if (bits & UF_MODEL)
{
if (bits & UF_16BIT)
MSG_WriteShort(msg, state->modelindex);
else
MSG_WriteByte(msg, state->modelindex);
}
if (bits & UF_SKIN)
{
if (bits & UF_16BIT)
MSG_WriteShort(msg, state->skinnum);
else
MSG_WriteByte(msg, state->skinnum);
}
if (bits & UF_COLORMAP)
MSG_WriteByte(msg, state->colormap);
if (bits & UF_SOLID)
MSG_WriteShort(msg, state->solid);
if (bits & UF_FLAGS)
MSG_WriteByte(msg, state->dpflags);
if (bits & UF_ALPHA)
MSG_WriteByte(msg, state->trans);
if (bits & UF_SCALE)
MSG_WriteByte(msg, state->scale);
if (bits & UF_ABSLIGHT)
MSG_WriteByte(msg, state->abslight);
if (bits & UF_DRAWFLAGS)
MSG_WriteByte(msg, state->hexen2flags);
if (bits & UF_TAGINFO)
{
MSG_WriteShort(msg, state->tagentity);
MSG_WriteByte(msg, state->tagindex);
}
if (bits & UF_LIGHT)
{
MSG_WriteShort (msg, state->light[0]);
MSG_WriteShort (msg, state->light[1]);
MSG_WriteShort (msg, state->light[2]);
MSG_WriteShort (msg, state->light[3]);
MSG_WriteByte (msg, state->lightstyle);
MSG_WriteByte (msg, state->lightpflags);
}
if (bits & UF_COLORMOD)
{
MSG_WriteByte(msg, state->colormod[0]);
MSG_WriteByte(msg, state->colormod[1]);
MSG_WriteByte(msg, state->colormod[2]);
}
if (bits & UF_GLOWMOD)
{
MSG_WriteByte(msg, state->glowmod[0]);
MSG_WriteByte(msg, state->glowmod[1]);
MSG_WriteByte(msg, state->glowmod[2]);
}
if (bits & UF_FATNESS)
MSG_WriteByte(msg, state->fatness);
}
/*SVFTE_EmitPacketEntities
Writes changed entities to the client.
Changed ent states will be tracked, even if they're not sent just yet, dropped packets will also re-flag dropped delta bits
Only what changed is tracked, via bitmask, its previous value is never tracked.
*/
void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t *msg)
{
entity_state_t *o, *n;
unsigned int i;
unsigned int j;
unsigned int *resend;
qboolean reset = (client->delta_sequence == -1) || (client->pendingentbits[0] & UF_REMOVE);
if (reset)
{
for (j = 0; j < client->sentents.max_entities; j++)
{
client->sentents.entities[j].number = 0;
client->pendingentbits[j] = 0;
}
}
j = 0;
if (to->num_entities)
{
j = to->entities[to->num_entities-1].number+1;
if (j > client->sentents.max_entities)
{
client->sentents.entities = BZ_Realloc(client->sentents.entities, sizeof(*client->sentents.entities) * j);
memset(&client->sentents.entities[client->sentents.max_entities], 0, sizeof(client->sentents.entities[0]) * (j - client->sentents.max_entities));
client->sentents.max_entities = j;
}
}
/*figure out the bits that changed*/
for (i = 0, j = 0; i < to->num_entities; i++)
{
n = &to->entities[i];
/*gaps are dead entities*/
for (; j < n->number; j++)
{
o = &client->sentents.entities[j];
if (o->number)
{
client->pendingentbits[j] = UF_REMOVE;
o->number = 0; /*dead*/
}
}
o = &client->sentents.entities[j];
if (!o->number)
{
/*forget any remove bits*/
client->pendingentbits[j] = UF_RESET | SVFTE_DeltaCalcBits(&EDICT_NUM(svprogfuncs, n->number)->baseline, n);
}
else
{
client->pendingentbits[j] |= SVFTE_DeltaCalcBits(o, n);;
}
*o = *n;
j++;
}
/*gaps are dead entities*/
for (; j < client->sentents.max_entities; j++)
{
o = &client->sentents.entities[j];
if (o->number)
{
client->pendingentbits[j] = UF_REMOVE;
o->number = 0; /*dead*/
}
}
resend = client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK].resendentbits;
MSG_WriteByte (msg, svcfte_updateentities);
MSG_WriteFloat(msg, sv.world.physicstime);
if (reset)
MSG_WriteShort(msg, 0x8000);
memset(resend, 0, client->sentents.max_entities*sizeof(*resend));
for(j = 0; j < client->sentents.max_entities; j++)
{
if (!client->pendingentbits[j])
continue;
if (msg->cursize + 50 > msg->maxsize)
break; /*give up if it gets full*/
if (client->pendingentbits[j] & UF_REMOVE)
{
MSG_WriteShort(msg, j | 0x8000);
resend[j] = UF_REMOVE;
}
else
{
MSG_WriteShort(msg, j);
SVFTE_WriteUpdate(client->pendingentbits[j], &client->sentents.entities[j], msg);
resend[j] = client->pendingentbits[j];
}
client->pendingentbits[j] = 0;
}
MSG_WriteShort(msg, 0);
}
/*
=============
SV_EmitPacketEntities
SVQW_EmitPacketEntities
Writes a delta update of a packet_entities_t to the message.
deltaing is performed from one set of entity states directly to the next
=============
*/
void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
void SVQW_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
{
edict_t *ent;
client_frame_t *fromframe;
@ -732,9 +1128,9 @@ void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *
{ // delta update from old position
//Con_Printf ("delta %i\n", newnum);
#ifdef PROTOCOLEXTENSIONS
SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, client->fteprotocolextensions);
SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, client->fteprotocolextensions);
#else
SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false);
SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false);
#endif
oldindex++;
newindex++;
@ -749,9 +1145,9 @@ void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *
ent = NULL;
//Con_Printf ("baseline %i\n", newnum);
#ifdef PROTOCOLEXTENSIONS
SV_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true, client->fteprotocolextensions);
SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true, client->fteprotocolextensions);
#else
SV_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true);
SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true);
#endif
newindex++;
continue;
@ -1064,8 +1460,6 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t
if (client->protocol == SCP_DARKPLACES7)
MSG_WriteLong(msg, client->last_sequence);
for (newindex = 0; newindex < to->num_entities; newindex++)
to->entities[newindex].bitmask = 0;
//add in the bitmasks of dropped packets.
newindex = 0;
@ -2197,18 +2591,49 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
int i;
#ifdef Q2SERVER
state->modelindex2 = 0;
state->modelindex3 = 0;
state->modelindex4 = 0;
state->event = 0;
state->solid = 0;
state->sound = 0;
state->renderfx = 0;
state->old_origin[0] = 0;
state->old_origin[1] = 0;
state->old_origin[2] = 0;
#endif
state->number = NUM_FOR_EDICT(svprogfuncs, ent);
state->u.q1.msec = 0;
state->u.q1.pmovetype = 0;
state->u.q1.movement[0] = 0;
state->u.q1.movement[1] = 0;
state->u.q1.movement[2] = 0;
state->u.q1.velocity[0] = 0;
state->u.q1.velocity[1] = 0;
state->u.q1.velocity[2] = 0;
if ((state->number-1) < (unsigned short)sv.allocated_client_slots && ent->v->movetype)
{
client_t *cl = &svs.clients[state->number-1];
if (cl->isindependant)
{
state->u.q1.pmovetype = ent->v->movetype;
if (cl != client)
{ /*only generate movement values if the client doesn't already know them...*/
state->u.q1.movement[0] = ent->xv->movement[0];
state->u.q1.movement[1] = ent->xv->movement[1];
state->u.q1.movement[2] = ent->xv->movement[2];
state->u.q1.msec = bound(0, 1000*(sv.time - cl->localtime), 255);
}
state->u.q1.velocity[0] = ent->v->velocity[0] * 8;
state->u.q1.velocity[1] = ent->v->velocity[1] * 8;
state->u.q1.velocity[2] = ent->v->velocity[2] * 8;
}
}
if (ent->v->solid == SOLID_BSP || (ent->v->skin < 0 && ent->v->modelindex))
state->solid = ES_SOLID_BSP;
else if (ent->v->solid == SOLID_BBOX || ent->v->solid == SOLID_SLIDEBOX || ent->v->skin < 0)
{
i = bound(0, -ent->v->mins[0]/8, 31);
state->solid = i;
i = bound(0, -ent->v->mins[2]/8, 31);
state->solid |= i<<5;
i = bound(0, ((ent->v->maxs[2]+32)/8), 63); /*up can be negative*/
state->solid |= i<<10;
}
else
state->solid = 0;
state->dpflags = 0;
if (ent->xv->viewmodelforclient)
@ -2216,6 +2641,8 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
//if ent->viewmodelforclient == client then:
state->dpflags |= RENDER_VIEWMODEL;
}
if (ent->v->colormap >= 1024)
state->dpflags |= RENDER_COLORMAPPED;
if (ent->xv->exteriormodeltoclient && client)
{
if (ent->xv->exteriormodeltoclient == EDICT_TO_PROG(svprogfuncs, client->edict))
@ -2226,11 +2653,11 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
if (ent->v->movetype == MOVETYPE_STEP)
state->dpflags |= RENDER_STEP;
state->number = NUM_FOR_EDICT(svprogfuncs, ent);
state->flags = 0;
VectorCopy (ent->v->origin, state->origin);
VectorCopy (ent->v->angles, state->angles);
state->modelindex = ent->v->modelindex;
state->modelindex2 = ent->xv->vw_index;
state->frame = ent->v->frame;
state->colormap = ent->v->colormap;
state->skinnum = ent->v->skin;
@ -2247,7 +2674,7 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
state->lightstyle = ent->xv->style;
state->lightpflags = ent->xv->pflags;
if ((int)ent->v->flags & FL_CLASS_DEPENDENT && client->playerclass) //hexen2 wierdness.
if (((int)ent->v->flags & FL_CLASS_DEPENDENT) && client->playerclass) //hexen2 wierdness.
{
char modname[MAX_QPATH];
Q_strncpyz(modname, sv.strings.model_precache[state->modelindex], sizeof(modname));
@ -2306,6 +2733,9 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
i = ent->xv->colormod[1]*(256/8); state->colormod[1] = bound(0, i, 255);
i = ent->xv->colormod[2]*(256/8); state->colormod[2] = bound(0, i, 255);
}
state->glowmod[0] = ent->xv->glowmod[0]*(256/8);
state->glowmod[1] = ent->xv->glowmod[1]*(256/8);
state->glowmod[2] = ent->xv->glowmod[2]*(256/8);
state->glowsize = ent->xv->glow_size*0.25;
state->glowcolour = ent->xv->glow_color;
if (ent->xv->glow_trail)
@ -2338,6 +2768,8 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
#ifdef PEXT_FATNESS
state->fatness = ent->xv->fatness;
#endif
#pragma warningmsg("TODO: Fix attachments for more vanilla clients")
}
void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, edict_t *clent, qboolean ignorepvs)
@ -2349,7 +2781,7 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs,
#define DEPTHOPTIMISE
#ifdef DEPTHOPTIMISE
vec3_t org;
float distances[MAX_EXTENDED_PACKET_ENTITIES];
static float distances[32768];
float dist;
#endif
globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT);
@ -2401,12 +2833,13 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs,
}
/*legacy qw clients get their players separately*/
if (ISQWCLIENT(client) && !(client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
e = sv.allocated_client_slots+1;
else
e = 1;
#ifdef NQPROT
for (e=(ISQWCLIENT(client)?sv.allocated_client_slots+1:1) ; e<sv.world.num_edicts ; e++)
#else
for (e=sv.allocated_client_slots+1 ; e<sv.num_edicts ; e++)
#endif
for ( ; e<sv.world.num_edicts ; e++)
{
ent = EDICT_NUM(svprogfuncs, e);
@ -2446,7 +2879,7 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs,
else
{
// ignore ents without visible models
if (!ent->xv->SendEntity && (!ent->v->modelindex || !*PR_GetString(svprogfuncs, ent->v->model)) && !((int)ent->xv->pflags & PFLAGS_FULLDYNAMIC))
if (!ent->xv->SendEntity && (!ent->v->modelindex || !*PR_GetString(svprogfuncs, ent->v->model)) && !((int)ent->xv->pflags & PFLAGS_FULLDYNAMIC) && ent->v->skin >= 0)
continue;
pvsflags = ent->xv->pvsflags;
@ -2698,13 +3131,20 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
}
host_client = client;
pack = &frame->entities;
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
pack = &svs.entstatebuffer;
if (pack->max_entities < client->max_net_ents)
{
pack->max_entities = client->max_net_ents;
pack->entities = BZ_Realloc(pack->entities, sizeof(*pack->entities) * pack->max_entities);
memset(pack->entities, 0, sizeof(entity_state_t) * pack->max_entities);
}
}
else
pack = &frame->entities;
SV_Snapshot_Clear(pack);
// send over the players in the PVS
if (svs.gametype != GT_HALFLIFE)
SV_WritePlayersToClient (client, frame, clent, pvs, msg);
// put other visible entities into either a packet_entities or a nails message
#ifdef SERVER_DEMO_PLAYBACK
@ -2749,7 +3189,41 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
// encode the packet entities as a delta from the
// last packetentities acknowledged by the client
SV_EmitPacketEntities (client, pack, msg);
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
SVFTE_EmitPacketEntities(client, pack, msg);
}
else
{
// Z_EXT_TIME protocol extension
// every now and then, send an update so that extrapolation
// on client side doesn't stray too far off
if (ISQWCLIENT(client))
{
if (client->fteprotocolextensions & PEXT_ACCURATETIMINGS && sv.world.physicstime - client->nextservertimeupdate > 0)
{ //the fte pext causes the server to send out accurate timings, allowing for perfect interpolation.
MSG_WriteByte (msg, svc_updatestatlong);
MSG_WriteByte (msg, STAT_TIME);
MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000));
client->nextservertimeupdate = sv.world.physicstime;//+10;
}
else if (client->zquake_extensions & Z_EXT_SERVERTIME && sv.world.physicstime - client->nextservertimeupdate > 0)
{ //the zquake ext causes the server to send out peridoic timings, allowing for moderatly accurate game time.
MSG_WriteByte (msg, svc_updatestatlong);
MSG_WriteByte (msg, STAT_TIME);
MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000));
client->nextservertimeupdate = sv.world.physicstime+10;
}
}
// send over the players in the PVS
if (svs.gametype != GT_HALFLIFE)
SV_WritePlayersToClient (client, frame, clent, pvs, msg);
SVQW_EmitPacketEntities (client, pack, msg);
}
SV_EmitCSQCUpdate(client, msg);

View file

@ -256,6 +256,9 @@ void SV_EdictToEntState (int num, edict_t *ent, entity_state_t *state)
if (/*progstype == PROG_H2 &&*/ ent->v->solid == SOLID_BSP)
state->angles[0]*=-1;
if (ent->v->solid == SOLID_BSP)
state->solid = ES_SOLID_BSP;
if (state->effects & EF_FULLBRIGHT)
{
state->hexen2flags |= MLS_FULLBRIGHT;
@ -296,6 +299,7 @@ void SVNQ_CreateBaseline (void)
{
edict_t *svent;
int entnum;
extern entity_state_t nullentitystate;
int playermodel = SV_SafeModelIndex("progs/player.mdl");
@ -303,16 +307,9 @@ void SVNQ_CreateBaseline (void)
{
svent = EDICT_NUM(svprogfuncs, entnum);
memset(&svent->baseline, 0, sizeof(entity_state_t));
memcpy(&svent->baseline, &nullentitystate, sizeof(entity_state_t));
svent->baseline.number = entnum;
#ifdef PEXT_SCALE
svent->baseline.scale = 1*16;
#endif
#ifdef PEXT_TRANS
svent->baseline.trans = 255;
#endif
if (svent->isfree)
continue;
// create baselines for all player slots,
@ -616,6 +613,7 @@ void SV_UnspawnServer (void) //terminate the running server.
*svs.clients[i].namebuf = '\0';
svs.clients[i].name = NULL;
}
SV_FlushLevelCache();
NET_CloseServer ();
}
@ -836,7 +834,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
Info_SetValueForStarKey(svs.info, "*gamespeed", "", MAX_SERVERINFO_STRING);
}
//reset the server time.
sv.time = 0.1; //some progs don't like time starting at 0.
sv.time = 0.01; //some progs don't like time starting at 0.
//cos of spawn funcs like self.nextthink = time...
//NQ uses 1, QW uses 0. Awkward.
sv.starttime = Sys_DoubleTime();
@ -1098,6 +1096,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
for (i=0 ; i<MAX_CLIENTS ; i++)
{
svs.clients[i].edict = NULL;
svs.clients[i].name = svs.clients[i].namebuf;
svs.clients[i].team = svs.clients[i].teambuf;
}

View file

@ -596,6 +596,11 @@ void SV_DropClient (client_t *drop)
Z_Free(drop->frameunion.frames);
drop->frameunion.frames = NULL;
}
if (drop->sentents.entities)
{
Z_Free(drop->sentents.entities);
memset(&drop->sentents.entities, 0, sizeof(drop->sentents.entities));
}
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) //gamecode should do it all for us.
{
@ -1380,30 +1385,45 @@ void SVC_GetChallenge (void)
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM)
{
#ifdef PROTOCOL_VERSION_FTE
unsigned int mask;
//tell the client what fte extensions we support
if (svs.fteprotocolextensions)
mask = Net_PextMask(1);
if (mask)
{
lng = LittleLong(PROTOCOL_VERSION_FTE);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
lng = LittleLong(svs.fteprotocolextensions);
lng = LittleLong(mask);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
}
//tell the client what fte extensions we support
if (svs.fteprotocolextensions2)
mask = Net_PextMask(2);
if (mask)
{
lng = LittleLong(PROTOCOL_VERSION_FTE2);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
lng = LittleLong(svs.fteprotocolextensions2);
lng = LittleLong(mask);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
}
#endif
mask = net_mtu.ival&~7;
if (mask > 64)
{
lng = LittleLong(PROTOCOL_VERSION_FRAGMENT);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
lng = LittleLong(mask);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
}
#ifdef HUFFNETWORK
compressioncrc = Huff_PreferedCompressionCRC();
if (compressioncrc)
@ -1674,6 +1694,7 @@ client_t *SVC_DirectConnect(void)
int version;
int challenge;
int huffcrc = 0;
int mtu = 0;
char guid[128] = "";
char basic[80];
qboolean redirect = false;
@ -1823,33 +1844,48 @@ client_t *SVC_DirectConnect(void)
Con_Printf ("* rejected connect from quakeworld\n");
return NULL;
}
}
while(!msg_badread)
while(!msg_badread)
{
Cmd_TokenizeString(MSG_ReadStringLine(), false, false);
switch(Q_atoi(Cmd_Argv(0)))
{
Cmd_TokenizeString(MSG_ReadStringLine(), false, false);
switch(Q_atoi(Cmd_Argv(0)))
case PROTOCOL_VERSION_FTE:
if (protocol == SCP_QUAKEWORLD)
{
case PROTOCOL_VERSION_FTE:
protextsupported = Q_atoi(Cmd_Argv(1));
Con_DPrintf("Client supports 0x%x fte extensions\n", protextsupported);
break;
case PROTOCOL_VERSION_FTE2:
}
break;
case PROTOCOL_VERSION_FTE2:
if (protocol == SCP_QUAKEWORLD)
{
protextsupported2 = Q_atoi(Cmd_Argv(1));
Con_DPrintf("Client supports 0x%x fte2 extensions\n", protextsupported2);
break;
case PROTOCOL_VERSION_HUFFMAN:
huffcrc = Q_atoi(Cmd_Argv(1));
Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc);
break;
case PROTOCOL_INFO_GUID:
Q_strncpyz(guid, Cmd_Argv(1), sizeof(guid));
Con_DPrintf("GUID %s\n", Cmd_Argv(1));
break;
}
break;
case PROTOCOL_VERSION_HUFFMAN:
huffcrc = Q_atoi(Cmd_Argv(1));
Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc);
break;
case PROTOCOL_VERSION_FRAGMENT:
mtu = Q_atoi(Cmd_Argv(1)) & ~7;
if (mtu < 64)
mtu = 64;
Con_DPrintf("Client supports fragmentation. mtu %i.\n", mtu);
break;
case PROTOCOL_INFO_GUID:
Q_strncpyz(guid, Cmd_Argv(1), sizeof(guid));
Con_DPrintf("GUID %s\n", Cmd_Argv(1));
break;
}
msg_badread=false;
}
msg_badread=false;
if (protextsupported & PEXT_256PACKETENTITIES)
maxpacketentities = MAX_EXTENDED_PACKET_ENTITIES;
@ -2230,11 +2266,23 @@ client_t *SVC_DirectConnect(void)
Z_Free(temp.frameunion.frames);
}
temp.frameunion.frames = Z_Malloc((sizeof(client_frame_t)+sizeof(entity_state_t)*maxpacketentities)*UPDATE_BACKUP);
for (i = 0; i < UPDATE_BACKUP; i++)
if ((temp.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))// || ISDPCLIENT(&temp))
{
temp.frameunion.frames[i].entities.max_entities = maxpacketentities;
temp.frameunion.frames[i].entities.entities = (entity_state_t*)(temp.frameunion.frames+UPDATE_BACKUP) + i*temp.frameunion.frames[i].entities.max_entities;
temp.frameunion.frames = Z_Malloc(sizeof(client_frame_t)*UPDATE_BACKUP+sizeof(unsigned int)*temp.max_net_ents*UPDATE_BACKUP + sizeof(unsigned int)*temp.max_net_ents);
for (i = 0; i < UPDATE_BACKUP; i++)
{
temp.frameunion.frames[i].resendentbits = (unsigned int*)(temp.frameunion.frames+UPDATE_BACKUP) + i*temp.max_net_ents;
}
temp.pendingentbits = (unsigned int*)(temp.frameunion.frames+UPDATE_BACKUP) + UPDATE_BACKUP*temp.max_net_ents;
}
else
{
temp.frameunion.frames = Z_Malloc((sizeof(client_frame_t)+sizeof(entity_state_t)*maxpacketentities)*UPDATE_BACKUP);
for (i = 0; i < UPDATE_BACKUP; i++)
{
temp.frameunion.frames[i].entities.max_entities = maxpacketentities;
temp.frameunion.frames[i].entities.entities = (entity_state_t*)(temp.frameunion.frames+UPDATE_BACKUP) + i*temp.frameunion.frames[i].entities.max_entities;
}
}
break;
}
@ -2263,6 +2311,8 @@ client_t *SVC_DirectConnect(void)
newcl->netchan.compress = true;
else
newcl->netchan.compress = false;
if (mtu >= 0)
newcl->netchan.fragmentsize = mtu;
newcl->protocol = protocol;
#ifdef NQPROT
@ -3257,20 +3307,40 @@ qboolean SV_ReadPackets (float *delay)
net_from = cl->netchan.remote_address; //not sure if anything depends on this, but lets not screw them up willynilly
if (Netchan_Process(&cl->netchan))
{ // this is a valid, sequenced packet, so process it
received++;
svs.stats.packets++;
if (cl->state > cs_zombie)
{ //make sure they didn't already disconnect
cl->send_message = true; // reply at end of frame
if (ISNQCLIENT(cl))
{
if (cl->state != cs_zombie)
{
if (NQNetChan_Process(&cl->netchan))
{
received++;
svs.stats.packets++;
SVNQ_ExecuteClientMessage(cl);
}
}
break;
}
else
{
/*QW*/
if (Netchan_Process(&cl->netchan))
{ // this is a valid, sequenced packet, so process it
received++;
svs.stats.packets++;
if (cl->state > cs_zombie)
{ //make sure they didn't already disconnect
if (cl->send_message)
cl->chokecount++;
else
cl->send_message = true; // reply at end of frame
#ifdef Q2SERVER
if (cl->protocol == SCP_QUAKE2)
SVQ2_ExecuteClientMessage(cl);
else
#endif
SV_ExecuteClientMessage (cl);
#ifdef Q2SERVER
if (cl->protocol == SCP_QUAKE2)
SVQ2_ExecuteClientMessage(cl);
else
#endif
SV_ExecuteClientMessage (cl);
}
}
}
}
@ -3328,6 +3398,9 @@ qboolean SV_ReadPackets (float *delay)
{
if (cl->state != cs_zombie)
{
if (cl->delay > 0)
goto dominping;
if (NQNetChan_Process(&cl->netchan))
{
received++;
@ -3341,17 +3414,7 @@ qboolean SV_ReadPackets (float *delay)
#ifdef Q3SERVER
if (ISQ3CLIENT(cl))
{
#ifdef warningmsg
#pragma warningmsg("qwoverq3: fixme: this will block qw+q3 clients from the same ip")
#endif
if (cl->state != cs_zombie)
{
received++;
SVQ3_HandleClient();
}
break;
}
continue;
#endif
if (cl->netchan.qport != qport)
@ -3364,6 +3427,7 @@ qboolean SV_ReadPackets (float *delay)
if (cl->delay > 0)
{
dominping:
if (cl->state == cs_zombie)
break;
if (net_message.cursize > sizeof(svs.free_lagged_packet->data))
@ -3414,6 +3478,14 @@ qboolean SV_ReadPackets (float *delay)
if (i != MAX_CLIENTS)
continue;
#ifdef Q3SERVER
if (sv_listen_q3.ival && SVQ3_HandleClient())
{
received++;
continue;
}
#endif
#ifdef NQPROT
SVNQ_ConnectionlessPacket();
#endif
@ -4077,88 +4149,6 @@ void SV_InitLocal (void)
for (i=0 ; i<MAX_MODELS ; i++)
sprintf (localmodels[i], "*%i", i);
#ifdef PEXT_SCALE
svs.fteprotocolextensions |= PEXT_SCALE;
#endif
#ifdef PEXT_LIGHTSTYLECOL
svs.fteprotocolextensions |= PEXT_LIGHTSTYLECOL;
#endif
#ifdef PEXT_TRANS
svs.fteprotocolextensions |= PEXT_TRANS;
#endif
#ifdef PEXT_VIEW2
svs.fteprotocolextensions |= PEXT_VIEW2;
#endif
svs.fteprotocolextensions |= PEXT_ACCURATETIMINGS;
#ifdef PEXT_ZLIBDL
svs.fteprotocolextensions |= PEXT_ZLIBDL;
#endif
#ifdef PEXT_FATNESS
svs.fteprotocolextensions |= PEXT_FATNESS;
#endif
#ifdef PEXT_HLBSP
svs.fteprotocolextensions |= PEXT_HLBSP;
#endif
#ifdef PEXT_Q2BSP
svs.fteprotocolextensions |= PEXT_Q2BSP;
#endif
#ifdef PEXT_Q3BSP
svs.fteprotocolextensions |= PEXT_Q3BSP;
#endif
#ifdef PEXT_TE_BULLET
svs.fteprotocolextensions |= PEXT_TE_BULLET;
#endif
#ifdef PEXT_HULLSIZE
svs.fteprotocolextensions |= PEXT_HULLSIZE;
#endif
#ifdef PEXT_SETVIEW
svs.fteprotocolextensions |= PEXT_SETVIEW;
#endif
#ifdef PEXT_MODELDBL
svs.fteprotocolextensions |= PEXT_MODELDBL;
#endif
#ifdef PEXT_SOUNDDBL
svs.fteprotocolextensions |= PEXT_SOUNDDBL;
#endif
#ifdef PEXT_FLOATCOORDS
svs.fteprotocolextensions |= PEXT_FLOATCOORDS;
#endif
svs.fteprotocolextensions |= PEXT_SPLITSCREEN;
svs.fteprotocolextensions |= PEXT_HEXEN2;
svs.fteprotocolextensions |= PEXT_COLOURMOD;
svs.fteprotocolextensions |= PEXT_SPAWNSTATIC2;
svs.fteprotocolextensions |= PEXT_CUSTOMTEMPEFFECTS;
svs.fteprotocolextensions |= PEXT_256PACKETENTITIES;
svs.fteprotocolextensions |= PEXT_ENTITYDBL;
svs.fteprotocolextensions |= PEXT_ENTITYDBL2;
// svs.fteprotocolextensions |= PEXT_64PLAYERS;
svs.fteprotocolextensions |= PEXT_SHOWPIC;
svs.fteprotocolextensions |= PEXT_SETATTACHMENT;
#ifdef PEXT_PK3DOWNLOADS
svs.fteprotocolextensions |= PEXT_PK3DOWNLOADS;
#endif
#ifdef PEXT_CHUNKEDDOWNLOADS
svs.fteprotocolextensions |= PEXT_CHUNKEDDOWNLOADS;
#endif
#ifdef PEXT_CSQC
svs.fteprotocolextensions |= PEXT_CSQC;
#endif
#ifdef PEXT_DPFLAGS
svs.fteprotocolextensions |= PEXT_DPFLAGS;
#endif
svs.fteprotocolextensions2 |= PEXT2_PRYDONCURSOR;
#ifdef VOICECHAT
svs.fteprotocolextensions2 |= PEXT2_VOICECHAT;
#endif
svs.fteprotocolextensions2 |= PEXT2_SETANGLEDELTA;
// if (svs.protocolextensions)
// Info_SetValueForStarKey (svs.info, "*"DISTRIBUTION"_ext", va("%x", svs.protocolextensions), MAX_SERVERINFO_STRING);
Info_SetValueForStarKey (svs.info, "*version", version_string(), MAX_SERVERINFO_STRING);
Info_SetValueForStarKey (svs.info, "*z_ext", va("%i", SUPPORTED_Z_EXTENSIONS), MAX_SERVERINFO_STRING);
@ -4176,10 +4166,7 @@ void SV_InitLocal (void)
svs.log[1].allowoverflow = true;
svs.free_lagged_packet = Hunk_Alloc(1024*sizeof(*svs.free_lagged_packet));
for (i = 0; i < 1024-1; i++)
svs.free_lagged_packet[i].next = &svs.free_lagged_packet[i+1];
svs.free_lagged_packet[i].next = 0;
svs.free_lagged_packet = NULL;
// parse params for cvars
p = COM_CheckParm ("-port");

View file

@ -1748,6 +1748,8 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
MSG_WriteLong (&buf, svs.spawncount);
MSG_WriteString (&buf, gamedir);
if (demo.recorder.fteprotocolextensions2 & PEXT2_MAXPLAYERS)
MSG_WriteByte(&buf, MAX_CLIENTS);
MSG_WriteFloat (&buf, sv.time);
@ -1875,7 +1877,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest)
else if (demo.recorder.fteprotocolextensions & PEXT_SPAWNSTATIC2)
{
MSG_WriteByte(&buf, svcfte_spawnbaseline2);
SV_WriteDelta(&from, state, &buf, true, demo.recorder.fteprotocolextensions);
SVQW_WriteDelta(&from, state, &buf, true, demo.recorder.fteprotocolextensions);
}
else
{

View file

@ -24,11 +24,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "pr_common.h"
#ifdef warningmsg
#pragma warningmsg("fixme, fix this up before adding to csqc")
#endif
extern globalptrs_t realpr_global_ptrs;
/*
@ -444,16 +439,11 @@ SV_AddGravity
============
*/
static void WPhys_AddGravity (wedict_t *ent, float scale)
static void WPhys_AddGravity (world_t *w, wedict_t *ent, float scale)
{
if (!scale
#ifndef CLIENTONLY
#pragma warningmsg("This doesn't do csqc properly")
&& progstype != PROG_QW
#endif
)
scale = 1;
ent->v->velocity[2] -= scale * sv_gravity.value/*movevars.gravity*/ * host_frametime;
if (!scale)
scale = w->defaultgravityscale;
ent->v->velocity[2] -= scale * movevars.gravity * host_frametime;
}
/*
@ -537,7 +527,7 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
int i, e;
wedict_t *check, *block;
vec3_t mins, maxs;
float oldsolid;
//float oldsolid;
pushed_t *p;
vec3_t org, org2, move2, forward, right, up;
@ -577,14 +567,14 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
|| check->v->movetype == MOVETYPE_NOCLIP
|| check->v->movetype == MOVETYPE_ANGLENOCLIP)
continue;
/*
oldsolid = pusher->v->solid;
pusher->v->solid = SOLID_NOT;
block = World_TestEntityPosition (w, check);
pusher->v->solid = oldsolid;
if (block)
continue;
*/
// if the entity is standing on the pusher, it will definitely be moved
if ( ! ( ((int)check->v->flags & FL_ONGROUND)
&& PROG_TO_WEDICT(w->progs, check->v->groundentity) == pusher) )
@ -1103,15 +1093,16 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent)
&& ent->v->movetype != MOVETYPE_FLYMISSILE
&& ent->v->movetype != MOVETYPE_BOUNCEMISSILE
&& ent->v->movetype != MOVETYPE_H2SWIM)
WPhys_AddGravity (ent, 1.0);
WPhys_AddGravity (w, ent, 1.0);
// move angles
VectorMA (ent->v->angles, host_frametime, ent->v->avelocity, ent->v->angles);
// move origin
VectorScale (ent->v->velocity, host_frametime, move);
if (!DotProduct(move, move))
return;
VectorCopy(ent->v->origin, temporg);
VectorCopy(temporg, ent->v->origin);
fl = 0;
#ifndef CLIENTONLY
@ -1123,7 +1114,14 @@ static void WPhys_Physics_Toss (world_t *w, wedict_t *ent)
trace = WPhys_PushEntity (w, ent, move, fl);
if (trace.allsolid)
{
trace.fraction = 0;
#pragma warningmsg("These three lines might help boost framerates a lot in rmq, not sure if they violate expected behaviour in other mods though - check that they're safe.")
trace.plane.normal[0] = 0;
trace.plane.normal[1] = 0;
trace.plane.normal[2] = 1;
}
if (trace.fraction == 1)
return;
if (ent->isfree)
@ -1206,7 +1204,7 @@ static void WPhys_Physics_Step (world_t *w, wedict_t *ent)
{
hitsound = ent->v->velocity[2] < movevars.gravity*-0.1;
WPhys_AddGravity (ent, 1.0);
WPhys_AddGravity (w, ent, 1.0);
WPhys_CheckVelocity (w, ent);
WPhys_FlyMove (w, ent, host_frametime, NULL);
World_LinkEdict (w, ent, true);
@ -1897,7 +1895,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent)
if (!WPhys_RunThink (w, ent))
return;
if (!WPhys_CheckWater (w, ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
WPhys_AddGravity (ent, ent->xv->gravity);
WPhys_AddGravity (w, ent, ent->xv->gravity);
WPhys_CheckStuck (w, ent);
WPhys_WalkMove (w, ent);
@ -2093,6 +2091,8 @@ qboolean SV_Physics (void)
qboolean moved = false;
int maxtics;
//keep gravity tracking the cvar properly
movevars.gravity = sv_gravity.value;
if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM && svs.gametype != GT_HALFLIFE) //make tics multiples of sv_maxtic (defaults to 0.1)
{
@ -2265,7 +2265,6 @@ qboolean SV_Physics (void)
void SV_SetMoveVars(void)
{
movevars.gravity = sv_gravity.value;
movevars.stopspeed = sv_stopspeed.value;
movevars.maxspeed = sv_maxspeed.value;
movevars.spectatormaxspeed = sv_spectatormaxspeed.value;

View file

@ -1090,7 +1090,7 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum)
MSG_WriteByte(msg, svcfte_choosesplitclient);
MSG_WriteByte(msg, pnum);
}
if (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA && client->delta_sequence != -1)
if (!client->lockangles && (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA) && client->delta_sequence != -1)
{
MSG_WriteByte (msg, svcfte_setangledelta);
for (i=0 ; i < 3 ; i++)
@ -1107,7 +1107,10 @@ void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum)
MSG_WriteAngle (msg, ent->v->angles[i]);
}
ent->v->fixangle = 0;
client->lockangles = true;
}
else
client->lockangles = false;
}
/*sends the a centerprint string directly to the client*/
@ -1160,13 +1163,6 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
client_t *split;
int pnum=0;
if (client->centerprintstring && ! client->num_backbuf)
{
SV_WriteCenterPrint(client, client->centerprintstring);
Z_Free(client->centerprintstring);
client->centerprintstring = NULL;
}
// send the chokecount for r_netgraph
if (ISQWCLIENT(client))
if (client->chokecount)
@ -1177,34 +1173,21 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
}
for (split = client; split; split=split->controlled, pnum++)
{
SV_WriteEntityDataToMessage(split, msg, pnum);
if (split->centerprintstring && ! client->num_backbuf)
{
SV_WriteCenterPrint(split, split->centerprintstring);
Z_Free(split->centerprintstring);
split->centerprintstring = NULL;
}
}
/*
MSG_WriteByte (msg, svc_time);
MSG_WriteFloat(msg, sv.physicstime);
client->nextservertimeupdate = sv.physicstime;
*/
// Z_EXT_TIME protocol extension
// every now and then, send an update so that extrapolation
// on client side doesn't stray too far off
if (ISQWCLIENT(client))
{
if (client->fteprotocolextensions & PEXT_ACCURATETIMINGS && sv.world.physicstime - client->nextservertimeupdate > 0)
{ //the fte pext causes the server to send out accurate timings, allowing for perfect interpolation.
MSG_WriteByte (msg, svc_updatestatlong);
MSG_WriteByte (msg, STAT_TIME);
MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000));
client->nextservertimeupdate = sv.world.physicstime;//+10;
}
else if (client->zquake_extensions & Z_EXT_SERVERTIME && sv.world.physicstime - client->nextservertimeupdate > 0)
{ //the zquake ext causes the server to send out peridoic timings, allowing for moderatly accurate game time.
MSG_WriteByte (msg, svc_updatestatlong);
MSG_WriteByte (msg, STAT_TIME);
MSG_WriteLong (msg, (int)(sv.world.physicstime * 1000));
client->nextservertimeupdate = sv.world.physicstime+10;
}
}
#ifdef NQPROT
if (ISQWCLIENT(client))
@ -1548,9 +1531,9 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf
statsf[STAT_CELLS] = ent->v->ammo_cells;
if (!client->spectator)
{
statsi[STAT_ACTIVEWEAPON] = ent->v->weapon;
statsf[STAT_ACTIVEWEAPON] = ent->v->weapon;
if (client->csqcactive || client->protocol != SCP_QUAKEWORLD)
statsi[STAT_WEAPONFRAME] = ent->v->weaponframe;
statsf[STAT_WEAPONFRAME] = ent->v->weaponframe;
}
// stuff the sigil bits into the high bits of items for sbar
@ -1574,6 +1557,7 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf
if (client->protocol == SCP_DARKPLACES7)
{
/*note: statsf is truncated, which would mess things up*/
float *statsfi = (float*)statsi;
// statsfi[STAT_MOVEVARS_WALLFRICTION] = sv_wall
statsfi[STAT_MOVEVARS_FRICTION] = sv_friction.value;
@ -1789,7 +1773,7 @@ SV_SendClientDatagram
*/
qboolean SV_SendClientDatagram (client_t *client)
{
qbyte buf[MAX_DATAGRAM];
qbyte buf[MAX_OVERALLMSGLEN];
sizebuf_t msg;
unsigned int sentbytes, fnum;
@ -1800,15 +1784,18 @@ qboolean SV_SendClientDatagram (client_t *client)
msg.overflowed = false;
msg.prim = client->datagram.prim;
if (!client->netchan.fragmentsize)
msg.maxsize = MAX_DATAGRAM;
if (sv.world.worldmodel && !client->controller)
{
if (ISQ2CLIENT(client))
{
SV_BuildClientFrame (client);
SVQ2_BuildClientFrame (client);
// send over all the relevant entity_state_t
// and the player_state_t
SV_WriteFrameToClient (client, &msg);
SVQ2_WriteFrameToClient (client, &msg);
}
else
{
@ -2306,9 +2293,9 @@ void SV_SendClientMessages (void)
SZ_Clear (&c->datagram);
SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
Con_Printf ("WARNING: reliable overflow for %s\n",c->name);
SV_DropClient (c);
c->send_message = true;
c->netchan.cleartime = 0; // don't choke this message
SV_DropClient (c);
continue;
}

View file

@ -50,6 +50,7 @@ cvar_t sv_antilag_frac = CVARF("sv_antilag_frac", "1", CVAR_SERVERINFO);
cvar_t sv_cheatpc = CVAR("sv_cheatpc", "125");
cvar_t sv_cheatspeedchecktime = CVAR("sv_cheatspeedchecktime", "30");
cvar_t sv_playermodelchecks = CVAR("sv_playermodelchecks", "0");
cvar_t sv_ping_ignorepl = CVARD("sv_ping_ignorepl", "0", "If 1, ping times reported for players will ignore the effects of packetloss on ping times. 0 is slightly more honest, but less useful for connection diagnosis.");
cvar_t sv_cmdlikercon = SCVAR("sv_cmdlikercon", "0"); //set to 1 to allow a password of username:password instead of the correct rcon password.
cvar_t cmd_allowaccess = SCVAR("cmd_allowaccess", "0"); //set to 1 to allow cmd to execute console commands on the server.
@ -289,52 +290,77 @@ void SV_New_f (void)
ClientReliableWrite_Byte (host_client, 0);
ClientReliableWrite_String (host_client, gamedir);
splitnum = 0;
for (split = host_client; split; split = split->controlled)
if (host_client->fteprotocolextensions2 & PEXT2_MAXPLAYERS)
{
switch(svs.gametype)
/*is this a sane way to do it? or should we split the spectator thing off entirely?*/
ClientReliableWrite_Byte (host_client, sv.allocated_client_slots);
splitnum = 0;
for (split = host_client, splitnum = 0; split; split = split->controlled)
splitnum++;
ClientReliableWrite_Byte (host_client, (split->spectator?128:0) | splitnum);
for (split = host_client; split; split = split->controlled)
{
#ifdef HLSERVER
case GT_HALFLIFE:
playernum = split - svs.clients;
break;
#endif
#ifdef Q2SERVER
case GT_QUAKE2:
playernum = Q2NUM_FOR_EDICT(split->q2edict)-1;
break;
#endif
default:
playernum = NUM_FOR_EDICT(svprogfuncs, split->edict)-1;
}
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostate)
{
playernum = (MAX_CLIENTS-1-splitnum)|128;
}
else
#endif
if (split->spectator)
playernum |= 128;
if (sv.state == ss_cinematic)
playernum = -1;
if (ISQ2CLIENT(host_client))
ClientReliableWrite_Short (host_client, playernum);
else
if (sv.state == ss_cinematic)
playernum = -1;
ClientReliableWrite_Byte (host_client, playernum);
split->state = cs_connected;
split->connection_started = realtime;
#ifdef SVRANKING
split->stats_started = realtime;
#endif
splitnum++;
split->state = cs_connected;
split->connection_started = realtime;
#ifdef SVRANKING
split->stats_started = realtime;
splitnum++;
}
}
else
{
splitnum = 0;
for (split = host_client; split; split = split->controlled)
{
switch(svs.gametype)
{
#ifdef HLSERVER
case GT_HALFLIFE:
playernum = split - svs.clients;
break;
#endif
#ifdef Q2SERVER
case GT_QUAKE2:
playernum = Q2NUM_FOR_EDICT(split->q2edict)-1;
break;
#endif
default:
playernum = NUM_FOR_EDICT(svprogfuncs, split->edict)-1;
}
#ifdef SERVER_DEMO_PLAYBACK
if (sv.demostate)
{
playernum = (MAX_CLIENTS-1-splitnum)|128;
}
else
#endif
if (split->spectator)
playernum |= 128;
if (host_client->fteprotocolextensions & PEXT_SPLITSCREEN)
ClientReliableWrite_Byte (host_client, 128);
if (sv.state == ss_cinematic)
playernum = -1;
if (ISQ2CLIENT(host_client))
ClientReliableWrite_Short (host_client, playernum);
else
ClientReliableWrite_Byte (host_client, playernum);
split->state = cs_connected;
split->connection_started = realtime;
#ifdef SVRANKING
split->stats_started = realtime;
#endif
splitnum++;
}
if (host_client->fteprotocolextensions & PEXT_SPLITSCREEN)
ClientReliableWrite_Byte (host_client, 128);
}
// send full levelname
#ifdef SERVER_DEMO_PLAYBACK
@ -1244,7 +1270,7 @@ void SVQW_PreSpawn_f (void)
if (state->hexen2flags || state->trans || state->modelindex >= 256 || state->frame > 255 || state->scale || state->abslight)
{
MSG_WriteByte(&host_client->netchan.message, svc_spawnstatic2);
SV_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions);
SVQW_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions);
continue;
}
}
@ -1305,7 +1331,7 @@ void SVQW_PreSpawn_f (void)
else if (host_client->fteprotocolextensions & PEXT_SPAWNSTATIC2)
{
MSG_WriteByte(&host_client->netchan.message, svcfte_spawnbaseline2);
SV_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions);
SVQW_WriteDelta(&from, state, &host_client->netchan.message, true, host_client->fteprotocolextensions);
}
else if (state->modelindex < 256)
{
@ -1601,6 +1627,7 @@ void SV_Begin_Core(client_t *split)
ge->ClientBegin(split->q2edict);
split->istobeloaded = false;
sv.spawned_client_slots++;
}
else
#endif
@ -4751,10 +4778,10 @@ void SV_Pext_f(void)
switch(strtoul(tag, NULL, 0))
{
case PROTOCOL_VERSION_FTE:
host_client->fteprotocolextensions = strtoul(val, NULL, 0) & svs.fteprotocolextensions;
host_client->fteprotocolextensions = strtoul(val, NULL, 0) & Net_PextMask(1);
break;
case PROTOCOL_VERSION_FTE2:
host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & svs.fteprotocolextensions2;
host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & Net_PextMask(2);
break;
}
}
@ -5231,14 +5258,14 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
if (check->v->owner == pl)
continue; // player's own missile
if (check->v->solid == SOLID_BSP
if (check == player)
continue;
if ((check->v->solid == SOLID_TRIGGER && check->v->skin < 0) || check->v->solid == SOLID_BSP
|| check->v->solid == SOLID_BBOX
|| check->v->solid == SOLID_SLIDEBOX
//|| (check->v->solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it
)
{
if (check == player)
continue;
for (i=0 ; i<3 ; i++)
if (check->v->absmin[i] > pmove_maxs[i]
@ -5259,6 +5286,28 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
VectorCopy (check->v->origin, pe->origin);
pe->info = NUM_FOR_EDICT(svprogfuncs, check);
pe->nonsolid = check->v->solid == SOLID_TRIGGER;
switch((int)check->v->skin)
{
case Q1CONTENTS_WATER:
pe->forcecontentsmask = FTECONTENTS_WATER;
break;
case Q1CONTENTS_LAVA:
pe->forcecontentsmask = FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SLIME:
pe->forcecontentsmask = FTECONTENTS_SLIME;
break;
case Q1CONTENTS_SKY:
pe->forcecontentsmask = FTECONTENTS_SKY;
break;
case -16:
pe->forcecontentsmask = FTECONTENTS_LADDER;
break;
default:
pe->forcecontentsmask = 0;
break;
}
if (check->v->solid == SOLID_BSP)
{
if(progstype != PROG_H2)
@ -5709,7 +5758,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
pmove.numphysent = 1;
pmove.physents[0].model = sv.world.worldmodel;
pmove.cmd = *ucmd;
pmove.hullnum = SV_HullNumForPlayer(sv_player->xv->hull, sv_player->v->mins, sv_player->v->maxs);
pmove.skipent = -1;
movevars.entgravity = host_client->entgravity/movevars.gravity;
movevars.maxspeed = host_client->maxspeed;
@ -6064,9 +6113,12 @@ void SV_ExecuteClientMessage (client_t *cl)
{ //split screen doesn't always have frames.
frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
if (cl->lastsequence_acknoledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged)
if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged)
{
frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please
/*note that if there is packetloss, we can change a single frame's ping_time multiple times
this means that the 'ping' is more latency than ping times*/
if (frame->ping_time == -1 || !sv_ping_ignorepl.ival)
frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please
if (cl->spectator)
cl->delay = 0;
@ -6087,15 +6139,18 @@ void SV_ExecuteClientMessage (client_t *cl)
}
}
#ifdef PEXT_CSQC
if (cl->lastsequence_acknoledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged)
if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged)
{
for (i = cl->lastsequence_acknoledged+1; i < cl->netchan.incoming_acknowledged; i++)
for (i = cl->lastsequence_acknowledged+1; i < cl->netchan.incoming_acknowledged; i++)
SV_CSQC_DroppedPacket(cl, i);
}
else
{
/*too much loss, we don't know what was sent when, so reset the entire entity state*/
SV_CSQC_DropAll(cl);
}
#endif
cl->lastsequence_acknoledged = cl->netchan.incoming_acknowledged;
cl->lastsequence_acknowledged = cl->netchan.incoming_acknowledged;
if (sv_antilag.ival)
{
@ -6137,6 +6192,7 @@ void SV_ExecuteClientMessage (client_t *cl)
// save time for ping calculations
if (cl->frameunion.frames)
{ //split screen doesn't always have frames.
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].sequence = cl->netchan.outgoing_sequence;
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
cl->frameunion.frames[cl->netchan.outgoing_sequence & UPDATE_MASK].move_msecs = -1;

View file

@ -1533,26 +1533,6 @@ extern vec3_t player_maxs;
continue;
pe = &pmove.physents[pmove.numphysent];
if (other->v.modelindex)
{
pe->model = sv.models[other->v.modelindex];
if (pe->model && pe->model->type != mod_brush)
pe->model = NULL;
}
else
pe->model = NULL;
pmove.numphysent++;
pe->info = other - SVHL_Edict;
VectorCopy(other->v.origin, pe->origin);
VectorCopy(other->v.mins, pe->mins);
VectorCopy(other->v.maxs, pe->maxs);
VectorCopy(other->v.angles, pe->angles);
if (other->v.solid == SOLID_NOT || other->v.solid == SOLID_TRIGGER)
pe->nonsolid = true;
else
pe->nonsolid = false;
switch(other->v.skin)
{
case Q1CONTENTS_EMPTY:
@ -1580,6 +1560,30 @@ extern vec3_t player_maxs;
pe->forcecontentsmask = 0;
break;
}
if (other->v.solid == SOLID_NOT || other->v.solid == SOLID_TRIGGER)
{
if (!pe->forcecontentsmask)
continue;
pe->nonsolid = true;
}
else
pe->nonsolid = false;
if (other->v.modelindex)
{
pe->model = sv.models[other->v.modelindex];
if (pe->model && pe->model->type != mod_brush)
pe->model = NULL;
}
else
pe->model = NULL;
pmove.numphysent++;
pe->info = other - SVHL_Edict;
VectorCopy(other->v.origin, pe->origin);
VectorCopy(other->v.mins, pe->mins);
VectorCopy(other->v.maxs, pe->maxs);
VectorCopy(other->v.angles, pe->angles);
}
}

View file

@ -541,7 +541,7 @@ void SVQ2_WritePlayerstateToClient (q2client_frame_t *from, q2client_frame_t *to
SV_WriteFrameToClient
==================
*/
void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
void SVQ2_WriteFrameToClient (client_t *client, sizebuf_t *msg)
{
q2client_frame_t *frame, *oldframe;
int lastframe;
@ -602,7 +602,7 @@ copies off the playerstat and areabits.
=============
*/
void SVQ2_Ents_Init(void);
void SV_BuildClientFrame (client_t *client)
void SVQ2_BuildClientFrame (client_t *client)
{
int e, i;
vec3_t org;

View file

@ -736,6 +736,9 @@ qboolean SVQ2_InitGameProgs(void)
*/
}
Cvar_ForceSet(Cvar_Get("game", "", CVAR_LATCH, "Q2 compat"), FS_GetGamedir());
Cvar_ForceSet(Cvar_Get("basedir", "", CVAR_LATCH, "Q2 compat"), FS_GetBasedir());
ge = (game_export_t *)Sys_GetGameAPI ((game_import_t*)&import);
if (!ge)

View file

@ -1773,6 +1773,7 @@ void SVQ3_ClientCommand(client_t *cl)
void SVQ3_ClientBegin(client_t *cl)
{
VM_Call(q3gamevm, GAME_CLIENT_BEGIN, (int)(cl-svs.clients));
sv.spawned_client_slots++;
}
void SVQ3_ClientThink(client_t *cl)
@ -2360,7 +2361,7 @@ void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3)
q3->apos.trBase[1] = 0;
q3->pos.trDelta[2] = 0;
q3->apos.trBase[0] = 0;
q3->event = q1->event;
q3->event = 0;
q3->angles2[1] = 0;
q3->eType = 0;
q3->torsoAnim = q1->skinnum;
@ -2382,12 +2383,12 @@ void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3)
q3->powerups = q1->effects;
q3->modelindex = q1->modelindex;
q3->otherEntityNum2 = 0;
q3->loopSound = q1->sound;
q3->loopSound = 0;
q3->generic1 = q1->trans;
q3->origin2[2] = q1->old_origin[2];
q3->origin2[0] = q1->old_origin[0];
q3->origin2[1] = q1->old_origin[1];
q3->modelindex2 = q1->modelindex2;
q3->origin2[2] = 0;//q1->old_origin[2];
q3->origin2[0] = 0;//q1->old_origin[0];
q3->origin2[1] = 0;//q1->old_origin[1];
q3->modelindex2 = 0;//q1->modelindex2;
q3->angles[0] = q1->angles[0];
q3->time = 0;
q3->apos.trTime = 0;
@ -3068,13 +3069,13 @@ void SVQ3_ParseClientMessage(client_t *client)
Con_Printf(CON_WARNING "WARNING: Junk at end of packet for client %s\n", client->name );
}
};
void SVQ3_HandleClient(void)
qboolean SVQ3_HandleClient(void)
{
int i;
int qport;
if (net_message.cursize<6)
return; //urm. :/
return false; //urm. :/
MSG_BeginReading(msg_nullnetprim);
MSG_ReadBits(32);
@ -3088,19 +3089,22 @@ void SVQ3_HandleClient(void)
continue;
if (!NET_CompareBaseAdr(svs.clients[i].netchan.remote_address, net_from))
continue;
if (!ISQ3CLIENT(&svs.clients[i]))
continue;
//found them.
break;
}
if (i == sv.allocated_client_slots)
return; //nope
return false; //nope
if (!SVQ3_Netchan_Process(&svs.clients[i]))
{
return; // wasn't accepted for some reason
return true; // wasn't accepted for some reason
}
SVQ3_ParseClientMessage(&svs.clients[i]);
return true;
}
void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and let the gamecode know of it.