View Single Post
PM
hello, i am pm
Join Date: Jan 2004
Location: Canalization
Old 03-05-2011 , 04:12   Re: Accessing Private Data
Reply With Quote #2

Uhhh, this is not a good situation

This is how it's supposed to work in C++ :
the interface IGamePlayer would provide a public function SetLanguageId( id ).
You would do

Code:
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer( params[1] );
pPlayer->SetLanguageId( blabla );
Here, as far as I can see at the moment, the interface IGamePlayer does not have such a function. The ideal solution would be to add it to sourcemod core.

Other than that, if you really want to set the field anyway, you can hack.
From here, you're using implementation details of sourcemod, which are not part of the "contract", ie. interface. This code can be broken on updates.

First of all, you'd have to use your knowledge that what playerhelpers->GetGamePlayer( ... ) returns is actually a CPlayer instance.

Code:
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer( params[1] );
CPlayer *pPlayerImpl = (CPlayer*)pPlayer;
The next problem is accessing the field m_LangId. As you can see, it's in the private: section of the class. Ie. you can't access it from outside. The PlayerManager class in SourceMod can only access it because it is declared "friend" of class CPlayer: friend class PlayerManager;

You're not friend, so you have three possibilities:
1) Copy the CPlayer class declaration into your source file (and don't #include the .h file where CPlayer is declared) and change the private section containing m_LangId to public.

OR

2) Copy the CPlayer class declaration into your source file and declare your class friend.

OR

3) Copy the CPlayer class declaration into your source file and add a setter method

OR

4) Don't use the CPlayer declaration at all and access the field by a pointer offset.

I'd go with 3) which would result in the following code:

Code:
// Warning: This code may break on sourcemod updates

// Don't #include playermanager.h because we're using our own CPlayer

/* actually from PlayerManager.h */
class CPlayer : public IGamePlayer
{
public:
	CPlayer();
public:
	const char *GetName();
	const char *GetIPAddress();
	const char *GetAuthString();
	edict_t *GetEdict();
	bool IsInGame();
	bool WasCountedAsInGame();
	bool IsConnected();
	bool IsAuthorized();
	bool IsFakeClient();
	void SetAdminId(AdminId id, bool temporary);
	AdminId GetAdminId();
	void Kick(const char *str);
	bool IsInKickQueue();
	IPlayerInfo *GetPlayerInfo();
	unsigned int GetLanguageId();
	int GetUserId();
	bool RunAdminCacheChecks();
	void NotifyPostAdminChecks();
	unsigned int GetSerial();
public:
	void DoBasicAdminChecks();
	void MarkAsBeingKicked();
	int GetLifeState();
private:
	void Initialize(const char *name, const char *ip, edict_t *pEntity);
	void Connect();
	void Disconnect();
	void SetName(const char *name);
	void DumpAdmin(bool deleting);
	void Authorize(const char *auth);
	void Authorize_Post();
	void DoPostConnectAuthorization();
private:
	bool m_IsConnected;
	bool m_IsInGame;
	bool m_IsAuthorized;
	bool m_bIsInKickQueue;
	String m_Name;
	String m_Ip;
	String m_IpNoPort;
	String m_AuthID;
	AdminId m_Admin;
	bool m_TempAdmin;
	edict_t *m_pEdict;
	IPlayerInfo *m_Info;
	String m_LastPassword;
	bool m_bAdminCheckSignalled;
	int m_iIndex;
	unsigned int m_LangId;
	int m_UserId;
	bool m_bFakeClient;
	serial_t m_Serial;

public:
	void SetLanguageId(unsigned int newLangId) {
		m_LangId = newLangId;
	}
};

static cell_t SetClientLanguage(IPluginContext *pContext, const cell_t *params)
{
	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer( params[1] );

	CPlayer *pPlayerHack = (CPlayer*)pPlayer;
	pPlayerHack->SetLanguageId( blablabla );

	return 1;
}
I'm in a hurry so I haven't tried to compile so I may be wrong
__________________
hello, i am pm
PM is offline