From 3184d16d6c76bba8c6994c9975dad3c64eff030e Mon Sep 17 00:00:00 2001 From: delimeats-ch Date: Thu, 1 Apr 2021 09:09:00 -0500 Subject: [PATCH 1/6] Happy April Fools' Day --- src/hacks/AutoParty.cpp | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/hacks/AutoParty.cpp b/src/hacks/AutoParty.cpp index 40e4bb08..99f398f0 100644 --- a/src/hacks/AutoParty.cpp +++ b/src/hacks/AutoParty.cpp @@ -3,6 +3,51 @@ * * Created on: Nov 27, 2020 * Author: delimeats-ch + * + * ... + * :ssssssssoooo+////:` + * `:osyyyyyyyyyhdhyyyyyho. + * -oosyyyyyyyyyyyyyyyhhyydhs- + * .soosyyssssyyyyyyyyyyyyyddhh+ + * odsssssyhhhhyyyyyyyyhhhhddhhyo` + * syhhhhhyyyyso++osyyyyhyhhhhyhy+` + * :shdhhyyso+++/////+osyyyyyyyyyyyys: + * .ydmddyssssooo++////++oosyyyyyyyyyhhys:` + * `smmmmdysssyhdys++++++oossyyyyyyhhyyyyyys` + * `/shhhyyyhhhyso+//++oossyyyyyhhhhyyyyyyy/` + * :ssssoo++++++oossyyyhhhhhyyyyyyyyyys:` + * `+oo+++++++oossyyyhhhhhyyyyyyyyyyyhhhy+-` + * .+++++++++oossyyyyyyyyyyyysyyyyyyhhhhhhys. + * .++++++++++oosssssssssssssssyyhhhhhhhhhyy+ + * .+++++++//++oooooooooooosssyyhhhhhhdhhhyyy/ + * -++++++////++++++++ooossssyyyyyhhhdhhyyyyhh- + * :++++++++++/+++ooooooossooosyyyhhhdhyyyyhhdy. + * :+++++++++++++++++++++ooooosyyhhhhhhyyyhhddds + * -+++oo++++++++++++++++++ooyyyyhhhhhyyhhhdddy- + * .+ooooo+++++++++++++++oosyyyyhhhhhyyhhhhhds. + * `+oossoo++++oooooooooossyyyhhhhhhhhhhhhys/ + * `osooooooo++oooooooosyyyyyyhhhhhhhhhhhy. + * osooooooooooooooosssyyyyyhhhdhhhhhhhdh` + * `osoo+++osysssssssossyyyyyhhdddhhhhhhds + * .oooo++oshdhyssssysossyyyyhhdmddddhhddo + * `.-:+ooooo++oyhhdhysssssoossyyyhhdddddhhddd: + * `-:++ossyyysoooooshhddyysssssosssyyyhhdmddddhdds` + * `sssysso+/:-ooooosyyyysoooooooossyyhhhhddmddddy/` + * .--:. :soossyhysoooo+++ooossyyhhhdmmmds/. + * ``--:/osoossyyyo+++++ooossosyyyhhhdhy+. + * `/+ossssssooooo:``....`....-/ossyyhhh:` + * :yysoooooo+o+:` -ssyyhh- + * `:ooooooooo:` .sysyhy` + * -///++/:` +sssyys + * `````` + * _ _ + * | | | | + * ___| |__ ___ ___ _ __ ___ ___| |__ _ _ _ __ __ _ ___ _ __ + * / __| '_ \ / _ \/ _ \ '_ ` _ \/ __| '_ \| | | | '__/ _` |/ _ \ '__| + * | (__| | | | __/ __/ | | | | \__ \ |_) | |_| | | | (_| | __/ | + * \___|_| |_|\___|\___|_| |_| |_|___/_.__/ \__,_|_| \__, |\___|_| + * __/ | + * |___/ */ #include "common.hpp" From 4236bd8e4fd638c5813d203fe9e96840d2f878e5 Mon Sep 17 00:00:00 2001 From: delimeats-ch Date: Thu, 1 Apr 2021 10:52:15 -0500 Subject: [PATCH 2/6] Add IPC support to autoparty --- src/hacks/AutoParty.cpp | 178 ++++++++++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 63 deletions(-) diff --git a/src/hacks/AutoParty.cpp b/src/hacks/AutoParty.cpp index 99f398f0..16735b78 100644 --- a/src/hacks/AutoParty.cpp +++ b/src/hacks/AutoParty.cpp @@ -52,6 +52,7 @@ #include "common.hpp" #include "hack.hpp" +#include "ipc.hpp" namespace hacks::tf2::autoparty { @@ -75,6 +76,10 @@ static settings::Boolean autoparty_log{ "autoparty.log", "true" }; static settings::Boolean message_kicks{ "autoparty.message-kicks", "true" }; // Extra debugging information like locking/unlocking the party static settings::Boolean autoparty_debug{ "autoparty.debug", "false" }; +// Use the longest-running IPC members as party hosts +static settings::Boolean ipc_mode{ "autoparty.ipc-mode", "false" }; +// How many IPC members to use as party hosts +static settings::Int ipc_count{ "autoparty.ipc-count", "0" }; // How often to run the autoparty routine, in seconds static settings::Int timeout{ "autoparty.run-frequency", "60" }; // Only run the autoparty routine once every N seconds @@ -91,12 +96,48 @@ static std::vector party_hosts = {}; if (*autoparty_debug) \ logging::Info("AutoParty (debug): " __VA_ARGS__) +// I can't think of a better way to do this right now +struct ipc_peer +{ + uint32 friendid; + time_t ts_injected; +}; + +bool compare_ts(ipc_peer &a, ipc_peer &b) +{ + return a.ts_injected < b.ts_injected; +} + // Re-populates party_hosts from the current or new configuration void repopulate(std::string str) { // Empty previous values party_hosts.clear(); + // IPC autoparty mode + if (*ipc_mode) + { + if (!ipc::peer) + { + // uh oh + return; + } + auto &peer_data = ipc::peer->memory->peer_user_data; + std::vector sorted_peers = {}; + for (int i = 0; i < cat_ipc::max_peers; i++) + { + ipc::user_data_s &data = peer_data[i]; + struct ipc_peer peer = { .friendid = data.friendid, .ts_injected = data.ts_injected }; + sorted_peers.push_back(peer); + } + std::sort(sorted_peers.begin(), sorted_peers.end(), compare_ts); + for (int i = 0; i < *ipc_count; i++) + { + party_hosts.push_back(sorted_peers[i].friendid); + } + return; + } + // Add Steam32 IDs to party_hosts std::stringstream ss(str); for (uint32 id; ss >> id;) @@ -202,79 +243,89 @@ void party_routine() else { // We are in a party! - // Get a list of party members, then check each one to determine the leader - std::vector members = client->GetPartySteamIDs(); - uint32 leader_id = 0; - for (int i = 0; i < members.size(); i++) + // Are we the *designated* leader of the current party? + if (is_host()) { - CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual); - // Are you my mummy? - if (client->GetCurrentPartyLeader(id)) + // And are we actually the leader? + // Get a list of party members, then check each one to determine the leader + std::vector members = client->GetPartySteamIDs(); + uint32 leader_id = 0; + for (int i = 0; i < members.size(); i++) { - leader_id = members[i]; - break; - } - } - - // Are we the leader of the current party? - // If so, manage it - if (leader_id == g_ISteamUser->GetSteamID().GetAccountID()) - { - // If a member is offline, just leave the party and allow new join requests - if (*auto_leave and client->GetNumMembers() > client->GetNumOnlineMembers()) - { - leave_party(client, true); - return; - } - - // If enabled, check for any raged players who may have joined our party and kick them - // If there are any, return so we don't kick other members in the event we're also over the set size limit - if (*kick_rage) - { - bool should_ret = false; - for (int i = 0; i < members.size(); i++) + CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual); + // Are you my mummy? + if (client->GetCurrentPartyLeader(id)) { - auto &pl = playerlist::AccessData(members[i]); - if (pl.state == playerlist::k_EState::RAGE) + leader_id = members[i]; + break; + } + } + if (leader_id == g_ISteamUser->GetSteamID().GetAccountID()) + { + // Great, let's manage it + // If a member is offline, just leave the party and allow new join requests + if (*auto_leave and client->GetNumMembers() > client->GetNumOnlineMembers()) + { + leave_party(client, true); + return; + } + + // If enabled, check for any raged players who may have joined our party and kick them + // If there are any, return so we don't kick other members in the event we're also over the set size limit + if (*kick_rage) + { + bool should_ret = false; + for (int i = 0; i < members.size(); i++) { - std::string message = "Kicking Steam32 ID " + std::to_string(members[i]) + " from the party because they are set to RAGE"; - logging::Info("AutoParty: %s", message); - if (*message_kicks) - client->SendPartyChat(message.c_str()); - CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual); + auto &pl = playerlist::AccessData(members[i]); + if (pl.state == playerlist::k_EState::RAGE) + { + std::string message = "Kicking Steam32 ID " + std::to_string(members[i]) + " from the party because they are set to RAGE"; + logging::Info("AutoParty: %s", message); + if (*message_kicks) + client->SendPartyChat(message.c_str()); + CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual); + client->KickPlayer(id); + should_ret = true; + } + } + if (should_ret) + return; + } + + // If we are at or over the specified limit, lock the party so we auto-reject future join requests + if (*auto_lock and members.size() >= *max_size) + { + log_debug("Locking the party because we have %d out of %d allowed members", members.size(), *max_size); + lock_party(); + } + + // Kick extra members from the party + if (members.size() > *max_size) + { + int num_to_kick = members.size() - *max_size; + std::string message = "Kicking " + std::to_string(num_to_kick) + " party members because there are " + std::to_string(members.size()) + " out of " + std::to_string(*max_size) + " allowed members"; + logging::Info("AutoParty: %s", message); + if (*message_kicks) + client->SendPartyChat(message.c_str()); + for (int i = 0; i < num_to_kick; i++) + { + CSteamID id = CSteamID(members[members.size() - (1 + i)], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual); client->KickPlayer(id); - should_ret = true; } } - if (should_ret) - return; - } - // If we are at or over the specified limit, lock the party so we auto-reject future join requests - if (*auto_lock and members.size() >= *max_size) + // Unlock the party if it's not full + if (*auto_unlock and members.size() < *max_size) + unlock_party(); + } + else { - log_debug("Locking the party because we have %d out of %d allowed members", members.size(), *max_size); - lock_party(); - } - - // Kick extra members from the party - if (members.size() > *max_size) - { - int num_to_kick = members.size() - *max_size; - std::string message = "Kicking " + std::to_string(num_to_kick) + " party members because there are " + std::to_string(members.size()) + " out of " + std::to_string(*max_size) + " allowed members"; - logging::Info("AutoParty: %s", message); - if (*message_kicks) - client->SendPartyChat(message.c_str()); - for (int i = 0; i < num_to_kick; i++) - { - CSteamID id = CSteamID(members[members.size() - (1 + i)], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual); - client->KickPlayer(id); - } - } - - // Unlock the party if it's not full - if (*auto_unlock and members.size() < *max_size) + // We are in someone else's party as a leader! + // Leave the party and unlock our join request mode + hack::ExecuteCommand("tf_party_leave"); unlock_party(); + } } else { @@ -297,6 +348,7 @@ void party_routine() static InitRoutine init([]() { host_list.installChangeCallback([](settings::VariableBase &var, std::string after) { repopulate(after); }); + ipc_mode.installChangeCallback([](settings::VariableBase &var, bool after) { repopulate(*host_list); }); EC::Register(EC::Paint, party_routine, "paint_autoparty", EC::average); }); } // namespace hacks::tf2::autoparty From a776ee92266025ca688d1071bac229248e96518c Mon Sep 17 00:00:00 2001 From: delimeats-ch Date: Thu, 1 Apr 2021 11:59:45 -0500 Subject: [PATCH 3/6] Finish half-baked code --- src/hacks/AutoParty.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hacks/AutoParty.cpp b/src/hacks/AutoParty.cpp index 16735b78..5bd63448 100644 --- a/src/hacks/AutoParty.cpp +++ b/src/hacks/AutoParty.cpp @@ -194,6 +194,8 @@ void leave_party(re::CTFPartyClient *client, bool was_leader) { log("Leaving the party because %d/%d members are offline", client->GetNumMembers() - client->GetNumOnlineMembers(), client->GetNumMembers()); hack::ExecuteCommand("tf_party_leave"); + if (was_leader and *auto_unlock) + unlock_party(); } // Automatically join/leave parties and kick bad members @@ -232,8 +234,11 @@ void party_routine() if (is_host()) { // We are a party host but have no members; allow access to the party - log_debug("No members; unlocking the party"); - unlock_party(); + if (*auto_unlock) + { + log_debug("No members; unlocking the party"); + unlock_party(); + } } else { @@ -324,7 +329,8 @@ void party_routine() // We are in someone else's party as a leader! // Leave the party and unlock our join request mode hack::ExecuteCommand("tf_party_leave"); - unlock_party(); + if (*auto_unlock) + unlock_party(); } } else From 80c5d386f1afe0c3d9160509e4d9d922d04b8d5a Mon Sep 17 00:00:00 2001 From: delimeats-ch Date: Thu, 1 Apr 2021 12:09:25 -0500 Subject: [PATCH 4/6] Add menu options --- data/menu/nullifiedcat/misc/autoparty.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/menu/nullifiedcat/misc/autoparty.xml b/data/menu/nullifiedcat/misc/autoparty.xml index 983d1de3..43bffe63 100755 --- a/data/menu/nullifiedcat/misc/autoparty.xml +++ b/data/menu/nullifiedcat/misc/autoparty.xml @@ -9,6 +9,8 @@ + + From 2bd71a9abc1a6682af2ddc7f91b3c86969488229 Mon Sep 17 00:00:00 2001 From: delimeats-ch Date: Thu, 1 Apr 2021 13:46:10 -0500 Subject: [PATCH 5/6] Fix bug --- src/hacks/AutoParty.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hacks/AutoParty.cpp b/src/hacks/AutoParty.cpp index 5bd63448..a821f1e5 100644 --- a/src/hacks/AutoParty.cpp +++ b/src/hacks/AutoParty.cpp @@ -105,7 +105,7 @@ struct ipc_peer bool compare_ts(ipc_peer &a, ipc_peer &b) { - return a.ts_injected < b.ts_injected; + return a.ts_injected > b.ts_injected; } // Re-populates party_hosts from the current or new configuration From 4b0be40dce9db4b7909a631c25d6d86eeb682d21 Mon Sep 17 00:00:00 2001 From: delimeats-ch Date: Thu, 1 Apr 2021 14:27:15 -0500 Subject: [PATCH 6/6] Empty the party_hosts vector when IPC mode is disabled so any configuration will get loaded again --- src/hacks/AutoParty.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hacks/AutoParty.cpp b/src/hacks/AutoParty.cpp index a821f1e5..3ae7d2a2 100644 --- a/src/hacks/AutoParty.cpp +++ b/src/hacks/AutoParty.cpp @@ -354,7 +354,7 @@ void party_routine() static InitRoutine init([]() { host_list.installChangeCallback([](settings::VariableBase &var, std::string after) { repopulate(after); }); - ipc_mode.installChangeCallback([](settings::VariableBase &var, bool after) { repopulate(*host_list); }); + ipc_mode.installChangeCallback([](settings::VariableBase &var, bool after) { party_hosts.clear(); }); EC::Register(EC::Paint, party_routine, "paint_autoparty", EC::average); }); } // namespace hacks::tf2::autoparty