UserCmd strings: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (added debugging code)
m (→‎UserCmd.cpp: need nowiki tags to avoid parsing)
 
(13 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{warning|These changes are only theoretical and haven't been tested whatsoever.}}
==Introduction==
This modification allows a mod to send messages from the client to the server without using commands. This allows for a more secure method of communication from the client to the server. A possible implementation would be with [[VGUI Screen]]s.
This modification allows a mod to send messages from the client to the server without using commands. This allows for a more secure method of communication from the client to the server. A possible implementation would be with [[VGUI Screen]]s.
{{note|This method should only be used on multiplayer servers, where cheating has a negative effect on gameplay.}}
==Changes==
==Changes==
===UserCmd.cpp===
===UserCmd.cpp===
<nowiki>
#include "baseplayer_shared.h" before memdbgon.h
</nowiki>
Note how WriteUsercmd only writes data if there is a delta (change). Notice how the count is tested, the data is then sent, and all of the saved data is then purged. This means only delta data will be sent.
====WriteUsercmd====
====WriteUsercmd====
At the end:
At the end:
  if(g_pLocalPlayer&&g_pLocalPlayer->UserDataChanged())
 
#ifdef CLIENT_DLL
  CBasePlayer *pLocalPlayer = CBasePlayer::GetLocalPlayer();
byte count = pLocalPlayer->GetUserDataCount();
if(count)
  {
  {
  buf->WriteOneBit( 1 );
  buf->WriteOneBit( 1 );
int count = g_pLocalPlayer->GetUserDataCount();
const char *pData;
  buf->WriteByte(count);
  buf->WriteByte(count);
  for(int x=0;x<count;x++)
  for(byte x=0;x<count;x++)
  {
  {
  buf->WriteString(g_pLocalPlayer->GetUserData(x));
  buf->WriteString(pLocalPlayer->GetUserData(x));
  }
  }
  g_pLocalPlayer->ClearUserData();
  pLocalPlayer->ClearUserData();
  }
  }
  else
  else
Line 22: Line 35:
  buf->WriteOneBit( 0 );
  buf->WriteOneBit( 0 );
  }
  }
#endif
====ReadUsercmd====
====ReadUsercmd====
  void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from<font color="green">, CBasePlayer *pPlayer</font> )
 
  void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from<font color="green">, CBasePlayer *pPlayer /*= NULL*/</font> )
 
At the end:
At the end:
  if( buf->ReadOneBit() )
  if( buf->ReadOneBit() )
  {
  {
Line 30: Line 48:
  for(int x=0;x<count;x++)
  for(int x=0;x<count;x++)
  {
  {
#ifdef DEBUG
  bool bOverflow = false;
  bool bOverflow = false;
#endif
  char *cmd = buf->ReadAndAllocateString(&bOverflow);
  char *cmd = buf->ReadAndAllocateString(&bOverflow);
  Assert(!bOverflow);
  Assert(!bOverflow);
  #ifndef CLIENT_DLL
  #ifndef CLIENT_DLL
Assert(pPlayer);
  pPlayer->EvaluateUserData(cmd);
  pPlayer->EvaluateUserData(cmd);
  #endif
  #endif
Line 41: Line 58:
  }
  }
  }
  }
====UserCmd.h====
====UserCmd.h====
#include "baseplayer_shared.h"


  void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from<font color="green">, CBasePlayer *pPlayer</font> );
//Forward declaration.
====in_main.cpp====
class CBasePlayer;
ReadUsercmd( buf, to, from<font color="green">, NULL</font> );
  void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from<font color="green">, CBasePlayer *pPlayer = NULL</font> );
 
====Changes to gameinterface.cpp====
====Changes to gameinterface.cpp====
  ReadUsercmd( buf, to, from<font color="green">, pPlayer</font> );
  ReadUsercmd( buf, to, from<font color="green">, pPlayer</font> );


==Implementation==
==Implementation==
===Client===
 
*<code>int GetUserDataCount(void)</code> returns the number of data strings stored in a char array stored on the player.
===C_BasePlayer===
*<code>const char *GetUserData(int index)</code> returns the data stored in the array of user data stored on the player.
 
*<code>void ClearUserData(void)</code> clears the client-side char*[] and sets the boolean so they don't get sent twice.
*protected <code>CUtlLinkedList<const char *, byte> m_UserData</code> stores all of the data to send (The player should '''never''' have to send over 255 strings for 1 usercmd).
*<code>bool UserDataChanged(void)</code> returns the boolean modified by ClearUserData.
*public <code>void AddUserData(const char *pNewData)</code> adds data to send.
===Server===
*public <code>byte GetUserDataCount(void)</code> returns <code>m_UserData.Count()</code>.
*<code>void EvaluateUserData(const char *pData)</code> evaluates what to do with the commands stored in pData.
*public <code>const char *GetUserData(byte index)</code> returns <code>m_UserData.Element(index)</code>.
[[Category:Programming]][[Category:Tutorials]]
*public <code>void ClearUserData(void)</code> calls <code>m_UserData.PurgeAndDeleteElements()</code>. See [[strdup]] to make sure you don't accidentally get any null pointers.
 
===CBasePlayer===
 
*public <code>void EvaluateUserData(const char *pData)</code> evaluates what to do with the command stored in pData.
 
[[Category:Networking]]
[[Category:Tutorials]]

Latest revision as of 13:04, 14 July 2009

This modification allows a mod to send messages from the client to the server without using commands. This allows for a more secure method of communication from the client to the server. A possible implementation would be with VGUI Screens.

Note.pngNote:This method should only be used on multiplayer servers, where cheating has a negative effect on gameplay.

Changes

UserCmd.cpp

#include "baseplayer_shared.h" before memdbgon.h

Note how WriteUsercmd only writes data if there is a delta (change). Notice how the count is tested, the data is then sent, and all of the saved data is then purged. This means only delta data will be sent.

WriteUsercmd

At the end:

#ifdef CLIENT_DLL
	CBasePlayer *pLocalPlayer = CBasePlayer::GetLocalPlayer();
	byte count = pLocalPlayer->GetUserDataCount();
	if(count)
	{
		buf->WriteOneBit( 1 );

		buf->WriteByte(count);

		for(byte x=0;x<count;x++)
		{
			buf->WriteString(pLocalPlayer->GetUserData(x));
		}

		pLocalPlayer->ClearUserData();
	}
	else
	{
		buf->WriteOneBit( 0 );
	}
#endif

ReadUsercmd

void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from, CBasePlayer *pPlayer /*= NULL*/ )

At the end:

	if( buf->ReadOneBit() )
	{
		int count = buf->ReadByte();
		for(int x=0;x<count;x++)
		{
			bool bOverflow = false;
			char *cmd = buf->ReadAndAllocateString(&bOverflow);
			Assert(!bOverflow);
#ifndef CLIENT_DLL
			Assert(pPlayer);
			pPlayer->EvaluateUserData(cmd);
#endif
			delete cmd;
		}
	}

UserCmd.h

//Forward declaration.
class CBasePlayer;
void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from, CBasePlayer *pPlayer = NULL );

Changes to gameinterface.cpp

ReadUsercmd( buf, to, from, pPlayer );

Implementation

C_BasePlayer

  • protected CUtlLinkedList<const char *, byte> m_UserData stores all of the data to send (The player should never have to send over 255 strings for 1 usercmd).
  • public void AddUserData(const char *pNewData) adds data to send.
  • public byte GetUserDataCount(void) returns m_UserData.Count().
  • public const char *GetUserData(byte index) returns m_UserData.Element(index).
  • public void ClearUserData(void) calls m_UserData.PurgeAndDeleteElements(). See strdup to make sure you don't accidentally get any null pointers.

CBasePlayer

  • public void EvaluateUserData(const char *pData) evaluates what to do with the command stored in pData.