osb/source/application/StarP2PNetworkingService_pc.cpp

617 lines
24 KiB
C++
Raw Normal View History

2023-06-20 04:33:09 +00:00
#include "StarP2PNetworkingService_pc.hpp"
#include "StarLexicalCast.hpp"
#include "StarEither.hpp"
#include "StarLogging.hpp"
#include "StarRandom.hpp"
#include "StarEncode.hpp"
#include "StarUuid.hpp"
namespace Star {
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
discord::NetworkChannelId const DiscordMainNetworkChannel = 0;
#endif
PcP2PNetworkingService::PcP2PNetworkingService(PcPlatformServicesStatePtr state)
#ifdef STAR_ENABLE_STEAM_INTEGRATION
: m_callbackConnectionFailure(this, &PcP2PNetworkingService::steamOnConnectionFailure),
m_callbackJoinRequested(this, &PcP2PNetworkingService::steamOnJoinRequested),
m_callbackSessionRequest(this, &PcP2PNetworkingService::steamOnSessionRequest),
m_state(move(state)) {
#else
: m_state(move(state)) {
#endif
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
if (m_state->discordAvailable) {
MutexLocker discordLocker(m_state->discordMutex);
m_discordPartySize = {};
m_discordOnActivityJoinToken = m_state->discordCore->ActivityManager().OnActivityJoin.Connect([this](char const* peerId) {
MutexLocker serviceLocker(m_mutex);
2023-06-27 10:23:44 +00:00
Logger::info("Joining discord peer at '{}'", peerId);
addPendingJoin(strf("+platform:{}", peerId));
2023-06-20 04:33:09 +00:00
});
m_discordOnActivityRequestToken = m_state->discordCore->ActivityManager().OnActivityJoinRequest.Connect([this](discord::User const& user) {
MutexLocker serviceLocker(m_mutex);
String userName = String(user.GetUsername());
2023-06-27 10:23:44 +00:00
Logger::info("Received join request from user '{}'", userName);
2023-06-20 04:33:09 +00:00
m_discordJoinRequests.emplace_back(make_pair(user.GetId(), userName));
});
m_discordOnReceiveMessage = m_state->discordCore->LobbyManager().OnNetworkMessage.Connect(bind(&PcP2PNetworkingService::discordOnReceiveMessage, this, _1, _2, _3, _4, _5));
m_discordOnLobbyMemberConnect = m_state->discordCore->LobbyManager().OnMemberConnect.Connect(bind(&PcP2PNetworkingService::discordOnLobbyMemberConnect, this, _1, _2));
m_discordOnLobbyMemberUpdate = m_state->discordCore->LobbyManager().OnMemberUpdate.Connect(bind(&PcP2PNetworkingService::discordOnLobbyMemberUpdate, this, _1, _2));
m_discordOnLobbyMemberDisconnect = m_state->discordCore->LobbyManager().OnMemberDisconnect.Connect(bind(&PcP2PNetworkingService::discordOnLobbyMemberDisconnect, this, _1, _2));
}
#endif
}
PcP2PNetworkingService::~PcP2PNetworkingService() {
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
if (m_state->discordAvailable) {
MutexLocker discordLocker(m_state->discordMutex);
if (m_discordServerLobby) {
2023-06-27 10:23:44 +00:00
Logger::info("Deleting discord server lobby {}", m_discordServerLobby->first);
2023-06-20 04:33:09 +00:00
m_state->discordCore->LobbyManager().DeleteLobby(m_discordServerLobby->first, [](discord::Result res) {
2023-06-27 10:23:44 +00:00
Logger::error("Could not connect delete server lobby (err {})", (int)res);
2023-06-20 04:33:09 +00:00
});
}
m_state->discordCore->ActivityManager().OnActivityJoin.Disconnect(m_discordOnActivityJoinToken);
m_state->discordCore->LobbyManager().OnNetworkMessage.Disconnect(m_discordOnReceiveMessage);
m_state->discordCore->LobbyManager().OnMemberConnect.Disconnect(m_discordOnLobbyMemberConnect);
m_state->discordCore->LobbyManager().OnMemberUpdate.Disconnect(m_discordOnLobbyMemberUpdate);
m_state->discordCore->LobbyManager().OnMemberDisconnect.Disconnect(m_discordOnLobbyMemberDisconnect);
}
#endif
}
void PcP2PNetworkingService::setJoinUnavailable() {
setJoinLocation(JoinUnavailable());
}
void PcP2PNetworkingService::setJoinLocal(uint32_t capacity) {
setJoinLocation(JoinLocal{capacity});
}
void PcP2PNetworkingService::setJoinRemote(HostAddressWithPort location) {
setJoinLocation(JoinRemote(location));
}
void Star::PcP2PNetworkingService::setActivityData(String const& title, Maybe<pair<uint16_t, uint16_t>> party) {
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
MutexLocker discordLocker(m_state->discordMutex);
#endif
MutexLocker serviceLocker(m_mutex);
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
if (m_state->discordAvailable && m_state->discordCurrentUser) {
if (m_discordUpdatingActivity)
return;
if (title != m_discordActivityTitle || party != m_discordPartySize || m_discordForceUpdateActivity) {
m_discordForceUpdateActivity = false;
m_discordPartySize = party;
m_discordActivityTitle = title;
discord::Activity activity = {};
activity.SetType(discord::ActivityType::Playing);
activity.SetName("Starbound");
activity.SetState(title.utf8Ptr());
if (auto p = party) {
activity.GetParty().GetSize().SetCurrentSize(p->first);
activity.GetParty().GetSize().SetMaxSize(p->second);
}
if (auto lobby = m_discordServerLobby)
2023-06-27 10:23:44 +00:00
activity.GetParty().SetId(strf("{}", lobby->first).c_str());
2023-06-20 04:33:09 +00:00
if (m_joinLocation.is<JoinLocal>()) {
if (auto lobby = m_discordServerLobby) {
2023-06-27 10:23:44 +00:00
String joinSecret = strf("connect:discord_{}_{}_{}", m_state->discordCurrentUser->GetId(), lobby->first, lobby->second);
Logger::info("Setting discord join secret as {}", joinSecret);
2023-06-20 04:33:09 +00:00
activity.GetSecrets().SetJoin(joinSecret.utf8Ptr());
}
} else if (m_joinLocation.is<JoinRemote>()) {
2023-06-27 10:23:44 +00:00
String address = strf("{}", (HostAddressWithPort)m_joinLocation.get<JoinRemote>());
String joinSecret = strf("connect:address_{}", address);
Logger::info("Setting discord join secret as {}", joinSecret);
2023-06-20 04:33:09 +00:00
activity.GetSecrets().SetJoin(joinSecret.utf8Ptr());
activity.GetParty().SetId(address.utf8Ptr());
}
m_discordUpdatingActivity = true;
m_state->discordCore->ActivityManager().UpdateActivity(activity, [this](discord::Result res) {
if (res != discord::Result::Ok)
2023-06-27 10:23:44 +00:00
Logger::error("failed to set discord activity (err {})", (int)res);
2023-06-20 04:33:09 +00:00
MutexLocker serviceLocker(m_mutex);
m_discordUpdatingActivity = false;
});
}
}
#endif
}
MVariant<P2PNetworkingPeerId, HostAddressWithPort> PcP2PNetworkingService::pullPendingJoin() {
MutexLocker serviceLocker(m_mutex);
return take(m_pendingJoin);
}
Maybe<pair<String, RpcPromiseKeeper<P2PJoinRequestReply>>> Star::PcP2PNetworkingService::pullJoinRequest() {
MutexLocker serviceLocker(m_mutex);
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
if (auto request = m_discordJoinRequests.maybeTakeLast()) {
auto promisePair = RpcPromise<P2PJoinRequestReply>::createPair();
m_pendingDiscordJoinRequests.push_back(make_pair(request->first, promisePair.first));
return make_pair(request->second, promisePair.second);
}
#endif
return {};
}
void PcP2PNetworkingService::setAcceptingP2PConnections(bool acceptingP2PConnections) {
MutexLocker serviceLocker(m_mutex);
m_acceptingP2PConnections = acceptingP2PConnections;
if (!m_acceptingP2PConnections)
m_pendingIncomingConnections.clear();
}
List<P2PSocketUPtr> PcP2PNetworkingService::acceptP2PConnections() {
MutexLocker serviceLocker(m_mutex);
return take(m_pendingIncomingConnections);
}
void Star::PcP2PNetworkingService::update() {
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
MutexLocker discordLocker(m_state->discordMutex);
#endif
MutexLocker serviceLocker(m_mutex);
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
for (auto& p : m_pendingDiscordJoinRequests) {
if (auto res = p.second.result()) {
discord::ActivityJoinRequestReply reply;
switch (*res) {
case P2PJoinRequestReply::Yes:
reply = discord::ActivityJoinRequestReply::Yes;
break;
case P2PJoinRequestReply::No:
reply = discord::ActivityJoinRequestReply::No;
break;
case P2PJoinRequestReply::Ignore:
reply = discord::ActivityJoinRequestReply::Ignore;
break;
}
m_state->discordCore->ActivityManager().SendRequestReply(p.first, reply, [](discord::Result res) {
if (res != discord::Result::Ok)
2023-06-27 10:23:44 +00:00
Logger::error("Could not send discord activity join response (err {})", (int)res);
2023-06-20 04:33:09 +00:00
});
}
}
m_pendingDiscordJoinRequests = m_pendingDiscordJoinRequests.filtered([this](pair<discord::UserId, RpcPromise<P2PJoinRequestReply>>& p) {
return !p.second.finished();
});
#endif
}
Either<String, P2PSocketUPtr> PcP2PNetworkingService::connectToPeer(P2PNetworkingPeerId peerId) {
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
MutexLocker discordLocker(m_state->discordMutex);
#endif
MutexLocker serviceLocker(m_mutex);
String type = peerId.extract("_");
#ifdef STAR_ENABLE_STEAM_INTEGRATION
if (m_state->steamAvailable) {
if (type == "steamid") {
CSteamID steamId(lexicalCast<uint64>(peerId));
return makeRight(createSteamP2PSocket(steamId));
}
}
#endif
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
if (m_state->discordAvailable) {
if (type == "discord") {
auto remoteUserId = lexicalCast<discord::UserId>(peerId.extract("_"));
auto lobbyId = lexicalCast<discord::LobbyId>(peerId.extract("_"));
String lobbySecret = move(peerId);
return makeRight(discordConnectRemote(remoteUserId, lobbyId, lobbySecret));
}
}
#endif
2023-06-27 10:23:44 +00:00
return makeLeft(strf("Unsupported peer type '{}'", type));
2023-06-20 04:33:09 +00:00
}
void PcP2PNetworkingService::addPendingJoin(String connectionString) {
MutexLocker serviceLocker(m_mutex);
if (connectionString.extract(":") != "+platform")
2023-06-27 10:23:44 +00:00
throw ApplicationException::format("malformed connection string '{}'", connectionString);
2023-06-20 04:33:09 +00:00
if (connectionString.extract(":") != "connect")
2023-06-27 10:23:44 +00:00
throw ApplicationException::format("malformed connection string '{}'", connectionString);
2023-06-20 04:33:09 +00:00
String target = move(connectionString);
String targetType = target.extract("_");
if (targetType == "address")
m_pendingJoin = HostAddressWithPort(target);
else
2023-06-27 10:23:44 +00:00
m_pendingJoin = P2PNetworkingPeerId(strf("{}_{}", targetType, target));
2023-06-20 04:33:09 +00:00
}
#ifdef STAR_ENABLE_STEAM_INTEGRATION
PcP2PNetworkingService::SteamP2PSocket::~SteamP2PSocket() {
MutexLocker serviceLocker(parent->m_mutex);
MutexLocker socketLocker(mutex);
parent->steamCloseSocket(this);
}
bool PcP2PNetworkingService::SteamP2PSocket::isOpen() {
MutexLocker socketLocker(mutex);
return connected;
}
bool PcP2PNetworkingService::SteamP2PSocket::sendMessage(ByteArray const& message) {
MutexLocker socketLocker(mutex);
if (!connected)
return false;
if (!SteamNetworking()->SendP2PPacket(steamId, message.ptr(), message.size(), k_EP2PSendReliable))
throw ApplicationException("SteamNetworking::SendP2PPacket unexpectedly returned false");
return true;
}
Maybe<ByteArray> PcP2PNetworkingService::SteamP2PSocket::receiveMessage() {
MutexLocker socketLocker(mutex);
if (!incoming.empty())
return incoming.takeFirst();
if (connected) {
socketLocker.unlock();
{
MutexLocker serviceLocker(parent->m_mutex);
parent->steamReceiveAll();
}
socketLocker.lock();
if (!incoming.empty())
return incoming.takeFirst();
}
return {};
}
auto PcP2PNetworkingService::createSteamP2PSocket(CSteamID steamId) -> unique_ptr<SteamP2PSocket> {
if (auto oldSocket = m_steamOpenSockets.value(steamId.ConvertToUint64())) {
MutexLocker socketLocker(oldSocket->mutex);
steamCloseSocket(oldSocket);
}
unique_ptr<SteamP2PSocket> socket(new SteamP2PSocket);
socket->parent = this;
socket->steamId = steamId;
socket->connected = true;
m_steamOpenSockets[steamId.ConvertToUint64()] = socket.get();
return socket;
}
void PcP2PNetworkingService::steamOnConnectionFailure(P2PSessionConnectFail_t* callback) {
MutexLocker serviceLocker(m_mutex);
2023-06-27 10:23:44 +00:00
Logger::warn("Connection with steam user {} failed", callback->m_steamIDRemote.ConvertToUint64());
2023-06-20 04:33:09 +00:00
if (auto socket = m_steamOpenSockets.value(callback->m_steamIDRemote.ConvertToUint64())) {
MutexLocker socketLocker(socket->mutex);
steamCloseSocket(socket);
}
}
void PcP2PNetworkingService::steamOnJoinRequested(GameRichPresenceJoinRequested_t* callback) {
2023-06-27 10:23:44 +00:00
Logger::info("Queueing join request with steam friend id {} to address {}", callback->m_steamIDFriend.ConvertToUint64(), callback->m_rgchConnect);
2023-06-20 04:33:09 +00:00
addPendingJoin(callback->m_rgchConnect);
}
void PcP2PNetworkingService::steamOnSessionRequest(P2PSessionRequest_t* callback) {
MutexLocker serviceLocker(m_mutex);
// Not sure whether this HasFriend call is actually necessary, or whether
// non-friends can even initiate P2P sessions.
if (m_acceptingP2PConnections && SteamFriends()->HasFriend(callback->m_steamIDRemote, k_EFriendFlagImmediate)) {
if (SteamNetworking()->AcceptP2PSessionWithUser(callback->m_steamIDRemote)) {
2023-06-27 10:23:44 +00:00
Logger::info("Accepted steam p2p connection with user {}", callback->m_steamIDRemote.ConvertToUint64());
2023-06-20 04:33:09 +00:00
m_pendingIncomingConnections.append(createSteamP2PSocket(callback->m_steamIDRemote));
} else {
2023-06-27 10:23:44 +00:00
Logger::error("Accepting steam p2p connection from user {} failed!", callback->m_steamIDRemote.ConvertToUint64());
2023-06-20 04:33:09 +00:00
}
} else {
2023-06-27 10:23:44 +00:00
Logger::error("Ignoring steam p2p connection from user {}", callback->m_steamIDRemote.ConvertToUint64());
2023-06-20 04:33:09 +00:00
}
}
void PcP2PNetworkingService::steamCloseSocket(SteamP2PSocket* socket) {
if (socket->connected) {
2023-06-27 10:23:44 +00:00
Logger::info("Closing p2p connection with steam user {}", socket->steamId.ConvertToUint64());
2023-06-20 04:33:09 +00:00
m_steamOpenSockets.remove(socket->steamId.ConvertToUint64());
socket->connected = false;
}
SteamNetworking()->CloseP2PSessionWithUser(socket->steamId);
}
void PcP2PNetworkingService::steamReceiveAll() {
uint32_t messageSize;
CSteamID messageRemoteUser;
while (SteamNetworking()->IsP2PPacketAvailable(&messageSize)) {
ByteArray data(messageSize, 0);
SteamNetworking()->ReadP2PPacket(data.ptr(), messageSize, &messageSize, &messageRemoteUser);
if (auto openSocket = m_steamOpenSockets.value(messageRemoteUser.ConvertToUint64())) {
MutexLocker socketLocker(openSocket->mutex);
openSocket->incoming.append(move(data));
}
}
}
#endif
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
PcP2PNetworkingService::DiscordP2PSocket::~DiscordP2PSocket() {
MutexLocker discordLocker(parent->m_state->discordMutex);
MutexLocker serviceLocker(parent->m_mutex);
MutexLocker socketLocker(mutex);
parent->discordCloseSocket(this);
}
bool PcP2PNetworkingService::DiscordP2PSocket::isOpen() {
MutexLocker socketLocker(mutex);
return mode != DiscordSocketMode::Disconnected;
}
bool PcP2PNetworkingService::DiscordP2PSocket::sendMessage(ByteArray const& message) {
MutexLocker discordLocker(parent->m_state->discordMutex);
MutexLocker socketLocker(mutex);
if (mode != DiscordSocketMode::Connected)
return false;
discord::Result res = parent->m_state->discordCore->LobbyManager().SendNetworkMessage(lobbyId, remoteUserId, DiscordMainNetworkChannel, (uint8_t*)message.ptr(), message.size());
if (res != discord::Result::Ok)
2023-06-27 10:23:44 +00:00
throw ApplicationException::format("discord::Network::Send returned error (err {})", (int)res);
2023-06-20 04:33:09 +00:00
return true;
}
Maybe<ByteArray> PcP2PNetworkingService::DiscordP2PSocket::receiveMessage() {
MutexLocker socketLocker(mutex);
if (!incoming.empty())
return incoming.takeFirst();
else
return {};
}
void PcP2PNetworkingService::discordCloseSocket(DiscordP2PSocket* socket) {
if (socket->mode != DiscordSocketMode::Disconnected) {
m_discordOpenSockets.remove(socket->remoteUserId);
if (socket->mode == DiscordSocketMode::Connected) {
if (!m_joinLocation.is<JoinLocal>() && m_discordOpenSockets.empty()) {
auto res = m_state->discordCore->LobbyManager().DisconnectNetwork(socket->lobbyId);
if (res != discord::Result::Ok)
2023-06-27 10:23:44 +00:00
Logger::error("failed to leave network for lobby {} (err {})", socket->lobbyId, (int)res);
2023-06-20 04:33:09 +00:00
m_state->discordCore->LobbyManager().DisconnectLobby(socket->lobbyId, [this, lobbyId = socket->lobbyId](discord::Result res) {
if (res != discord::Result::Ok)
2023-06-27 10:23:44 +00:00
Logger::error("failed to leave discord lobby {}", lobbyId);
2023-06-20 04:33:09 +00:00
2023-06-27 10:23:44 +00:00
Logger::info("Left discord lobby {}", lobbyId);
2023-06-20 04:33:09 +00:00
MutexLocker serviceLocker(m_mutex);
m_discordServerLobby = {};
m_discordForceUpdateActivity = true;
});
}
}
socket->mode = DiscordSocketMode::Disconnected;
}
}
P2PSocketUPtr PcP2PNetworkingService::discordConnectRemote(discord::UserId remoteUserId, discord::LobbyId lobbyId, String const& lobbySecret) {
if (auto oldSocket = m_discordOpenSockets.value(remoteUserId)) {
MutexLocker socketLocker(oldSocket->mutex);
discordCloseSocket(oldSocket);
}
unique_ptr<DiscordP2PSocket> socket(new DiscordP2PSocket);
socket->parent = this;
socket->mode = DiscordSocketMode::Startup;
socket->remoteUserId = remoteUserId;
socket->lobbyId = lobbyId;
m_discordOpenSockets[remoteUserId] = socket.get();
2023-06-27 10:23:44 +00:00
Logger::info("Connect to discord lobby {}", lobbyId);
2023-06-20 04:33:09 +00:00
m_state->discordCore->LobbyManager().ConnectLobby(lobbyId, lobbySecret.utf8Ptr(), [this, remoteUserId, lobbyId](discord::Result res, discord::Lobby const& lobby) {
MutexLocker serviceLocker(m_mutex);
if (res == discord::Result::Ok) {
if (auto socket = m_discordOpenSockets.value(remoteUserId)) {
MutexLocker socketLocker(socket->mutex);
res = m_state->discordCore->LobbyManager().ConnectNetwork(lobbyId);
if (res != discord::Result::Ok) {
discordCloseSocket(socket);
2023-06-27 10:23:44 +00:00
return Logger::error("Could not connect to discord lobby network (err {})", (int)res);
2023-06-20 04:33:09 +00:00
}
res = m_state->discordCore->LobbyManager().OpenNetworkChannel(lobbyId, DiscordMainNetworkChannel, true);
if (res != discord::Result::Ok) {
discordCloseSocket(socket);
2023-06-27 10:23:44 +00:00
return Logger::error("Could not open discord main network channel (err {})", (int)res);
2023-06-20 04:33:09 +00:00
}
socket->mode = DiscordSocketMode::Connected;
2023-06-27 10:23:44 +00:00
Logger::info("Discord p2p connection opened to remote user {} via lobby {}", remoteUserId, lobbyId);
2023-06-20 04:33:09 +00:00
m_discordServerLobby = make_pair(lobbyId, String());
m_discordForceUpdateActivity = true;
} else {
2023-06-27 10:23:44 +00:00
Logger::error("discord::Lobbies::Connect callback no matching remoteUserId {} found", remoteUserId);
2023-06-20 04:33:09 +00:00
}
} else {
2023-06-27 10:23:44 +00:00
Logger::error("failed to connect to remote lobby (err {})", (int)res);
2023-06-20 04:33:09 +00:00
if (auto socket = m_discordOpenSockets.value(remoteUserId)) {
MutexLocker socketLocker(socket->mutex);
discordCloseSocket(socket);
}
}
});
return unique_ptr<P2PSocket>(move(socket));
}
void PcP2PNetworkingService::discordOnReceiveMessage(discord::LobbyId lobbyId, discord::UserId userId, discord::NetworkChannelId channel, uint8_t* data, uint32_t size) {
MutexLocker serviceLocker(m_mutex);
if (lobbyId != m_discordServerLobby->first)
2023-06-27 10:23:44 +00:00
return Logger::error("Received message from unexpected lobby {}", lobbyId);
2023-06-20 04:33:09 +00:00
if (auto socket = m_discordOpenSockets.value(userId)) {
if (channel == DiscordMainNetworkChannel) {
MutexLocker socketLocker(socket->mutex);
socket->incoming.append(ByteArray((char const*)data, size));
} else {
2023-06-27 10:23:44 +00:00
Logger::error("Received discord message on unexpected channel {}, ignoring", channel);
2023-06-20 04:33:09 +00:00
}
} else {
2023-06-27 10:23:44 +00:00
Logger::error("Could not find associated discord socket for user id {}", userId);
2023-06-20 04:33:09 +00:00
}
}
void PcP2PNetworkingService::discordOnLobbyMemberConnect(discord::LobbyId lobbyId, discord::UserId userId) {
MutexLocker serviceLocker(m_mutex);
if (m_discordServerLobby && m_discordServerLobby->first == lobbyId && userId != m_state->discordCurrentUser->GetId()) {
if (!m_discordOpenSockets.contains(userId)) {
unique_ptr<DiscordP2PSocket> socket(new DiscordP2PSocket);
socket->parent = this;
socket->lobbyId = lobbyId;
socket->remoteUserId = userId;
socket->mode = DiscordSocketMode::Connected;
m_discordOpenSockets[userId] = socket.get();
m_pendingIncomingConnections.append(move(socket));
2023-06-27 10:23:44 +00:00
Logger::info("Accepted new discord connection from remote user {}", userId);
2023-06-20 04:33:09 +00:00
}
}
}
void PcP2PNetworkingService::discordOnLobbyMemberUpdate(discord::LobbyId lobbyId, discord::UserId userId) {
discordOnLobbyMemberConnect(lobbyId, userId);
}
void PcP2PNetworkingService::discordOnLobbyMemberDisconnect(discord::LobbyId lobbyId, discord::UserId userId) {
MutexLocker serviceLocker(m_mutex);
if (m_discordServerLobby && m_discordServerLobby->first == lobbyId && userId != m_state->discordCurrentUser->GetId()) {
if (auto socket = m_discordOpenSockets.value(userId)) {
MutexLocker socketLocker(socket->mutex);
discordCloseSocket(socket);
}
}
}
#endif
void PcP2PNetworkingService::setJoinLocation(JoinLocation location) {
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
MutexLocker discordLocker(m_state->discordMutex);
#endif
MutexLocker serviceLocker(m_mutex);
if (location == m_joinLocation)
return;
m_joinLocation = location;
#ifdef STAR_ENABLE_STEAM_INTEGRATION
if (m_state->steamAvailable) {
if (m_joinLocation.is<JoinUnavailable>()) {
Logger::info("Clearing steam rich presence connection");
SteamFriends()->SetRichPresence("connect", "");
} else if (m_joinLocation.is<JoinLocal>()) {
auto steamId = SteamUser()->GetSteamID().ConvertToUint64();
2023-06-27 10:23:44 +00:00
Logger::info("Setting steam rich presence connection as steamid_{}", steamId);
SteamFriends()->SetRichPresence("connect", strf("+platform:connect:steamid_{}", steamId).c_str());
2023-06-20 04:33:09 +00:00
} else if (m_joinLocation.is<JoinRemote>()) {
auto address = (HostAddressWithPort)location.get<JoinRemote>();
2023-06-27 10:23:44 +00:00
Logger::info("Setting steam rich presence connection as address_{}", address);
SteamFriends()->SetRichPresence("connect", strf("+platform:connect:address_{}", address).c_str());
2023-06-20 04:33:09 +00:00
}
}
#endif
#ifdef STAR_ENABLE_DISCORD_INTEGRATION
if (m_state->discordAvailable && m_state->discordCurrentUser) {
if (m_discordServerLobby) {
2023-06-27 10:23:44 +00:00
Logger::info("Deleting discord server lobby {}", m_discordServerLobby->first);
2023-06-20 04:33:09 +00:00
m_state->discordCore->LobbyManager().DeleteLobby(m_discordServerLobby->first, [](discord::Result res) {
2023-06-27 10:23:44 +00:00
Logger::error("Could not connect delete server lobby (err {})", (int)res);
2023-06-20 04:33:09 +00:00
});
}
if (auto joinLocal = m_joinLocation.maybe<JoinLocal>()) {
discord::LobbyTransaction createLobby{};
if (m_state->discordCore->LobbyManager().GetLobbyCreateTransaction(&createLobby) != discord::Result::Ok)
throw ApplicationException::format("discord::Lobbies::CreateLobbyTransaction failed");
createLobby.SetCapacity(joinLocal->capacity);
createLobby.SetType(discord::LobbyType::Private);
m_state->discordCore->LobbyManager().CreateLobby(createLobby, [this](discord::Result res, discord::Lobby const& lobby) {
if (res == discord::Result::Ok) {
MutexLocker serviceLocker(m_mutex);
discord::LobbyId lobbyId = lobby.GetId();
res = m_state->discordCore->LobbyManager().ConnectNetwork(lobbyId);
if (res == discord::Result::Ok) {
res = m_state->discordCore->LobbyManager().OpenNetworkChannel(lobbyId, DiscordMainNetworkChannel, true);
if (res == discord::Result::Ok) {
m_discordServerLobby = make_pair(lobbyId, String(lobby.GetSecret()));
m_discordForceUpdateActivity = true;
// successfully joined lobby network
return;
} else {
2023-06-27 10:23:44 +00:00
Logger::error("Failed to open discord main network channel (err {})", (int)res);
2023-06-20 04:33:09 +00:00
}
} else {
2023-06-27 10:23:44 +00:00
Logger::error("Failed to join discord lobby network (err {})", (int)res);
2023-06-20 04:33:09 +00:00
}
// Created lobby but failed to join the lobby network, delete lobby
2023-06-27 10:23:44 +00:00
Logger::error("Failed to join discord lobby network (err {})", (int)res);
2023-06-20 04:33:09 +00:00
2023-06-27 10:23:44 +00:00
Logger::info("Deleting discord lobby {}", lobbyId);
2023-06-20 04:33:09 +00:00
m_state->discordCore->LobbyManager().DeleteLobby(lobbyId, [lobbyId](discord::Result res) {
2023-06-27 10:23:44 +00:00
Logger::error("failed to delete lobby {} (err {})", lobbyId, (int)res);
2023-06-20 04:33:09 +00:00
});
} else {
2023-06-27 10:23:44 +00:00
Logger::error("failed to create discord lobby (err {})", (int)res);
2023-06-20 04:33:09 +00:00
}
});
}
}
#endif
}
}