Support ezquake's kinda flawed float-ent-coords workaround extension. Update PEXT2_VRINPUTS for base angles (for angle nudges when standing on rotating objects).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5998 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-08-04 21:16:57 +00:00
parent 5584fb1ab1
commit 14e7517b16
17 changed files with 321 additions and 113 deletions

View File

@ -1456,7 +1456,7 @@ static int CL_Record_ParticlesStaticsBaselines(sizebuf_t *buf, int seq)
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{ {
MSG_WriteByte(buf, svcfte_spawnstatic2); MSG_WriteByte(buf, svcfte_spawnstatic2);
SVFTE_EmitBaseline(es, false, buf, cls.fteprotocolextensions2); SVFTE_EmitBaseline(es, false, buf, cls.fteprotocolextensions2, cls.ezprotocolextensions1);
} }
//else if (cls.fteprotocolextensions & PEXT_SPAWNSTATIC2) //qw deltas //else if (cls.fteprotocolextensions & PEXT_SPAWNSTATIC2) //qw deltas
else else
@ -1516,7 +1516,7 @@ static int CL_Record_ParticlesStaticsBaselines(sizebuf_t *buf, int seq)
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{ {
MSG_WriteByte(buf, svcfte_spawnbaseline2); MSG_WriteByte(buf, svcfte_spawnbaseline2);
SVFTE_EmitBaseline(es, true, buf, cls.fteprotocolextensions2); SVFTE_EmitBaseline(es, true, buf, cls.fteprotocolextensions2, cls.ezprotocolextensions1);
} }
//else if (cls.fteprotocolextensions & PEXT_SPAWNSTATIC2) //qw deltas //else if (cls.fteprotocolextensions & PEXT_SPAWNSTATIC2) //qw deltas
else else

View File

@ -621,13 +621,26 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
news->frame = MSG_ReadByte(); news->frame = MSG_ReadByte();
} }
if (bits & UF_ORIGINXY) if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS)
{ {
news->origin[0] = MSG_ReadCoord(); if (bits & UF_ORIGINXY)
news->origin[1] = MSG_ReadCoord(); {
news->origin[0] = MSG_ReadFloat();
news->origin[1] = MSG_ReadFloat();
}
if (bits & UF_ORIGINZ)
news->origin[2] = MSG_ReadFloat();
}
else
{
if (bits & UF_ORIGINXY)
{
news->origin[0] = MSG_ReadCoord();
news->origin[1] = MSG_ReadCoord();
}
if (bits & UF_ORIGINZ)
news->origin[2] = MSG_ReadCoord();
} }
if (bits & UF_ORIGINZ)
news->origin[2] = MSG_ReadCoord();
if ((bits & UF_PREDINFO) && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO)) if ((bits & UF_PREDINFO) && !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{ {

View File

@ -1276,16 +1276,18 @@ static qboolean CLFTE_SendVRCmd (sizebuf_t *buf, unsigned int seats)
cl.numackframes = 0; cl.numackframes = 0;
} }
from = &nullcmd;
for (seat = 0; seat < seats; seat++) for (seat = 0; seat < seats; seat++)
{
from = &nullcmd;
for (frame = last-count; frame < last; frame++) for (frame = last-count; frame < last; frame++)
{ {
to = &cl.outframes[frame&UPDATE_MASK].cmd[seat]; to = &cl.outframes[frame&UPDATE_MASK].cmd[seat];
MSGFTE_WriteDeltaUsercmd (buf, from, to); MSGFTE_WriteDeltaUsercmd (buf, cl.playerview[seat].baseangles, from, to);
if (to->impulse && (int)(last-frame)>=cl_c2sImpulseBackup.ival) if (to->impulse && (int)(last-frame)>=cl_c2sImpulseBackup.ival)
dontdrop = true; dontdrop = true;
from = to; from = to;
} }
}
return dontdrop; return dontdrop;
} }
@ -1788,9 +1790,7 @@ void CL_UpdateSeats(void)
{ {
if (!cls.netchan.message.cursize && cl.allocated_client_slots > 1 && cls.state == ca_active && cl.splitclients && (cls.fteprotocolextensions & PEXT_SPLITSCREEN) && cl.worldmodel) if (!cls.netchan.message.cursize && cl.allocated_client_slots > 1 && cls.state == ca_active && cl.splitclients && (cls.fteprotocolextensions & PEXT_SPLITSCREEN) && cl.worldmodel)
{ {
int targ = cl_splitscreen.ival+1; int targ = bound(1, cl_splitscreen.ival+1, MAX_SPLITS);
if (targ > MAX_SPLITS)
targ = MAX_SPLITS;
if (cl.splitclients < targ) if (cl.splitclients < targ)
{ {
char *ver; char *ver;
@ -1823,7 +1823,7 @@ void CL_UpdateSeats(void)
InfoBuf_SetStarKey(info, "*ver", ver); InfoBuf_SetStarKey(info, "*ver", ver);
InfoBuf_ToString(info, infostr, sizeof(infostr), NULL, NULL, NULL, &cls.userinfosync, info); InfoBuf_ToString(info, infostr, sizeof(infostr), NULL, NULL, NULL, &cls.userinfosync, info);
CL_SendClientCommand(true, "addseat %i %s", cl.splitclients, COM_QuotedString(infostr, buffer, sizeof(buffer), false)); CL_SendClientCommand(true, "addseat %i %s", cl.splitclients+1, COM_QuotedString(infostr, buffer, sizeof(buffer), false));
} }
else if (cl.splitclients > targ && targ >= 1) else if (cl.splitclients > targ && targ >= 1)
CL_SendClientCommand(true, "addseat %i", targ); CL_SendClientCommand(true, "addseat %i", targ);

View File

@ -6929,6 +6929,55 @@ static void CL_ParsePortalState(void)
} }
} }
static void CL_ParseBaseAngle(int seat)
{
int i;
short diff[3];
short newbase[3];
vec3_t newang;
inframe_t *inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK];
qbyte fl = MSG_ReadByte(); //pitch yaw roll lock
for (i=0 ; i<3 ; i++)
{
if (fl & (1u<<i))
newbase[i] = MSG_ReadShort();
else
newbase[i] = 0;
diff[i] = newbase[i]-cl.playerview[seat].baseangles[i];
cl.playerview[seat].baseangles[i] = newbase[i];
if (fl & 8) //locking the view
newang[i] = SHORT2ANGLE(newbase[i]);
else //free-look
newang[i] = cl.playerview[seat].viewangles[i] + SHORT2ANGLE(diff[i]);
}
if (cl.ackedmovesequence)
{
//tweak all unacked input frames to the new base. the server will do similar on receipt of them.
i = min(64, cl.movesequence-cl.ackedmovesequence);
for (i = cl.movesequence-i; i < cl.movesequence; i++)
{
cl.outframes[i & UPDATE_MASK].cmd[seat].angles[0] += diff[0];
cl.outframes[i & UPDATE_MASK].cmd[seat].angles[1] += diff[1];
cl.outframes[i & UPDATE_MASK].cmd[seat].angles[2] += diff[2];
}
}
if (!CSQC_Parse_SetAngles(seat, newang, false))
{
if (fl & 8)
{
inf->packet_entities.fixangles[seat] = true;
VectorCopy (newang, inf->packet_entities.fixedangles[seat]);
}
VectorCopy (newang, cl.playerview[seat].viewangles);
}
VectorCopy (newang, cl.playerview[seat].intermissionangles);
}
#define SHOWNET(x) if(cl_shownet.value>=2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); #define SHOWNET(x) if(cl_shownet.value>=2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
#define SHOWNET2(x, y) if(cl_shownet.value>=2)Con_Printf ("%3i:%3i:%s\n", msg_readcount-1, y, x); #define SHOWNET2(x, y) if(cl_shownet.value>=2)Con_Printf ("%3i:%3i:%s\n", msg_readcount-1, y, x);
/* /*
@ -7130,6 +7179,9 @@ void CLQW_ParseServerMessage (void)
cl.playerview[destsplit].viewentity=MSGCL_ReadEntity(); cl.playerview[destsplit].viewentity=MSGCL_ReadEntity();
break; break;
#endif #endif
case svcfte_setanglebase:
CL_ParseBaseAngle(destsplit);
break;
case svcfte_setangledelta: case svcfte_setangledelta:
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
ang[i] = cl.playerview[destsplit].viewangles[i] + MSG_ReadAngle16 (); ang[i] = cl.playerview[destsplit].viewangles[i] + MSG_ReadAngle16 ();
@ -8385,6 +8437,10 @@ void CLNQ_ParseServerMessage (void)
CL_SetStatNumeric (destsplit, i, f, f); CL_SetStatNumeric (destsplit, i, f, f);
} }
break; break;
case svcfte_setanglebase:
CL_ParseBaseAngle(destsplit);
break;
case svcfte_setangledelta: case svcfte_setangledelta:
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
ang[i] = cl.playerview[destsplit].viewangles[i] + MSG_ReadAngle16 (); ang[i] = cl.playerview[destsplit].viewangles[i] + MSG_ReadAngle16 ();
@ -8396,6 +8452,8 @@ void CLNQ_ParseServerMessage (void)
case svc_setangle: case svc_setangle:
{ {
inframe_t *inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK]; inframe_t *inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK];
if (cls.ezprotocolextensions1 & EZPEXT1_SETANGLEREASON)
MSG_ReadByte(); //0=unknown, 1=tele, 2=spawn
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
ang[i] = MSG_ReadAngle(); ang[i] = MSG_ReadAngle();
if (!CSQC_Parse_SetAngles(destsplit, ang, false)) if (!CSQC_Parse_SetAngles(destsplit, ang, false))

View File

@ -664,6 +664,7 @@ struct playerview_s
vec3_t aimangles; //angles actually being sent to the server (different due to in_vraim) vec3_t aimangles; //angles actually being sent to the server (different due to in_vraim)
vec3_t viewangles; //current angles vec3_t viewangles; //current angles
vec3_t viewanglechange; //angles set by input code this frame vec3_t viewanglechange; //angles set by input code this frame
short baseangles[3]; //networked angles are relative to this value
vec3_t intermissionangles; //absolute angles for intermission vec3_t intermissionangles; //absolute angles for intermission
vec3_t gravitydir; vec3_t gravitydir;

View File

@ -1381,11 +1381,12 @@ static void MSG_WriteVR(int i, sizebuf_t *buf, const usercmd_t *from, const use
MSG_WriteFloat(buf, cmd->vr[i].velocity[2]); MSG_WriteFloat(buf, cmd->vr[i].velocity[2]);
} }
} }
void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const usercmd_t *cmd) void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const short baseangles[3], const usercmd_t *from, const usercmd_t *cmd)
{ {
unsigned int bits = 0; unsigned int bits = 0;
int i; int i;
short d; short d;
// //
// send the movement message // send the movement message
// //
@ -1440,15 +1441,16 @@ void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const user
if (MSG_CompareVR(VRDEV_LEFT, from, cmd)) if (MSG_CompareVR(VRDEV_LEFT, from, cmd))
bits |= UC_VR_LEFT; bits |= UC_VR_LEFT;
//NOTE: WriteUInt64 actually uses some utf-8-like length coding, so its not quite as bloated as it looks. //NOTE: WriteUInt64 actually uses some length coding, so its not quite as bloated as it looks.
MSG_WriteUInt64(buf, bits); MSG_WriteUInt64(buf, bits);
MSG_WriteUInt64(buf, cmd->servertime-from->servertime); MSG_WriteUInt64(buf, cmd->servertime-from->servertime);
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
if (bits & (UC_ANGLE1<<i)) if (bits & (UC_ANGLE1<<i))
{ {
if (bits & UC_ABSANG) if (bits & UC_ABSANG)
MSG_WriteShort(buf, cmd->angles[i]); MSG_WriteShort(buf, cmd->angles[i]-baseangles[i]);
else else
MSG_WriteChar(buf, cmd->angles[i]-from->angles[i]); MSG_WriteChar(buf, cmd->angles[i]-from->angles[i]);
} }
@ -1539,7 +1541,9 @@ static void MSG_ReadVR(int i, usercmd_t *cmd)
void MSGFTE_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *cmd) void MSGFTE_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *cmd)
{ {
int i; int i;
unsigned int bits = MSG_ReadUInt64(); unsigned int bits;
bits = MSG_ReadUInt64();
if (bits & UC_UNSUPPORTED) if (bits & UC_UNSUPPORTED)
{ {

View File

@ -318,7 +318,7 @@ void MSG_WriteBigCoord (sizebuf_t *sb, float f);
void MSG_WriteAngle (sizebuf_t *sb, float f); void MSG_WriteAngle (sizebuf_t *sb, float f);
void MSG_WriteAngle8 (sizebuf_t *sb, float f); void MSG_WriteAngle8 (sizebuf_t *sb, float f);
void MSG_WriteAngle16 (sizebuf_t *sb, float f); void MSG_WriteAngle16 (sizebuf_t *sb, float f);
void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const struct usercmd_s *from, const struct usercmd_s *cmd); void MSGFTE_WriteDeltaUsercmd (sizebuf_t *buf, const short baseanges[3], const struct usercmd_s *from, const struct usercmd_s *cmd);
void MSGQW_WriteDeltaUsercmd (sizebuf_t *sb, const struct usercmd_s *from, const struct usercmd_s *cmd); void MSGQW_WriteDeltaUsercmd (sizebuf_t *sb, const struct usercmd_s *from, const struct usercmd_s *cmd);
void MSGCL_WriteDeltaUsercmd (sizebuf_t *sb, const struct usercmd_s *from, const struct usercmd_s *cmd); void MSGCL_WriteDeltaUsercmd (sizebuf_t *sb, const struct usercmd_s *from, const struct usercmd_s *cmd);
void MSG_WriteDir (sizebuf_t *sb, float *dir); void MSG_WriteDir (sizebuf_t *sb, float *dir);

View File

@ -243,7 +243,13 @@ unsigned int Net_PextMask(unsigned int protover, qboolean fornq)
} }
else if (protover == PROTOCOL_VERSION_EZQUAKE1) else if (protover == PROTOCOL_VERSION_EZQUAKE1)
{ {
mask = EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON; mask = EZPEXT1_FLOATENTCOORDS;//|EZPEXT1_SETANGLEREASON;
if (fornq)
{
mask &= ~EZPEXT1_FLOATENTCOORDS; //keep things simple. interactions are not defined.
mask &= ~EZPEXT1_SETANGLEREASON; //potentially breaks too many nq mods. don't encourage it.
}
} }
return mask; return mask;

View File

@ -1242,14 +1242,14 @@ static void PM_NudgePosition (void)
{ {
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
{ {
if (pmove.velocity[i]) /*if (pmove.velocity[i])
{ //round in the direction of velocity, which means we're less likely to get stuck. { //round in the direction of velocity, which means we're less likely to get stuck.
if (pmove.velocity[i] >= 0) if (pmove.velocity[i] >= 0)
nudged[i] = (qintptr_t)(base[i]*8+0.5f) / 8.0; nudged[i] = (qintptr_t)(base[i]*8+0.5f) / 8.0;
else else
nudged[i] = (qintptr_t)(base[i]*8-0.5f) / 8.0; nudged[i] = (qintptr_t)(base[i]*8-0.5f) / 8.0;
} }
else else*/
{ {
if (base[i] >= 0) if (base[i] >= 0)
nudged[i] = (qintptr_t)(base[i]*8+0.5f) / 8.0; nudged[i] = (qintptr_t)(base[i]*8+0.5f) / 8.0;

View File

@ -123,7 +123,7 @@ typedef struct {
qboolean autobunny; qboolean autobunny;
int stepheight; int stepheight;
qbyte coordtype; //FIXME: EZPEXT1_FLOATENTCOORDS should mean 4, but the result does not match ezquake/mvdsv which would result in inconsistencies. so player coords are rounded inconsistently. qbyte coordtype; //FIXME: EZPEXT1_FLOATENTCOORDS should mean 4, but the result does not match ezquake/mvdsv's round-towards-origin which would result in inconsistencies. so player coords are rounded inconsistently.
unsigned int flags; unsigned int flags;
} movevars_t; } movevars_t;

View File

@ -89,7 +89,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//EzQuake/Mvdsv extensions. (use ezquake name, to avoid confusion about .mvd format and its protocol differences) //EzQuake/Mvdsv extensions. (use ezquake name, to avoid confusion about .mvd format and its protocol differences)
#define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding... #define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding...
#define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue. #define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue.
#define EZPEXT1_SERVERADVERTISE 0 #define EZPEXT1_SERVERADVERTISE EZPEXT1_FLOATENTCOORDS/* - implemented, but interactions with replacementdeltas is not defined*/ /*EZPEXT1_SETANGLEREASON - potentially causes compat issues with mods that stuffcmd it (common in nq)*/
#define EZPEXT1_CLIENTADVERTISE EZPEXT1_FLOATENTCOORDS //might as well ask for it, as a way around mvdsv's writecoord/PM_NudgePosition rounding difference bug. #define EZPEXT1_CLIENTADVERTISE EZPEXT1_FLOATENTCOORDS //might as well ask for it, as a way around mvdsv's writecoord/PM_NudgePosition rounding difference bug.
#define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON) //ones we can support in demos. warning if other bits. #define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON) //ones we can support in demos. warning if other bits.
@ -330,6 +330,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define svcfte_cgamepacket_sized 90 //svcfte_cgamepacket with an extra short size right after the svc. #define svcfte_cgamepacket_sized 90 //svcfte_cgamepacket with an extra short size right after the svc.
#define svcfte_temp_entity_sized 91 //svc_temp_entity with an extra short size right after the svc (high bit means nq, unset means qw). #define svcfte_temp_entity_sized 91 //svc_temp_entity with an extra short size right after the svc (high bit means nq, unset means qw).
#define svcfte_csqcentities_sized 92 //entity lump for csqc (with size info) #define svcfte_csqcentities_sized 92 //entity lump for csqc (with size info)
#define svcfte_setanglebase 93 //updates the base angle (and optionally locks the view, otherwise nudging it without race conditions.)
//fitz svcs //fitz svcs
#define svcfitz_skybox 37 #define svcfitz_skybox 37

View File

@ -360,6 +360,9 @@ typedef struct
unsigned short resendstats[32];//the number of each entity that was sent in this frame unsigned short resendstats[32];//the number of each entity that was sent in this frame
unsigned int numresendstats; //the bits of each entity that were sent in this frame unsigned int numresendstats; //the bits of each entity that were sent in this frame
short baseangles[MAX_SPLITS][3];
unsigned int baseanglelocked[MAX_SPLITS];
//antilag //antilag
//these are to recalculate the player's origin without old knockbacks nor teleporters, to give more accurate weapon start positions (post-command). //these are to recalculate the player's origin without old knockbacks nor teleporters, to give more accurate weapon start positions (post-command).
vec3_t pmorigin; vec3_t pmorigin;
@ -502,6 +505,8 @@ typedef struct client_s
infosync_t infosync; // information about the infos that the client still doesn't know (server and multiple clients). infosync_t infosync; // information about the infos that the client still doesn't know (server and multiple clients).
char *transfer; char *transfer;
unsigned int baseanglelock; // lock the player angles to base (until baseangle sequence is acked)
short baseangles[3]; // incoming angle inputs are relative to this value.
usercmd_t lastcmd; // for filling in big drops and partial predictions usercmd_t lastcmd; // for filling in big drops and partial predictions
double localtime; // of last message double localtime; // of last message
qboolean jump_held; qboolean jump_held;
@ -1197,7 +1202,7 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info);
int SV_ModelIndex (const char *name); int SV_ModelIndex (const char *name);
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg); void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
void SVQW_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, unsigned int ezext);
client_t *SV_AddSplit(client_t *controller, char *info, int id); client_t *SV_AddSplit(client_t *controller, char *info, int id);
void SV_SpawnParmsToQC(client_t *client); void SV_SpawnParmsToQC(client_t *client);
@ -1412,7 +1417,7 @@ qboolean PR_ShouldTogglePause(client_t *initiator, qboolean pausedornot);
// sv_ents.c // sv_ents.c
// //
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs); void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs);
void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, unsigned int pext2); void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, unsigned int pext2, unsigned int ezext);
void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack); void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack);
void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *client, packet_entities_t *pack); void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *client, packet_entities_t *pack);
int SV_HullNumForPlayer(int h2hull, float *mins, float *maxs); int SV_HullNumForPlayer(int h2hull, float *mins, float *maxs);

View File

@ -649,7 +649,7 @@ Writes part of a packetentities message.
Can delta from either a baseline or a previous packet_entity Can delta from either a baseline or a previous packet_entity
================== ==================
*/ */
void SVQW_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, unsigned int ezext)
{ {
#ifdef PROTOCOLEXTENSIONS #ifdef PROTOCOLEXTENSIONS
int evenmorebits=0; int evenmorebits=0;
@ -659,19 +659,23 @@ void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
int fromeffects; int fromeffects;
coorddata coordd[3]; coorddata coordd[3];
coorddata angled[3]; coorddata angled[3];
qbyte coordtype = msg->prim.coordtype;
if (from == &((edict_t*)NULL)->baseline) if (from == &((edict_t*)NULL)->baseline)
from = &nullentitystate; from = &nullentitystate;
if (ezext&EZPEXT1_FLOATENTCOORDS)
coordtype = COORDTYPE_FLOAT_32;
// send an update // send an update
bits = 0; bits = 0;
if (msg->prim.coordtype != COORDTYPE_FLOAT_32) if (coordtype != COORDTYPE_FLOAT_32)
{ {
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
{ {
coordd[i] = MSG_ToCoord(to->origin[i], msg->prim.coordtype); coordd[i] = MSG_ToCoord(to->origin[i], coordtype);
if (MSG_ToCoord(from->origin[i], msg->prim.coordtype).b4 != coordd[i].b4) if (MSG_ToCoord(from->origin[i], coordtype).b4 != coordd[i].b4)
bits |= U_ORIGIN1<<i; bits |= U_ORIGIN1<<i;
else else
to->origin[i] = from->origin[i]; to->origin[i] = from->origin[i];
@ -681,7 +685,7 @@ void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
{ {
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
{ {
coordd[i] = MSG_ToCoord(to->origin[i], msg->prim.coordtype); coordd[i] = MSG_ToCoord(to->origin[i], coordtype);
if (to->origin[i] != from->origin[i]) if (to->origin[i] != from->origin[i])
bits |= U_ORIGIN1<<i; bits |= U_ORIGIN1<<i;
} }
@ -845,15 +849,15 @@ void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg,
if (bits & U_EFFECTS) if (bits & U_EFFECTS)
MSG_WriteByte (msg, to->effects&0x00ff); MSG_WriteByte (msg, to->effects&0x00ff);
if (bits & U_ORIGIN1) if (bits & U_ORIGIN1)
SZ_Write(msg, &coordd[0], msg->prim.coordtype&0xf); SZ_Write(msg, &coordd[0], (coordtype&0xf));
if (bits & U_ANGLE1) if (bits & U_ANGLE1)
SZ_Write(msg, &angled[0], msg->prim.anglesize); SZ_Write(msg, &angled[0], msg->prim.anglesize);
if (bits & U_ORIGIN2) if (bits & U_ORIGIN2)
SZ_Write(msg, &coordd[1], msg->prim.coordtype&0xf); SZ_Write(msg, &coordd[1], (coordtype&0xf));
if (bits & U_ANGLE2) if (bits & U_ANGLE2)
SZ_Write(msg, &angled[1], msg->prim.anglesize); SZ_Write(msg, &angled[1], msg->prim.anglesize);
if (bits & U_ORIGIN3) if (bits & U_ORIGIN3)
SZ_Write(msg, &coordd[2], msg->prim.coordtype&0xf); SZ_Write(msg, &coordd[2], (coordtype&0xf));
if (bits & U_ANGLE3) if (bits & U_ANGLE3)
SZ_Write(msg, &angled[2], msg->prim.anglesize); SZ_Write(msg, &angled[2], msg->prim.anglesize);
@ -1030,7 +1034,7 @@ static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, qbyte *frombonedat
return bits; return bits;
} }
static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg, unsigned int pext2, qbyte *boneptr) static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg, unsigned int pext2, unsigned int ezext1, qbyte *boneptr)
{ {
unsigned int predbits = 0; unsigned int predbits = 0;
if (bits & UF_MOVETYPE) if (bits & UF_MOVETYPE)
@ -1102,13 +1106,27 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_
else else
MSG_WriteByte(msg, state->frame); MSG_WriteByte(msg, state->frame);
} }
if (bits & UF_ORIGINXY)
if (ezext1 & EZPEXT1_FLOATENTCOORDS)
{ {
MSG_WriteCoord(msg, state->origin[0]); if (bits & UF_ORIGINXY)
MSG_WriteCoord(msg, state->origin[1]); {
MSG_WriteFloat(msg, state->origin[0]);
MSG_WriteFloat(msg, state->origin[1]);
}
if (bits & UF_ORIGINZ)
MSG_WriteFloat(msg, state->origin[2]);
}
else
{
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_ORIGINZ)
MSG_WriteCoord(msg, state->origin[2]);
if ((bits & UF_PREDINFO) && !(pext2 & PEXT2_PREDINFO)) if ((bits & UF_PREDINFO) && !(pext2 & PEXT2_PREDINFO))
{ /*if we have pred info, use more precise angles*/ { /*if we have pred info, use more precise angles*/
@ -1327,13 +1345,13 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_
} }
/*dump out the delta from baseline (used for baselines and statics, so has no svc)*/ /*dump out the delta from baseline (used for baselines and statics, so has no svc)*/
void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, unsigned int pext2) void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, unsigned int pext2, unsigned int ezext)
{ {
unsigned int bits; unsigned int bits;
if (numberisimportant) if (numberisimportant)
MSG_WriteEntity(msg, to->number); MSG_WriteEntity(msg, to->number);
bits = UF_RESET | SVFTE_DeltaCalcBits(&nullentitystate, NULL, to, NULL); bits = UF_RESET | SVFTE_DeltaCalcBits(&nullentitystate, NULL, to, NULL);
SVFTE_WriteUpdate(bits, to, msg, pext2, NULL); SVFTE_WriteUpdate(bits, to, msg, pext2, ezext, NULL);
} }
/*SVFTE_EmitPacketEntities /*SVFTE_EmitPacketEntities
@ -1508,6 +1526,43 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
outno = 0; outno = 0;
outmax = frame->maxresend; outmax = frame->maxresend;
if (client->fteprotocolextensions2 & PEXT2_VRINPUTS)
{
client_frame_t *ackedframe = &client->frameunion.frames[client->delta_sequence & UPDATE_MASK];
client_t *seat;
for (i = 0, seat = client; i < MAX_SPLITS && seat; i++, seat = seat->controlled)
{
if (ackedframe->baseanglelocked[i] != seat->baseanglelock ||
ackedframe->baseangles[i][0] != seat->baseangles[0] ||
ackedframe->baseangles[i][1] != seat->baseangles[1] ||
ackedframe->baseangles[i][2] != seat->baseangles[2])
{ //change the base angle, and force the client to it.
//sent every frame its valid for, because we really don't want packetloss here.
int fl = 0, j;
for (j = 0; j < 3; j++)
if (seat->baseangles[j])
fl |= (1u<<j);
if (ackedframe->baseanglelocked[i] != seat->baseanglelock)
fl |= 8;
if (seat->seat)
{
MSG_WriteByte (msg, svcfte_choosesplitclient);
MSG_WriteByte (msg, seat->seat);
}
MSG_WriteByte (msg, svcfte_setanglebase);
MSG_WriteByte(msg, fl);
for (j = 0; j < 3; j++)
if (fl&(1u<<j))
MSG_WriteShort(msg, seat->baseangles[j]);
}
VectorCopy(seat->baseangles, frame->baseangles[i]);
frame->baseanglelocked[i] = seat->baseanglelock;
}
}
if (msg->cursize + 52 <= msg->maxsize) if (msg->cursize + 52 <= msg->maxsize)
{ {
/*start writing the packet*/ /*start writing the packet*/
@ -1579,7 +1634,7 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
resend[outno].bits = bits; resend[outno].bits = bits;
SV_EmitDeltaEntIndex(msg, j, false, true); SV_EmitDeltaEntIndex(msg, j, false, true);
SVFTE_WriteUpdate(bits, &client->sentents.entities[j], msg, client->fteprotocolextensions2, client->sentents.bonedata); SVFTE_WriteUpdate(bits, &client->sentents.entities[j], msg, client->fteprotocolextensions2, client->ezprotocolextensions1, client->sentents.bonedata);
} }
client->pendingdeltabits[j] = 0; client->pendingdeltabits[j] = 0;
@ -1675,7 +1730,7 @@ void SVQW_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t
{ // delta update from old position { // delta update from old position
//Con_Printf ("delta %i\n", newnum); //Con_Printf ("delta %i\n", newnum);
#ifdef PROTOCOLEXTENSIONS #ifdef PROTOCOLEXTENSIONS
SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, client->fteprotocolextensions); SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false, client->fteprotocolextensions, client->ezprotocolextensions1);
#else #else
SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false); SVQW_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false);
#endif #endif
@ -1692,7 +1747,7 @@ void SVQW_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t
ent = NULL; ent = NULL;
//Con_Printf ("baseline %i\n", newnum); //Con_Printf ("baseline %i\n", newnum);
#ifdef PROTOCOLEXTENSIONS #ifdef PROTOCOLEXTENSIONS
SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true, client->fteprotocolextensions); SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true, client->fteprotocolextensions, client->ezprotocolextensions1);
#else #else
SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true); SVQW_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true);
#endif #endif
@ -2127,8 +2182,9 @@ typedef struct {
qboolean isself; qboolean isself;
qboolean onground; qboolean onground;
qboolean solid; qboolean solid;
int fteext; unsigned int fteext1;
int zext; unsigned int ezext1;
unsigned int zext;
int hull; int hull;
client_t *cl; client_t *cl;
} clstate_t; } clstate_t;
@ -2188,29 +2244,29 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent)
if (ent->spectator == 2 && ent->weaponframe) //it's not us, but we are spectating, so we need the correct weaponframe if (ent->spectator == 2 && ent->weaponframe) //it's not us, but we are spectating, so we need the correct weaponframe
pflags |= PF_WEAPONFRAME; pflags |= PF_WEAPONFRAME;
if (!ent->isself || (ent->fteext & PEXT_SPLITSCREEN)) if (!ent->isself || (ent->fteext1 & PEXT_SPLITSCREEN))
{ {
#ifdef PEXT_SCALE //this is graphics, not physics #ifdef PEXT_SCALE //this is graphics, not physics
if (ent->fteext & PEXT_SCALE) if (ent->fteext1 & PEXT_SCALE)
{ {
if (ent->scale && ent->scale != 1) pflags |= PF_SCALE; if (ent->scale && ent->scale != 1) pflags |= PF_SCALE;
} }
#endif #endif
#ifdef PEXT_TRANS #ifdef PEXT_TRANS
if (ent->fteext & PEXT_TRANS) if (ent->fteext1 & PEXT_TRANS)
{ {
if (ent->transparency) pflags |= PF_TRANS; if (ent->transparency) pflags |= PF_TRANS;
} }
#endif #endif
#ifdef PEXT_FATNESS #ifdef PEXT_FATNESS
if (ent->fteext & PEXT_FATNESS) if (ent->fteext1 & PEXT_FATNESS)
{ {
if (ent->fatness) pflags |= PF_FATNESS; if (ent->fatness) pflags |= PF_FATNESS;
} }
#endif #endif
} }
#ifdef PEXT_HULLSIZE #ifdef PEXT_HULLSIZE
if (ent->fteext & PEXT_HULLSIZE) if (ent->fteext1 & PEXT_HULLSIZE)
{ {
hullnumber = SV_HullNumForPlayer(ent->hull, ent->mins, ent->maxs); hullnumber = SV_HullNumForPlayer(ent->hull, ent->mins, ent->maxs);
if (hullnumber != 1) if (hullnumber != 1)
@ -2273,7 +2329,7 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent)
MSG_WriteByte (msg, svc_playerinfo); MSG_WriteByte (msg, svc_playerinfo);
MSG_WriteByte (msg, ent->playernum); MSG_WriteByte (msg, ent->playernum);
if (ent->fteext & (PEXT_HULLSIZE|PEXT_TRANS|PEXT_SCALE|PEXT_FATNESS)) if (ent->fteext1 & (PEXT_HULLSIZE|PEXT_TRANS|PEXT_SCALE|PEXT_FATNESS))
{ {
if (pflags & 0xff0000) if (pflags & 0xff0000)
pflags |= PF_EXTRA_PFS; pflags |= PF_EXTRA_PFS;
@ -2286,7 +2342,12 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent)
//we need to tell the client that it's moved, as it's own origin might not be natural //we need to tell the client that it's moved, as it's own origin might not be natural
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
MSG_WriteCoord (msg, ent->origin[i]); {
if (ent->ezext1 & EZPEXT1_FLOATENTCOORDS)
MSG_WriteFloat (msg, ent->origin[i]);
else
MSG_WriteCoord (msg, ent->origin[i]);
}
MSG_WriteByte (msg, ent->frame); MSG_WriteByte (msg, ent->frame);
@ -2803,7 +2864,8 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
clst.localtime = cl->localtime; clst.localtime = cl->localtime;
clst.health = ent->v->health; clst.health = ent->v->health;
clst.spectator = 0; clst.spectator = 0;
clst.fteext = client->fteprotocolextensions; clst.fteext1 = client->fteprotocolextensions;
clst.ezext1 = client->ezprotocolextensions1;
clst.zext = client->zquake_extensions; clst.zext = client->zquake_extensions;
clst.cl = cl; clst.cl = cl;
@ -4227,7 +4289,7 @@ void SV_CleanupEnts(void)
//FIXME: check if Version exists and do it earlier. //FIXME: check if Version exists and do it earlier.
if ((int)ent->xv->Version != sv.csqcentversion[ent->entnum]) if ((int)ent->xv->Version != sv.csqcentversion[ent->entnum])
{ {
ent->xv->SendFlags = SENDFLAGS_USABLE; ent->xv->SendFlags = -1;
sv.csqcentversion[ent->entnum] = (int)ent->xv->Version; sv.csqcentversion[ent->entnum] = (int)ent->xv->Version;
} }
#endif #endif

View File

@ -1623,7 +1623,7 @@ qboolean SVC_GetChallenge (qboolean respond_dp)
over+=sizeof(lng); over+=sizeof(lng);
} }
//tell the client what mvdsv/ezquake extensions we support //tell the client what mvdsv/ezquake extensions we support
mask = Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, false); mask = Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, false)&EZPEXT1_SERVERADVERTISE;
if (mask) if (mask)
{ {
lng = LittleLong(PROTOCOL_VERSION_EZQUAKE1); lng = LittleLong(PROTOCOL_VERSION_EZQUAKE1);
@ -2002,6 +2002,10 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
client->ezprotocolextensions1 &= Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, ISNQCLIENT(client)) & EZPEXT1_SERVERADVERTISE; client->ezprotocolextensions1 &= Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, ISNQCLIENT(client)) & EZPEXT1_SERVERADVERTISE;
client->zquake_extensions &= SERVER_SUPPORTED_Z_EXTENSIONS; client->zquake_extensions &= SERVER_SUPPORTED_Z_EXTENSIONS;
//older versions of fte didn't understand any interactions between ez's limited float support and replacement deltas. so only activate both when vrinputs is also supported.
if ((client->ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS) && (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && !(client->fteprotocolextensions2 & PEXT2_VRINPUTS))
client->ezprotocolextensions1 &= ~EZPEXT1_FLOATENTCOORDS;
//some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope. //some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope.
if (svs.gametype == GT_HALFLIFE) if (svs.gametype == GT_HALFLIFE)
client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS; //baseline issues client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS; //baseline issues
@ -2357,9 +2361,11 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id)
cl->spectator = asspec; cl->spectator = asspec;
cl->netchan.remote_address = controller->netchan.remote_address; cl->netchan.remote_address = controller->netchan.remote_address;
cl->netchan.message.prim = controller->netchan.message.prim; cl->netchan.message.prim = controller->netchan.message.prim;
cl->netchan.netprim = controller->netchan.netprim;
cl->zquake_extensions = controller->zquake_extensions; cl->zquake_extensions = controller->zquake_extensions;
cl->fteprotocolextensions = controller->fteprotocolextensions; cl->fteprotocolextensions = controller->fteprotocolextensions;
cl->fteprotocolextensions2 = controller->fteprotocolextensions2; cl->fteprotocolextensions2 = controller->fteprotocolextensions2;
cl->ezprotocolextensions1 = controller->ezprotocolextensions1;
cl->penalties = controller->penalties; cl->penalties = controller->penalties;
cl->protocol = controller->protocol; cl->protocol = controller->protocol;
cl->maxmodels = controller->maxmodels; cl->maxmodels = controller->maxmodels;

View File

@ -670,7 +670,6 @@ typedef struct
wedict_t *ent; wedict_t *ent;
vec3_t origin; vec3_t origin;
vec3_t angles; vec3_t angles;
// float deltayaw;
} pushed_t; } pushed_t;
static pushed_t pushed[1024], *pushed_p; static pushed_t pushed[1024], *pushed_p;
@ -690,6 +689,9 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
//float oldsolid; //float oldsolid;
pushed_t *p; pushed_t *p;
vec3_t org, org2, move2, forward, right, up; vec3_t org, org2, move2, forward, right, up;
short yawchange;
yawchange = (amove[PITCH]||amove[ROLL])?0:ANGLE2SHORT(amove[YAW]);
pushed_p = pushed; pushed_p = pushed;
@ -768,6 +770,8 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
// try moving the contacted entity // try moving the contacted entity
VectorAdd (check->v->origin, move, check->v->origin); VectorAdd (check->v->origin, move, check->v->origin);
VectorAdd (check->v->angles, amove, check->v->angles); VectorAdd (check->v->angles, amove, check->v->angles);
if (check->entnum>0&&(check->entnum)<=sv.allocated_client_slots)
svs.clients[check->entnum-1].baseangles[YAW] += yawchange;
// figure movement due to the pusher's amove // figure movement due to the pusher's amove
VectorSubtract (check->v->origin, pusher->v->origin, org); VectorSubtract (check->v->origin, pusher->v->origin, org);
@ -868,6 +872,9 @@ static qboolean WPhys_PushAngles (world_t *w, wedict_t *pusher, vec3_t move, vec
VectorCopy (p->origin, p->ent->v->origin); VectorCopy (p->origin, p->ent->v->origin);
VectorCopy (p->angles, p->ent->v->angles); VectorCopy (p->angles, p->ent->v->angles);
World_LinkEdict (w, p->ent, false); World_LinkEdict (w, p->ent, false);
if (p->ent->entnum>0&&(p->ent->entnum)<=sv.allocated_client_slots)
svs.clients[p->ent->entnum-1].baseangles[YAW] -= yawchange;
} }
return false; return false;
} }

View File

@ -1644,36 +1644,63 @@ void SV_SendFixAngle(client_t *client, sizebuf_t *msg, int fixtype, qboolean rol
else else
fixtype = FIXANGLE_FIXED; fixtype = FIXANGLE_FIXED;
} }
if (fixtype == FIXANGLE_DELTA && !(controller->fteprotocolextensions2 & PEXT2_SETANGLEDELTA)) else
fixtype = FIXANGLE_FIXED; //sorry, can't do it. roll = true;
if (client->lockanglesseq>=controller->netchan.incoming_acknowledged && controller->netchan.message.cursize < controller->netchan.message.maxsize/2) if (controller->fteprotocolextensions2 & PEXT2_VRINPUTS)
msg = NULL; //try to keep them vaugely reliable, where feasable.
if (!msg)
msg = ClientReliable_StartWrite(client, 10);
else if (client->seat)
{ {
MSG_WriteByte(msg, svcfte_choosesplitclient); if (fixtype == FIXANGLE_DELTA)
MSG_WriteByte(msg, client->seat);
}
if (fixtype == FIXANGLE_DELTA && (controller->fteprotocolextensions2 & PEXT2_SETANGLEDELTA))
{
MSG_WriteByte (msg, svcfte_setangledelta);
for (i=0 ; i < 3 ; i++)
{ {
int newa = ang[i] - SHORT2ANGLE(client->lastcmd.angles[i]); //fiddle with the base angle, server will see future moves with that change already applied.
MSG_WriteAngle16 (msg, newa); vec3_t diff;
client->lastcmd.angles[i] = ANGLE2SHORT(ang[i]); for (i = 0; i < 3; i++)
diff[i] = ANGLE2SHORT(ang[i]) - client->lastcmd.angles[i];
if (!roll)
diff[2] = 0;
VectorAdd(client->baseangles, diff, client->baseangles);
}
else
{
client->baseangles[0] = ANGLE2SHORT(ang[0]);
client->baseangles[1] = ANGLE2SHORT(ang[1]);
client->baseangles[2] = ANGLE2SHORT(ang[2]);
client->baseanglelock++;
} }
} }
else else
{ {
MSG_WriteByte (msg, svc_setangle); if (fixtype == FIXANGLE_DELTA && !(controller->fteprotocolextensions2 & PEXT2_SETANGLEDELTA))
if (client->ezprotocolextensions1 & EZPEXT1_SETANGLEREASON) fixtype = FIXANGLE_FIXED; //sorry, can't do it.
MSG_WriteByte (msg, (fixtype == FIXANGLE_DELTA)?2:0); //shitty backwards incompatible protocol extension that breaks from writebytes.
for (i=0 ; i < 3 ; i++) if (client->lockanglesseq>=controller->netchan.incoming_acknowledged && controller->netchan.message.cursize < controller->netchan.message.maxsize/2)
MSG_WriteAngle (msg, (i==2&&!roll)?0:ang[i]); msg = NULL; //try to keep them vaugely reliable, where feasable.
if (!msg)
msg = ClientReliable_StartWrite(client, 10);
else if (client->seat)
{
MSG_WriteByte(msg, svcfte_choosesplitclient);
MSG_WriteByte(msg, client->seat);
}
if (fixtype == FIXANGLE_DELTA && (controller->fteprotocolextensions2 & PEXT2_SETANGLEDELTA))
{
MSG_WriteByte (msg, svcfte_setangledelta);
for (i=0 ; i < 3 ; i++)
{
int newa = ang[i] - SHORT2ANGLE(client->lastcmd.angles[i]);
MSG_WriteAngle16 (msg, newa);
client->lastcmd.angles[i] = ANGLE2SHORT(ang[i]);
}
}
else
{
MSG_WriteByte (msg, svc_setangle);
if (client->ezprotocolextensions1 & EZPEXT1_SETANGLEREASON)
MSG_WriteByte (msg, (fixtype == FIXANGLE_DELTA)?2:0); //shitty backwards incompatible protocol extension that breaks from writebytes.
for (i=0 ; i < 3 ; i++)
MSG_WriteAngle (msg, (i==2&&!roll)?0:ang[i]);
}
} }
ClientReliable_FinishWrite(client);
client->lockanglesseq = controller->netchan.outgoing_sequence+1; //so that spammed fixangles use absolute values, locking the camera in place. client->lockanglesseq = controller->netchan.outgoing_sequence+1; //so that spammed fixangles use absolute values, locking the camera in place.
} }

View File

@ -245,7 +245,7 @@ void SV_New_f (void)
int playernum; int playernum;
int splitnum; int splitnum;
client_t *split; client_t *split;
unsigned int fteext1, fteext2; //reported to client unsigned int fteext1, fteext2, ezext1; //reported to client
host_client->prespawn_stage = PRESPAWN_INVALID; host_client->prespawn_stage = PRESPAWN_INVALID;
host_client->prespawn_idx = 0; host_client->prespawn_idx = 0;
@ -305,16 +305,19 @@ void SV_New_f (void)
fteext1 = host_client->fteprotocolextensions; fteext1 = host_client->fteprotocolextensions;
fteext2 = host_client->fteprotocolextensions2; fteext2 = host_client->fteprotocolextensions2;
ezext1 = host_client->ezprotocolextensions1;
switch(svs.netprim.coordtype) switch(svs.netprim.coordtype)
{ {
case COORDTYPE_FLOAT_32: case COORDTYPE_FLOAT_32:
fteext1 |= PEXT_FLOATCOORDS; fteext1 |= PEXT_FLOATCOORDS;
ezext1 &= ~EZPEXT1_FLOATENTCOORDS; //redundant.
if (!(host_client->fteprotocolextensions & PEXT_FLOATCOORDS)) if (!(host_client->fteprotocolextensions & PEXT_FLOATCOORDS))
{ {
SV_ClientPrintf(host_client, 2, "\n\n\n\nPlease set cl_nopext to 0 and then reconnect.\nIf that doesn't work, please update your engine\n"); SV_ClientPrintf(host_client, 2, "\nForcing bigcoords.\nIf this doesn't work, please update your engine\n");
Con_Printf("%s does not support bigcoords\n", host_client->name); host_client->fteprotocolextensions |= PEXT_FLOATCOORDS;
host_client->drop = true; // Con_Printf("%s does not support bigcoords\n", host_client->name);
return; // host_client->drop = true;
// return;
} }
break; break;
case COORDTYPE_FIXED_13_3: case COORDTYPE_FIXED_13_3:
@ -342,6 +345,11 @@ void SV_New_f (void)
ClientReliableWrite_Long (host_client, PROTOCOL_VERSION_FTE2); ClientReliableWrite_Long (host_client, PROTOCOL_VERSION_FTE2);
ClientReliableWrite_Long (host_client, fteext2); ClientReliableWrite_Long (host_client, fteext2);
} }
if (ezext1)//let the client know
{
ClientReliableWrite_Long (host_client, PROTOCOL_VERSION_EZQUAKE1);
ClientReliableWrite_Long (host_client, ezext1);
}
ClientReliableWrite_Long (host_client, ISQ2CLIENT(host_client)?PROTOCOL_VERSION_Q2:PROTOCOL_VERSION_QW); ClientReliableWrite_Long (host_client, ISQ2CLIENT(host_client)?PROTOCOL_VERSION_Q2:PROTOCOL_VERSION_QW);
ClientReliableWrite_Long (host_client, svs.spawncount); ClientReliableWrite_Long (host_client, svs.spawncount);
if (ISQ2CLIENT(host_client)) if (ISQ2CLIENT(host_client))
@ -1577,7 +1585,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{ {
MSG_WriteByte(&client->netchan.message, svcfte_spawnstatic2); MSG_WriteByte(&client->netchan.message, svcfte_spawnstatic2);
SVFTE_EmitBaseline(state, false, &client->netchan.message, client->fteprotocolextensions2); SVFTE_EmitBaseline(state, false, &client->netchan.message, client->fteprotocolextensions2, client->ezprotocolextensions1);
continue; continue;
} }
if (client->fteprotocolextensions & PEXT_SPAWNSTATIC2) if (client->fteprotocolextensions & PEXT_SPAWNSTATIC2)
@ -1586,7 +1594,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
if (state->hexen2flags || state->trans || state->modelindex >= 256 || state->frame > 255 || state->scale || state->abslight) if (state->hexen2flags || state->trans || state->modelindex >= 256 || state->frame > 255 || state->scale || state->abslight)
{ {
MSG_WriteByte(&client->netchan.message, svcfte_spawnstatic2); MSG_WriteByte(&client->netchan.message, svcfte_spawnstatic2);
SVQW_WriteDelta(&nullentitystate, state, &client->netchan.message, true, client->fteprotocolextensions); SVQW_WriteDelta(&nullentitystate, state, &client->netchan.message, true, client->fteprotocolextensions, client->ezprotocolextensions1);
continue; continue;
} }
} }
@ -1705,12 +1713,12 @@ void SV_SendClientPrespawnInfo(client_t *client)
else if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) else if (client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{ {
MSG_WriteByte(&client->netchan.message, svcfte_spawnbaseline2); MSG_WriteByte(&client->netchan.message, svcfte_spawnbaseline2);
SVFTE_EmitBaseline(state, true, &client->netchan.message, client->fteprotocolextensions2); SVFTE_EmitBaseline(state, true, &client->netchan.message, client->fteprotocolextensions2, client->ezprotocolextensions1);
} }
else if (client->fteprotocolextensions & PEXT_SPAWNSTATIC2) else if (client->fteprotocolextensions & PEXT_SPAWNSTATIC2)
{ {
MSG_WriteByte(&client->netchan.message, svcfte_spawnbaseline2); MSG_WriteByte(&client->netchan.message, svcfte_spawnbaseline2);
SVQW_WriteDelta(&nullentitystate, state, &client->netchan.message, true, client->fteprotocolextensions); SVQW_WriteDelta(&nullentitystate, state, &client->netchan.message, true, client->fteprotocolextensions, client->ezprotocolextensions1);
} }
else if (ISDPCLIENT(client) && (state->modelindex > 255 || state->frame > 255)) else if (ISDPCLIENT(client) && (state->modelindex > 255 || state->frame > 255))
{ {
@ -5373,14 +5381,14 @@ static void Cmd_AddSeat_f(void)
int num = atoi(Cmd_Argv(1)); int num = atoi(Cmd_Argv(1));
int count; int count;
if (!num || host_client->joinobservelockeduntil > realtime) if (num<=0 || host_client->joinobservelockeduntil > realtime)
return; return;
if (host_client->netchan.remote_address.type != NA_LOOPBACK) if (host_client->netchan.remote_address.type != NA_LOOPBACK)
host_client->joinobservelockeduntil = realtime + 2; host_client->joinobservelockeduntil = realtime + 2;
for (count = 1, prev = host_client, cl = host_client->controlled; cl; cl = cl->controlled) for (count = 1, prev = host_client, cl = host_client->controlled; cl; cl = cl->controlled)
{ {
if (count > num) if (count >= num)
{ {
for(; cl; cl = prev->controlled) for(; cl; cl = prev->controlled)
{ {
@ -5404,8 +5412,8 @@ static void Cmd_AddSeat_f(void)
count++; count++;
} }
if (!changed && count <= num) if (!changed && count+1 == num && Cmd_Argc()>2)
changed = !!SV_AddSplit(host_client, Cmd_Argv(2), num); changed = !!SV_AddSplit(host_client, Cmd_Argv(2), num-1);
} }
else else
{ {
@ -7939,7 +7947,7 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
for (seat = 0; seat < seats; seat++) for (seat = 0; seat < seats; seat++)
{ {
if (!split) if (!split)
{ //err, they sent too many seats... assume we kicked one. { //err, they sent too many seats... assume we kicked one. swallow the extra data.
for (frame = 0; frame < frames; frame++) for (frame = 0; frame < frames; frame++)
MSGFTE_ReadDeltaUsercmd(&nullcmd, &old); MSGFTE_ReadDeltaUsercmd(&nullcmd, &old);
continue; continue;
@ -7960,6 +7968,9 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
{ {
MSGFTE_ReadDeltaUsercmd(&old, &split->lastcmd); MSGFTE_ReadDeltaUsercmd(&old, &split->lastcmd);
old = split->lastcmd; old = split->lastcmd;
split->lastcmd.angles[0] += split->baseangles[0];
split->lastcmd.angles[1] += split->baseangles[1];
split->lastcmd.angles[2] += split->baseangles[2];
if (split->penalties & BAN_CRIPPLED) if (split->penalties & BAN_CRIPPLED)
{ {
@ -7970,8 +7981,10 @@ static double SVFTE_ExecuteClientMove(client_t *controller)
if (split->state == cs_spawned) if (split->state == cs_spawned)
{ {
//handle impulse here, doing it later might mean it got skipped entirely (nq physics often skips frames).
if (split->lastcmd.impulse) if (split->lastcmd.impulse)
split->edict->v->impulse = split->lastcmd.impulse; split->edict->v->impulse = split->lastcmd.impulse;
if (split->isindependant) if (split->isindependant)
{ //this protocol uses bigger timestamps instead of msecs { //this protocol uses bigger timestamps instead of msecs
unsigned int curtime = sv.time*1000; unsigned int curtime = sv.time*1000;
@ -8053,14 +8066,14 @@ void SV_ExecuteClientMessage (client_t *cl)
// calc ping time // calc ping time
frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; frame = &cl->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged) if (cl->lastsequence_acknowledged + UPDATE_BACKUP > cl->netchan.incoming_acknowledged && cl->netchan.incoming_sequence-cl->netchan.incoming_acknowledged<UPDATE_BACKUP)
{ {
/*note that if there is packetloss, we can change a single frame's ping_time multiple times /*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*/ this means that the 'ping' is more latency than ping times*/
if (frame->ping_time == -1 || !sv_ping_ignorepl.ival) if (frame->ping_time == -1 || !sv_ping_ignorepl.ival)
frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please frame->ping_time = realtime - frame->senttime; //no more phenomanally low pings please
if (cl->spectator) if (cl->spectator || sv_minping.value<=0)
cl->delay = 0; cl->delay = 0;
else else
{ {
@ -8070,7 +8083,7 @@ void SV_ExecuteClientMessage (client_t *cl)
//FIXME: we should use actual arrival times instead, so we don't get so much noise and seesawing. //FIXME: we should use actual arrival times instead, so we don't get so much noise and seesawing.
diff = bound(-25, diff, 25); //don't swing wildly diff = bound(-25, diff, 25); //don't swing wildly
cl->delay -= 0.001*(diff/25); //scale towards the ideal value cl->delay -= 0.001*(diff/25); //scale towards the ideal value
cl->delay = bound(0, cl->delay, 1); //but make sure things don't go crazy cl->delay = bound(0, cl->delay, UPDATE_BACKUP/77.0); //but make sure things don't go crazy
} }
} }
if (cl->penalties & BAN_LAGGED) if (cl->penalties & BAN_LAGGED)
@ -8455,13 +8468,8 @@ void SVQ2_ExecuteClientMessage (client_t *cl)
if (c == -1) if (c == -1)
break; break;
switch ((enum clcq2_ops_e)c) safeswitch ((enum clcq2_ops_e)c)
{ {
default:
Con_Printf ("SVQ2_ReadClientMessage: unknown command char %i\n", c);
SV_DropClient (cl);
return;
case clcq2_nop: case clcq2_nop:
break; break;
@ -8581,6 +8589,14 @@ void SVQ2_ExecuteClientMessage (client_t *cl)
SV_VoiceReadPacket(); SV_VoiceReadPacket();
break; break;
#endif #endif
case clcq2_bad:
case clcr1q2_setting:
case clcr1q2_multimoves:
safedefault:
Con_Printf ("SVQ2_ReadClientMessage: unknown command char %i\n", c);
SV_DropClient (cl);
return;
} }
} }
} }
@ -8824,13 +8840,8 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
if (c == -1) if (c == -1)
break; break;
switch (c) safeswitch (c)
{ {
default:
Con_Printf ("SVNQ_ReadClientMessage: unknown command char %i\n", c);
SV_DropClient (cl);
return;
case clc_disconnect: case clc_disconnect:
host_client = cl; host_client = cl;
sv_player = cl->edict; sv_player = cl->edict;
@ -8856,16 +8867,16 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
host_client->last_sequence += 0x10000; //wrapped host_client->last_sequence += 0x10000; //wrapped
host_client->last_sequence = (host_client->last_sequence&0xffff0000) | seq; host_client->last_sequence = (host_client->last_sequence&0xffff0000) | seq;
if (cl->lastsequence_acknowledged) if (cl->lastsequence_acknowledged>0 && cl->netchan.incoming_sequence-cl->lastsequence_acknowledged<UPDATE_BACKUP)
{ {
frame = &host_client->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; frame = &host_client->frameunion.frames[cl->lastsequence_acknowledged & UPDATE_MASK];
if (frame->ping_time == -1) if (frame->ping_time == -1)
frame->ping_time = (realtime - frame->senttime) - delay; frame->ping_time = (realtime - frame->senttime);
} }
else else
{ {
frame = &host_client->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; frame = &host_client->frameunion.frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
frame->ping_time = (sv.time - cl->lastcmd.servertime/1000.0) - delay; frame->ping_time = (sv.time - cl->lastcmd.servertime/1000.0);
} }
frame->move_msecs = cl->lastcmd.servertime - oldservertime; frame->move_msecs = cl->lastcmd.servertime - oldservertime;
if (frame->ping_time*1000 > sv_minping.value+1) if (frame->ping_time*1000 > sv_minping.value+1)
@ -8880,6 +8891,7 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
if (host_client->delay > 1) if (host_client->delay > 1)
host_client->delay = 1; host_client->delay = 1;
} }
frame->ping_time -= delay;
} }
break; break;
case clc_move: //bytes: 16(nq), 19(proquake/fitz), 56(dp7) case clc_move: //bytes: 16(nq), 19(proquake/fitz), 56(dp7)
@ -8887,7 +8899,7 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
return; //shouldn't be sending moves at this point. typically they're stale, left from the previous map. this results in crashes if the protocol is different. return; //shouldn't be sending moves at this point. typically they're stale, left from the previous map. this results in crashes if the protocol is different.
forceangle16 = false; forceangle16 = false;
switch(cl->protocol) safeswitch(cl->protocol)
{ {
case SCP_FITZ666: case SCP_FITZ666:
forceangle16 = true; forceangle16 = true;
@ -8913,6 +8925,7 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
case SCP_QUAKE3: case SCP_QUAKE3:
case SCP_DARKPLACES6: case SCP_DARKPLACES6:
case SCP_DARKPLACES7: case SCP_DARKPLACES7:
safedefault:
break; break;
} }
@ -8968,6 +8981,11 @@ void SVNQ_ExecuteClientMessage (client_t *cl)
SV_VoiceReadPacket(); SV_VoiceReadPacket();
break; break;
#endif #endif
safedefault:
Con_Printf ("SVNQ_ReadClientMessage: unknown command char %i\n", c);
SV_DropClient (cl);
return;
} }
} }
} }