[Friends] First working version of the friend system

This commit is contained in:
momo5502 2017-01-29 17:16:09 +01:00
parent f20fa5763c
commit 22b91c7a77
4 changed files with 188 additions and 21 deletions

View File

@ -6,6 +6,59 @@ namespace Components
std::recursive_mutex Friends::Mutex; std::recursive_mutex Friends::Mutex;
std::vector<Friends::Friend> Friends::FriendsList; std::vector<Friends::Friend> Friends::FriendsList;
void Friends::SortIndividualList(std::vector<Friends::Friend>* list)
{
qsort(list->data(), list->size(), sizeof(Friends::Friend), [](const void* first, const void* second)
{
const Friends::Friend* friend1 = static_cast<const Friends::Friend*>(first);
const Friends::Friend* friend2 = static_cast<const Friends::Friend*>(second);
std::string name1 = Utils::String::ToLower(Colors::Strip(friend1->name));
std::string name2 = Utils::String::ToLower(Colors::Strip(friend2->name));
return name1.compare(name2);
});
}
void Friends::SortList()
{
std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
std::vector<Friends::Friend> playingList;
std::vector<Friends::Friend> onlineList;
std::vector<Friends::Friend> offlineList;
// Split up the list
for(auto entry : Friends::FriendsList)
{
if(entry.online)
{
if(entry.server.getType() == Game::NA_BAD)
{
onlineList.push_back(entry);
}
else
{
playingList.push_back(entry);
}
}
else
{
offlineList.push_back(entry);
}
}
Friends::SortIndividualList(&playingList);
Friends::SortIndividualList(&onlineList);
Friends::SortIndividualList(&offlineList);
Friends::FriendsList.clear();
Utils::Merge(&Friends::FriendsList, playingList);
Utils::Merge(&Friends::FriendsList, onlineList);
Utils::Merge(&Friends::FriendsList, offlineList);
}
void Friends::UpdateUserInfo(SteamID user) void Friends::UpdateUserInfo(SteamID user)
{ {
Proto::IPC::Function function; Proto::IPC::Function function;
@ -30,6 +83,42 @@ namespace Components
IPCHandler::SendWorker("friends", function.SerializeAsString()); IPCHandler::SendWorker("friends", function.SerializeAsString());
} }
void Friends::UpdateHostname(Network::Address server, std::string hostname)
{
std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
for(auto& entry : Friends::FriendsList)
{
if(entry.server == server)
{
entry.serverName = hostname;
}
}
}
void Friends::SetServer()
{
Proto::IPC::Function function;
function.set_name("setPresence");
*function.add_params() = "iw4x_server";
*function.add_params() = Network::Address(*Game::connectedHost).getString();//reinterpret_cast<char*>(0x7ED3F8);
IPCHandler::SendWorker("friends", function.SerializeAsString());
Friends::UpdateState();
}
void Friends::ClearServer()
{
Proto::IPC::Function function;
function.set_name("setPresence");
*function.add_params() = "iw4x_server";
IPCHandler::SendWorker("friends", function.SerializeAsString());
Friends::UpdateState();
}
void Friends::UpdateRank() void Friends::UpdateRank()
{ {
static Utils::Value<int> levelVal; static Utils::Value<int> levelVal;
@ -64,7 +153,6 @@ namespace Components
unsigned int Friends::GetFriendCount() unsigned int Friends::GetFriendCount()
{ {
std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
return Friends::FriendsList.size(); return Friends::FriendsList.size();
} }
@ -107,7 +195,27 @@ namespace Components
return Utils::String::VA("%s", user.name.data()); return Utils::String::VA("%s", user.name.data());
case 2: case 2:
return "Trickshot Isnipe server"; {
if(user.online && user.server.getType() != Game::NA_BAD)
{
if(user.serverName.empty())
{
return Utils::String::VA("Playing on %s", user.server.getCString());
}
else
{
return Utils::String::VA("Playing on %s", user.serverName.data());
}
}
else if(user.online)
{
return "Online";
}
else
{
return "Offline";
}
}
default: default:
break; break;
@ -144,7 +252,7 @@ namespace Components
} }
} }
void Friends::PresenceResponse(std::vector<std::string> params) void Friends::ParsePresence(std::vector<std::string> params, bool sort)
{ {
if (params.size() >= 3) if (params.size() >= 3)
{ {
@ -162,15 +270,26 @@ namespace Components
if (entry == Friends::FriendsList.end()) return; if (entry == Friends::FriendsList.end()) return;
if (key == "iw4x_status") if (key == "iw4x_name")
{ {
entry->statusName = value; entry->playerName = value;
} }
else if (key == "iw4x_server") else if (key == "iw4x_server")
{ {
entry->server = value; Network::Address oldAddress = entry->server;
if (entry->server.getType() != Game::NA_BAD) if (value.empty())
{
entry->server.setType(Game::NA_BAD);
entry->serverName.clear();
}
else if (entry->server != value)
{
entry->server = value;
entry->serverName.clear();
}
if (entry->server.getType() != Game::NA_BAD && entry->server != oldAddress)
{ {
Node::AddNode(entry->server); Node::AddNode(entry->server);
Network::SendCommand(entry->server, "getinfo", Utils::Cryptography::Rand::GenerateChallenge()); Network::SendCommand(entry->server, "getinfo", Utils::Cryptography::Rand::GenerateChallenge());
@ -186,9 +305,16 @@ namespace Components
entry->prestige = (data >> 24) & 0xFF; entry->prestige = (data >> 24) & 0xFF;
} }
} }
if (sort) Friends::SortList();
} }
} }
void Friends::PresenceResponse(std::vector<std::string> params)
{
Friends::ParsePresence(params, true);
}
void Friends::InfoResponse(std::vector<std::string> params) void Friends::InfoResponse(std::vector<std::string> params)
{ {
if (params.size() >= 1) if (params.size() >= 1)
@ -221,9 +347,11 @@ namespace Components
} }
else else
{ {
Friends::PresenceResponse({ Utils::String::VA("%llx", id.Bits), key, value }); Friends::ParsePresence({ Utils::String::VA("%llx", id.Bits), key, value }, false);
} }
} }
Friends::SortList();
} }
} }
@ -244,6 +372,7 @@ namespace Components
entry.online = false; entry.online = false;
entry.prestige = 0; entry.prestige = 0;
entry.experience = 0; entry.experience = 0;
entry.server.setType(Game::NA_BAD);
auto oldEntry = std::find_if(oldFriends.begin(), oldFriends.end(), [id](Friends::Friend entry) auto oldEntry = std::find_if(oldFriends.begin(), oldFriends.end(), [id](Friends::Friend entry)
{ {
@ -263,10 +392,27 @@ namespace Components
} }
} }
__declspec(naked) void Friends::DisconnectStub()
{
__asm
{
pushad
call Friends::ClearServer
popad
push 467CC0h
retn
}
}
Friends::Friends() Friends::Friends()
{ {
Friends::UpdateFriends(); Friends::UpdateFriends();
// Update state when connecting/disconnecting
Utils::Hook(0x403582, Friends::DisconnectStub, HOOK_CALL).install()->quick();
Utils::Hook(0x4CD023, Friends::SetServer, HOOK_JUMP).install()->quick();
auto fInterface = IPCHandler::NewInterface("steamCallbacks"); auto fInterface = IPCHandler::NewInterface("steamCallbacks");
// Callback to update user information // Callback to update user information
@ -298,6 +444,23 @@ namespace Components
Friends::UpdateFriends(); Friends::UpdateFriends();
}); });
UIScript::Add("JoinFriend", [](UIScript::Token)
{
std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
if (Friends::CurrentFriend >= Friends::FriendsList.size()) return;
auto& user = Friends::FriendsList[Friends::CurrentFriend];
if(user.online && user.server.getType() != Game::NA_BAD)
{
Party::Connect(user.server);
}
else
{
Command::Execute("snd_playLocal exit_prestige", false);
}
});
QuickPatch::OnFrame([]() QuickPatch::OnFrame([]()
{ {
if(*reinterpret_cast<bool*>(0x1AD5690)) // LiveStorage_DoWeHaveStats if(*reinterpret_cast<bool*>(0x1AD5690)) // LiveStorage_DoWeHaveStats

View File

@ -14,6 +14,7 @@ namespace Components
static void UpdateFriends(); static void UpdateFriends();
static void UpdateRank(); static void UpdateRank();
static void UpdateHostname(Network::Address server, std::string hostname);
private: private:
#pragma pack(push, 4) #pragma pack(push, 4)
@ -35,8 +36,9 @@ namespace Components
public: public:
SteamID userId; SteamID userId;
std::string name; std::string name;
std::string playerName;
Network::Address server; Network::Address server;
std::string statusName; std::string serverName;
bool online; bool online;
int experience; int experience;
int prestige; int prestige;
@ -46,13 +48,22 @@ namespace Components
static std::recursive_mutex Mutex; static std::recursive_mutex Mutex;
static std::vector<Friend> FriendsList; static std::vector<Friend> FriendsList;
static void DisconnectStub();
static void ClearServer();
static void SetServer();
static void UpdateUserInfo(SteamID user); static void UpdateUserInfo(SteamID user);
static void UpdateState(); static void UpdateState();
static void SortList();
static void SortIndividualList(std::vector<Friend>* list);
static unsigned int GetFriendCount(); static unsigned int GetFriendCount();
static const char* GetFriendText(unsigned int index, int column); static const char* GetFriendText(unsigned int index, int column);
static void SelectFriend(unsigned int index); static void SelectFriend(unsigned int index);
static void ParsePresence(std::vector<std::string> params, bool sort);
static void FriendsResponse(std::vector<std::string> params); static void FriendsResponse(std::vector<std::string> params);
static void NameResponse(std::vector<std::string> params); static void NameResponse(std::vector<std::string> params);
static void PresenceResponse(std::vector<std::string> params); static void PresenceResponse(std::vector<std::string> params);

View File

@ -451,6 +451,7 @@ namespace Components
} }
ServerList::Insert(address, info); ServerList::Insert(address, info);
Friends::UpdateHostname(address, info.get("hostname"));
}); });
} }

View File

@ -76,9 +76,9 @@ namespace Handlers
void Friends::setPresence(Worker::Endpoint /*endpoint*/, std::vector<std::string> params) void Friends::setPresence(Worker::Endpoint /*endpoint*/, std::vector<std::string> params)
{ {
if (params.size() >= 2 && Steam::Proxy::SteamFriends) if (params.size() >= 1 && Steam::Proxy::SteamFriends)
{ {
Steam::Proxy::SteamFriends->SetRichPresence(params[0].data(), params[1].data()); Steam::Proxy::SteamFriends->SetRichPresence(params[0].data(), (params.size() >= 2 ? params[1].data() : nullptr));
} }
} }
@ -141,14 +141,6 @@ namespace Handlers
{ {
*response.add_params() = Utils::String::VA("%d", Steam::Proxy::SteamFriends->GetFriendPersonaState(id)); *response.add_params() = Utils::String::VA("%d", Steam::Proxy::SteamFriends->GetFriendPersonaState(id));
} }
/*else if (key == "iw4x_rank") // This is just a test
{
int experience = Utils::Cryptography::Rand::GenerateInt() % (2516000 + 1);
int prestige = Utils::Cryptography::Rand::GenerateInt() % (10 + 1);
int data = (experience & 0xFFFFFF) | ((prestige & 0xFF) << 24);
*response.add_params() = std::string(reinterpret_cast<char*>(&data), 4);
}*/
else else
{ {
*response.add_params() = Steam::Proxy::SteamFriends->GetFriendRichPresence(id, key.data()); *response.add_params() = Steam::Proxy::SteamFriends->GetFriendRichPresence(id, key.data());
@ -180,7 +172,7 @@ namespace Handlers
{ {
if(Steam::Proxy::SteamFriends) if(Steam::Proxy::SteamFriends)
{ {
Steam::Proxy::SteamFriends->ClearRichPresence(); Steam::Proxy::SteamFriends->SetRichPresence("iw4x_server", nullptr);
} }
if(Steam::Proxy::SteamLegacyFriends) if(Steam::Proxy::SteamLegacyFriends)