FriendsManager

From Valve Developer Community
Jump to: navigation, search
Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no links to other VDC articles. Please help improve this article by adding links that are relevant to the context within the existing text.
January 2024


About

This is a class that handles pulling friends data from the registry so that you can access it ingame (client side). One of the uses for this is to simply put an icon on the scoreboard for those that are on someones buddy list, or create a chat mode that says messages only to buddies.

IFriendsManager.h

///////////// Copyright © 2006, Scott Loyd. All rights reserved. /////////////
// 
// File: IFriendsManager.h
// Description:
//			For use with CLIENT SIDE ONLY.
//			Provides an interface for working with friends data.
// License:  This code is now open source, free for use without any obligation 
// of putting my name in any credits or anything.  All I ask is that you leave
// my name intact where it lies in the code.  I also ask that if you do improve
// upon this code at all that you can make those changes public for every ones
// benefit, but you are certainly not obligated to do so.
//
// Created On: 7/1/06 9:28 PM
// Created By: Scott Loyd <mailto:[email protected]> 
/////////////////////////////////////////////////////////////////////////////
#ifndef IFRIENDSMANAGER_H
#define IFRIENDSMANAGER_H

class IFriendsManager
{
public:
	//Optional: Sets the Tracker ID of the local player.
	virtual void SetTrackerID(unsigned int iTrackerID) = 0;

	//Returns true if iFriendTrackerID is in iMyTrackerIDs buddy list.
	//iFriendTrackerID - Tracker ID of a friend to search for
	//iMyTrackerID - Tracker ID of the local player (if 0, it uses value from SetTrackerID)
	virtual bool IsFriend(unsigned int iFriendTrackerID, unsigned int iMyTrackerID = 0) = 0;

	//Returns string of most recently used buddy name that friends has.  It returns NULL if
	//	no one was found using that TrackerID.
	//iTrackerID - ID of a buddy to lookup
	//iMyTrackerID - Tracker ID of the local player (if 0, it uses value from SetTrackerID)
	virtual const char *BuddyName(unsigned int iTrackerID, unsigned int iMyTrackerID = 0) = 0;
};

//Accessor
IFriendsManager *FriendsManager();

/*
//TODO: You need to set this next chunk up in your code!
//Used to get the TrackerID that can be compared in friends.
unsigned int C_PlayerResource::GetFriendsID( int iIndex )
{
	if ( !IsConnected( iIndex ) )
		return 0;

	player_info_t sPlayerInfo;
	if ( engine->GetPlayerInfo( iIndex, &sPlayerInfo ) )
		return sPlayerInfo.friendsID;
	return 0;
}

//Example Usage (ge_scoreboard.cpp)
void CGEScoreBoard::InitScoreboardSections()
{
	[snip]

	C_BasePlayer *pPlayer =	C_BasePlayer::GetLocalPlayer();
	if ( pPlayer )
		FriendsManager()->SetTrackerID(g_PR->GetFriendsID(pPlayer->entindex()));

	[snip]
}

bool CGEScoreBoard::GetPlayerScoreInfo(int playerIndex, KeyValues *kv)
{
	[snip]

	unsigned int trackerID = g_PR->GetFriendsID(playerIndex);

	//Now that we have a trackerID, is this guy on the local players buddy list?
	// Also if trackerID is the local players trackerID, it will return false.
	if(FriendsManager()->IsFriend(trackerID))
		kv->SetInt("tracker",TrackerImage); //You should find some more code for this in
											// CClientScoreBoardDialog

	[snip]
}
*/
#endif //IFRIENDSMANAGER_H

CFriendsManager.cpp

///////////// Copyright © 2006, Scott Loyd. All rights reserved. /////////////
// 
// File: CFriendsManager.cpp
// Description:
//      see IFriendsManager.h
//      If you use PCHs by default, make sure you disable them for this file.
//       in your project settings.
// License:  This code is now open source, free for use without any obligation 
// of putting my name in any credits or anything.  All I ask is that you leave
// my name intact where it lies in the code.  I also ask that if you do improve
// upon this code at all that you can make those changes public for every ones
// benefit, but you are certainly not obligated to do so.
//
// Created On: 7/1/06 9:50 PM
// Created By: Scott Loyd <mailto:[email protected]> 
/////////////////////////////////////////////////////////////////////////////
#include "windows.h"
#include "IFriendsManager.h"

//in HKEY_CURRENT_USER
#define STEAM_FRIENDS_REGISTRY_PATH "Software\\Valve\\Steam\\Users\\"
#define STEAM_USER_FRIEND_KEY "\\Friends\\"

struct Friend
{
	unsigned int iTrackerID;
	char	szRecentName[32];
	Friend *pNext;

	void Reset()
	{
		pNext = NULL;
		iTrackerID = 0;
		szRecentName[0] = '\0';
	}
};

struct SteamUser
{
	unsigned int iTrackerID;
	Friend	*pFirstFriend;
	SteamUser	*pNext;
	
	void Reset()
	{
		pFirstFriend = NULL;
		pNext = NULL;
		iTrackerID = 0;
	}
	Friend *EmptyFriend();
};

class CFriendsManager : public IFriendsManager
{
public:
	CFriendsManager();
	~CFriendsManager();

private:
	void			Initialize();
	void			Shutdown();
	void			RegReadUser(const char *pszUser);
	SteamUser		*GetEmptySteamUser();

	SteamUser		*pMainUser; //Head Node
	unsigned int	m_iLocalTrackerID;

//Overrides
public:
	virtual void SetTrackerID(unsigned int iTrackerID);
	virtual bool IsFriend(unsigned int iFriendTrackerID, unsigned int iMyTrackerID);
	virtual const char *BuddyName(unsigned int iTrackerID, unsigned int iMyTrackerID);
};

CFriendsManager g_FriendsManager;
IFriendsManager *FriendsManager()
{
	return &g_FriendsManager;
}

CFriendsManager::CFriendsManager()
{
	m_iLocalTrackerID = 0;
	Initialize();
}
CFriendsManager::~CFriendsManager()
{
	Shutdown();
}

void CFriendsManager::Initialize()
{
	HKEY hkSteamFriends;
	if((RegOpenKeyEx( HKEY_CURRENT_USER, STEAM_FRIENDS_REGISTRY_PATH, 
		NULL, KEY_READ, &hkSteamFriends) != ERROR_SUCCESS))
		return;
	
	int iIndex = 0;
	char szName[512];
	DWORD size = sizeof(szName);
	while(RegEnumKeyEx(hkSteamFriends, iIndex, szName, &size, 
		NULL,NULL,NULL,NULL) == ERROR_SUCCESS)
	{
		RegReadUser(szName);
		iIndex++;
		size = sizeof(szName);
	}
	RegCloseKey(hkSteamFriends);
}

void CFriendsManager::Shutdown()
{
	if(pMainUser == NULL)
		return;
	SteamUser *pMover = pMainUser;
	while(pMover)
	{
		Friend *pFriend = pMover->pFirstFriend;
		Friend *pReplacer;
		while(pFriend)
		{
			pReplacer = pFriend->pNext;
			delete pFriend;
			pFriend = pReplacer;
		}
		SteamUser *pTempMover = pMover->pNext;
		delete pMover;
		pMover = pTempMover;
	}
}

void CFriendsManager::RegReadUser(const char *pszUser)
{
	char szKeyPath[512];
	HKEY hkSteamFriends;

	SteamUser *pUser = GetEmptySteamUser();
	pUser->iTrackerID = strtoul(pszUser,NULL,0);

	//Not really concerned about path length, should exceed 512!
	strcpy(szKeyPath,STEAM_FRIENDS_REGISTRY_PATH);
	strcat(szKeyPath,pszUser);
	strcat(szKeyPath,STEAM_USER_FRIEND_KEY);

	if((RegOpenKeyEx( HKEY_CURRENT_USER, szKeyPath, NULL, 
		KEY_READ, &hkSteamFriends) != ERROR_SUCCESS))
		return;

	int iIndex = 0;
	char szName[512];
	char szRegPathToRealName[512];
	DWORD size = sizeof(szName);
	while(RegEnumKeyEx(hkSteamFriends, iIndex, szName, &size, 
		NULL,NULL,NULL,NULL) == ERROR_SUCCESS)
	{
		Friend *pFriend = pUser->EmptyFriend();
		pFriend->iTrackerID = strtoul(szName,NULL,0);

		//Build a path to the user.
		strcpy(szRegPathToRealName,szKeyPath);
		strcat(szRegPathToRealName,szName);
		HKEY hkOpenedUser;

		if((RegOpenKeyEx( HKEY_CURRENT_USER, szRegPathToRealName, NULL, 
			KEY_READ, &hkOpenedUser) == ERROR_SUCCESS))
		{
			DWORD dwType = REG_SZ;
			DWORD dwRecentNameSize = sizeof(pFriend->szRecentName);
			
			RegQueryValueEx(hkOpenedUser, "name", NULL, 
				&dwType,(LPBYTE)&pFriend->szRecentName, &dwRecentNameSize);
			RegCloseKey(hkOpenedUser);
		}
		iIndex++;
		size = sizeof(szName);
	}
	RegCloseKey(hkSteamFriends);
}

SteamUser *CFriendsManager::GetEmptySteamUser()
{
	if(pMainUser == NULL)
	{
		pMainUser = new SteamUser;
		pMainUser->Reset();
		return pMainUser;
	} else {
		SteamUser *pMover = pMainUser;
		while(pMover)
		{
			if(pMover->pNext == NULL)
			{
				pMover->pNext = new SteamUser;
				pMover->pNext->Reset();
				return pMover->pNext;
			}
			pMover = pMover->pNext;
		}
	}
	return NULL; //Should never get here...
}
Friend *SteamUser::EmptyFriend()
{
	if(pFirstFriend == NULL)
	{
		pFirstFriend = new Friend;
		pFirstFriend->Reset();
		return pFirstFriend;
	} else {
		Friend *pFriend = pFirstFriend;
		while(pFriend)
		{
			if(pFriend->pNext == NULL)
			{
				pFriend->pNext = new Friend;
				pFriend->pNext->Reset();
				return pFriend->pNext;
			}
			pFriend = pFriend->pNext;
		}
	}
	return NULL; //Should never get here...
}

// -----------------------------------------------------------------------------
// Start of overrides to IFriendsManager
//

void CFriendsManager::SetTrackerID(unsigned int iTrackerID)
{
	m_iLocalTrackerID = iTrackerID;
};

bool CFriendsManager::IsFriend(unsigned int iFriendTrackerID, unsigned int iMyTrackerID)
{
	if(iMyTrackerID == 0)
		iMyTrackerID = m_iLocalTrackerID;
	if(iMyTrackerID == iFriendTrackerID)
		return false;
	SteamUser *pUserMover = pMainUser;
	while(pUserMover)
	{
		if(pUserMover->iTrackerID != iMyTrackerID)
			goto endOfUserLoop;

		Friend *pFriendMover = pUserMover->pFirstFriend;
		while(pFriendMover)
		{
			if(pFriendMover->iTrackerID == iFriendTrackerID)
				return true;
			pFriendMover = pFriendMover->pNext;
		}

endOfUserLoop:
		pUserMover = pUserMover->pNext;
	}
	return false;
}

const char *CFriendsManager::BuddyName(unsigned int iTrackerID, unsigned int iMyTrackerID)
{
	if(iMyTrackerID == 0)
		iMyTrackerID = m_iLocalTrackerID;
	SteamUser *pUserMover = pMainUser;
	while(pUserMover)
	{
		Friend *pFriendMover = pUserMover->pFirstFriend;
		while(pFriendMover)
		{
			if(pFriendMover->iTrackerID == iTrackerID)
				return pFriendMover->szRecentName;
			pFriendMover = pFriendMover->pNext;
		}
		pUserMover = pUserMover->pNext;
	}
	return NULL;
}