Merge pull request #1399 from delimeats-ch/autoparty-ipc
Add IPC support to autoparty
This commit is contained in:
commit
b4678bd210
@ -9,6 +9,8 @@
|
|||||||
<AutoVariable width="fill" target="autoparty.auto-lock" label="Autolock party" tooltip="Lock the party when max party size is reached."/>
|
<AutoVariable width="fill" target="autoparty.auto-lock" label="Autolock party" tooltip="Lock the party when max party size is reached."/>
|
||||||
<AutoVariable width="fill" target="autoparty.auto-unlock" label="Auto unlock party" tooltip="Unlock the party when max party size has not been reached."/>
|
<AutoVariable width="fill" target="autoparty.auto-unlock" label="Auto unlock party" tooltip="Unlock the party when max party size has not been reached."/>
|
||||||
<AutoVariable width="fill" target="autoparty.party-hosts" label="Party hosts" tooltip="Comma-separated list of Steam32 IDs to use as party hosts."/>
|
<AutoVariable width="fill" target="autoparty.party-hosts" label="Party hosts" tooltip="Comma-separated list of Steam32 IDs to use as party hosts."/>
|
||||||
|
<AutoVariable width="fill" target="autoparty.ipc_mode" label="IPC mode" tooltip="Use IPC members as party hosts instead."/>
|
||||||
|
<AutoVariable width="fill" target="autoparty.ipc_count" label="IPC host count" tooltip="How many IPC members to use as party hosts."/>
|
||||||
<AutoVariable width="fill" target="autoparty.log" label="Log party leaves and kicks"/>
|
<AutoVariable width="fill" target="autoparty.log" label="Log party leaves and kicks"/>
|
||||||
<AutoVariable width="fill" target="autoparty.message-kicks" label="Log to chat" tooltip="Log kick notifications to party chat."/>
|
<AutoVariable width="fill" target="autoparty.message-kicks" label="Log to chat" tooltip="Log kick notifications to party chat."/>
|
||||||
<AutoVariable width="fill" target="autoparty.debug" label="Log locks/unlocks"/>
|
<AutoVariable width="fill" target="autoparty.debug" label="Log locks/unlocks"/>
|
||||||
|
@ -3,10 +3,56 @@
|
|||||||
*
|
*
|
||||||
* Created on: Nov 27, 2020
|
* Created on: Nov 27, 2020
|
||||||
* Author: delimeats-ch
|
* 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"
|
#include "common.hpp"
|
||||||
#include "hack.hpp"
|
#include "hack.hpp"
|
||||||
|
#include "ipc.hpp"
|
||||||
|
|
||||||
namespace hacks::tf2::autoparty
|
namespace hacks::tf2::autoparty
|
||||||
{
|
{
|
||||||
@ -30,6 +76,10 @@ static settings::Boolean autoparty_log{ "autoparty.log", "true" };
|
|||||||
static settings::Boolean message_kicks{ "autoparty.message-kicks", "true" };
|
static settings::Boolean message_kicks{ "autoparty.message-kicks", "true" };
|
||||||
// Extra debugging information like locking/unlocking the party
|
// Extra debugging information like locking/unlocking the party
|
||||||
static settings::Boolean autoparty_debug{ "autoparty.debug", "false" };
|
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
|
// How often to run the autoparty routine, in seconds
|
||||||
static settings::Int timeout{ "autoparty.run-frequency", "60" };
|
static settings::Int timeout{ "autoparty.run-frequency", "60" };
|
||||||
// Only run the autoparty routine once every N seconds
|
// Only run the autoparty routine once every N seconds
|
||||||
@ -46,12 +96,48 @@ static std::vector<uint32> party_hosts = {};
|
|||||||
if (*autoparty_debug) \
|
if (*autoparty_debug) \
|
||||||
logging::Info("AutoParty (debug): " __VA_ARGS__)
|
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
|
// Re-populates party_hosts from the current or new configuration
|
||||||
void repopulate(std::string str)
|
void repopulate(std::string str)
|
||||||
{
|
{
|
||||||
// Empty previous values
|
// Empty previous values
|
||||||
party_hosts.clear();
|
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<struct ipc_peer> 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
|
// Add Steam32 IDs to party_hosts
|
||||||
std::stringstream ss(str);
|
std::stringstream ss(str);
|
||||||
for (uint32 id; ss >> id;)
|
for (uint32 id; ss >> id;)
|
||||||
@ -108,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());
|
log("Leaving the party because %d/%d members are offline", client->GetNumMembers() - client->GetNumOnlineMembers(), client->GetNumMembers());
|
||||||
hack::ExecuteCommand("tf_party_leave");
|
hack::ExecuteCommand("tf_party_leave");
|
||||||
|
if (was_leader and *auto_unlock)
|
||||||
|
unlock_party();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automatically join/leave parties and kick bad members
|
// Automatically join/leave parties and kick bad members
|
||||||
@ -146,8 +234,11 @@ void party_routine()
|
|||||||
if (is_host())
|
if (is_host())
|
||||||
{
|
{
|
||||||
// We are a party host but have no members; allow access to the party
|
// We are a party host but have no members; allow access to the party
|
||||||
log_debug("No members; unlocking the party");
|
if (*auto_unlock)
|
||||||
unlock_party();
|
{
|
||||||
|
log_debug("No members; unlocking the party");
|
||||||
|
unlock_party();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -157,79 +248,90 @@ void party_routine()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We are in a party!
|
// We are in a party!
|
||||||
// Get a list of party members, then check each one to determine the leader
|
// Are we the *designated* leader of the current party?
|
||||||
std::vector<unsigned> members = client->GetPartySteamIDs();
|
if (is_host())
|
||||||
uint32 leader_id = 0;
|
|
||||||
for (int i = 0; i < members.size(); i++)
|
|
||||||
{
|
{
|
||||||
CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual);
|
// And are we actually the leader?
|
||||||
// Are you my mummy?
|
// Get a list of party members, then check each one to determine the leader
|
||||||
if (client->GetCurrentPartyLeader(id))
|
std::vector<unsigned> members = client->GetPartySteamIDs();
|
||||||
|
uint32 leader_id = 0;
|
||||||
|
for (int i = 0; i < members.size(); i++)
|
||||||
{
|
{
|
||||||
leader_id = members[i];
|
CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual);
|
||||||
break;
|
// Are you my mummy?
|
||||||
}
|
if (client->GetCurrentPartyLeader(id))
|
||||||
}
|
|
||||||
|
|
||||||
// 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++)
|
|
||||||
{
|
{
|
||||||
auto &pl = playerlist::AccessData(members[i]);
|
leader_id = members[i];
|
||||||
if (pl.state == playerlist::k_EState::RAGE)
|
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";
|
auto &pl = playerlist::AccessData(members[i]);
|
||||||
logging::Info("AutoParty: %s", message);
|
if (pl.state == playerlist::k_EState::RAGE)
|
||||||
if (*message_kicks)
|
{
|
||||||
client->SendPartyChat(message.c_str());
|
std::string message = "Kicking Steam32 ID " + std::to_string(members[i]) + " from the party because they are set to RAGE";
|
||||||
CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual);
|
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);
|
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
|
// Unlock the party if it's not full
|
||||||
if (*auto_lock and members.size() >= *max_size)
|
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);
|
// We are in someone else's party as a leader!
|
||||||
lock_party();
|
// Leave the party and unlock our join request mode
|
||||||
|
hack::ExecuteCommand("tf_party_leave");
|
||||||
|
if (*auto_unlock)
|
||||||
|
unlock_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)
|
|
||||||
unlock_party();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -252,6 +354,7 @@ void party_routine()
|
|||||||
|
|
||||||
static InitRoutine init([]() {
|
static InitRoutine init([]() {
|
||||||
host_list.installChangeCallback([](settings::VariableBase<std::string> &var, std::string after) { repopulate(after); });
|
host_list.installChangeCallback([](settings::VariableBase<std::string> &var, std::string after) { repopulate(after); });
|
||||||
|
ipc_mode.installChangeCallback([](settings::VariableBase<bool> &var, bool after) { party_hosts.clear(); });
|
||||||
EC::Register(EC::Paint, party_routine, "paint_autoparty", EC::average);
|
EC::Register(EC::Paint, party_routine, "paint_autoparty", EC::average);
|
||||||
});
|
});
|
||||||
} // namespace hacks::tf2::autoparty
|
} // namespace hacks::tf2::autoparty
|
||||||
|
Reference in New Issue
Block a user