431a9c00a5
On Linux and macOS, using Clang to compile OpenStarbound produces about 400 MB worth of warnings during the build, making the compiler output unreadable and slowing the build down considerably. 99% of the warnings were unqualified uses of std::move and std::forward, which are now all properly qualified. Fixed a few other minor warnings about non-virtual destructors and some uses of std::move preventing copy elision on temporary objects. Most remaining warnings are now unused parameters.
309 lines
8.9 KiB
C++
309 lines
8.9 KiB
C++
#include "StarTeamManager.hpp"
|
|
#include "StarRandom.hpp"
|
|
#include "StarJsonExtra.hpp"
|
|
#include "StarRoot.hpp"
|
|
#include "StarAssets.hpp"
|
|
|
|
namespace Star {
|
|
|
|
TeamManager::TeamManager() {
|
|
m_pvpTeamCounter = 1;
|
|
m_maxTeamSize = Root::singleton().configuration()->get("maxTeamSize").toUInt();
|
|
}
|
|
|
|
JsonRpcHandlers TeamManager::rpcHandlers() {
|
|
return JsonRpcHandlers{
|
|
{"team.fetchTeamStatus", bind(&TeamManager::fetchTeamStatus, this, _1)},
|
|
{"team.updateStatus", bind(&TeamManager::updateStatus, this, _1)},
|
|
{"team.invite", bind(&TeamManager::invite, this, _1)},
|
|
{"team.pollInvitation", bind(&TeamManager::pollInvitation, this, _1)},
|
|
{"team.acceptInvitation", bind(&TeamManager::acceptInvitation, this, _1)},
|
|
{"team.makeLeader", bind(&TeamManager::makeLeader, this, _1)},
|
|
{"team.removeFromTeam", [&](Json request) -> Json { return removeFromTeam(request); }}
|
|
};
|
|
}
|
|
|
|
void TeamManager::setConnectedPlayers(StringMap<List<Uuid>> const& connectedPlayers) {
|
|
m_connectedPlayers = std::move(connectedPlayers);
|
|
}
|
|
|
|
void TeamManager::playerDisconnected(Uuid const& playerUuid) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
|
|
purgeInvitationsFor(playerUuid);
|
|
purgeInvitationsFrom(playerUuid);
|
|
|
|
for (auto teamUuid : m_teams.keys()) {
|
|
auto& team = m_teams[teamUuid];
|
|
if (team.members.contains(playerUuid))
|
|
removeFromTeam(playerUuid, teamUuid);
|
|
}
|
|
}
|
|
|
|
TeamNumber TeamManager::getPvpTeam(Uuid const& playerUuid) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
for (auto const& teamPair : m_teams) {
|
|
if (teamPair.second.members.contains(playerUuid))
|
|
return teamPair.second.pvpTeamNumber;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
HashMap<Uuid, TeamNumber> TeamManager::getPvpTeams() {
|
|
HashMap<Uuid, TeamNumber> result;
|
|
for (auto const& teamPair : m_teams) {
|
|
for (auto const& memberPair : teamPair.second.members)
|
|
result[memberPair.first] = teamPair.second.pvpTeamNumber;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Maybe<Uuid> TeamManager::getTeam(Uuid const& playerUuid) const {
|
|
for (auto const& teamPair : m_teams) {
|
|
if (teamPair.second.members.contains(playerUuid))
|
|
return teamPair.first;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
void TeamManager::purgeInvitationsFor(Uuid const& playerUuid) {
|
|
m_invitations.remove(playerUuid);
|
|
}
|
|
|
|
void TeamManager::purgeInvitationsFrom(Uuid const& playerUuid) {
|
|
eraseWhere(m_invitations, [playerUuid](auto const& invitation) {
|
|
return invitation.second.inviterUuid == playerUuid;
|
|
});
|
|
}
|
|
|
|
bool TeamManager::playerWithUuidExists(Uuid const& playerUuid) const {
|
|
for (auto const& p : m_connectedPlayers) {
|
|
if (p.second.contains(playerUuid))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Uuid TeamManager::createTeam(Uuid const& leaderUuid) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
|
|
Uuid teamUuid;
|
|
auto& team = m_teams[teamUuid]; // create
|
|
|
|
int limiter = 256;
|
|
while (true) {
|
|
team.pvpTeamNumber = m_pvpTeamCounter++;
|
|
if (m_pvpTeamCounter == 0)
|
|
m_pvpTeamCounter = 1;
|
|
bool done = true;
|
|
for (auto k : m_teams.keys()) {
|
|
auto t = m_teams[k];
|
|
if (t.pvpTeamNumber == team.pvpTeamNumber) {
|
|
if (k != teamUuid)
|
|
done = false;
|
|
}
|
|
}
|
|
if (done)
|
|
break;
|
|
if (limiter-- == 0) {
|
|
team.pvpTeamNumber = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
addToTeam(leaderUuid, teamUuid);
|
|
team.leaderUuid = leaderUuid;
|
|
|
|
return teamUuid;
|
|
}
|
|
|
|
bool TeamManager::addToTeam(Uuid const& playerUuid, Uuid const& teamUuid) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
|
|
if (!m_teams.contains(teamUuid))
|
|
return false;
|
|
|
|
auto& team = m_teams.get(teamUuid);
|
|
|
|
if (team.members.contains(playerUuid))
|
|
return false;
|
|
|
|
if (team.members.size() >= m_maxTeamSize)
|
|
return false;
|
|
|
|
purgeInvitationsFor(playerUuid);
|
|
|
|
for (auto otherTeam : m_teams) {
|
|
List<Uuid> alreadyMemberOf;
|
|
if (otherTeam.second.members.contains(playerUuid))
|
|
alreadyMemberOf.append(otherTeam.first);
|
|
for (auto leaveTeamUuid : alreadyMemberOf)
|
|
removeFromTeam(playerUuid, leaveTeamUuid);
|
|
}
|
|
|
|
team.members.insert(playerUuid, TeamMember());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TeamManager::removeFromTeam(Uuid const& playerUuid, Uuid const& teamUuid) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
|
|
if (!m_teams.contains(teamUuid))
|
|
return false;
|
|
|
|
auto& team = m_teams.get(teamUuid);
|
|
|
|
if (!team.members.contains(playerUuid))
|
|
return false;
|
|
|
|
purgeInvitationsFrom(playerUuid);
|
|
|
|
team.members.remove(playerUuid);
|
|
if (team.members.size() <= 1)
|
|
m_teams.remove(teamUuid);
|
|
else if (team.leaderUuid == playerUuid)
|
|
team.leaderUuid = Random::randFrom(team.members).first;
|
|
|
|
return true;
|
|
}
|
|
|
|
Json TeamManager::fetchTeamStatus(Json const& arguments) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
auto playerUuid = Uuid(arguments.getString("playerUuid"));
|
|
JsonObject result;
|
|
if (auto teamUuid = getTeam(playerUuid)) {
|
|
auto& team = m_teams.get(*teamUuid);
|
|
|
|
result["teamUuid"] = teamUuid->hex();
|
|
result["leader"] = team.leaderUuid.hex();
|
|
JsonArray members;
|
|
for (auto const& m : team.members) {
|
|
JsonObject member;
|
|
auto const& mem = m.second;
|
|
member["name"] = mem.name;
|
|
member["uuid"] = m.first.hex();
|
|
member["leader"] = m.first == team.leaderUuid;
|
|
member["entity"] = mem.entity;
|
|
member["health"] = mem.healthPercentage;
|
|
member["energy"] = mem.energyPercentage;
|
|
member["x"] = mem.position[0];
|
|
member["y"] = mem.position[1];
|
|
member["world"] = printWorldId(mem.world);
|
|
member["warpMode"] = WarpModeNames.getRight(mem.warpMode);
|
|
member["portrait"] = jsonFromList(mem.portrait, mem_fn(&Drawable::toJson));
|
|
members.push_back(member);
|
|
}
|
|
result["members"] = members;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Json TeamManager::updateStatus(Json const& arguments) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
auto playerUuid = Uuid(arguments.getString("playerUuid"));
|
|
if (auto teamUuid = getTeam(playerUuid)) {
|
|
auto& team = m_teams.get(*teamUuid);
|
|
auto& entry = team.members.get(playerUuid);
|
|
if (arguments.contains("name"))
|
|
entry.name = arguments.getString("name");
|
|
if (arguments.contains("entity"))
|
|
entry.entity = arguments.getInt("entity");
|
|
entry.healthPercentage = arguments.getFloat("health");
|
|
entry.energyPercentage = arguments.getFloat("energy");
|
|
entry.position[0] = arguments.getFloat("x");
|
|
entry.position[1] = arguments.getFloat("y");
|
|
entry.warpMode = WarpModeNames.getLeft(arguments.getString("warpMode"));
|
|
if (arguments.contains("world"))
|
|
entry.world = parseWorldId(arguments.getString("world"));
|
|
if (arguments.contains("portrait"))
|
|
entry.portrait = jsonToList<Drawable>(arguments.get("portrait"));
|
|
return {};
|
|
} else {
|
|
return "notAMemberOfTeam";
|
|
}
|
|
}
|
|
|
|
Json TeamManager::invite(Json const& arguments) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
auto inviteeName = arguments.getString("inviteeName").toLower();
|
|
|
|
if (!m_connectedPlayers.contains(inviteeName))
|
|
return "inviteeNotFound";
|
|
|
|
auto inviterUuid = Uuid(arguments.getString("inviterUuid"));
|
|
|
|
for (auto inviteeUuid : m_connectedPlayers[inviteeName]) {
|
|
if (inviteeUuid == inviterUuid)
|
|
continue;
|
|
|
|
Invitation invitation;
|
|
invitation.inviterUuid = inviterUuid;
|
|
invitation.inviterName = arguments.getString("inviterName");
|
|
m_invitations[inviteeUuid] = invitation;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
Json TeamManager::pollInvitation(Json const& arguments) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
auto playerUuid = Uuid(arguments.getString("playerUuid"));
|
|
if (m_invitations.contains(playerUuid)) {
|
|
auto invite = m_invitations.take(playerUuid);
|
|
JsonObject result;
|
|
result["inviterUuid"] = invite.inviterUuid.hex();
|
|
result["inviterName"] = invite.inviterName;
|
|
return result;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
Json TeamManager::acceptInvitation(Json const& arguments) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
auto inviterUuid = Uuid(arguments.getString("inviterUuid"));
|
|
auto inviteeUuid = Uuid(arguments.getString("inviteeUuid"));
|
|
|
|
if (!playerWithUuidExists(inviterUuid) || !playerWithUuidExists(inviteeUuid))
|
|
return "acceptInvitationFailed";
|
|
|
|
purgeInvitationsFrom(inviteeUuid);
|
|
|
|
Uuid teamUuid;
|
|
if (auto existingTeamUuid = getTeam(inviterUuid))
|
|
teamUuid = *existingTeamUuid;
|
|
else
|
|
teamUuid = createTeam(inviterUuid);
|
|
|
|
auto success = addToTeam(inviteeUuid, teamUuid);
|
|
return success ? Json() : "acceptInvitationFailed";
|
|
}
|
|
|
|
Json TeamManager::removeFromTeam(Json const& arguments) {
|
|
auto playerUuid = Uuid(arguments.getString("playerUuid"));
|
|
auto teamUuid = Uuid(arguments.getString("teamUuid"));
|
|
|
|
auto success = removeFromTeam(playerUuid, teamUuid);
|
|
return success ? Json() : "removeFromTeamFailed";
|
|
}
|
|
|
|
Json TeamManager::makeLeader(Json const& arguments) {
|
|
RecursiveMutexLocker lock(m_mutex);
|
|
auto playerUuid = Uuid(arguments.getString("playerUuid"));
|
|
auto teamUuid = Uuid(arguments.getString("teamUuid"));
|
|
|
|
if (!m_teams.contains(teamUuid))
|
|
return "noSuchTeam";
|
|
|
|
auto& team = m_teams.get(teamUuid);
|
|
|
|
if (!team.members.contains(playerUuid))
|
|
return "notAMemberOfTeam";
|
|
|
|
team.leaderUuid = playerUuid;
|
|
|
|
return {};
|
|
}
|
|
|
|
}
|