Skip to content

Commit

Permalink
fix multiplayer audio bug caused by editing usercmd
Browse files Browse the repository at this point in the history
  • Loading branch information
sd805 committed May 27, 2022
1 parent 37cd693 commit 2d1c0ea
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 45 deletions.
24 changes: 13 additions & 11 deletions L4D2VR/hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ int Hooks::dServerFireTerrorBullets(int playerId, const Vector &vecOrigin, const
QAngle vecNewAngles = vecAngles;

// Server host
if (playerId == mGame->EngineClient->GetLocalPlayer())
if (mVR->isVREnabled && playerId == mGame->EngineClient->GetLocalPlayer())
{
vecNewOrigin = mVR->GetRecommendedViewmodelAbsPos();
vecNewAngles = mVR->GetRecommendedViewmodelAbsAngle();
Expand Down Expand Up @@ -368,16 +368,11 @@ int Hooks::dReadUsercmd(void *buf, CUserCmd *move, CUserCmd *from)
hkReadUsercmd.fOriginal(buf, move, from);

int i = mGame->currentUsercmdID;
if (move->tick_count < 0)
if (move->viewangles.z == -1.0) // Signal for VR CUserCmd
{
move->tick_count *= -1;

mGame->playersVRInfo[i].isUsingVR = true;
mGame->playersVRInfo[i].controllerAngles.x = (float)move->mousedx / 10;
mGame->playersVRInfo[i].controllerAngles.y = (float)move->mousedy / 10;

move->mousedx = 0;
move->mousedy = 0;
}
else
{
Expand All @@ -393,16 +388,23 @@ void __fastcall Hooks::dWriteUsercmdDeltaToBuffer(void *ecx, void *edx, int a1,

int Hooks::dWriteUsercmd(void *buf, CUserCmd *to, CUserCmd *from)
{
// TODO: Double gunshot sound bug possibly caused by wrong checksum for CUserCmd
if (mVR->isVREnabled)
{
// Signal to the server that this CUserCmd has VR info by making
// tick_count negative. The server will make it positive.
to->tick_count *= -1;
CInput *g_pInput = *(CInput **)(mGame->g_client + offsets::g_ppInput);
CVerifiedUserCmd *pVerifiedCommands = *(CVerifiedUserCmd **)((uintptr_t)g_pInput + 0xF0);
CVerifiedUserCmd *pVerified = &pVerifiedCommands[(to->command_number) % 150];

// Signal to the server that this CUserCmd has VR info
to->viewangles.z = -1;

QAngle controllerAngles = mVR->GetRecommendedViewmodelAbsAngle();
to->mousedx = controllerAngles.x * 10; // Strip off 2nd decimal to save bits.
to->mousedy = controllerAngles.y * 10;

// Must recalculate checksum for the edited CUserCmd or gunshots will sound
// terrible in multiplayer.
pVerified->m_cmd = *to;
pVerified->m_crc = to->GetChecksum();
}
return hkWriteUsercmd.fOriginal(buf, to, from);
}
2 changes: 2 additions & 0 deletions L4D2VR/l4d2vr.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
<ClInclude Include="game.h" />
<ClInclude Include="hooks.h" />
<ClInclude Include="offsets.h" />
<ClInclude Include="sdk\checksum_crc.h" />
<ClInclude Include="sdk\CUserCmd.h" />
<ClInclude Include="sdk\material.h" />
<ClInclude Include="sdk\QAngle.h" />
Expand All @@ -200,6 +201,7 @@
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="game.cpp" />
<ClCompile Include="hooks.cpp" />
<ClCompile Include="sdk\checksum_crc.cpp" />
<ClCompile Include="sdk\QAngle.cpp" />
<ClCompile Include="vr.cpp" />
</ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions L4D2VR/l4d2vr.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
<ClInclude Include="sdk\vector.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="sdk\checksum_crc.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
Expand All @@ -68,5 +71,8 @@
<ClCompile Include="sdk\QAngle.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sdk\checksum_crc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions L4D2VR/offsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace offsets
static int ClientFireTerrorBullets = 0x2F4350; // E8 ? ? ? ? 83 C4 1C 80 BE ? ? ? ? ?
static int WriteUsercmdDeltaToBuffer = 0x134790; // 55 8B EC 83 EC 60 0F 57 C0 8B 55 0C
static int WriteUsercmd = 0x1AAD50; // E8 ? ? ? ? 83 C4 0C 38 5E 10
static int g_ppInput = 0x6E0F04; // 8B 0D ? ? ? ? 8B 01 8B 50 58 FF E2

// server.dll offsets
static int ServerFireTerrorBullets = 0x3C3FC0; // E8 ? ? ? ? D9 86 ? ? ? ? 8B 4D F4
Expand Down
76 changes: 42 additions & 34 deletions L4D2VR/sdk/CUserCmd.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#pragma once
#include "vector.h"
#include "QAngle.h"
#include "checksum_crc.h"

typedef unsigned int CRC32_t;
typedef unsigned char byte;
Expand Down Expand Up @@ -56,18 +58,11 @@ class CUserCmd
weaponselect = src.weaponselect;
weaponsubtype = src.weaponsubtype;
random_seed = src.random_seed;
#ifdef GAME_DLL
server_random_seed = src.server_random_seed;
#endif
mousedx = src.mousedx;
mousedy = src.mousedy;

hasbeenpredicted = src.hasbeenpredicted;

#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )
entitygroundcontact = src.entitygroundcontact;
#endif

return *this;
}

Expand All @@ -80,7 +75,21 @@ class CUserCmd
{
CRC32_t crc;

// ...
CRC32_Init(&crc);
CRC32_ProcessBuffer(&crc, &command_number, sizeof(command_number));
CRC32_ProcessBuffer(&crc, &tick_count, sizeof(tick_count));
CRC32_ProcessBuffer(&crc, &viewangles, sizeof(viewangles));
CRC32_ProcessBuffer(&crc, &forwardmove, sizeof(forwardmove));
CRC32_ProcessBuffer(&crc, &sidemove, sizeof(sidemove));
CRC32_ProcessBuffer(&crc, &upmove, sizeof(upmove));
CRC32_ProcessBuffer(&crc, &buttons, sizeof(buttons));
CRC32_ProcessBuffer(&crc, &impulse, sizeof(impulse));
CRC32_ProcessBuffer(&crc, &weaponselect, sizeof(weaponselect));
CRC32_ProcessBuffer(&crc, &weaponsubtype, sizeof(weaponsubtype));
CRC32_ProcessBuffer(&crc, &random_seed, sizeof(random_seed));
CRC32_ProcessBuffer(&crc, &mousedx, sizeof(mousedx));
CRC32_ProcessBuffer(&crc, &mousedy, sizeof(mousedy));
CRC32_Final(&crc);

return crc;
}
Expand All @@ -96,43 +105,42 @@ class CUserCmd
impulse = 0;
}

// For matching server and client commands for debugging
int command_number;

// the tick the client created this command
int tick_count;

// Player instantaneous view angles.
QAngle viewangles;
// Intended velocities
// forward velocity.
float forwardmove;
// sideways velocity.
float sidemove;
// upward velocity.
float upmove;
// Attack button states
int buttons;
// Impulse command issued.
byte impulse;
// Current weapon id
int weaponselect;
int weaponsubtype;

int random_seed; // For shared random functions
#ifdef GAME_DLL
int server_random_seed; // Only the server populates this seed
#endif

short mousedx; // mouse accum in x from create move
short mousedy; // mouse accum in y from create move

// Client only, tracks whether we've predicted this command at least once
int random_seed;
short mousedx;
short mousedy;
bool hasbeenpredicted;
char pad[25];
};
static_assert(sizeof(CUserCmd) == 0x58);

// Back channel to communicate IK state
#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )
CUtlVector< CEntityGroundContact > entitygroundcontact;
#endif
class CVerifiedUserCmd
{
public:
CUserCmd m_cmd;
CRC32_t m_crc;
};

class CInput
{
public:
virtual void Init_All(void);
virtual void Shutdown_All(void);
virtual int GetButtonBits(int);
virtual void CreateMove(int sequence_number, float input_sample_frametime, bool active);
virtual void ExtraMouseSample(float frametime, bool active);
virtual bool WriteUsercmdDeltaToBuffer(int *buf, int from, int to, bool isnewcommand);
virtual void EncodeUserCmdToBuffer(int buf, int slot);
virtual void DecodeUserCmdFromBuffer(int buf, int slot);
virtual CUserCmd *GetUserCmd(int uk, int sequence_number);

};
178 changes: 178 additions & 0 deletions L4D2VR/sdk/checksum_crc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Generic CRC functions
//
//=============================================================================//

#include "checksum_crc.h"

#define CRC32_INIT_VALUE 0xFFFFFFFFUL
#define CRC32_XOR_VALUE 0xFFFFFFFFUL

#define NUM_BYTES 256

#define LittleLong( val ) ( val )

static const CRC32_t pulCRCTable[NUM_BYTES] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

void CRC32_Init(CRC32_t *pulCRC)
{
*pulCRC = CRC32_INIT_VALUE;
}

void CRC32_Final(CRC32_t *pulCRC)
{
*pulCRC ^= CRC32_XOR_VALUE;
}

CRC32_t CRC32_GetTableEntry( unsigned int slot )
{
return pulCRCTable[(unsigned char)slot];
}

void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer)
{
CRC32_t ulCrc = *pulCRC;
unsigned char *pb = (unsigned char *)pBuffer;
unsigned int nFront;
int nMain;

JustAfew:

switch (nBuffer)
{
case 7:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);

case 6:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);

case 5:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);

case 4:
ulCrc ^= LittleLong( *(CRC32_t *)pb );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
*pulCRC = ulCrc;
return;

case 3:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);

case 2:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);

case 1:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);

case 0:
*pulCRC = ulCrc;
return;
}

// We may need to do some alignment work up front, and at the end, so that
// the main loop is aligned and only has to worry about 8 byte at a time.
//
// The low-order two bits of pb and nBuffer in total control the
// upfront work.
//
nFront = ((unsigned int)pb) & 3;
nBuffer -= nFront;
switch (nFront)
{
case 3:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 2:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 1:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
}

nMain = nBuffer >> 3;
while (nMain--)
{
ulCrc ^= LittleLong( *(CRC32_t *)pb );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
pb += 8;
}

nBuffer &= 7;
goto JustAfew;
}
Loading

0 comments on commit 2d1c0ea

Please sign in to comment.