Bug Tracker – Attachment #362: Weapon desync correction (take 2) for bug #269

View | Details | Raw Unified | Return to bug 269
Collapse All | Expand All

(-)client/src/g_game.cpp (-7 / +4 lines)
Lines 503-516 Link Here
503
	}
503
	}
504
	Impulse = 0;
504
	Impulse = 0;
505
505
506
	// [SL] 2012-04-18 - Set the impulse to denote the current weapon when
506
	// [SL] 2012-03-31 - Let the server know when the client is predicting a
507
	// firing.  The server will correct the client if this is incorrect.
507
	// weapon change due to a weapon pickup
508
	if (!cmd->ucmd.impulse && !(cmd->ucmd.buttons & BT_CHANGE) &&
508
	if (!cmd->ucmd.impulse && !(cmd->ucmd.buttons & BT_CHANGE) &&
509
		consoleplayer().pendingweapon == wp_nochange &&
509
		consoleplayer().pendingweapon != wp_nochange)
510
		cmd->ucmd.buttons & BT_ATTACK)
510
		cmd->ucmd.impulse = 50 + static_cast<int>(consoleplayer().pendingweapon);
511
	{
512
		cmd->ucmd.impulse = 25 + static_cast<int>(consoleplayer().readyweapon);
513
	}
514
511
515
	if (strafe || lookstrafe)
512
	if (strafe || lookstrafe)
516
		side += (int)(((float)joyturn / (float)SHRT_MAX) * sidemove[speed]);
513
		side += (int)(((float)joyturn / (float)SHRT_MAX) * sidemove[speed]);
(-)client/src/cl_main.cpp (-18 / +62 lines)
Lines 60-65 Link Here
60
#include "cl_maplist.h"
60
#include "cl_maplist.h"
61
#include "cl_vote.h"
61
#include "cl_vote.h"
62
#include "p_mobj.h"
62
#include "p_mobj.h"
63
#include "p_pspr.h"
63
64
64
#include <string>
65
#include <string>
65
#include <vector>
66
#include <vector>
Lines 265-271 Link Here
265
void G_SetDefaultTurbo (void);
266
void G_SetDefaultTurbo (void);
266
void P_CalcHeight (player_t *player);
267
void P_CalcHeight (player_t *player);
267
bool P_CheckMissileSpawn (AActor* th);
268
bool P_CheckMissileSpawn (AActor* th);
268
void P_MovePsprites (player_t* player);
269
void CL_SetMobjSpeedAndAngle(void);
269
void CL_SetMobjSpeedAndAngle(void);
270
270
271
void P_PlayerLookUpDown (player_t *p);
271
void P_PlayerLookUpDown (player_t *p);
Lines 2093-2098 Link Here
2093
///// CL_Fire* called when someone uses a weapon  /////////
2093
///// CL_Fire* called when someone uses a weapon  /////////
2094
///////////////////////////////////////////////////////////
2094
///////////////////////////////////////////////////////////
2095
2095
2096
// [tm512] attempt at squashing weapon desyncs.
2097
// The server will send us what weapon we fired, and if that
2098
// doesn't match the weapon we have up at the moment, fix it
2099
// and request that we get a full update of playerinfo - apr 14 2012
2100
void CL_FireWeapon (void)
2101
{
2102
	player_t *p = &consoleplayer ();
2103
	weapontype_t firedweap = (weapontype_t) MSG_ReadByte ();
2104
	int servertic = MSG_ReadLong ();
2105
2106
	if (firedweap != p->readyweapon)
2107
	{
2108
		Printf (PRINT_HIGH, "CL_FireWeapon: weapon misprediction\n");
2109
		p->readyweapon = firedweap;
2110
		P_SetPsprite (p, ps_weapon, weaponinfo[p->readyweapon].atkstate);
2111
2112
		while (servertic++ < gametic)
2113
			P_MovePsprites(p);
2114
2115
		p->psprites[p->psprnum].sy = WEAPONTOP;
2116
		MSG_WriteMarker (&net_buffer, clc_getplayerinfo);
2117
	}
2118
2119
}
2120
2096
//
2121
//
2097
// CL_FirePistol
2122
// CL_FirePistol
2098
//
2123
//
Lines 2162-2195 Link Here
2162
		S_Sound (p.mo, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
2187
		S_Sound (p.mo, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
2163
}
2188
}
2164
2189
2190
/////////////////////////////////////////////////////////
2191
/*
2192
void CL_ChangeWeapon (void)
2193
{
2194
player_t* player = &players[consoleplayer];
2195
2196
	player->pendingweapon = (weapontype_t)MSG_ReadByte();
2197
2198
	 // Now set appropriate weapon overlay.
2199
	 P_SetPsprite (player,
2200
	 ps_weapon,
2201
	 weaponinfo[player->readyweapon].downstate);
2202
	 }
2203
*/
2204
2165
//
2205
//
2166
// CL_ChangeWeapon
2206
// CL_ChangeWeapon
2207
// [ML] From Zdaemon .99
2167
//
2208
//
2168
// Immediately changes the client's weapon to the weapon specified by the
2169
// server.  Sets the weapons animation state as well.
2170
//
2171
void CL_ChangeWeapon (void)
2209
void CL_ChangeWeapon (void)
2172
{
2210
{
2173
	player_t *player = &consoleplayer();
2211
	player_t *player = &consoleplayer();
2174
	
2212
	weapontype_t newweapon = (weapontype_t)MSG_ReadByte();
2175
	int when = MSG_ReadLong();
2176
	weapontype_t newweapon = static_cast<weapontype_t>(MSG_ReadByte());
2177
	statenum_t stnum = static_cast<statenum_t>(MSG_ReadShort());
2178
	byte tics = MSG_ReadByte();
2179
2213
2180
	if (newweapon > NUMWEAPONS)
2181
		return;
2182
2183
	// ensure that the client has the weapon
2214
	// ensure that the client has the weapon
2184
	player->weaponowned[newweapon] = true;
2215
	player->weaponowned[newweapon] = true;
2185
2216
2186
	A_ForceWeaponChange(player->mo, newweapon, stnum, tics);
2217
	// [SL] 2011-09-22 - Only change the weapon if the client doesn't already
2187
2218
	// have that weapon up.
2188
	// Move the animation forward to account for latency
2219
	if (player->readyweapon != newweapon)
2189
	for (int i = 0; i < gametic - when; i++)
2220
		player->pendingweapon = newweapon;
2190
		P_MovePsprites(player);
2191
}
2221
}
2192
2222
2223
2224
2193
//
2225
//
2194
// CL_Sound
2226
// CL_Sound
2195
//
2227
//
Lines 2865-2870 Link Here
2865
//	cmds[svc_spawnhiddenplayer]	= &CL_SpawnHiddenPlayer;
2897
//	cmds[svc_spawnhiddenplayer]	= &CL_SpawnHiddenPlayer;
2866
	cmds[svc_damageplayer]		= &CL_DamagePlayer;
2898
	cmds[svc_damageplayer]		= &CL_DamagePlayer;
2867
	cmds[svc_firepistol]		= &CL_FirePistol;
2899
	cmds[svc_firepistol]		= &CL_FirePistol;
2900
	cmds[svc_fireweapon]		= &CL_FireWeapon;
2868
2901
2869
	cmds[svc_fireshotgun]		= &CL_FireShotgun;
2902
	cmds[svc_fireshotgun]		= &CL_FireShotgun;
2870
	cmds[svc_firessg]			= &CL_FireSSG;
2903
	cmds[svc_firessg]			= &CL_FireSSG;
Lines 3039-3046 Link Here
3039
	MSG_WriteShort(&net_buffer,	curcmd->ucmd.forwardmove);
3072
	MSG_WriteShort(&net_buffer,	curcmd->ucmd.forwardmove);
3040
	MSG_WriteShort(&net_buffer,	curcmd->ucmd.sidemove);
3073
	MSG_WriteShort(&net_buffer,	curcmd->ucmd.sidemove);
3041
	MSG_WriteShort(&net_buffer,	curcmd->ucmd.upmove);
3074
	MSG_WriteShort(&net_buffer,	curcmd->ucmd.upmove);
3042
	MSG_WriteByte(&net_buffer,	curcmd->ucmd.impulse);
3043
3075
3076
	// [SL] 2011-11-20 - Player isn't requesting a weapon change
3077
	// send player's weapon to server and server will correct it if wrong
3078
	if (!curcmd->ucmd.impulse && !(curcmd->ucmd.buttons & BT_CHANGE))
3079
	{
3080
		if (p->pendingweapon != wp_nochange)
3081
			MSG_WriteByte(&net_buffer, p->pendingweapon);
3082
		else
3083
			MSG_WriteByte(&net_buffer, p->readyweapon);
3084
	}
3085
	else
3086
		MSG_WriteByte(&net_buffer, curcmd->ucmd.impulse);
3087
3044
#ifdef _UNLAG_DEBUG_
3088
#ifdef _UNLAG_DEBUG_
3045
	if 	(player.size() == 2 && 
3089
	if 	(player.size() == 2 && 
3046
		(prevcmd->ucmd.buttons & BT_ATTACK || curcmd->ucmd.buttons & BT_ATTACK))
3090
		(prevcmd->ucmd.buttons & BT_ATTACK || curcmd->ucmd.buttons & BT_ATTACK))
(-)client/src/m_options.cpp (+2 lines)
Lines 152-157 Link Here
152
EXTERN_CVAR (cl_unlag)
152
EXTERN_CVAR (cl_unlag)
153
EXTERN_CVAR (cl_updaterate)
153
EXTERN_CVAR (cl_updaterate)
154
EXTERN_CVAR (cl_interp)
154
EXTERN_CVAR (cl_interp)
155
EXTERN_CVAR (cl_predictpickup)
155
156
156
// Weapon Preferences
157
// Weapon Preferences
157
EXTERN_CVAR (cl_switchweapon)
158
EXTERN_CVAR (cl_switchweapon)
Lines 622-627 Link Here
622
	{ discrete,		"Position update freq",			{&cl_updaterate},	{3.0},		{0.0},		{0.0},		{UpdateRate} },
623
	{ discrete,		"Position update freq",			{&cl_updaterate},	{3.0},		{0.0},		{0.0},		{UpdateRate} },
623
	{ slider,		"Interpolation time",			{&cl_interp},		{0.0},		{4.0},		{1.0},		{NULL} },
624
	{ slider,		"Interpolation time",			{&cl_interp},		{0.0},		{4.0},		{1.0},		{NULL} },
624
	{ discrete,		"Adjust weapons for lag",		{&cl_unlag},		{2.0},		{0.0},		{0.0},		{OnOff} },
625
	{ discrete,		"Adjust weapons for lag",		{&cl_unlag},		{2.0},		{0.0},		{0.0},		{OnOff} },
626
	{ discrete,		"Predict weapon pickups",		{&cl_predictpickup},{2.0},		{0.0},		{0.0},		{OnOff} },
625
};
627
};
626
628
627
menu_t NetworkMenu = {
629
menu_t NetworkMenu = {
(-)server/src/sv_main.cpp (-30 / +7 lines)
Lines 279-285 Link Here
279
279
280
QWORD gametime;
280
QWORD gametime;
281
281
282
void SV_SendPlayerInfo(player_t &player);
283
void SV_UpdateConsolePlayer(player_t &player);
282
void SV_UpdateConsolePlayer(player_t &player);
284
283
285
void SV_CheckTeam (player_t & playernum);
284
void SV_CheckTeam (player_t & playernum);
Lines 3274-3295 Link Here
3274
	}
3273
	}
3275
}
3274
}
3276
3275
3277
3278
void SV_SendCurrentWeapon(player_t *player)
3279
{
3280
	if (!player)
3281
		return;
3282
3283
	buf_t *netbuffer = &player->client.reliablebuf;
3284
	struct pspdef_s *psp = &player->psprites[player->psprnum];
3285
3286
	MSG_WriteMarker(netbuffer, svc_changeweapon);
3287
	MSG_WriteLong(netbuffer, player->tic);
3288
	MSG_WriteByte(netbuffer, static_cast<byte>(player->readyweapon));
3289
	MSG_WriteShort(netbuffer, psp->state - states); 
3290
	MSG_WriteByte(netbuffer, psp->tics);
3291
}
3292
3293
//
3276
//
3294
// SV_SendPingRequest
3277
// SV_SendPingRequest
3295
// Pings the client and requests a reply
3278
// Pings the client and requests a reply
Lines 3619-3637 Link Here
3619
		if (ucmd->buttons & BT_ATTACK)
3602
		if (ucmd->buttons & BT_ATTACK)
3620
		{
3603
		{
3621
			Unlag::getInstance().setRoundtripDelay(player.id, player.cmds.front().svgametic);
3604
			Unlag::getInstance().setRoundtripDelay(player.id, player.cmds.front().svgametic);
3622
3623
			// Handle the client holding the wrong weapon
3624
			if (ucmd->impulse >= 25 && ucmd->impulse < 25 + NUMWEAPONS)
3625
			{
3626
				weapontype_t clientweapon =
3627
					static_cast<weapontype_t>(ucmd->impulse - 25);
3628
				if (player.readyweapon != clientweapon)
3629
				{
3630
					SV_SendPlayerInfo(player);
3631
					SV_SendCurrentWeapon(&player);
3632
				}
3633
					
3634
			}
3635
		}
3605
		}
3636
3606
3637
		// Apply this ticcmd using the game logic
3607
		// Apply this ticcmd using the game logic
Lines 4246-4251 Link Here
4246
//
4216
//
4247
// SV_ParseCommands
4217
// SV_ParseCommands
4248
//
4218
//
4219
4220
void SV_SendPlayerInfo(player_t &player);
4221
4249
void SV_ParseCommands(player_t &player)
4222
void SV_ParseCommands(player_t &player)
4250
{
4223
{
4251
	 while(validplayer(player))
4224
	 while(validplayer(player))
Lines 4265-4270 Link Here
4265
			SV_SetupUserInfo(player);
4238
			SV_SetupUserInfo(player);
4266
			break;
4239
			break;
4267
4240
4241
		case clc_getplayerinfo:
4242
			SV_SendPlayerInfo (player);
4243
			break;
4244
4268
		case clc_say:
4245
		case clc_say:
4269
			SV_Say(player);
4246
			SV_Say(player);
4270
			break;
4247
			break;
(-)common/p_pspr.h (-2 / +4 lines)
Lines 47-53 Link Here
47
#define FF_FULLBRIGHT	0x8000	// flag in thing->frame
47
#define FF_FULLBRIGHT	0x8000	// flag in thing->frame
48
#define FF_FRAMEMASK	0x7fff
48
#define FF_FRAMEMASK	0x7fff
49
49
50
#define LOWERSPEED				FRACUNIT*6
51
#define RAISESPEED				FRACUNIT*6
50
52
53
#define WEAPONBOTTOM			128*FRACUNIT
54
#define WEAPONTOP				32*FRACUNIT
51
55
52
//
56
//
53
// Overlay psprites are scaled shapes
57
// Overlay psprites are scaled shapes
Lines 62-69 Link Here
62
66
63
} psprnum_t;
67
} psprnum_t;
64
68
65
void A_ForceWeaponChange(AActor *mo, weapontype_t weapon, statenum_t state, int tics);
66
67
inline FArchive &operator<< (FArchive &arc, psprnum_t i)
69
inline FArchive &operator<< (FArchive &arc, psprnum_t i)
68
{
70
{
69
	return arc << (BYTE)i;
71
	return arc << (BYTE)i;
(-)common/p_pspr.cpp (-27 / +9 lines)
Lines 41-52 Link Here
41
41
42
#include "p_unlag.h"
42
#include "p_unlag.h"
43
43
44
#define LOWERSPEED				FRACUNIT*6
45
#define RAISESPEED				FRACUNIT*6
46
47
#define WEAPONBOTTOM			128*FRACUNIT
48
#define WEAPONTOP				32*FRACUNIT
49
50
EXTERN_CVAR(sv_infiniteammo)
44
EXTERN_CVAR(sv_infiniteammo)
51
EXTERN_CVAR(sv_freelook)
45
EXTERN_CVAR(sv_freelook)
52
EXTERN_CVAR(sv_allowmovebob)
46
EXTERN_CVAR(sv_allowmovebob)
Lines 467-472 Link Here
467
	if (!P_CheckAmmo (player))
461
	if (!P_CheckAmmo (player))
468
		return;
462
		return;
469
463
464
	// [tm512] Send the client the weapon they just fired so
465
	// that they can fix any weapon desyncs that they get - apr 14 2012
466
	if (serverside && !clientside)
467
	{
468
		MSG_WriteMarker (&player->client.reliablebuf, svc_fireweapon);
469
		MSG_WriteByte (&player->client.reliablebuf, (char)player->readyweapon);
470
		MSG_WriteLong (&player->client.reliablebuf, player->tic);
471
	}
472
470
	P_SetMobjState (player->mo, S_PLAY_ATK1);
473
	P_SetMobjState (player->mo, S_PLAY_ATK1);
471
	newstate = weaponinfo[player->readyweapon].atkstate;
474
	newstate = weaponinfo[player->readyweapon].atkstate;
472
	P_SetPsprite (player, ps_weapon, newstate);
475
	P_SetPsprite (player, ps_weapon, newstate);
Lines 1263-1289 Link Here
1263
	A_ReFire(mo);
1266
	A_ReFire(mo);
1264
}
1267
}
1265
1268
1266
//
1267
// A_ForceWeaponChange
1268
//
1269
// Immediately changes a players weapon to a new weapon and new animation state
1270
// 
1271
void A_ForceWeaponChange(AActor *mo, weapontype_t weapon, statenum_t stnum, int tics)
1272
{
1273
	player_t *player = mo->player;
1274
	struct pspdef_s *psp = &player->psprites[player->psprnum];
1275
1276
	if (weapon < NUMWEAPONS && player->readyweapon != weapon)
1277
	{
1278
		player->readyweapon = weapon;
1279
1280
		P_SetPsprite(player, ps_weapon, stnum);
1281
	
1282
		psp->sy = WEAPONTOP;
1283
		psp->tics = tics;
1284
	}
1285
}
1286
1287
FArchive &operator<< (FArchive &arc, pspdef_t &def)
1269
FArchive &operator<< (FArchive &arc, pspdef_t &def)
1288
{
1270
{
1289
	return arc << def.state << def.tics << def.sx << def.sy;
1271
	return arc << def.state << def.tics << def.sx << def.sy;
(-)common/i_net.h (+1 lines)
Lines 176-181 Link Here
176
	clc_vote,				// [AM] - Casting a vote
176
	clc_vote,				// [AM] - Casting a vote
177
	clc_maplist,			// [AM] - Maplist status request.
177
	clc_maplist,			// [AM] - Maplist status request.
178
	clc_maplist_update,     // [AM] - Request the entire maplist from the server.
178
	clc_maplist_update,     // [AM] - Request the entire maplist from the server.
179
	clc_getplayerinfo,
179
	clc_ready,				// [AM] Toggle ready state.
180
	clc_ready,				// [AM] Toggle ready state.
180
181
181
	// for when launcher packets go astray
182
	// for when launcher packets go astray
(-)common/c_cvarlist.cpp (+2 lines)
Lines 168-173 Link Here
168
CVAR (cl_deathcam, "1", "Dead player's view follows the actor who killed them", 
168
CVAR (cl_deathcam, "1", "Dead player's view follows the actor who killed them", 
169
      CVARTYPE_BOOL, CVAR_ARCHIVE)
169
      CVARTYPE_BOOL, CVAR_ARCHIVE)
170
170
171
CVAR (cl_predictpickup, "1", "Predict weapon pickups", CVARTYPE_BOOL, CVAR_ARCHIVE)
172
171
// Movebob
173
// Movebob
172
CVAR_FUNC_DECL (cl_movebob, "1.0", "Adjust weapon and movement bobbing", 
174
CVAR_FUNC_DECL (cl_movebob, "1.0", "Adjust weapon and movement bobbing", 
173
      CVARTYPE_BOOL, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE | CVAR_CLIENTINFO)
175
      CVARTYPE_BOOL, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE | CVAR_CLIENTINFO)
(-)common/i_net.cpp (+1 lines)
Lines 902-907 Link Here
902
      MSG(clc_callvote,           "x"),
902
      MSG(clc_callvote,           "x"),
903
      MSG(clc_vote,               "x"),
903
      MSG(clc_vote,               "x"),
904
      MSG(clc_maplist,            "x"),
904
      MSG(clc_maplist,            "x"),
905
      MSG(clc_getplayerinfo,      "x"),
905
      MSG(clc_launcher_challenge, "x"),
906
      MSG(clc_launcher_challenge, "x"),
906
      MSG(clc_challenge,          "x")
907
      MSG(clc_challenge,          "x")
907
   };
908
   };
(-)common/p_interaction.cpp (-1 / +2 lines)
Lines 48-53 Link Here
48
EXTERN_CVAR(sv_forcerespawn)
48
EXTERN_CVAR(sv_forcerespawn)
49
EXTERN_CVAR(sv_forcerespawntime)
49
EXTERN_CVAR(sv_forcerespawntime)
50
EXTERN_CVAR(co_zdoomphys)
50
EXTERN_CVAR(co_zdoomphys)
51
EXTERN_CVAR (cl_predictpickup)
51
52
52
int shotclock = 0;
53
int shotclock = 0;
53
int MeansOfDeath;
54
int MeansOfDeath;
Lines 914-920 Link Here
914
		return;
915
		return;
915
916
916
	// Only allow clients to predict touching weapons, not health, armor, etc
917
	// Only allow clients to predict touching weapons, not health, armor, etc
917
	if (!serverside && !P_SpecialIsWeapon(special))
918
	if (!serverside && (!cl_predictpickup || !P_SpecialIsWeapon(special)))
918
		return;
919
		return;
919
920
920
	P_GiveSpecial(toucher->player, special);
921
	P_GiveSpecial(toucher->player, special);

Return to bug 269