refactoring

This commit is contained in:
pigreco 2024-09-27 14:47:03 +02:00
parent dd09cc932e
commit 35a94d1240
76 changed files with 1040 additions and 1623 deletions

View file

@ -37,7 +37,6 @@ namespace Auth
if (ec)
{
std::cerr << "Error during read: " << ec.message() << std::endl;
asio::error_code ec;
socket.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket.close();
@ -51,7 +50,6 @@ namespace Auth
auto [ptr, ecc] = std::from_chars(response.data(), response.data() + response.size(), playerCount);
if (ecc != std::errc{})
{
std::cerr << "Conversion error\n";
asio::error_code ec;
socket.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket.close();
@ -62,7 +60,6 @@ namespace Auth
}
catch (const std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
asio::error_code ec;
socket.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket.close();

View file

@ -25,33 +25,6 @@ namespace Cast
public:
Room() = default;
~Room()
{
// Just for debug.
std::cout << "Room with number: " << m_roomNumber << " is being closed!\n";
}
// Debug
void printRoomState(const std::string& furtherInfo) const
{
/*
std::cout << "____________________________\n";
std::cout << furtherInfo << ":\n\n";
std::cout << "Room Information:\n";
std::cout << " Room Number: " << m_roomNumber << '\n';
std::cout << "Players:\n";
for (const auto& currentPlayer : m_players)
{
std::cout << " - SessionID: " << currentPlayer.first
//<< "\n RoomID: " << currentPlayer.second->getRoomId()
<< "\n RoomNum: " << currentPlayer.second->getRoomNumber()
<< "\n Is In Match: " << (currentPlayer.second->isInMatch() ? "Yes" : "No") << '\n';
}
std::cout << "____________________________\n";
*/
}
Room(std::uint64_t hostSessionId, Cast::Network::Session* hostSession);
std::uint32_t getRoomNumber() const;
@ -90,10 +63,6 @@ namespace Cast
std::uint32_t getMode() const;
std::uint32_t getTick() const;
void setTick(std::uint32_t tick);
void leaveAllPLayers();
};
}

View file

@ -17,7 +17,6 @@ namespace Cast
public:
void addRoom(std::shared_ptr<Cast::Classes::Room> room, std::uint64_t playerId);
// Debug
void printRoomInfo(std::uint64_t sessionId, const std::string& furtherInfo)
{
}
@ -34,8 +33,6 @@ namespace Cast
void setMapFor(std::uint64_t playerId, std::uint32_t map);
void setModeFor(std::uint64_t hostId, std::uint32_t mode);
void endMatch(std::uint64_t hostId);
std::uint32_t getMapOf(std::uint64_t hostId);

View file

@ -10,11 +10,8 @@ namespace Cast
{
inline void handleAccountNames(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
std::cout << "OKKKKKKKKKKKKKKKKKKKKKK\n";
// This should only be broadcast to players that are NOT inside the match, but inside the room!
roomsManager.broadcastToRoomExceptSelf(session.getId(), const_cast<Common::Network::Packet&>(request)); // note: do not broadcast to self!
// roomsManager.printRoomInfo(session.getRoomId(), "after HandleAccountNames");
}
}
}

View file

@ -13,10 +13,6 @@ namespace Cast
{
inline void handleCrash(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
auto& logger = ::Utils::Logger::getInstance(true);
logger.log<::Utils::LogDestination::File>("User crashed (SessionID: " + std::to_string(session.getId()) + ", RoomNum: "
+ std::to_string(session.getRoomNumber()), ::Utils::LogType::Info, "handleCrash");
const auto selfSessionId = session.getId();
const auto roomHostId = request.getSession();
Main::Structures::UniqueId uniqueId{ selfSessionId, 4, 0 };
@ -26,8 +22,6 @@ namespace Cast
// This sets is in match to false, roomNum to -1, removes player from room, removes player from roomsManager's unordered_map
roomsManager.removePlayerFromRoom(session.getId());
//roomsManager.printRoomInfo(session.getRoomId(), "After CrashHandler");
}
}
}

View file

@ -10,17 +10,12 @@ namespace Cast
namespace Handlers
{
// Client sends packet to the host whenever someone joins their room
// Ok. checked
inline void handlePlayerJoinRoom(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
const std::uint64_t hostSessionId = request.getSession();
const std::uint64_t selfSessionId = session.getId();
std::cout << "Player: " << selfSessionId << " attempting to join room of player: " << hostSessionId << '\n';
roomsManager.switchRoomJoinOrExit(session, hostSessionId);
// roomsManager.printRoomInfo(session.getRoomId(), "after PlayerJoinRoom");
}
}
}

View file

@ -11,8 +11,6 @@ namespace Cast
inline void handleMatchEnd(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
roomsManager.endMatch(session.getId());
// roomsManager.printRoomInfo(session.getRoomId(), "After HandleMatchEnd");
}
}
}

View file

@ -12,19 +12,11 @@ namespace Cast
inline void handleMatchLeave(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
const auto selfSessionId = session.getId();
auto& logger = ::Utils::Logger::getInstance();
logger.log("Player is leaving the match (SessionID: " + std::to_string(session.getId())
+ ", roomNum: " + std::to_string(session.getRoomNumber()), ::Utils::LogType::Info, "handleMatchLeave");
Main::Structures::UniqueId uniqueId{ selfSessionId, 4, 0 };
auto response = request;
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
session.setIsInMatch(false);
//roomsManager.printRoomInfo(session.getRoomId(), "after PlayerLeaveMatch");
}
}
}

View file

@ -121,20 +121,6 @@ namespace Cast
}
roomsManager.broadcastToRoomExceptSelf(session.getId(), response);
response.setOrder(284);
response.setMission(0);
response.setOption(0);
response.setExtra(52);
struct Nickname
{
char nick[16] = "test1";
} nick;
response.setData(reinterpret_cast<std::uint8_t*>(&nick),sizeof(nick));
if (session.getId() == 500)
{
roomsManager.broadcastToRoomExceptSelf(session.getId(), response);
}
}
}
}

View file

@ -16,14 +16,9 @@ namespace Cast
// 2. they don't respawn at all.
inline void handlePlayerSyncWithRoom(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
auto& logger = ::Utils::Logger::getInstance();
logger.log("Getting player sync room info", ::Utils::LogType::Info, "handlePlayerSyncWithRoom");
const auto receiverSessionId = request.getSession();
const auto hostSessionId = session.getId();
roomsManager.hostForwardToPlayer(hostSessionId, receiverSessionId, const_cast<Common::Network::Packet&>(request));
// roomsManager.printRoomInfo(session.getRoomId(), "After handlePlayerSyncWithRoom");
}
}
}

View file

@ -41,23 +41,15 @@ namespace Cast
const auto targetSessionId = playerRespawnPosition.targetUniqueId.session;
roomsManager.broadcastToRoom(session.getId(), response);
// roomsManager.printRoomInfo(session.getRoomId(), "After handle Player Respawn");
}
// Non host client requests host to respawn them
inline void handlePlayerRespawnRequest(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
auto& logger = ::Utils::Logger::getInstance(true);
logger.log("Respawning player", ::Utils::LogType::Info, "handlePlayerRespawnRequest");
const auto roomHostSessionId = request.getSession();
const auto selfSessionId = session.getId();
roomsManager.playerForwardToHost(roomHostSessionId, selfSessionId, const_cast<Common::Network::Packet&>(request));
//roomsManager.printRoomInfo(session.getRoomId(), "After handle Player Respawn Req");
}
}
}

View file

@ -17,8 +17,6 @@ namespace Cast
// Create a room, add the player to id (sessionID=>Session pair).
// Then, add the room to roomsManager. Pass the room and the sessionID of the player. Don't keep track that it's the host: the client does this for us in P2P.
roomsManager.addRoom(std::make_shared<Cast::Classes::Room>(session.getId(), &session), session.getId());
// roomsManager.printRoomInfo(session.getRoomId(), "After RoomCreation");
}
}
}

View file

@ -19,11 +19,7 @@ namespace Cast
const auto receiverSessionId = request.getSession();
const auto hostSessionId = session.getId();
std::cout << "Host: " << hostSessionId << " sending tick to: " << receiverSessionId << '\n';
roomsManager.hostForwardToPlayer(hostSessionId, receiverSessionId, const_cast<Common::Network::Packet&>(request));
// roomsManager.printRoomInfo(session.getRoomId(), "After handle room tick providing");
}
}
}

View file

@ -18,8 +18,6 @@ namespace Cast
*/
inline void handleRoomTickSyncRequest(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
std::cout << "Player: " << session.getId() << " asking Tick Request to: " << request.getSession() << '\n';
const auto roomHostSessionId = request.getSession();
const auto selfSessionId = session.getId();

View file

@ -13,7 +13,6 @@ namespace Cast
inline void leaveRoom(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
roomsManager.switchRoomJoinOrExit(session);
// roomsManager.printRoomInfo(session.getRoomId(), "After switch state handler");
}
}
}

View file

@ -14,15 +14,10 @@ namespace Cast
// This is a request from the client to get the Room Info (e.g. how many wins in which team, etc)
inline void roomInfoHandler(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
auto& logger = ::Utils::Logger::getInstance();
logger.log("Room Info Handler...", ::Utils::LogType::Info, "roomInfoHandler");
const auto roomHostSessionId = request.getSession();
const auto selfSessionId = session.getId();
// roomsManager.playerForwardToHost(session.getRoomId(), selfSessionId, const_cast<Common::Network::Packet&>(request));
// This command does NOT exist in the client! [order = 255]
// roomsManager.printRoomInfo(session.getRoomId(), "After room info handler");
}
}
}

View file

@ -17,16 +17,11 @@ namespace Cast
{
inline void handleMatchStart(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
auto& logger = ::Utils::Logger::getInstance();
logger.log("Handling match start", ::Utils::LogType::Info, "handleMatchStart");
session.setIsInMatch(true);
auto mapIdInfoFromMain = ::Utils::IPCManager::ipc_castGetFromMain<::Utils::MapInfo>(std::to_string(session.getRoomNumber()), "map_info");
roomsManager.setMapFor(mapIdInfoFromMain.hostId, mapIdInfoFromMain.mapId);
std::cout << "Map Host From Main: " << mapIdInfoFromMain.hostId << ", map ID: " << mapIdInfoFromMain.mapId << '\n';
const auto receiverSessionId = request.getSession();
const auto hostSessionId = session.getId();
@ -36,25 +31,16 @@ namespace Cast
// And if we resend this packet to the host client, it resets the score to 0... so we just avoid doing that.
if (hostSessionId != receiverSessionId)
{
logger.log("session.getRoomId() != receiverSessionId", ::Utils::LogType::Info, "handleMatchStart");
roomsManager.hostForwardToPlayer(hostSessionId, receiverSessionId, const_cast<Common::Network::Packet&>(request));
}
//roomsManager.printRoomInfo(session.getRoomId(), "After Handle Match Start");
}
// order 94
inline void unknownHandler3(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
{
auto& logger = ::Utils::Logger::getInstance();
logger.log("Unknown Handler 3", ::Utils::LogType::Info, "unknownHandler3");
const auto receiverSessionId = request.getSession();
const auto hostSessionId = session.getId();
roomsManager.broadcastToRoomExceptSelf(hostSessionId, const_cast<Common::Network::Packet&>(request));
//roomsManager.printRoomInfo(session.getRoomId(), "After unknownHandler3");
}
inline void unknownHandler306(const Common::Network::Packet& request, Cast::Network::Session& session, Cast::Classes::RoomsManager& roomsManager)
@ -63,10 +49,6 @@ namespace Cast
const auto receiverSessionId = request.getSession();
const auto hostSessionId = session.getId();
roomsManager.hostForwardToPlayer(hostSessionId, receiverSessionId, const_cast<Common::Network::Packet&>(request));
std::cout << "(unknownHandler306) HostSessionID: " << hostSessionId << " => playerSessionID: " << receiverSessionId << '\n';
// roomsManager.printRoomInfo(session.getRoomId(), "After unknownHandler306");
}
// CTB battery respawn when host changes, Bomb battle bomb plant,
@ -82,11 +64,6 @@ namespace Cast
const auto hostSessionId = request.getSession();
const auto selfId = session.getId();
roomsManager.playerForwardToHost(hostSessionId, selfId, const_cast<Common::Network::Packet&>(request));
//roomsManager.broadcastToRoom(session.getId(), const_cast<Common::Network::Packet&>(request));
std::cout << "(unknownHandler90) HostSessionID: " << hostSessionId << " => playerSessionID: " << selfId << '\n';
// roomsManager.printRoomInfo(session.getRoomId(), "After unknownHandler306");
}
}
}

View file

@ -18,10 +18,6 @@ namespace Cast
hostSession->setRoomId(hostSessionId);
m_roomNumber = ++idCounter;
hostSession->setRoomNumber(m_roomNumber);
auto& logger = ::Utils::Logger::getInstance();
logger.log("Creating Room. Added Host (ID: " + std::to_string(hostSessionId)
+ ", RoomNumber: " + std::to_string(hostSession->getRoomNumber()) + ")", ::Utils::LogType::Info, "Room::Room");
}
std::uint32_t Room::getRoomNumber() const
@ -71,11 +67,10 @@ namespace Cast
{
if (!m_players.contains(playerSessionId))
{
std::cout << "Room::removePlayer: player not found\n";
return true;
}
else
{
std::cout << "removing player from room: " << m_players[playerSessionId]->getRoomNumber() << "\n";
m_players[playerSessionId]->setIsInMatch(false);
m_players[playerSessionId]->setRoomNumber(-1);
m_players.erase(playerSessionId);
@ -100,10 +95,6 @@ namespace Cast
void Room::addPlayer(Cast::Network::Session* playerSession)
{
auto& logger = ::Utils::Logger::getInstance(true);
logger.log("Added playerID: " + std::to_string(playerSession->getId())
+ " to room number: " + std::to_string(m_roomNumber), ::Utils::LogType::Info, "Room::addPlayer");
// Check whether m_players or m_observerPlayers is full?
m_players[playerSession->getId()] = playerSession;
m_playersVec.push_back(playerSession);
@ -143,24 +134,16 @@ namespace Cast
void Room::playerForwardToHost(std::uint64_t hostSessionId, std::uint64_t senderSessionId, Common::Network::Packet& packet)
{
auto& logger = ::Utils::Logger::getInstance();
packet.setTcpHeader(senderSessionId, Common::Enums::NO_ENCRYPTION);
if (m_players.contains(hostSessionId))
{
m_players[hostSessionId]->asyncWrite(packet);
logger.log("Forwarding Packet from SenderSessionID: " + std::to_string(senderSessionId) +
" to Room Host SessionID: " + std::to_string(hostSessionId), ::Utils::LogType::Info, "Room::playerForwardToHost");
}
}
void Room::hostForwardToPlayer(std::uint64_t hostSessionId, std::uint64_t playerId, Common::Network::Packet& packet, bool useHostIdInTcpHeader)
{
auto& logger = ::Utils::Logger::getInstance();
if (useHostIdInTcpHeader)
{
packet.setTcpHeader(hostSessionId, Common::Enums::NO_ENCRYPTION);
@ -172,9 +155,6 @@ namespace Cast
if (m_players.contains(playerId))
{
m_players[playerId]->asyncWrite(packet);
logger.log("Forwarding Packet from Host: " + std::to_string(hostSessionId) +
" to Player SessionID: " + std::to_string(playerId), ::Utils::LogType::Info, "Room::hostForwardToPlayer");
}
}
@ -208,30 +188,6 @@ namespace Cast
++totalInMatch;
}
}
if (totalInMatch == 1)
{
if (m_mode == Common::Enums::SquareMode || m_mode == Common::Enums::AiBattle || m_mode == Common::Enums::BossBattle)
{
return;
}
for (auto& player : m_playersVec)
{
player->setIsInMatch(false);
}
}
}
void Room::setTick(std::uint32_t tick)
{
m_tick = tick;
std::cout << "tick set to : " << tick << '\n';
}
std::uint32_t Room::getTick() const
{
return m_tick;
}
};
}

View file

@ -9,7 +9,6 @@ namespace Cast
{
void RoomsManager::addRoom(std::shared_ptr<Cast::Classes::Room> room, std::uint64_t playerId)
{
std::cout << "[addRoom] New room created. RoomNumber: " << room->getRoomNumber() << ", playerID: " << playerId << '\n';
m_playerSessionIdToRoom[playerId] = room;
}
@ -19,7 +18,6 @@ namespace Cast
// Otherwise, they join it.
if (m_playerSessionIdToRoom.contains(session.getId()))
{
std::cout << "SwitchRoomJoinOrExit: Found player inside a room. Removing it.\n";
// The player identified by "session" is inside the room where the host's sessionId equals "roomId", thus the room exists
removePlayerFromRoom(session.getId());
}
@ -74,15 +72,6 @@ namespace Cast
room->setMap(map);
}
/*
void RoomsManager::setModeFor(std::uint64_t hostId, std::uint32_t mode)
{
if (!m_roomsByHostSessionId.contains(hostId)) return;
auto& room = m_roomsByHostSessionId[hostId];
room.setMode(mode);
std::cout << "MODE HAS BEEN SET TO: " << mode << "\n";
}*/
bool RoomsManager::exists(std::uint64_t playerId)
{
return m_playerSessionIdToRoom.contains(playerId);
@ -109,17 +98,14 @@ namespace Cast
{
if (m_playerSessionIdToRoom.contains(sessionId))
{
std::cout << "Room found, match end: leaving all players...\n";
m_playerSessionIdToRoom[sessionId]->endMatch();
}
}
void RoomsManager::leaveAllPlayers(std::uint64_t sessionId)
{
std::cout << "Inside leaveAllPlayers\n";
if (m_playerSessionIdToRoom.contains(sessionId))
{
std::cout << "Room found, leaving all players...\n";
m_playerSessionIdToRoom[sessionId]->leaveAllPLayers();
}
}

View file

@ -78,7 +78,6 @@ namespace Cast
void Session::setIsInMatch(bool val)
{
std::cout << "Set Is In Match set to: " << val << " for sessionID: " << m_id << '\n';
m_isInMatch = val;
}
};

View file

@ -18,23 +18,15 @@ namespace Cast
void SessionsManager::addSession(Cast::Network::Session* session, std::size_t sessionId)
{
auto& logger = ::Utils::Logger::getInstance(true, false, "cast_log.txt");
logger.log<::Utils::LogDestination::File>("Trying to add session with ID: " + std::to_string(sessionId), ::Utils::LogType::Info, "SessionsManager::addSession");
if (!m_sessionsBySessionId.contains(sessionId))
{
m_sessionsBySessionId.emplace(sessionId, session);
session->setSessionId(sessionId);
logger.log<::Utils::LogDestination::File>("Added session with ID: " + std::to_string(sessionId), ::Utils::LogType::Info, "SessionsManager::addSession");
}
}
void SessionsManager::removeSession(std::size_t sessionId)
{
auto& logger = ::Utils::Logger::getInstance(true);
logger.log("Trying to remove SessionID: " + std::to_string(sessionId), ::Utils::LogType::Info, "SessionsManager::removeSession");
// The player is inside a room.
if (m_sessionsBySessionId.contains(sessionId) && m_sessionsBySessionId[sessionId]->getRoomNumber() != -1)
{
@ -42,7 +34,6 @@ namespace Cast
if (m_sessionsBySessionId.contains(sessionId))
{
m_sessionsBySessionId.erase(sessionId);
logger.log<::Utils::LogDestination::File>("Session removed from sessions list: " + std::to_string(sessionId), ::Utils::LogType::Info, "SessionsManager::removeSession");
}
}
};

View file

@ -56,10 +56,6 @@ namespace Common
auto entries = cdbWeapon.getEntries();
for (const auto& [id, structType] : entries)
{
if (m_itemByType.contains(structType.ii_id))
{
std::cout << "Item Already Contained in FirstLoop\n";
}
m_itemByType[structType.ii_id] = structType.ii_type;
}
@ -68,10 +64,6 @@ namespace Common
auto entries2 = cdbItem.getEntries();
for (const auto& [id, structType] : entries2)
{
if (m_itemByType.contains(structType.ii_id))
{
std::cout << "Item Already Contained in SecondLoop\n";
}
m_itemByType[structType.ii_id] = structType.ii_type;
}
}

View file

@ -267,7 +267,7 @@
<ClInclude Include="include\Structures\AccountInfo\MainAccountInfo.h" />
<ClInclude Include="include\Structures\AccountInfo\MainAccountUniqueId.h" />
<ClInclude Include="include\Structures\AccountInfo\MuteInfo.h" />
<ClInclude Include="include\Structures\ClientData\PingData.h" />
<ClInclude Include="include\Structures\ClientData\Structures.h" />
<ClInclude Include="include\Structures\PlayerLists\BlockedPlayer.h" />
<ClInclude Include="include\Structures\Capsule\CapsuleList.h" />
<ClInclude Include="include\Structures\Capsule\CapsuleSpin.h" />

View file

@ -133,7 +133,7 @@
<ClInclude Include="include\Boxes\MpBox.h" />
<ClInclude Include="include\Network\AuthSession.h" />
<ClInclude Include="include\Handlers\CapsuleReqHandler.h" />
<ClInclude Include="include\Structures\ClientData\PingData.h" />
<ClInclude Include="include\Structures\ClientData\Structures.h" />
<ClInclude Include="include\Handlers\Item\ItemAndCapsuleHandler.h" />
</ItemGroup>
</Project>

View file

@ -63,7 +63,6 @@ namespace Main
{
const auto mapInfoMap = cdbMapInfo::getInstance().getEntry(itemId);
if (mapInfoMap == std::nullopt) return std::nullopt;
std::cout << "Name: " << mapInfoMap.value().mi_name << ", height: " << mapInfoMap.value().mi_death_height << '\n';
return mapInfoMap.value().mi_death_height;
}
@ -87,6 +86,16 @@ namespace Main
return itemDurability;
}
std::optional<std::uint16_t> getItemRefundPrice() const
{
const auto refundValue = getRefundValue(cdbItems::getInstance());
if (refundValue == std::nullopt)
{
return getRefundValue(cdbWeapons::getInstance());
}
return refundValue;
}
std::optional<Common::ConstantDatabase::CdbRewardInfo> getRewardInfoForMode(std::uint32_t mode) const
{
auto entry = cdbRewardInfo::getInstance().getEntry("ri_mod", mode);
@ -167,25 +176,6 @@ namespace Main
return entry->ui_parentid;
}
/*
std::vector<Main::Structures::CapsuleList> getCapsuleItems(std::uint32_t maxItems)
{
m_maxCapsuleItems = maxItems;
//auto entries = cdbCapsuleInfos::getInstance().getEntries();
auto entries = cdbCapsulePackageInfos::getInstance().getEntries();
std::vector<Main::Structures::CapsuleList> ret;
for (std::size_t total = 0; const auto& [id, capsuleInfoStruct] : entries)
{
std::cout << "CapsuleID: " << capsuleInfoStruct.gi_id << '\n';
if (total >= maxItems) break;
//ret.push_back(Main::Structures::CapsuleList{ static_cast<std::uint32_t>(capsuleInfoStruct.gi_id), static_cast<std::uint32_t>(capsuleInfoStruct.gi_price) });
ret.push_back(Main::Structures::CapsuleList{ static_cast<std::uint32_t>(capsuleInfoStruct.gi_id) });
++total;
}
return ret;
}*/
std::optional<Common::ConstantDatabase::CdbCapsuleInfo> getCapsuleInfoById(std::uint32_t gi_id) const
{
const auto& entries = cdbCapsuleInfos::getInstance().getEntries();
@ -206,8 +196,6 @@ namespace Main
for (std::size_t total = 0; const auto & [id, capsuleInfoStruct] : cdbCapsuleInfos::getInstance().getEntries())
{
if (total == m_maxCapsuleItems) break;
// assume max index = MP = 2
//averageCosts[capsuleInfoStruct.gi_type] += capsuleInfoStruct.gi_price;
++totalCapsuleTypesByCurrency[capsuleInfoStruct.gi_type];
}
averageCosts[0] /= totalCapsuleTypesByCurrency[0];
@ -314,6 +302,14 @@ namespace Main
if (entry == std::nullopt) return std::nullopt;
return entry->ii_durable_value;
}
template<typename T>
std::optional<std::uint16_t> getRefundValue(const Common::ConstantDatabase::Cdb<T>& cdb) const
{
const std::optional<T> entry = cdb.getEntry("ii_id", itemId);
if (entry == std::nullopt) return std::nullopt;
return entry->ii_sell_point;
}
};
}
}

View file

@ -46,7 +46,6 @@ namespace Main
std::string m_mutedBy;
std::string m_muteReason;
std::string m_mutedUntil;
bool m_isInLobby{ true };
// Mailbox specific
std::vector<Mailbox> m_mailboxReceived{};
@ -71,7 +70,6 @@ namespace Main
const char* const getPlayerName() const;
void setAccountRockTotens(std::uint32_t rt);
void setAccountMicroPoints(std::uint32_t mp);
void setAccountCoins(std::uint16_t coins);
void setAccountLatestCharacterSelected(std::uint16_t latestCharacterSelected);
void setLevel(std::uint16_t level);
void setPlayerName(const char* playerName);
@ -83,7 +81,6 @@ namespace Main
std::uint32_t getLuckyPoints() const;
void setPing(std::uint16_t ping);
std::uint16_t getPing() const;
void setIsInLobby(bool val);
bool isInLobby() const;
void mute(const std::string& reason, const std::string& mutedBy, const std::string& mutedUntil);
void unmute();
@ -155,8 +152,7 @@ namespace Main
std::string getPlayerInfoAsString() const
{
return "(PlayerName: " + std::string(m_accountInfo.nickname) + ", RoomNumber: " + std::to_string(m_roomNumber) + ", IsInMatch : " + std::to_string(m_isInMatch)
+ ", IsInLobby: " + std::to_string(m_isInLobby) + ")";
return "(PlayerName: " + std::string(m_accountInfo.nickname) + ", RoomNumber: " + std::to_string(m_roomNumber) + ", IsInMatch : " + std::to_string(m_isInMatch) + "\n";
}
};
}

View file

@ -23,6 +23,12 @@ namespace Main
class Room
{
private:
struct MapValue
{
Main::Network::Session* session;
Main::Structures::RoomPlayerInfo* playerInfo;
};
inline static std::uint16_t idCounter{};
std::uint64_t m_tick{};
@ -35,6 +41,8 @@ namespace Main
Main::Structures::RoomSettings m_settings{};
std::vector<std::pair<Main::Structures::RoomPlayerInfo, Main::Network::Session*>> m_players{};
std::vector<std::pair<Main::Structures::RoomPlayerInfo, Main::Network::Session*>> m_observerPlayers{};
std::unordered_map<std::uint32_t, std::size_t> m_playerSessionIdToVecIdx{};
std::unordered_map<std::uint32_t, std::size_t> m_obsPlayerSessionIdToVecIdx{};
std::vector<std::uint32_t> m_kickedPlayerAccountIds{};
// Points
@ -44,6 +52,9 @@ namespace Main
// Other
bool m_isMuted = false;
private:
Main::Structures::RoomPlayerInfo createRoomPlayerInfo(Main::Network::Session* session, std::uint32_t team) const;
public:
Room() = default;
explicit Room(const std::string& title, const Main::Structures::RoomSettings& settings, const Main::Structures::RoomPlayerInfo& player, Main::Network::Session* session);
@ -54,124 +65,72 @@ namespace Main
+ ", TotalPlayers: " + std::to_string(m_players.size()) + ", TotalObserverPlayers: " + std::to_string(m_observerPlayers.size()) + ")";
}
Main::Network::Session* getHost() { return m_players[0].second; }
Main::Network::Session* getPlayer(const Main::Structures::UniqueId& uniqueId);
void addObserverPlayer(Main::Network::Session* session);
// Setters
void addPlayer(Main::Network::Session* session, std::uint32_t team);
void addObserverPlayer(Main::Network::Session* session);
void removeAllPlayers();
void updatePlayerInfo(Main::Network::Session* session);
void addKickedPlayer(std::uint32_t accountId);
bool removeHostFromMatch();
bool removePlayer(Main::Network::Session* session, std::uint32_t extra);
void breakroom();
bool changeHost(std::size_t newHostIdx);
void updatePlayersTeamToTeamBased();
void updatePlayersTeamToNonTeamBased();
void setStateFor(const Main::Structures::UniqueId& uniqueId, const Common::Enums::PlayerState& playerState);
void setPlayersPerTeam(std::uint16_t playersPerTeam);
bool kickPlayer(const std::string& name);
void startMatch(const Main::Structures::UniqueId& uniqueId);
void endMatch();
void updateMap(std::uint16_t newMap);
void updateRoomSettings(const Main::Structures::RoomSettingsUpdateBase& newRoomSettings, std::uint16_t newMode);
void updateTitle(const std::string& newTitle);
void updatePassword(const std::string& newPassword);
void setPassword(const std::string& password);
void addPoint(std::uint32_t team);
void sendTo(const Main::Structures::UniqueId& uniqueId, const Common::Network::Packet& packet);
void storeEndMatchStatsFor(const Main::Structures::UniqueId& uniqueId, const Main::Structures::ScoreboardResponse& stats,
std::uint32_t blueScore, std::uint32_t redScore, bool hasLeveledUp);
void setSpecificSetting(std::uint8_t setting);
void setTime(std::uint16_t time);
std::optional<std::uint32_t> changePlayerTeam(const Main::Structures::UniqueId& uniqueId, std::uint32_t newTeam);
void muteRoom();
void unmuteRoom();
void unmuteRoom();
bool isMuted() const;
void removeAllPlayers();
Main::Network::Session* getPlayer(const Main::Structures::UniqueId& uniqueId);
std::uint32_t getBestMsIndexExceptSelf(bool checkIsInMatch, std::uint64_t selfId);
void setTick(std::uint64_t tick);
std::uint64_t getTick() const { return m_tick; }
std::uint32_t getPlayerIdx(std::uint64_t playerIndex) const;
void setPassword(const std::string& password);
const std::string& getPassword() const;
std::uint16_t getRoomNumber() const;
void updatePlayerInfo(Main::Network::Session* session);
void addKickedPlayer(std::uint32_t accountId);
bool removeHostFromMatch();
bool removePlayer(Main::Network::Session* session, std::uint32_t extra);
bool changeHostByNickname(const std::string&);
std::vector<Main::Structures::RoomPlayerInfo> getAllPlayers() const;
Main::Structures::SingleRoom getRoomInfo() const;
const Main::Structures::RoomSettings& getRoomSettings() const;
Main::Structures::RoomJoin getRoomJoinInfo() const;
std::vector<Main::Structures::RoomPlayerItems> getPlayersItems() const;
std::vector<Main::Structures::PlayerClan> getPlayersClans() const;
void breakroom();
bool isHost(const Main::Structures::UniqueId& uniqueId) const;
Common::Enums::Team calculateNewPlayerTeam() const;
bool isModeTeamBased() const;
std::uint8_t getSpecificSetting() const;
const std::string& getRoomTitle() const;
bool isRoomFullObserverExcluded() const;
bool hasMatchStarted() const;
bool isObserverFull() const;
std::size_t getPlayersCount() const;
std::uint32_t getHostLevel() const;
bool wasPreviouslyKicked(std::uint32_t accountId) const;
Main::Structures::RoomSettingsUpdateTitlePassword getRoomSettingsUpdate() const;
Main::Network::Session::AccountInfo getAccountInfoFor(const Main::Structures::UniqueId& uniqueId) const;
void broadcastToRoom(Common::Network::Packet& packet);
void broadcastToReady(Common::Network::Packet& packet)
{
for (auto& [roomInfo, session] : m_players)
{
if (roomInfo.state == Common::Enums::STATE_READY)
{
packet.setTcpHeader(session->getSessionId(), Common::Enums::USER_LARGE_ENCRYPTION);
session->asyncWrite(packet);
}
}
}
void broadcastToRoomExceptSelf(Common::Network::Packet& packet, const Main::Structures::UniqueId& uniqueId);
// In-room chat messages
void broadcastToTeamExceptSelf(Common::Network::Packet& packet, const Main::Structures::UniqueId& uniqueId, bool inMatch);
void broadcastToMatchExceptSelf(Common::Network::Packet& packet, const Main::Structures::UniqueId& uniqueId, std::uint32_t extra);
void broadcastOutsideMatchExceptSelf(Common::Network::Packet& packet, const Main::Structures::UniqueId& selfUniqueId, std::uint32_t extra);
bool changeHost(std::size_t newHostIdx);
void setCurrentHostAsOriginalHost();
bool isHost(const Main::Structures::UniqueId& uniqueId) const;
void setSpecificSetting(std::uint8_t setting);
void setTime(std::uint16_t time);
std::optional<std::uint32_t> changePlayerTeam(const Main::Structures::UniqueId& uniqueId, std::uint32_t newTeam);
void updatePlayersTeamToTeamBased();
void updatePlayersTeamToNonTeamBased();
Common::Enums::Team calculateNewPlayerTeam() const;
bool isModeTeamBased() const;
void setPlayersPerTeam(std::uint16_t playersPerTeam);
std::uint8_t getSpecificSetting() const;
const std::string& getRoomTitle() const;
bool kickPlayer(const std::string& name);
bool isRoomFullObserverExcluded() const;
void setStateFor(const Main::Structures::UniqueId& uniqueId, const Common::Enums::PlayerState& playerState);
void startMatch(const Main::Structures::UniqueId& uniqueId);
void endMatch();
bool hasMatchStarted() const;
bool isObserverFull() const;
std::size_t getPlayersCount() const;
std::uint32_t getHostLevel() const;
bool wasPreviouslyKicked(std::uint32_t accountId) const;
template<Main::Enums::RoomSimpleSetting T> requires (T == Main::Enums::SETTING_ITEM)
void switchSimpleSetting()
@ -196,25 +155,6 @@ namespace Main
{
m_settings.isObserverModeOn = ~m_settings.isObserverModeOn;
}
void updateMap(std::uint16_t newMap);
void updateRoomSettings(const Main::Structures::RoomSettingsUpdateBase& newRoomSettings, std::uint16_t newMode);
Main::Structures::RoomSettingsUpdateTitlePassword getRoomSettingsUpdate() const;
void updateTitle(const std::string& newTitle);
void updatePassword(const std::string& newPassword);
void addPoint(std::uint32_t team);
void sendTo(const Main::Structures::UniqueId& uniqueId, const Common::Network::Packet& packet);
void storeEndMatchStatsFor(const Main::Structures::UniqueId& uniqueId, const Main::Structures::ScoreboardResponse& stats,
std::uint32_t blueScore, std::uint32_t redScore, bool hasLeveledUp);
Main::Network::Session::AccountInfo getAccountInfoFor(const Main::Structures::UniqueId& uniqueId) const;
};
}
}

View file

@ -24,7 +24,7 @@ namespace Main
std::vector<Main::Structures::SingleRoom> getRoomsList() const;
std::optional<std::reference_wrapper<Main::Classes::Room>> getRoomByNumber(std::uint16_t roomNumber);
Main::Classes::Room* getRoomByNumber(std::uint16_t roomNumber);
void broadcastToRoom(std::uint16_t roomNumber, Common::Network::Packet& packet);

View file

@ -16,7 +16,6 @@ namespace Main
inline void handleCapsuleReq(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager)
{
// capsules are all completely client sided
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setOrder(83);

View file

@ -9,10 +9,8 @@ namespace Main
{
namespace Handlers
{
inline void handleItemDelete(const Common::Network::Packet& request, Main::Network::Session& session)
inline void handleItemDelete(const Common::Network::Packet& request, Main::Network::Session& session, const Main::Structures::ItemSerialInfo& itemSerialInfoToDelete)
{
Main::Structures::ItemSerialInfo itemSerialInfoToDelete{};
std::memcpy(&itemSerialInfoToDelete, request.getData(), sizeof(itemSerialInfoToDelete));
session.deleteItem(itemSerialInfoToDelete);
}
}

View file

@ -16,7 +16,7 @@ namespace Main
namespace Handlers
{
inline void handleGeneralItem(const Common::Network::Packet& request, Main::Network::Session& session, Main::Persistence::PersistentDatabase& db,
const std::unordered_map<std::uint32_t, std::unique_ptr<Main::Box::IBox>>& m_boxes)
const std::unordered_map<std::uint32_t, std::unique_ptr<Main::Box::IBox>>& m_boxes, const Main::Structures::ItemSerialInfo& openedItemSerialInfo)
{
if (request.getMission() == 2) // capsule spin
{
@ -24,20 +24,15 @@ namespace Main
}
else
{
Main::Structures::ItemSerialInfo openedItemSerialInfo;
std::memcpy(&openedItemSerialInfo, request.getData(), request.getDataSize());
const auto& userItems = session.getItems();
auto response = request;
response.setOption(1);
if (userItems.contains(openedItemSerialInfo.itemNumber))
{
const auto& item = userItems.at(openedItemSerialInfo.itemNumber);
if (m_boxes.contains(item.id))
{
auto response = request;
if (item.id >= Main::Enums::MP_100 && item.id <= Main::Enums::MP_500000)
{ // mp box
response.setMission(1);
@ -53,6 +48,7 @@ namespace Main
boxItem.itemId = m_boxes.at(item.id)->get();
boxItem.serialInfo = wonItemSerialInfo;
response.setOption(1);
response.setData(reinterpret_cast<std::uint8_t*>(&boxItem), sizeof(boxItem));
session.asyncWrite(response);
session.deleteItem(openedItemSerialInfo); // Delete the box / item that was just opened
@ -69,6 +65,7 @@ namespace Main
Main::Structures::ItemSerialInfo wonItemSerialInfo;
wonItemSerialInfo.itemNumber = session.getLatestItemNumber() + 1;
response.setOption(1);
Main::Structures::BoxItem boxItem;
switch (item.id)

View file

@ -3,22 +3,34 @@
#include "../../Network/MainSession.h"
#include "../../../include/Structures/AccountInfo/MainAccountInfo.h"
#include "../../../include/Structures/ClientData/Structures.h"
#include "Network/Packet.h"
#include "../../../include/MainEnums.h"
#include <iostream>
namespace Main
{
namespace Handlers
{
inline void handleItemRefund(const Common::Network::Packet& request, Main::Network::Session& session)
inline void handleItemRefund(const Common::Network::Packet& request, Main::Network::Session& session, const Main::ClientData::ItemRefund& itemRefund)
{
std::uint32_t mpToAdd{};
Main::Structures::ItemSerialInfo serialInfo{};
std::memcpy(&mpToAdd, request.getData() + 8, sizeof(std::uint32_t));
std:memcpy(&serialInfo, request.getData(), sizeof(Main::Structures::ItemSerialInfo));
std::uint32_t toRefund = 0;
for (const auto& [itemNum, actualItem] : session.getItems())
{
if (itemNum == itemRefund.serialInfo.itemNumber)
{
Main::ConstantDatabase::CdbUtil cdbUtil(actualItem.id);
auto refund = cdbUtil.getItemRefundPrice();
if (refund == std::nullopt) return;
toRefund = *refund;
}
}
const bool removed = session.deleteItemBasic(serialInfo);
session.setAccountMicroPoints(session.getAccountInfo().microPoints + mpToAdd);
const bool removed = session.deleteItemBasic(itemRefund.serialInfo);
if (removed)
{
session.setAccountMicroPoints(session.getAccountInfo().microPoints + toRefund);
}
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);

View file

@ -10,6 +10,7 @@
#include "../../Utilities.h"
#include "../../Boxes/BoxBase.h"
#include "../CapsuleSpinHandler.h"
#include "../../Structures/ClientData/Structures.h"
namespace Main
{
@ -31,7 +32,7 @@ namespace Main
RESET_REQUEST = 55
};
inline void handleItemUpgrade(const Common::Network::Packet& request, Main::Network::Session& session)
inline void handleItemUpgrade(const Common::Network::Packet& request, Main::Network::Session& session, const Main::ClientData::ItemUpgrade& itemUpgradeData)
{
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
@ -41,23 +42,16 @@ namespace Main
if (request.getExtra() == ItemClientExtra::ADD_ENERGY_REQUEST)
{
std::uint32_t usedEnergy;
Main::Structures::ItemSerialInfo itemSerialInfo{};
std::memcpy(&usedEnergy, request.getData() + 8, sizeof(std::uint32_t));
std::memcpy(&itemSerialInfo, request.getData(), sizeof(itemSerialInfo));
if (usedEnergy > accountInfo.battery) return; // security check, client already prevents this
if (itemUpgradeData.usedEnergy > accountInfo.battery) return; // security check, client already prevents this
response.setExtra(ItemUpgradeExtra::ENERGY_ADD);
response.setData(reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())), sizeof(usedEnergy) + sizeof(Main::Structures::ItemSerialInfo));
if (!session.addEnergyToItem(itemSerialInfo, usedEnergy)) return;
response.setData(reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())), sizeof(itemUpgradeData.usedEnergy) + sizeof(Main::Structures::ItemSerialInfo));
if (!session.addEnergyToItem(itemUpgradeData.serialInfo, itemUpgradeData.usedEnergy)) return;
session.asyncWrite(response);
}
else if (request.getExtra() == ItemClientExtra::UPGRADE_REQUEST)
{
Main::Structures::ItemSerialInfo itemSerialInfo{};
std::memcpy(&itemSerialInfo, request.getData(), sizeof(itemSerialInfo));
std::array<std::uint8_t, 72> unused{};
auto found = session.findItemBySerialInfo(itemSerialInfo);
auto found = session.findItemBySerialInfo(itemUpgradeData.serialInfo);
if (found == std::nullopt) return;
Main::ConstantDatabase::CdbUtil cdbCurrentId(found->id);
@ -85,8 +79,8 @@ namespace Main
response.setExtra(ItemUpgradeExtra::UPGRADE_FAIL);
response.setData(unused.data(), unused.size());
session.asyncWrite(response);
session.deleteItem(itemSerialInfo);
session.spawnItem(found->id, itemSerialInfo); // spawn new item with correct energy (=reset energy)
session.deleteItem(itemUpgradeData.serialInfo);
session.spawnItem(found->id, itemUpgradeData.serialInfo); // spawn new item with correct energy (=reset energy)
return;
}
response.setExtra(ItemUpgradeExtra::UPGRADE_SUCCESS);
@ -94,8 +88,8 @@ namespace Main
session.asyncWrite(response);
// Delete the old item, respawn new (upgraded) one
session.deleteItem(itemSerialInfo);
session.spawnItem(found->id + toAdd, itemSerialInfo);
session.deleteItem(itemUpgradeData.serialInfo);
session.spawnItem(found->id + toAdd, itemUpgradeData.serialInfo);
session.setAccountMicroPoints(accountInfo.microPoints - *mpNeededForUpgrade);
session.sendCurrency();
}

View file

@ -207,17 +207,13 @@ namespace Main
if (request.getExtra() != Enums::ChatExtra::CLAN)
{
auto room = roomsManager.getRoomByNumber(session.getRoomNumber());
if (!room) return;
auto& actualRoom = room->get();
if (actualRoom.isMuted() && session.getAccountInfo().playerGrade < Common::Enums::GRADE_MOD)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
Details::sendMessage("the room is currently muted", session);
}
else
{
if (session.isInMatch())
if (room->isMuted() && session.getAccountInfo().playerGrade < Common::Enums::GRADE_MOD)
{
Details::sendMessage("the room is currently muted", session);
}
else if (session.isInMatch())
{
roomsManager.broadcastToMatchExceptSelf(session.getRoomNumber(), session.getAccountInfo().uniqueId, response, request.getExtra());
}
@ -225,7 +221,6 @@ namespace Main
{
roomsManager.broadcastOutsideMatchExceptSelf(session.getRoomNumber(), session.getAccountInfo().uniqueId, response, request.getExtra());
}
return;
}
}
else

View file

@ -10,32 +10,30 @@ namespace Main
{
namespace Handlers
{
template<std::size_t N>
inline void handlePlayerBlock(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager,
Main::Persistence::PersistentDatabase& database)
Main::Persistence::PersistentDatabase& database, const std::array<char, N>& targetAccountName)
{
if (request.getOption() == 2) // for some reason the client always sends this option for blocked players list
{
char targetAccountName[16]{};
std::memcpy(targetAccountName, request.getData(), sizeof(targetAccountName));
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, 1, 0);
if (auto* targetSession = sessionsManager.findSessionByName(targetAccountName))
if (auto* targetSession = sessionsManager.findSessionByName(targetAccountName.data()))
{
const std::uint32_t targetAccountId = targetSession->getAccountInfo().accountID;
session.blockAccount(targetAccountId, targetAccountName);
session.blockAccount(targetAccountId, targetAccountName.data());
session.deleteFriend(targetAccountId);
targetSession->deleteFriend(session.getAccountInfo().accountID, false);
session.asyncWrite(response);
}
else
{
const std::uint32_t targetAccountId = database.blockPlayerByNickname(session.getAccountInfo().accountID, targetAccountName);
const std::uint32_t targetAccountId = database.blockPlayerByNickname(session.getAccountInfo().accountID, targetAccountName.data());
if (targetAccountId != -1)
{
session.blockAccount(targetAccountId, targetAccountName);
session.blockAccount(targetAccountId, targetAccountName.data());
session.deleteFriend(targetAccountId);
session.asyncWrite(response);
}

View file

@ -9,11 +9,8 @@ namespace Main
{
namespace Handlers
{
inline void handlePlayerUnblock(const Common::Network::Packet& request, Main::Network::Session& session)
inline void handlePlayerUnblock(const Common::Network::Packet& request, Main::Network::Session& session, std::uint32_t targetAccountId)
{
std::uint32_t targetAccountId;
std::memcpy(&targetAccountId, request.getData(), sizeof(std::uint32_t));
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, session.unblockAccount(targetAccountId), 0);

View file

@ -9,11 +9,9 @@ namespace Main
{
namespace Handlers
{
inline void handleFriendDeletion(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager)
inline void handleFriendDeletion(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager,
std::uint32_t targetAccountIdToDelete)
{
std::uint32_t targetAccountIdToDelete;
std::memcpy(&targetAccountIdToDelete, request.getData(), sizeof(std::uint32_t));
session.deleteFriend(targetAccountIdToDelete);
if (auto* foundSession = sessionsManager.getSessionByAccountId(targetAccountIdToDelete))
{

View file

@ -14,10 +14,8 @@ namespace Main
namespace Handlers
{
inline void handleLobbyAccountInfo(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager,
std::uint32_t serverId)
std::uint32_t serverId, const Main::Structures::UniqueId& uniqueId)
{
Main::Structures::UniqueId uniqueId;
std::memcpy(&uniqueId, request.getData(), sizeof(Main::Structures::UniqueId));
auto* targetSession = sessionsManager.getSessionBySessionId(uniqueId.session);
if (!targetSession) return;

View file

@ -10,11 +10,8 @@ namespace Main
namespace Handlers
{
// TODO: Implement "mass" mailbox delete (= deleting multiple mailboxes at once), unsure if required by the client
inline void handleMailboxDelete(const Common::Network::Packet& request, Main::Network::Session& session)
{
std::uint32_t timestamp;
std::memcpy(&timestamp, request.getData() + 4, sizeof(timestamp));
inline void handleMailboxDelete(const Common::Network::Packet& request, Main::Network::Session& session, std::uint32_t timestamp)
{
if (request.getMission() == Main::Enums::MailboxMission::MISSION_MAILBOX_RECEIVED)
{
session.deleteReceivedMailbox(timestamp);

View file

@ -16,11 +16,11 @@ namespace Main
namespace Handlers
{
inline void handleMailboxCommunication(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager,
Main::Persistence::PersistentDatabase& database)
Main::Persistence::PersistentDatabase& database, const Main::ClientData::MailboxMessage& mailboxData)
{
const auto& accountInfo = session.getAccountInfo();
const auto* const data = request.getData();
constexpr const std::uint32_t maxMailboxes = 100;
constexpr const std::uint32_t nicknameSize = 16;
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
@ -35,16 +35,14 @@ namespace Main
return;
}
constexpr std::size_t nicknameSize = 16;
char nickname[nicknameSize]{};
std::memcpy(nickname, data, 16);
auto* targetSession = sessionsManager.findSessionByName(nickname);
auto* targetSession = sessionsManager.findSessionByName(mailboxData.nickname);
if (!targetSession)
{
Main::Structures::Mailbox mailbox;
mailbox.timestamp = static_cast<__time32_t>(std::time(0));
std::memcpy(mailbox.nickname, nickname, nicknameSize);
std::memcpy(mailbox.message, data + nicknameSize, request.getDataSize() - nicknameSize);
std::memcpy(mailbox.nickname, mailboxData.nickname, nicknameSize);
std::memcpy(mailbox.message, mailboxData.message, request.getDataSize() - nicknameSize);
auto res = database.storeOfflineMailbox(mailbox, accountInfo.nickname);
if (!res)
@ -56,7 +54,7 @@ namespace Main
else
{
mailbox.accountId = accountInfo.accountID;
std::memcpy(mailbox.nickname, nickname, nicknameSize);
std::memcpy(mailbox.nickname, mailboxData.nickname, nicknameSize);
session.addMailboxSent(mailbox);
}
}
@ -86,7 +84,7 @@ namespace Main
Main::Structures::Mailbox mailbox{ targetAccountInfo.accountID, static_cast<__time32_t>(std::time(0)) };
constexpr std::size_t nicknameSize = 16;
std::memcpy(mailbox.nickname, accountInfo.nickname, nicknameSize);
std::memcpy(mailbox.message, data + nicknameSize, request.getDataSize() - nicknameSize);
std::memcpy(mailbox.message, mailboxData.message, request.getDataSize() - nicknameSize);
targetSession->addMailboxReceived(mailbox);
mailbox.accountId = accountInfo.accountID;

View file

@ -9,11 +9,9 @@ namespace Main
{
namespace Handlers
{
inline void handleReadMailbox(const Common::Network::Packet& request, Main::Network::Session& session, Main::Persistence::PersistentDatabase& database)
inline void handleReadMailbox(const Common::Network::Packet& request, Main::Network::Session& session, Main::Persistence::PersistentDatabase& database,
std::uint32_t timestamp)
{
std::uint32_t timestamp;
std::memcpy(&timestamp, request.getData() + 4, sizeof(timestamp));
if (request.getExtra() == Main::Enums::MailboxExtra::MAILBOX_HAS_BEEN_READ)
{
database.updateReadMailbox(session.getAccountInfo().accountID, timestamp);

View file

@ -5,7 +5,7 @@
#include "../../../include/Structures/AccountInfo/MainAccountInfo.h"
#include "Network/Packet.h"
#include "../../../include/Classes/RoomsManager.h"
#include "../../Structures/ClientData/PingData.h"
#include "../../Structures/ClientData/Structures.h"
namespace Main
{
@ -16,11 +16,9 @@ namespace Main
{
if (request.getMission() == 1)
{
session.setPing(pingData.ping);
const std::uint16_t roomNumber = session.getRoomNumber();
if (roomNumber)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
session.setPing(pingData.ping);
struct Resp
{
Main::ClientData::Ping clientData;
@ -32,11 +30,7 @@ namespace Main
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder() + 1, request.getMission() + 1, 0, request.getOption());
response.setData(reinterpret_cast<std::uint8_t*>(&resp), sizeof(resp));
auto roomFound = roomsManager.getRoomByNumber(roomNumber);
if (roomFound == std::nullopt) return;
auto& room = roomFound->get();
room.broadcastToRoomExceptSelf(response, resp.uniqueId);
room->broadcastToRoomExceptSelf(response, resp.uniqueId);
}
}
}

View file

@ -17,19 +17,18 @@ namespace Main
{
session.setPlayerState(static_cast<Common::Enums::PlayerState>(request.getOption()));
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt) return;
auto& room = foundRoom->get();
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
auto uniqueId = session.getAccountInfo().uniqueId;
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(Details::Orders::PLAYER_STATE_NOTIFICATION, 0, 0, session.getPlayerState());
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
room->broadcastToRoom(response);
room->setStateFor(uniqueId, session.getPlayerState());
auto uniqueId = session.getAccountInfo().uniqueId;
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(Details::Orders::PLAYER_STATE_NOTIFICATION, 0, 0, session.getPlayerState());
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
room.broadcastToRoom(response);
room.setStateFor(uniqueId, session.getPlayerState());
Details::broadcastPlayerItems(roomsManager, session, request);
Details::broadcastPlayerItems(roomsManager, session, request);
}
}
}
}

View file

@ -39,108 +39,89 @@ namespace Main
roomsManager.broadcastToRoomExceptSelf(session.getRoomNumber(), session.getAccountInfo().uniqueId, const_cast<Common::Network::Packet&>(request));
// Next, specific ending info for each session
const auto& roomOpt = roomsManager.getRoomByNumber(session.getRoomNumber());
if (roomOpt == std::nullopt) return;
auto& room = roomOpt->get();
const Main::ConstantDatabase::CdbUtil cdbUtil;
const auto rewardInfo = cdbUtil.getRewardInfoForMode(room.getRoomSettings().mode);
if (!rewardInfo.has_value())
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
std::cerr << "Error: RewardInfo was nullopt!\n";
return;
}
Common::Network::Packet response;
for (std::size_t i = 0; i < request.getOption(); ++i)
{
// IMPORTANT: EXP and MP will be given even if the match was played for 1 second!
// TODO: Add matchStartTime to Room class, and here check whether at least 60 seconds passed. Otherwise don't give anything to the players! (FARM prevention)
Main::Structures::ClientEndingMatchNotification finalScoreGivenByClient;
std::memcpy(&finalScoreGivenByClient, request.getData()
+ sizeof(finalScoreGivenByClient) * i + sizeof(ClientEndingMatchNotificationHeader), sizeof(finalScoreGivenByClient));
finalScoreGivenByClient.uniqueId.server = 4;
Main::Structures::ScoreboardResponse responseStruct(finalScoreGivenByClient);
auto* targetSession = room.getPlayer(finalScoreGivenByClient.uniqueId);
if (!targetSession) continue;
response.setTcpHeader(targetSession->getId(), Common::Enums::USER_LARGE_ENCRYPTION);
std::cout << "EndMatch: Taking care of SessionID: " << targetSession->getId() << '\n';
// Calculate new EXP
auto targetAccountInfo = room.getAccountInfoFor(finalScoreGivenByClient.uniqueId);
responseStruct.newTotalEXP = targetAccountInfo.experience
+ rewardInfo->ri_exp_base + rewardInfo->ri_exp_kill * responseStruct.totalKills * 2 + rewardInfo->ri_exp_death * responseStruct.deaths
+ rewardInfo->ri_exp_assist * responseStruct.assists;
// Calculate new MP
responseStruct.newTotalMP = targetAccountInfo.microPoints
+ rewardInfo->ri_poi_base + rewardInfo->ri_poi_kill * responseStruct.totalKills * 2 + rewardInfo->ri_poi_death * responseStruct.deaths
+ rewardInfo->ri_poi_assist * responseStruct.assists;
// Check if player leveled up
auto gradeInfo = cdbUtil.getGradeInfoForLevel(targetAccountInfo.playerLevel + 1);
if (gradeInfo != std::nullopt)
const Main::ConstantDatabase::CdbUtil cdbUtil;
const auto rewardInfo = cdbUtil.getRewardInfoForMode(room->getRoomSettings().mode);
if (!rewardInfo.has_value())
{
if (responseStruct.newTotalEXP >= gradeInfo->gi_exp)
return;
}
Common::Network::Packet response;
for (std::size_t i = 0; i < request.getOption(); ++i)
{
// TODO: Add matchStartTime to Room class, and here check whether at least 60 seconds passed. Otherwise don't give anything to the players! (FARM prevention)
Main::Structures::ClientEndingMatchNotification finalScoreGivenByClient;
std::memcpy(&finalScoreGivenByClient, request.getData()
+ sizeof(finalScoreGivenByClient) * i + sizeof(ClientEndingMatchNotificationHeader), sizeof(finalScoreGivenByClient));
finalScoreGivenByClient.uniqueId.server = 4;
Main::Structures::ScoreboardResponse responseStruct(finalScoreGivenByClient);
auto* targetSession = room->getPlayer(finalScoreGivenByClient.uniqueId);
if (!targetSession) continue;
response.setTcpHeader(targetSession->getId(), Common::Enums::USER_LARGE_ENCRYPTION);
std::cout << "EndMatch: Taking care of SessionID: " << targetSession->getId() << '\n';
// Calculate new EXP
auto targetAccountInfo = room->getAccountInfoFor(finalScoreGivenByClient.uniqueId);
responseStruct.newTotalEXP = targetAccountInfo.experience
+ rewardInfo->ri_exp_base + rewardInfo->ri_exp_kill * responseStruct.totalKills * 2 + rewardInfo->ri_exp_death * responseStruct.deaths
+ rewardInfo->ri_exp_assist * responseStruct.assists;
// Calculate new MP
responseStruct.newTotalMP = targetAccountInfo.microPoints
+ rewardInfo->ri_poi_base + rewardInfo->ri_poi_kill * responseStruct.totalKills * 2 + rewardInfo->ri_poi_death * responseStruct.deaths
+ rewardInfo->ri_poi_assist * responseStruct.assists;
// Check if player leveled up
auto gradeInfo = cdbUtil.getGradeInfoForLevel(targetAccountInfo.playerLevel + 1);
if (gradeInfo != std::nullopt)
{
responseStruct.newTotalMP += gradeInfo->gi_reward_point;
room.storeEndMatchStatsFor(finalScoreGivenByClient.uniqueId, responseStruct,
clientEndMatchNotificationHeader.blueScore, clientEndMatchNotificationHeader.redScore, true);
const auto newPlayerLevel = targetAccountInfo.playerLevel + 1;
// Level up packet
response.setOrder(311);
response.setExtra(1);
response.setOption(newPlayerLevel);
response.setData(reinterpret_cast<std::uint8_t*>(&finalScoreGivenByClient.uniqueId), sizeof(finalScoreGivenByClient.uniqueId));
room.broadcastToRoomExceptSelf(response, finalScoreGivenByClient.uniqueId);
// Spawn won item
if (targetSession)
if (responseStruct.newTotalEXP >= gradeInfo->gi_exp)
{
/*
Main::Structures::SpawnedItem spawnedItem{};
spawnedItem.itemId = gradeInfo->gi_reward_item;
spawnedItem.serialInfo.itemNumber = session.getLatestItemNumber() + 1;
targetSession->spawnItem(gradeInfo->gi_reward_item, spawnedItem.serialInfo);
targetSession->setLatestItemNumber(spawnedItem.serialInfo.itemNumber);
*/
responseStruct.newTotalMP += gradeInfo->gi_reward_point;
room->storeEndMatchStatsFor(finalScoreGivenByClient.uniqueId, responseStruct,
clientEndMatchNotificationHeader.blueScore, clientEndMatchNotificationHeader.redScore, true);
// Give MP proportionally to the new level
targetSession->setAccountMicroPoints(targetAccountInfo.microPoints + (newPlayerLevel * 700));
const auto newPlayerLevel = targetAccountInfo.playerLevel + 1;
response.setCommand(311, 0, 1, newPlayerLevel); // level up packet
response.setData(reinterpret_cast<std::uint8_t*>(&finalScoreGivenByClient.uniqueId), sizeof(finalScoreGivenByClient.uniqueId));
room->broadcastToRoomExceptSelf(response, finalScoreGivenByClient.uniqueId);
if (targetSession)
{
// todo: spawn won item
// Give MP proportionally to the new level
targetSession->setAccountMicroPoints(targetAccountInfo.microPoints + (newPlayerLevel * 700));
}
}
else
{
room->storeEndMatchStatsFor(finalScoreGivenByClient.uniqueId, responseStruct,
clientEndMatchNotificationHeader.blueScore, clientEndMatchNotificationHeader.redScore, false);
}
}
else
{
room.storeEndMatchStatsFor(finalScoreGivenByClient.uniqueId, responseStruct,
room->storeEndMatchStatsFor(finalScoreGivenByClient.uniqueId, responseStruct,
clientEndMatchNotificationHeader.blueScore, clientEndMatchNotificationHeader.redScore, false);
}
// TODO: THE SIZE OF THIS PACKET CAN BE >= 1440 BYTES IF THERE ARE MAX NUM OF PLAYERS + MAX NUM OF OBS PLAYERS!
// BUT ARE OBS PLAYERS EVEN COUNTED???
response.setCommand(request.getOrder(), 0, 1, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&responseStruct), sizeof(responseStruct));
room->sendTo(finalScoreGivenByClient.uniqueId, response);
}
else
{
room.storeEndMatchStatsFor(finalScoreGivenByClient.uniqueId, responseStruct,
clientEndMatchNotificationHeader.blueScore, clientEndMatchNotificationHeader.redScore, false);
}
// TODO: THE SIZE OF THIS PACKET CAN BE >= 1440 BYTES IF THERE ARE MAX NUM OF PLAYERS + MAX NUM OF OBS PLAYERS!
// BUT ARE OBS PLAYERS EVEN COUNTED???
response.setOrder(request.getOrder());
response.setExtra(1);
response.setMission(0);
response.setData(reinterpret_cast<std::uint8_t*>(&responseStruct), sizeof(responseStruct));
room.sendTo(finalScoreGivenByClient.uniqueId, response);
room->endMatch();
// Notify client about match leave, MVR does this as well
response.setCommand(256, 0, 33, 0);
response.setData(nullptr, 0);
session.asyncWrite(response);
}
room.endMatch();
// Notify client about match leave, MVR does this as well
response.setMission(0);
response.setOption(0);
response.setExtra(33); // match leave
response.setOrder(256); // Match leave
response.setData(nullptr, 0);
session.asyncWrite(response);
}
}
}

View file

@ -5,7 +5,6 @@
#include "../../Classes/RoomsManager.h"
#include "Network/Packet.h"
#include "../../Network/MainSessionManager.h"
#include "Utils/Logger.h"
namespace Main
{
@ -13,48 +12,33 @@ namespace Main
{
inline void handleMatchLeave(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager, Main::Classes::RoomsManager& roomsManager)
{
Utils::Logger& logger = Utils::Logger::getInstance();
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
logger.log("Room not found by number!, Utils::LogType::Error, Main::handleMatchLeave");
return;
}
auto& room = foundRoom->get();
if (room.isHost(session.getAccountInfo().uniqueId))
{
logger.log("The host " + session.getPlayerInfoAsString() + " is attempting to leave the match. " + room.getRoomInfoAsString(),
Utils::LogType::Normal, "Main::handleMatchLeave");
if (room.removeHostFromMatch())
if (room->isHost(session.getAccountInfo().uniqueId))
{
logger.log("Attempting to close the room " + room.getRoomInfoAsString(),
Utils::LogType::Normal, "Main::handleMatchLeave");
roomsManager.removeRoom(room.getRoomNumber());
if (room->removeHostFromMatch())
{
roomsManager.removeRoom(room->getRoomNumber());
}
else
{
// handle error?
}
}
}
else
{
logger.log("The player " + session.getPlayerInfoAsString() + " is attempting to leave the match. " + room.getRoomInfoAsString(),
Utils::LogType::Normal, "Main::handleMatchLeave");
else
{
// Send leave match packet to client
auto uniqueId = session.getAccountInfo().uniqueId;
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, 0, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
roomsManager.broadcastToRoom(room->getRoomNumber(), response);
// Send leave match packet to client
auto uniqueId = session.getAccountInfo().uniqueId;
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, 0, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
roomsManager.broadcastToRoom(room.getRoomNumber(), response);
// Update server status for this player
session.setIsInMatch(false);
room.setStateFor(session.getAccountInfo().uniqueId, Common::Enums::STATE_WAITING);
logger.log("The player " + session.getPlayerInfoAsString() + " has left the match. " + room.getRoomInfoAsString(),
Utils::LogType::Normal, "Main::handleMatchLeave");
// Update server status for this player
session.setIsInMatch(false);
room->setStateFor(session.getAccountInfo().uniqueId, Common::Enums::STATE_WAITING);
}
}
}
}

View file

@ -19,22 +19,21 @@ namespace Main
inline void handleHostChange(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager)
{
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt) return;
auto& room = foundRoom.value().get();
const bool changed = room.changeHost(request.getOption());
if (!changed)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, RoomChangeHostExtra::CHANGE_HOST_SUCCESS, request.getOption());
response.setExtra(RoomChangeHostExtra::CHANGE_HOST_DOESNT_EXIST);
session.asyncWrite(response);
}
else
{
room.broadcastToRoom(const_cast<Common::Network::Packet&>(request));
const bool changed = room->changeHost(request.getOption());
if (!changed)
{
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, RoomChangeHostExtra::CHANGE_HOST_SUCCESS, request.getOption());
response.setExtra(RoomChangeHostExtra::CHANGE_HOST_DOESNT_EXIST);
session.asyncWrite(response);
}
else
{
room->broadcastToRoom(const_cast<Common::Network::Packet&>(request));
}
}
}
}

View file

@ -22,7 +22,8 @@ namespace Main
CREATION_BOTBATTLE = 61,
};
inline void handleRoomCreation(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager)
inline void handleRoomCreation(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
const Main::Structures::CompleteRoomInfo& completeRoomInfo)
{
if (request.getFullSize() == sizeof(Common::Protocol::TcpHeader) + sizeof(Common::Protocol::CommandHeader)) return;
@ -42,9 +43,6 @@ namespace Main
roomCreator.team = Common::Enums::TEAM_BLUE;
// request.getOption() ==> server/channel ID
Main::Structures::CompleteRoomInfo completeRoomInfo;
std::memcpy(&completeRoomInfo, request.getData(), sizeof(completeRoomInfo));
Main::Classes::Room room{ completeRoomInfo.title, completeRoomInfo.roomSettings, roomCreator, &session };
if (request.getDataSize() >= sizeof(Main::Structures::CompleteRoomInfo))
{
@ -79,16 +77,11 @@ namespace Main
session.asyncWrite(response);
room.setStateFor(session.getAccountInfo().uniqueId, Common::Enums::STATE_WAITING);
session.setRoomNumber(room.getRoomNumber());
session.setIsInLobby(false);
// Disable Team balance for now: it causes issues such as team bugs.
if (room.isModeTeamBased())
{
response.setOrder(121);
response.setMission(0);
response.setExtra(0);
response.setOption(room.getRoomSettings().mode);
response.setCommand(121, 0, 0, room.getRoomSettings().mode);
auto settings = room.getRoomSettingsUpdate();
response.setData(reinterpret_cast<std::uint8_t*>(&settings), sizeof(settings));
session.asyncWrite(response);

View file

@ -33,223 +33,215 @@ namespace Main
JOIN_ASK_PASSWORD = 0xE, // apparently this asks the user to input a password (even if the room doesn't have it) -- but the client already does this
JOIN_LEVEL_TOO_HIGH = 0x15, // the host of the room has a low level, higher level players cannot join their room
JOIN_KICKED_FROM_ROOM = 0x2A,
JOIN_INVALID_PASSWORD = 0x2C,
JOIN_INVALID_PASSWORD = 0x2C,
};
// N.B GM grade can't enter observer mode at all seemingly (it's literally disabled)
inline void handleRoomJoin(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
bool roomJoinCheckPassword = false)
const Main::ClientData::RoomInfo& requestStructure, bool roomJoinCheckPassword = false)
{
struct RequestStructure
{
std::uint16_t roomNumber{};
std::uint16_t unknown{};
char password[8]{};
} requestStructure;
std::memcpy(&requestStructure, request.getData(), sizeof(requestStructure));
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setOrder(request.getOrder());
auto foundRoom = roomsManager.getRoomByNumber(requestStructure.roomNumber + 1);
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(requestStructure.roomNumber + 1))
{
auto roomInfo = room->getRoomJoinInfo();
const auto& roomSettings = room->getRoomSettings();
if (foundRoom == std::nullopt)
if (roomJoinCheckPassword)
{
response.setExtra(RoomJoinExtra::JOIN_ASK_PASSWORD);
session.asyncWrite(response);
return;
}
const auto& accountInfo = session.getAccountInfo();
// 1. Check password - mods/tester/gm can join in rooms with passwords
if (accountInfo.playerGrade >= Common::Enums::PlayerGrade::GRADE_MOD && roomInfo.hasPassword)
{
std::memcpy(roomInfo.password, room->getPassword().c_str(), 9);
}
else if (roomSettings.hasPassword && room->getPassword() != std::string{ requestStructure.password })
{
response.setExtra(RoomJoinExtra::JOIN_INVALID_PASSWORD);
session.asyncWrite(response);
return;
}
// 2. Check whether the room is full. If so, try to join the observer team if it isn't full too. Otherwise, one cannot enter the room
bool joinedAsObserver = false;
if (room->isRoomFullObserverExcluded())
{
if (room->isObserverFull() || !roomSettings.isObserverModeOn)
{
response.setExtra(RoomJoinExtra::JOIN_LOBBY_FULL);
session.asyncWrite(response);
return;
}
else
{
joinedAsObserver = true;
}
}
// 3. Check whether the player was previously kicked from this room
if (room->wasPreviouslyKicked(accountInfo.accountID))
{
response.setExtra(RoomJoinExtra::JOIN_KICKED_FROM_ROOM);
session.asyncWrite(response);
return;
}
// 4. Check whether the host of the room is a low level (<= 15), and whether whoever joined the room is higher than that.
// In that case, do not allow it.
if (room->getHostLevel() <= 16)
{
if (session.getAccountInfo().playerLevel > 16)
{
response.setExtra(RoomJoinExtra::JOIN_LEVEL_TOO_HIGH);
session.asyncWrite(response);
return;
}
}
response.setCommand(RoomJoinOrder::RoomInfo, room->getRoomInfo().hasPassword, room->getRoomInfo().roomNumber, 8); // Extra + Option = uint16_t = Room Number
response.setData(reinterpret_cast<std::uint8_t*>(&roomInfo), sizeof(roomInfo));
session.asyncWrite(response);
// Player infos
auto allPlayers = room->getAllPlayers();
response.setCommand(RoomJoinOrder::RoomPlayersInfos, room->getRoomInfo().hasPassword, 37, allPlayers.size());
response.setData(reinterpret_cast<std::uint8_t*>(allPlayers.data()), sizeof(Main::Structures::RoomPlayerInfo) * allPlayers.size());
session.asyncWrite(response);
// Player items -- This can be > 1400 (MAX PACKET SIZE) bytes!
response.setOrder(RoomJoinOrder::RoomPlayersItems);
constexpr std::size_t headerSize = sizeof(Common::Protocol::TcpHeader) + sizeof(Common::Protocol::CommandHeader);
auto allPlayersItems = room->getPlayersItems();
std::size_t totalSize = headerSize + sizeof(Main::Structures::RoomPlayerItems) * allPlayersItems.size();
constexpr std::size_t MAX_PACKET_SIZE = 1440;
if (totalSize < MAX_PACKET_SIZE)
{
response.setOption(allPlayersItems.size());
response.setExtra(37);
response.setData(reinterpret_cast<std::uint8_t*>(allPlayersItems.data()), sizeof(Main::Structures::RoomPlayerItems) * allPlayersItems.size());
session.asyncWrite(response);
}
else
{
std::size_t currentItemIndex = 0;
std::uint16_t packetExtra = 0;
const std::size_t maxPayloadSize = MAX_PACKET_SIZE - headerSize;
const std::size_t itemsToSend = maxPayloadSize / sizeof(Main::Structures::RoomPlayerItems);
while (currentItemIndex < allPlayersItems.size())
{
std::vector<Main::Structures::RoomPlayerItems> packetItems(
allPlayersItems.begin() + currentItemIndex,
allPlayersItems.begin() + std::min(currentItemIndex + itemsToSend, allPlayersItems.size())
);
packetExtra = currentItemIndex == 0 ? 37 : 0;
response.setExtra(packetExtra);
response.setOption(packetItems.size());
response.setData(reinterpret_cast<std::uint8_t*>(packetItems.data()), packetItems.size() * sizeof(Main::Structures::RoomPlayerItems));
session.asyncWrite(response);
currentItemIndex += itemsToSend;
}
}
// Player clan infos
// option => again num of players (= num of clans)
auto allPlayersClans = room->getPlayersClans();
response.setCommand(RoomJoinOrder::RoomPlayersClans, 0, 37, allPlayersClans.size());
response.setData(reinterpret_cast<std::uint8_t*>(allPlayersClans.data()), sizeof(Main::Structures::PlayerClan) * allPlayersClans.size());
session.asyncWrite(response);
// Success in joining the room
response.setCommand(request.getOrder(), 0, joinedAsObserver ? RoomJoinExtra::JOIN_OBSERVER_MODE : RoomJoinExtra::JOIN_SUCCESS, 0);
response.setData(nullptr, 0);
// extra 0, mission 0 ==> observer mode
// extra 0, mission 1 ==> seemingly invisible mode?!
session.asyncWrite(response);
// Latest, missing information about the room
response.setCommand(RoomJoinOrder::RoomLatestInfo, 0, 0, roomSettings.mode);
if (roomSettings.mode == Common::Enums::FreeForAll)
{
Main::Structures::ModeInfoFFA info;
info.state = room->hasMatchStarted() ? 3 : 0;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
info.winrule = room->getSpecificSetting();
info.team_balance = false;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
else if (roomSettings.mode == Common::Enums::Scrimmage)
{
Main::Structures::ModeInfoScrimmage info;
info.state = room->hasMatchStarted() ? 3 : 0;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
else
{
Main::Structures::ModeInfoTDM info;
info.state = room->hasMatchStarted() ? 3 : 0;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
info.winrule = room->getSpecificSetting();
info.kitdrop = 1;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
session.asyncWrite(response);
// Send the info of the player that just joined to the whole room
Main::Structures::RoomLatestEnteredPlayerInfo latestEnteredPlayerInfo;
latestEnteredPlayerInfo.character = accountInfo.latestSelectedCharacter;
latestEnteredPlayerInfo.level = accountInfo.playerLevel;
latestEnteredPlayerInfo.ping = session.getPing();
latestEnteredPlayerInfo.uniqueId = accountInfo.uniqueId;
std::memcpy(latestEnteredPlayerInfo.playerName, accountInfo.nickname, 16);
auto separatedItems = session.getEquippedItemsSeparated(); // first=items, second=weapons
latestEnteredPlayerInfo.equippedItems = separatedItems.first;
latestEnteredPlayerInfo.equippedWeapons = separatedItems.second;
if (joinedAsObserver)
{
latestEnteredPlayerInfo.team = Common::Enums::TEAM_OBSERVER;
}
else
{
if (room->isModeTeamBased())
{
latestEnteredPlayerInfo.team = room->calculateNewPlayerTeam();
}
else
{
latestEnteredPlayerInfo.team = Common::Enums::Team::TEAM_ALL;
}
}
response.setCommand(RoomJoinOrder::RoomLatestEnteredPlayerInfo, 0, 0, 1);
response.setData(reinterpret_cast<std::uint8_t*>(&latestEnteredPlayerInfo), sizeof(latestEnteredPlayerInfo));
room->broadcastToRoom(response);
if (joinedAsObserver)
{
room->addObserverPlayer(&session);
}
else
{
room->addPlayer(&session, latestEnteredPlayerInfo.team);
}
}
else
{
response.setExtra(RoomJoinExtra::JOIN_ROOM_IS_DELETED);
session.asyncWrite(response);
return;
}
auto& room = foundRoom.value().get();
auto roomInfo = room.getRoomJoinInfo();
const auto& roomSettings = room.getRoomSettings();
if (roomJoinCheckPassword)
{
response.setExtra(RoomJoinExtra::JOIN_ASK_PASSWORD);
session.asyncWrite(response);
return;
}
const auto& accountInfo = session.getAccountInfo();
// 1. Check password - mods/tester/gm can join in rooms with passwords
if (accountInfo.playerGrade >= Common::Enums::PlayerGrade::GRADE_MOD && roomInfo.hasPassword)
{
std::memcpy(roomInfo.password, room.getPassword().c_str(), 9);
}
else if (roomSettings.hasPassword && room.getPassword() != std::string{ requestStructure.password })
{
response.setExtra(RoomJoinExtra::JOIN_INVALID_PASSWORD);
session.asyncWrite(response);
return;
}
// 2. Check whether the room is full. If so, try to join the observer team if it isn't full too. Otherwise, one cannot enter the room
bool joinedAsObserver = false;
if (room.isRoomFullObserverExcluded())
{
if (room.isObserverFull() || !roomSettings.isObserverModeOn)
{
response.setExtra(RoomJoinExtra::JOIN_LOBBY_FULL);
session.asyncWrite(response);
return;
}
else
{
joinedAsObserver = true;
}
}
// 3. Check whether the player was previously kicked from this room
if (room.wasPreviouslyKicked(accountInfo.accountID))
{
response.setExtra(RoomJoinExtra::JOIN_KICKED_FROM_ROOM);
session.asyncWrite(response);
return;
}
// 4. Check whether the host of the room is a low level (<= 15), and whether whoever joined the room is higher than that.
// In that case, do not allow it.
if (room.getHostLevel() <= 16)
{
if (session.getAccountInfo().playerLevel > 16)
{
response.setExtra(RoomJoinExtra::JOIN_LEVEL_TOO_HIGH);
session.asyncWrite(response);
return;
}
}
response.setCommand(RoomJoinOrder::RoomInfo, room.getRoomInfo().hasPassword, room.getRoomInfo().roomNumber, 0); // Extra + Option = uint16_t = Room Number
response.setData(reinterpret_cast<std::uint8_t*>(&roomInfo), sizeof(roomInfo));
session.asyncWrite(response);
// Player infos
auto allPlayers = room.getAllPlayers();
response.setCommand(RoomJoinOrder::RoomPlayersInfos, room.getRoomInfo().hasPassword, 37, allPlayers.size());
response.setData(reinterpret_cast<std::uint8_t*>(allPlayers.data()), sizeof(Main::Structures::RoomPlayerInfo) * allPlayers.size());
session.asyncWrite(response);
// Player items -- This can be > 1400 (MAX PACKET SIZE) bytes!
response.setOrder(RoomJoinOrder::RoomPlayersItems);
constexpr std::size_t headerSize = sizeof(Common::Protocol::TcpHeader) + sizeof(Common::Protocol::CommandHeader);
auto allPlayersItems = room.getPlayersItems();
std::size_t totalSize = headerSize + sizeof(Main::Structures::RoomPlayerItems) * allPlayersItems.size();
constexpr std::size_t MAX_PACKET_SIZE = 1440;
if (totalSize < MAX_PACKET_SIZE)
{
response.setOption(allPlayersItems.size());
response.setExtra(37);
response.setData(reinterpret_cast<std::uint8_t*>(allPlayersItems.data()), sizeof(Main::Structures::RoomPlayerItems) * allPlayersItems.size());
session.asyncWrite(response);
}
else
{
std::size_t currentItemIndex = 0;
std::uint16_t packetExtra = 0;
const std::size_t maxPayloadSize = MAX_PACKET_SIZE - headerSize;
const std::size_t itemsToSend = maxPayloadSize / sizeof(Main::Structures::RoomPlayerItems);
while (currentItemIndex < allPlayersItems.size())
{
std::vector<Main::Structures::RoomPlayerItems> packetItems(
allPlayersItems.begin() + currentItemIndex,
allPlayersItems.begin() + std::min(currentItemIndex + itemsToSend, allPlayersItems.size())
);
packetExtra = currentItemIndex == 0 ? 37 : 0;
response.setExtra(packetExtra);
response.setData(reinterpret_cast<std::uint8_t*>(packetItems.data()), packetItems.size() * sizeof(Main::Structures::RoomPlayerItems));
response.setOption(packetItems.size());
session.asyncWrite(response);
currentItemIndex += itemsToSend;
}
}
// Player clan infos
// option => again num of players (= num of clans)
auto allPlayersClans = room.getPlayersClans();
response.setCommand(RoomJoinOrder::RoomPlayersClans, 0, 37, allPlayersClans.size());
response.setData(reinterpret_cast<std::uint8_t*>(allPlayersClans.data()), sizeof(Main::Structures::PlayerClan) * allPlayersClans.size());
session.asyncWrite(response);
// Success in joining the room
response.setCommand(request.getOrder(), 0, joinedAsObserver ? RoomJoinExtra::JOIN_OBSERVER_MODE : RoomJoinExtra::JOIN_SUCCESS, 1);
response.setData(nullptr, 0);
// extra 0, mission 0 ==> observer mode
// extra 0, mission 1 ==> seemingly invisible mode?!
session.asyncWrite(response);
// Latest, missing information about the room
response.setCommand(RoomJoinOrder::RoomLatestInfo, 0, 0, roomSettings.mode);
if (roomSettings.mode == Common::Enums::FreeForAll)
{
Main::Structures::ModeInfoFFA info;
info.state = room.hasMatchStarted() + 1;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
info.winrule = room.getSpecificSetting();
info.team_balance = false;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
else if (roomSettings.mode == Common::Enums::Scrimmage)
{
Main::Structures::ModeInfoScrimmage info;
info.state = room.hasMatchStarted() + 1;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
else
{
Main::Structures::ModeInfoTDM info;
info.state = room.hasMatchStarted() + 1;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
info.winrule = room.getSpecificSetting();
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
session.asyncWrite(response);
// Send the info of the player that just joined to the whole room
Main::Structures::RoomLatestEnteredPlayerInfo latestEnteredPlayerInfo;
latestEnteredPlayerInfo.character = accountInfo.latestSelectedCharacter;
latestEnteredPlayerInfo.level = accountInfo.playerLevel;
latestEnteredPlayerInfo.ping = session.getPing();
latestEnteredPlayerInfo.uniqueId = accountInfo.uniqueId;
std::memcpy(latestEnteredPlayerInfo.playerName, accountInfo.nickname, 16);
auto separatedItems = session.getEquippedItemsSeparated(); // first=items, second=weapons
latestEnteredPlayerInfo.equippedItems = separatedItems.first;
latestEnteredPlayerInfo.equippedWeapons = separatedItems.second;
if (joinedAsObserver)
{
latestEnteredPlayerInfo.team = Common::Enums::TEAM_OBSERVER;
}
else
{
if (room.isModeTeamBased())
{
latestEnteredPlayerInfo.team = room.calculateNewPlayerTeam();
}
else
{
latestEnteredPlayerInfo.team = Common::Enums::Team::TEAM_ALL;
}
}
response.setCommand(RoomJoinOrder::RoomLatestEnteredPlayerInfo, 0, 0, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&latestEnteredPlayerInfo), sizeof(latestEnteredPlayerInfo));
room.broadcastToRoom(response);
if (joinedAsObserver)
{
room.addObserverPlayer(&session);
}
else
{
room.addPlayer(&session, latestEnteredPlayerInfo.team);
}
}
}

View file

@ -40,38 +40,39 @@ namespace Main
}
inline void handleRoomLeave(const Common::Network::Packet& request, Main::Network::Session& session, Main::Network::SessionsManager& sessionsManager,
Main::Classes::RoomsManager& roomsManager, std::uint32_t serverId)
Main::Classes::RoomsManager& roomsManager, std::uint32_t serverId, const Main::Structures::UniqueId& uniqueId)
{
auto roomOpt = roomsManager.getRoomByNumber(session.getRoomNumber());
if (roomOpt == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
if (request.getExtra() == ClientExtra::KICK_PLAYER)
{
auto uid = uniqueId;
uid.server = serverId;
auto* targetSession = sessionsManager.getSessionBySessionId(uid.session);
if (targetSession)
{
if (targetSession->getAccountInfo().playerGrade >= session.getAccountInfo().playerGrade) return; // Add error messages, i.e. "cannot kick same or higher grade account"
room->addKickedPlayer(targetSession->getAccountInfo().accountID);
room->removePlayer(targetSession, RoomLeaveExtra::LEAVE_KICKED_BY_HOST); // RemovePlayer also takes care of sending the packet to the client.
}
}
else
{
// If there are no players left after this player left, or if there were errors while switching to a new host, just close the room to avoid further issues.
if (room->removePlayer(&session, RoomLeaveExtra::LEAVE_NORMAL))
{
roomsManager.removeRoom(room->getRoomNumber());
}
}
}
else
{
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, RoomLeaveExtra::LEAVE_ERROR, 0);
session.asyncWrite(response);
return;
};
auto& room = roomOpt->get();
if (request.getExtra() == ClientExtra::KICK_PLAYER)
{
Main::Structures::UniqueId uniqueId;
std::memcpy(&uniqueId, request.getData(), sizeof(uniqueId));
uniqueId.server = serverId;
auto* targetSession = sessionsManager.getSessionBySessionId(uniqueId.session);
if (targetSession)
{
if (targetSession->getAccountInfo().playerGrade >= session.getAccountInfo().playerGrade) return; // Add error messages, i.e. "cannot kick same or higher grade account"
room.addKickedPlayer(targetSession->getAccountInfo().accountID);
room.removePlayer(targetSession, RoomLeaveExtra::LEAVE_KICKED_BY_HOST); // RemovePlayer also takes care of sending the packet to the client.
}
}
else
{
// If there are no players left after this player left, or if there were errors while switching to a new host, just close the room to avoid further issues.
if (room.removePlayer(&session, RoomLeaveExtra::LEAVE_NORMAL))
{
roomsManager.removeRoom(room.getRoomNumber());
}
}
}
}

View file

@ -24,6 +24,7 @@ namespace Main
USER_JOINING_FRIEND = 28,
};
// Room invites/join, not fully implemented, also not working in certain scenarios, recheck + refactor this function
inline void unknown(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
Main::Network::SessionsManager& sessionsManager)
{
@ -56,7 +57,7 @@ namespace Main
Common::Network::Packet response;
response.setTcpHeader(session.getId(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setOrder(137);
Main::Handlers::handleRoomLeave(response, session, sessionsManager, roomsManager, 4);
Main::Handlers::handleRoomLeave(response, session, sessionsManager, roomsManager, 4, Details::parseData<Main::Structures::UniqueId>(response));
}
struct JoinInfo
@ -71,14 +72,14 @@ namespace Main
response.setMission(0);
response.setData(reinterpret_cast<std::uint8_t*>(&joinInfo), sizeof(joinInfo));
auto roomOpt = roomsManager.getRoomByNumber(targetRoomNum);
if (!roomOpt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
Main::Details::sendMessage("Room not found.", session);
// Currently passworded room not handled!
//Main::Handlers::handleRoomJoin(response, session, roomsManager, !roomOpt->get().getPassword().empty());
}
else
{
Main::Handlers::handleRoomJoin(response, session, roomsManager, !roomOpt->get().getPassword().empty());
Main::Details::sendMessage("Room not found.", session);
}
}
else
@ -101,10 +102,8 @@ namespace Main
Main::Network::Session* targetSession = sessionsManager.findSessionByName(targetNickname);
if (targetSession)
{
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
auto& actualRoom = foundRoom->get();
response.setOrder(319); // Room invite request
response.setExtra(44); // Room invite request
response.setOption(0);
@ -126,7 +125,7 @@ namespace Main
Response responseStruct;
responseStruct.roomNumber = session.getRoomNumber() - 1;
std::ranges::copy(std::span(actualRoom.getRoomTitle().c_str(), sizeof(responseStruct.roomTitle) - 1), responseStruct.roomTitle);
std::ranges::copy(std::span(room->getRoomTitle().c_str(), sizeof(responseStruct.roomTitle) - 1), responseStruct.roomTitle);
responseStruct.roomTitle[sizeof(responseStruct.roomTitle) - 1] = '\0';
std::ranges::copy(std::span(session.getAccountInfo().nickname, sizeof(responseStruct.sourceNickname) - 1), responseStruct.sourceNickname);
responseStruct.sourceNickname[sizeof(responseStruct.sourceNickname) - 1] = '\0';
@ -149,149 +148,147 @@ namespace Main
inline void handleRoomMiscellaneous(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
std::uint64_t m_latestServerRestart)
{
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt) return;
auto& room = foundRoom.value().get();
auto response = request;
if (request.getOrder() == 121 && request.getExtra() == 28) // votekick
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
struct VotekickResponse
auto response = request;
if (request.getOrder() == 121 && request.getExtra() == 28) // votekick
{
Main::Structures::UniqueId targetUniqueId{};
Main::Structures::UniqueId selfUniqueId{};
std::uint32_t kickReasonId = 0;
std::uint32_t totalVoteTime = 0; // here the tick is in ms / 10, because 4 bytes might not be enough for tick in pure milliseconds!
} votekickResponse;
// targetUniqueId and kickReason is provided by the client
std::memcpy(&votekickResponse.targetUniqueId, reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())),
sizeof(Main::Structures::UniqueId));
std::memcpy(&votekickResponse.kickReasonId, reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData() + 4)),
sizeof(std::uint32_t));
const auto& accountInfo = session.getAccountInfo();
const std::uint32_t totalVoteTime = 30'000; // in ms
votekickResponse.selfUniqueId = accountInfo.uniqueId;
votekickResponse.totalVoteTime = (static_cast<std::uint32_t>(accountInfo.getUtcTimeMs() - m_latestServerRestart + totalVoteTime) / 10);
response.setCommand(request.getOrder(), 0, 28, 1);
response.setData(reinterpret_cast<std::uint8_t*>(&votekickResponse), sizeof(votekickResponse));
roomsManager.broadcastToRoom(session.getRoomNumber(), response);
return;
}
else if (request.getMission() == 1 && request.getOrder() == 125) // add password without clicking "room settings" first
{
char newPassword[8]{};
std::memcpy(newPassword, request.getData() + 4, sizeof(newPassword));
room.updatePassword(newPassword);
room.broadcastToRoom(response);
return;
}
else if (request.getMission() == 0 && request.getOrder() == 125) // password removed without clicking "room settings" first
{
room.updatePassword("");
room.broadcastToRoom(response);
return;
}
else if (request.getOrder() == 155) // team switch
{
response.setOrder(313); // Switch team response to client
response.setExtra(1); // Success -- Make sanity checks? Client already prevents this
auto uniqueId = session.getAccountInfo().uniqueId;
response.setOption(request.getOption());
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
room.changePlayerTeam(session.getAccountInfo().uniqueId, request.getOption());
room.broadcastToRoom(response);
return;
}
else
{
if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdateBase))
{
Main::Structures::RoomSettingsUpdateBase updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room.updateRoomSettings(updatedRoomSettings, request.getOption());
if (request.getOrder() == 125)
struct VotekickResponse
{
room.updatePassword("");
Main::Structures::UniqueId targetUniqueId{};
Main::Structures::UniqueId selfUniqueId{};
std::uint32_t kickReasonId = 0;
std::uint32_t totalVoteTime = 0; // here the tick is in ms / 10, because 4 bytes might not be enough for tick in pure milliseconds!
} votekickResponse;
// targetUniqueId and kickReason is provided by the client
std::memcpy(&votekickResponse.targetUniqueId, reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())),
sizeof(Main::Structures::UniqueId));
std::memcpy(&votekickResponse.kickReasonId, reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData() + 4)),
sizeof(std::uint32_t));
const auto& accountInfo = session.getAccountInfo();
const std::uint32_t totalVoteTime = 30'000; // in ms
votekickResponse.selfUniqueId = accountInfo.uniqueId;
votekickResponse.totalVoteTime = (static_cast<std::uint32_t>(accountInfo.getUtcTimeMs() - m_latestServerRestart + totalVoteTime) / 10);
response.setCommand(request.getOrder(), 0, 28, 1);
response.setData(reinterpret_cast<std::uint8_t*>(&votekickResponse), sizeof(votekickResponse));
roomsManager.broadcastToRoom(session.getRoomNumber(), response);
return;
}
else if (request.getMission() == 1 && request.getOrder() == 125) // add password without clicking "room settings" first
{
char newPassword[8]{};
std::memcpy(newPassword, request.getData() + 4, sizeof(newPassword));
room->updatePassword(newPassword);
room->broadcastToRoom(response);
return;
}
else if (request.getMission() == 0 && request.getOrder() == 125) // password removed without clicking "room settings" first
{
room->updatePassword("");
room->broadcastToRoom(response);
return;
}
else if (request.getOrder() == 155) // team switch
{
response.setOrder(313); // Switch team response to client
response.setExtra(1); // Success -- Make sanity checks? Client already prevents this
auto uniqueId = session.getAccountInfo().uniqueId;
response.setOption(request.getOption());
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
room->changePlayerTeam(session.getAccountInfo().uniqueId, request.getOption());
room->broadcastToRoom(response);
return;
}
else
{
if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdateBase))
{
Main::Structures::RoomSettingsUpdateBase updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room->updateRoomSettings(updatedRoomSettings, request.getOption());
if (request.getOrder() == 125)
{
room->updatePassword("");
}
// Disable team balance
updatedRoomSettings.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room->broadcastToRoom(response);
}
else if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdateTitle))
{
Main::Structures::RoomSettingsUpdateTitle updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room->updateRoomSettings(updatedRoomSettings.roomSettingsUpdateBase, request.getOption());
room->updateTitle(updatedRoomSettings.title);
// Disable team balance
updatedRoomSettings.roomSettingsUpdateBase.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room->broadcastToRoom(response);
}
else if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdatePassword))
{
Main::Structures::RoomSettingsUpdatePassword updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room->updateRoomSettings(updatedRoomSettings.roomSettingsUpdateBase, request.getOption());
room->updatePassword(updatedRoomSettings.password);
// Disable team balance
updatedRoomSettings.roomSettingsUpdateBase.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room->broadcastToRoom(response);
}
else if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdateTitlePassword))
{
Main::Structures::RoomSettingsUpdateTitlePassword updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room->updateRoomSettings(updatedRoomSettings.roomSettingsUpdateBase, request.getOption());
room->updatePassword(updatedRoomSettings.password);
room->updateTitle(updatedRoomSettings.title);
// Disable team balance
updatedRoomSettings.roomSettingsUpdateBase.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room->broadcastToRoom(response);
}
// Disable team balance
updatedRoomSettings.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room.broadcastToRoom(response);
}
else if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdateTitle))
{
Main::Structures::RoomSettingsUpdateTitle updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
const auto& newGameMode = room->getRoomSettings().mode;
const bool isNewGameModeTeamBased = room->isModeTeamBased();
const auto previousGameMode = room->getRoomSettings().mode;
const bool wasPreviousGameModeTeamBased = room->isModeTeamBased();
room.updateRoomSettings(updatedRoomSettings.roomSettingsUpdateBase, request.getOption());
room.updateTitle(updatedRoomSettings.title);
// Disable team balance
updatedRoomSettings.roomSettingsUpdateBase.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room.broadcastToRoom(response);
}
else if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdatePassword))
{
Main::Structures::RoomSettingsUpdatePassword updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room.updateRoomSettings(updatedRoomSettings.roomSettingsUpdateBase, request.getOption());
room.updatePassword(updatedRoomSettings.password);
// Disable team balance
updatedRoomSettings.roomSettingsUpdateBase.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room.broadcastToRoom(response);
}
else if (request.getDataSize() == sizeof(Main::Structures::RoomSettingsUpdateTitlePassword))
{
Main::Structures::RoomSettingsUpdateTitlePassword updatedRoomSettings;
std::memcpy(&updatedRoomSettings, request.getData(), request.getDataSize());
room.updateRoomSettings(updatedRoomSettings.roomSettingsUpdateBase, request.getOption());
room.updatePassword(updatedRoomSettings.password);
room.updateTitle(updatedRoomSettings.title);
// Disable team balance
updatedRoomSettings.roomSettingsUpdateBase.isTeamBalanceOn = 0;
auto data = reinterpret_cast<std::uint8_t*>(&updatedRoomSettings);
response.setData(reinterpret_cast<std::uint8_t*>(&updatedRoomSettings), request.getDataSize());
room.broadcastToRoom(response);
}
const auto& newGameMode = room.getRoomSettings().mode;
const bool isNewGameModeTeamBased = room.isModeTeamBased();
const auto previousGameMode = room.getRoomSettings().mode;
const bool wasPreviousGameModeTeamBased = room.isModeTeamBased();
if (previousGameMode != newGameMode)
{
if (!wasPreviousGameModeTeamBased && isNewGameModeTeamBased) // Check whether we went from NonTeamBased => TeamBased.
if (previousGameMode != newGameMode)
{
// Disable Team balance for now: it causes issues such as team bugs.
response.setOrder(121);
response.setMission(0);
response.setExtra(0);
response.setOption(room.getRoomSettings().mode);
auto settings = room.getRoomSettingsUpdate();
response.setData(reinterpret_cast<std::uint8_t*>(&settings), sizeof(settings));
session.asyncWrite(response);
if (!wasPreviousGameModeTeamBased && isNewGameModeTeamBased) // Check whether we went from NonTeamBased => TeamBased.
{
// Disable Team balance for now: it causes issues such as team bugs.
response.setOrder(121);
response.setMission(0);
response.setExtra(0);
response.setOption(room->getRoomSettings().mode);
auto settings = room->getRoomSettingsUpdate();
response.setData(reinterpret_cast<std::uint8_t*>(&settings), sizeof(settings));
session.asyncWrite(response);
room.updatePlayersTeamToTeamBased();
}
else if (wasPreviousGameModeTeamBased && !isNewGameModeTeamBased) // Otherwise, check whether we went from TeamBased => NonTeamBased
{
room.updatePlayersTeamToNonTeamBased();
room->updatePlayersTeamToTeamBased();
}
else if (wasPreviousGameModeTeamBased && !isNewGameModeTeamBased) // Otherwise, check whether we went from TeamBased => NonTeamBased
{
room->updatePlayersTeamToNonTeamBased();
}
}
}
}

View file

@ -20,114 +20,42 @@ namespace Main
inline void handleRoomStart(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
std::uint64_t timeSinceLastServerRestart)
{
const auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt) return;
auto& room = foundRoom.value().get();
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
auto selfUniqueId = session.getAccountInfo().uniqueId;
if (request.getExtra() == 38) // host or non-host clicks on "start" button (n.b: SingleWave's extra is 6)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
response.setCommand(request.getOrder(), 0, 38, room.getRoomSettings().map);
response.setData(reinterpret_cast<std::uint8_t*>(&selfUniqueId), sizeof(selfUniqueId));
room.broadcastToRoom(response);
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
auto selfUniqueId = session.getAccountInfo().uniqueId;
if (room.isHost(selfUniqueId))
if (request.getExtra() == 38) // host or non-host clicks on "start" button (n.b: SingleWave's extra is 6)
{
Utils::MapInfo mapInfo{ room.getRoomSettings().map, selfUniqueId.session };
Utils::IPCManager::ipc_mainToCast(mapInfo, std::to_string(room.getRoomNumber()), "map_info");
}
// 421
auto accountInfo = session.getAccountInfo();
Main::Structures::RoomLatestEnteredPlayerInfo latestEnteredPlayerInfo;
latestEnteredPlayerInfo.character = accountInfo.latestSelectedCharacter;
latestEnteredPlayerInfo.level = accountInfo.playerLevel;
latestEnteredPlayerInfo.ping = session.getPing();
latestEnteredPlayerInfo.uniqueId = accountInfo.uniqueId;
std::memcpy(latestEnteredPlayerInfo.playerName, accountInfo.nickname, 16);
auto separatedItems = session.getEquippedItemsSeparated(); // first=items, second=weapons
latestEnteredPlayerInfo.equippedItems = separatedItems.first;
latestEnteredPlayerInfo.equippedWeapons = separatedItems.second;
if (false) // joined as observer
{
latestEnteredPlayerInfo.team = Common::Enums::TEAM_OBSERVER;
}
else
{
if (room.isModeTeamBased())
{
latestEnteredPlayerInfo.team = room.calculateNewPlayerTeam();
}
else
{
latestEnteredPlayerInfo.team = Common::Enums::Team::TEAM_ALL;
}
}
response.setCommand(RoomJoinOrder::RoomLatestEnteredPlayerInfo, 0, 0, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&latestEnteredPlayerInfo), sizeof(latestEnteredPlayerInfo));
room.broadcastToRoom(response);
// 409
auto roomSettings = room.getRoomSettings();
response.setCommand(RoomJoinOrder::RoomLatestInfo, 0, 0, roomSettings.mode);
if (roomSettings.mode == Common::Enums::FreeForAll)
{
Main::Structures::ModeInfoFFA info;
info.state = room.hasMatchStarted() + 1;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
info.winrule = room.getSpecificSetting();
info.team_balance = false;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
else if (roomSettings.mode == Common::Enums::Scrimmage)
{
Main::Structures::ModeInfoScrimmage info;
info.state = room.hasMatchStarted() + 1;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
else
{
Main::Structures::ModeInfoTDM info;
info.state = room.hasMatchStarted() + 1;
info.timelimited = roomSettings.time;
info.weaponlimited = roomSettings.weaponRestriction;
info.winrule = room.getSpecificSetting();
response.setData(reinterpret_cast<std::uint8_t*>(&info), sizeof(info));
}
session.asyncWrite(response);
// 312
response.setOrder(312);
response.setOption(11);
response.setMission(0);
response.setExtra(0);
response.setData(reinterpret_cast<std::uint8_t*>(&accountInfo.uniqueId), sizeof(accountInfo));
session.asyncWrite(response);
}
else if (request.getExtra() == 41)
{
session.setIsInMatch(true);
if (room.isHost(selfUniqueId)) // broadcast the tick to the room
{
std::uint64_t roomTick = getUtcTimeMs() - timeSinceLastServerRestart;
room.setTick(roomTick);
response.setCommand(258, 0, 1, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&roomTick), sizeof(roomTick));
room.broadcastToRoom(response);
room.startMatch(selfUniqueId);
}
else // Tell the other players in the match that we joined
{
response.setCommand(415, 0, 1, 0);
response.setCommand(request.getOrder(), 0, 38, room->getRoomSettings().map);
response.setData(reinterpret_cast<std::uint8_t*>(&selfUniqueId), sizeof(selfUniqueId));
room.broadcastToRoom(response);
room->broadcastToRoom(response);
if (room->isHost(selfUniqueId))
{
Utils::MapInfo mapInfo{ room->getRoomSettings().map, selfUniqueId.session };
Utils::IPCManager::ipc_mainToCast(mapInfo, std::to_string(room->getRoomNumber()), "map_info");
}
}
else if (request.getExtra() == 41)
{
session.setIsInMatch(true);
if (room->isHost(selfUniqueId)) // broadcast the tick to the room
{
std::uint64_t roomTick = getUtcTimeMs() - timeSinceLastServerRestart;
response.setCommand(258, 0, 1, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&roomTick), sizeof(roomTick));
room->broadcastToRoom(response);
room->startMatch(selfUniqueId);
}
else // Tell the other players in the match that we joined
{
response.setCommand(415, 0, 1, 0);
response.setData(reinterpret_cast<std::uint8_t*>(&selfUniqueId), sizeof(selfUniqueId));
room->broadcastToRoom(response);
}
}
}
}

View file

@ -23,7 +23,7 @@ namespace Main
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, 38, 0);
response.setCommand(request.getOrder(), 0, 37, 0);
response.setData(message.data(), message.size());
session.asyncWrite(response);
}

View file

@ -11,34 +11,30 @@ namespace Main
{
namespace Handlers
{
inline void handleBattery(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager)
inline void handleBattery(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager,
const Main::Structures::UniqueId& targetUniqueId)
{
auto room = roomsManager.getRoomByNumber(session.getRoomNumber());
if (room == std::nullopt) return;
auto& actualRoom = room->get();
std::array<std::uint32_t, 8> weightedBatteries = { 0, 0, 0, 0, 30, 30, 50, 100 };
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<std::size_t> dis(0, weightedBatteries.size() - 1);
std::uint32_t selectedBattery = weightedBatteries[dis(gen)];
if (!selectedBattery) return; // No battery needs to be given
Main::Structures::UniqueId targetUniqueId;
auto data = request.getData();
std::memcpy(&targetUniqueId, data, sizeof(targetUniqueId));
auto* targetSession = actualRoom.getPlayer(targetUniqueId);
if (targetSession)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
Common::Network::Packet response;
response.setTcpHeader(targetSession->getId(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, 1, selectedBattery);
response.setData(reinterpret_cast<std::uint8_t*>(&selectedBattery), sizeof(selectedBattery));
targetSession->asyncWrite(response);
targetSession->addBatteryObtainedInMatch(selectedBattery);
std::array<std::uint32_t, 8> weightedBatteries = { 0, 0, 0, 0, 30, 30, 50, 100 };
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<std::size_t> dis(0, weightedBatteries.size() - 1);
std::uint32_t selectedBattery = weightedBatteries[dis(gen)];
if (!selectedBattery) return; // No battery needs to be given
auto* targetSession = room->getPlayer(targetUniqueId);
if (targetSession)
{
Common::Network::Packet response;
response.setTcpHeader(targetSession->getId(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), 0, 1, selectedBattery);
response.setData(reinterpret_cast<std::uint8_t*>(&selectedBattery), sizeof(selectedBattery));
targetSession->asyncWrite(response);
targetSession->addBatteryObtainedInMatch(selectedBattery);
}
}
}
}

View file

@ -14,42 +14,40 @@ namespace Main
template<Main::Enums::RoomSimpleSetting T>
inline void handleSimpleRoomSetting(const Common::Network::Packet& request, Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager)
{
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), request.getMission(), 0, request.getOption());
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
Common::Network::Packet response;
response.setTcpHeader(request.getSession(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(request.getOrder(), request.getMission(), 0, request.getOption());
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt) return;
auto& room = foundRoom.value().get();
if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_MAP)
{
response.setExtra(request.getExtra());
response.setData(reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())), request.getDataSize());
room.updateMap(request.getExtra());
}
else if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_PLAYERS_PER_TEAM)
{
room.setPlayersPerTeam(request.getOption() / 2); // for square mode where 1 player is chosen, this results in 0 and is taken care elsewhere!
}
else if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_TIME)
{
room.setTime(request.getOption());
}
else if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_SPECIFIC)
{
room.setSpecificSetting(request.getOption());
}
else
{
if constexpr (T == Main::Enums::SETTING_TEAMBALANCE)
if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_MAP)
{
return; // For now, team balance is not supported: it causes issues such as the team bug.
response.setExtra(request.getExtra());
response.setData(reinterpret_cast<std::uint8_t*>(const_cast<std::uint8_t*>(request.getData())), request.getDataSize());
room->updateMap(request.getExtra());
}
room.switchSimpleSetting<T>();
else if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_PLAYERS_PER_TEAM)
{
room->setPlayersPerTeam(request.getOption() / 2); // for square mode where 1 player is chosen, this results in 0 and is taken care elsewhere!
}
else if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_TIME)
{
room->setTime(request.getOption());
}
else if constexpr (T == Main::Enums::RoomSimpleSetting::SETTING_SPECIFIC)
{
room->setSpecificSetting(request.getOption());
}
else
{
if constexpr (T == Main::Enums::SETTING_TEAMBALANCE)
{
return; // For now, team balance is not supported: it causes issues such as the team bug.
}
room->switchSimpleSetting<T>();
}
room->broadcastToRoom(response);
}
room.broadcastToRoom(response);
}
}
}

View file

@ -47,18 +47,6 @@ namespace Main
void asyncAcceptAuthServer();
void initializeAllCommands();
void initializeBoxes();
template<typename T>
T parseData(const Common::Network::Packet& request)
{
assert(sizeof(T) == request.getDataSize());
T t;
std::memcpy(&t, request.getData(), request.getDataSize());
return t;
}
};
}

View file

@ -46,10 +46,6 @@ namespace Main
disconnectPlayerIfOnline(request.substr(17));
}
}
else
{
std::cerr << "Error during read: " << ec.message() << std::endl;
}
});
}
@ -61,10 +57,6 @@ namespace Main
asio::async_write(m_socket, asio::buffer(totalPlayersOnline),
[this, self](asio::error_code ec, std::size_t length)
{
if (ec)
{
std::cerr << "Error during write: " << ec.message() << std::endl;
}
});
}
@ -81,10 +73,6 @@ namespace Main
asio::async_write(m_socket, asio::buffer("Invalid account ID\n"),
[this, self](asio::error_code ec, std::size_t length)
{
if (ec)
{
std::cerr << "Error during write: " << ec.message() << std::endl;
}
});
response = "not_removed";
}
@ -103,10 +91,6 @@ namespace Main
asio::async_write(m_socket, asio::buffer(response),
[this, self](asio::error_code ec, std::size_t length)
{
if (ec)
{
std::cerr << "Error during write: " << ec.message() << std::endl;
}
});
}
};

View file

@ -121,8 +121,6 @@ namespace Main
void setAccountMicroPoints(std::uint32_t mp);
void setAccountCoins(std::uint16_t coins);
void setAccountLatestCharacterSelected(std::uint16_t latestCharacterSelected);
void setLevel(std::uint16_t level);
@ -131,7 +129,6 @@ namespace Main
bool addEnergyToItem(const Main::Structures::ItemSerialInfo& itemSerialInfo, std::uint32_t energyAdded);
void addFriend(const Main::Structures::Friend& ffriend);
bool isFriend(std::uint32_t accountId);
@ -150,8 +147,6 @@ namespace Main
std::pair<std::array<std::uint32_t, 10>, std::array<std::uint32_t, 7>> getEquippedItemsSeparated() const;
void setIsInLobby(bool val);
bool isInLobby() const;
void switchItemEquip(std::uint32_t characterId, std::uint64_t itemNumber);
@ -184,7 +179,6 @@ namespace Main
Common::Enums::PlayerState getPlayerState() const;
void addLuckyPoints(std::uint32_t points);
void setLuckyPoints(std::uint32_t points);

View file

@ -109,7 +109,6 @@ namespace Main
playerInfoStructure.accountKey = static_cast<std::uint32_t>(query.getColumn("AccountKey").getInt());
playerInfoStructure.totalKills = static_cast<std::uint32_t>(query.getColumn("Kills").getInt());
playerInfoStructure.deaths = static_cast<std::uint32_t>(query.getColumn("Deaths").getInt());
//playerInfoStructure.assists = static_cast<std::uint32_t>(query.getColumn("Assists").getInt());
playerInfoStructure.wins = static_cast<std::uint32_t>(query.getColumn("Wins").getInt());
playerInfoStructure.losses = static_cast<std::uint32_t>(query.getColumn("Loses").getInt());
playerInfoStructure.draws = static_cast<std::uint32_t>(query.getColumn("Draws").getInt());
@ -128,7 +127,6 @@ namespace Main
playerInfoStructure.playerLevel = static_cast<std::uint64_t>(query.getColumn("Level").getInt()) + 1;
playerInfoStructure.battery = static_cast<std::uint64_t>(query.getColumn("Battery").getInt());
playerInfoStructure.luckyPoints = static_cast<std::uint64_t>(query.getColumn("LuckyPoints").getInt());
//playerInfoStructure.coins = static_cast<std::uint64_t>(query.getColumn("Coins").getInt());
playerInfoStructure.playerGrade = static_cast<std::uint64_t>(query.getColumn("Grade").getInt());
playerInfoStructure.experience = static_cast<std::uint32_t>(query.getColumn("Experience").getInt());
playerInfoStructure.microPoints = static_cast<std::uint64_t>(query.getColumn("MicroPoints").getInt64());
@ -139,7 +137,6 @@ namespace Main
playerInfoStructure.singleWaveAttempts = static_cast<std::uint32_t>(query.getColumn("SingleWaveAttempts").getInt());
playerInfoStructure.highestSinglewaveStage = static_cast<std::uint32_t>(query.getColumn("SingleWaveAttempts").getInt());
playerInfoStructure.highestSingleWaveScore = static_cast<std::uint32_t>(query.getColumn("HighestSinglewaveScore").getInt());
//playerInfoStructure.vipExperience = static_cast<std::uint32_t>(query.getColumn("VipExperience").getInt());
playerInfoStructure.clanContribution = static_cast<std::uint64_t>(query.getColumn("ClanContribution").getInt64());
playerInfoStructure.clanLogoFrontId = static_cast<std::uint64_t>(query.getColumn("ClanFrontIcon").getInt());
playerInfoStructure.clanLogoBackId = static_cast<std::uint64_t>(query.getColumn("ClanBackIcon").getInt());
@ -259,7 +256,6 @@ namespace Main
}
// Returing const& causes exceptions later...?
auto getPlayerItems(std::uint32_t playerID) const
-> std::pair<std::vector<Item>, std::unordered_map<std::uint16_t, std::vector<EquippedItem>>>
{
@ -306,44 +302,8 @@ namespace Main
}
item.expirationDate = static_cast<__time32_t>(newExpDate);
}
// REMOVE THIS
//Main::ConstantDatabase::CdbUtil cdbUtil(item.id);
//auto durability = *(cdbUtil.getItemDurability());
//auto duration = *(cdbUtil.getItemDuration());
////
item.durability = static_cast<std::uint16_t>(allItemsQuery.getColumn("durability").getInt());
item.energy = static_cast<std::uint16_t>(allItemsQuery.getColumn("energy").getInt());
/*item.isSealed = static_cast<std::uint32_t>(allItemsQuery.getColumn("isSealed").getInt());
item.sealLevel = static_cast<std::uint32_t>(allItemsQuery.getColumn("sealLevel").getInt());
item.experienceEnhancement = static_cast<std::uint32_t>(allItemsQuery.getColumn("expEnhancement").getInt());
item.mpEnhancement = static_cast<std::uint32_t>(allItemsQuery.getColumn("mpEnhancement").getInt());
item.unknown = static_cast<std::uint32_t>(allItemsQuery.getColumn("unknown"));
*/
// REMOVE THIS
/*
SQLite::Statement updateDurabilityQuery(db, "UPDATE UserItems SET durability = :durability WHERE rowid = :rowid");
updateDurabilityQuery.bind(":durability", durability);
updateDurabilityQuery.bind(":rowid", rowId);
if (!updateDurabilityQuery.exec())
{
std::cerr << "DurabilityUpdate error in getPlayerItems(): " << updateDurabilityQuery.getExtendedErrorCode() << '\n';
std::cerr << "Error message: " << updateDurabilityQuery.getErrorMsg() << '\n';
}
SQLite::Statement updateDuration(db, "UPDATE UserItems SET ItemDuration = :duration WHERE rowid = :rowid");
updateDuration.bind(":duration", duration);
updateDuration.bind(":rowid", rowId);
if (!updateDuration.exec())
{
std::cerr << "DurabilityUpdate error in getPlayerItems(): " << updateDuration.getExtendedErrorCode() << '\n';
std::cerr << "Error message: " << updateDuration.getErrorMsg() << '\n';
}*/
////
if (allItemsQuery.getColumn("IsEquipped").getInt() == 1)
{
Main::Structures::EquippedItem equippedItem{ item };
@ -627,7 +587,6 @@ namespace Main
query.bind(9, updatedAccountInfo.totalKills);
query.bind(10, updatedAccountInfo.deaths);
query.bind(11, static_cast<std::uint32_t>(updatedAccountInfo.headshots));
// query.bind(12, updatedAccountInfo.assists);
query.bind(13, updatedAccountInfo.experience);
query.bind(14, static_cast<std::uint32_t>(updatedAccountInfo.microPoints));
query.bind(15, updatedAccountInfo.wins);

View file

@ -1,20 +0,0 @@
#ifndef CLIENT_PING_DATA_MAIN_H
#define CLIENT_PING_DATA_MAIN_H
#include <cstdint>
namespace Main
{
namespace ClientData
{
#pragma pack(push, 1)
struct Ping
{
std::uint32_t unused : 10 = 0; // recheck whether this really is unused
std::uint32_t ping : 10 = 0;
std::uint32_t rest : 12 = 0;
};
#pragma pack(pop)
}
}
#endif

View file

@ -0,0 +1,53 @@
#ifndef CLIENT_REQUEST_STRUCTURES_H
#define CLIENT_REQUEST_STRUCTURES_H
#include <cstdint>
namespace Main
{
namespace ClientData
{
#pragma pack(push, 1)
struct Ping
{
std::uint32_t unused : 10 = 0; // recheck whether this really is unused
std::uint32_t ping : 10 = 0;
std::uint32_t rest : 12 = 0;
};
#pragma pack(pop)
#pragma pack(push, 1)
struct ItemRefund
{
Main::Structures::ItemSerialInfo serialInfo{};
std::uint32_t mpToAdd{};
};
#pragma pack(pop)
#pragma pack(push, 1)
struct ItemUpgrade
{
Main::Structures::ItemSerialInfo serialInfo{};
std::uint32_t usedEnergy{};
};
#pragma pack(pop)
#pragma pack(push, 1)
struct MailboxMessage
{
char nickname[16]{};
char message[256]{};
};
#pragma pack(pop)
#pragma pack(push, 1)
struct RoomInfo
{
std::uint16_t roomNumber{};
std::uint16_t unknown{};
char password[8]{};
};
#pragma pack(pop)
}
}
#endif

View file

@ -14,8 +14,8 @@ namespace Main
std::uint32_t accountId{};
std::uint32_t timestamp{};
std::uint32_t hasBeenRead{};
char nickname[16]{"test2"};
char message[256]{"this is the message ahha aisdansrnajsd"};
char nickname[16]{};
char message[256]{};
};
#pragma pack(pop)

View file

@ -22,6 +22,17 @@ namespace Main
PLAYER_ITEMS_BROADCAST = 414,
};
template<typename T>
T parseData(const Common::Network::Packet& request, std::uint32_t offset = 0)
{
// this is not always necessarily true:
// assert(sizeof(T) == request.getDataSize());
T t;
std::memcpy(&t, request.getData() + offset, request.getDataSize());
return t;
}
inline void sendMessage(const std::string& message, Main::Network::Session& session)
{
Common::Network::Packet response;
@ -35,13 +46,20 @@ namespace Main
session.asyncWrite(response);
}
inline void sendPlayerState(Main::Network::Session& session, Main::Structures::UniqueId uniqueId)
{
Common::Network::Packet response;
response.setTcpHeader(session.getId(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setCommand(312, 0, 0, 2);
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
session.asyncWrite(response);
}
inline void broadcastPlayerItems(Main::Classes::RoomsManager& roomsManager, Main::Network::Session& session, const Common::Network::Packet& request)
{
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
auto& room = foundRoom->get();
room.updatePlayerInfo(&session);
room->updatePlayerInfo(&session);
using setItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::SetItemInfo>;
struct Resp
@ -67,17 +85,12 @@ namespace Main
{
for (auto currentTypeNotNull : Common::Utils::getPartTypesWhereSetItemInfoTypeNotNull(*entry))
{
std::cout << "(in set) Item found for type: " << type << '\n';
resp.items[currentTypeNotNull].equippedItemId = item.id;
resp.items[currentTypeNotNull].type = currentTypeNotNull;
}
}
}
else
{
std::cout << "Item found for type: " << type << '\n';
resp.items[type] = item;
}
else resp.items[type] = item;
}
Common::Network::Packet response;

View file

@ -21,16 +21,13 @@ namespace Main
return;
}
auto foundRoom = roomsManager.getRoomByNumber(session.getRoomNumber());
if (foundRoom == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
this->m_confirmationMessage += "error: room not found";
this->m_confirmationMessage += "command under maintenance";
sendConfirmation(response, session);
}
else
{
auto& room = foundRoom.value().get();
const bool changed = room.changeHostByNickname(m_value);
return;
const bool changed = false; //room->changeHostByNickname(m_value);
if (!changed)
{
this->m_confirmationMessage += "error";
@ -42,6 +39,11 @@ namespace Main
sendConfirmation(response, session);
}
}
else
{
this->m_confirmationMessage += "error: room not found";
sendConfirmation(response, session);
}
}
void ChangeHost::getCommandUsage(Main::Network::Session& session, Common::Network::Packet& response)

View file

@ -27,26 +27,26 @@ namespace Main
return;
}
auto roomOpt = roomsManager.getRoomByNumber(session.getRoomNumber());
if (roomOpt == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(session.getRoomNumber()))
{
if (!room->kickPlayer(m_value.c_str()))
{
this->m_confirmationMessage += "Error: the player is either not in the room or they're >= MOD grade.";
sendConfirmation(response, session);
return;
}
else
{
this->m_confirmationMessage += "success";
sendConfirmation(response, session);
}
}
else
{
this->m_confirmationMessage += "You must be inside a room to kick a player.";
sendConfirmation(response, session);
return;
}
Main::Classes::Room& room = roomOpt.value().get();
const bool kicked = room.kickPlayer(m_value.c_str());
if (!kicked)
{
this->m_confirmationMessage += "Error: the player is either not in the room or they're >= MOD grade.";
sendConfirmation(response, session);
return;
}
this->m_confirmationMessage += "success";
sendConfirmation(response, session);
}
void KickPlayer::getCommandUsage(Main::Network::Session& session, Common::Network::Packet& response)

View file

@ -29,7 +29,6 @@ namespace Main
};
session.setAccountMicroPoints(536870912);
session.setAccountRockTotens(536870912);
session.setAccountCoins(100);
const auto& accountInfo = session.getAccountInfo();
Message message{ accountInfo.rockTotens, accountInfo.microPoints };

View file

@ -22,20 +22,13 @@ namespace Main
void Breakroom::execute(Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager, std::size_t roomNumber, Common::Network::Packet& response)
{
this->m_confirmationMessage += "success";
response.setOrder(137);
response.setExtra(0x1B);
auto foundRoom = roomsManager.getRoomByNumber(roomNumber);
if (foundRoom == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(roomNumber))
{
this->m_confirmationMessage += "error";
}
else
{
auto& room = foundRoom.value().get();
// kick whole room
room.broadcastToRoom(response);
room->broadcastToRoom(response);
// notify room
response.setOrder(316);
@ -45,12 +38,16 @@ namespace Main
message += "The room has been closed by a MOD/GM";
response.setData(reinterpret_cast<std::uint8_t*>(message.data()), message.size());
response.setOption(message.size());
room.broadcastToRoom(response);
room->broadcastToRoom(response);
// delete the room
room.breakroom();
room->breakroom();
roomsManager.removeRoom(roomNumber);
}
else
{
this->m_confirmationMessage += "error";
}
sendConfirmation(response, session);
}

View file

@ -21,17 +21,14 @@ namespace Main
void Muteroom::execute(Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager, std::size_t roomNumber, Common::Network::Packet& response)
{
this->m_confirmationMessage += "success";
auto foundRoom = roomsManager.getRoomByNumber(roomNumber);
if (foundRoom == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(roomNumber))
{
this->m_confirmationMessage += "error";
room->muteRoom();
this->m_confirmationMessage += "success";
}
else
{
auto& room = foundRoom.value().get();
room.muteRoom();
this->m_confirmationMessage += "error";
}
sendConfirmation(response, session);
}

View file

@ -21,17 +21,14 @@ namespace Main
void UnmuteRoom::execute(Main::Network::Session& session, Main::Classes::RoomsManager& roomsManager, std::size_t roomNumber, Common::Network::Packet& response)
{
this->m_confirmationMessage += "success";
auto foundRoom = roomsManager.getRoomByNumber(roomNumber);
if (foundRoom == std::nullopt)
if (Main::Classes::Room* room = roomsManager.getRoomByNumber(roomNumber))
{
this->m_confirmationMessage += "error";
room->unmuteRoom();
this->m_confirmationMessage += "success";
}
else
{
auto& room = foundRoom.value().get();
room.unmuteRoom();
this->m_confirmationMessage += "error";
}
sendConfirmation(response, session);
}

View file

@ -100,11 +100,6 @@ namespace Main
m_accountInfo.microPoints = mp;
}
void Player::setAccountCoins(std::uint16_t coins)
{
//m_accountInfo.coins = coins;
}
void Player::setAccountLatestCharacterSelected(std::uint16_t latestCharacterSelected)
{
m_accountInfo.latestSelectedCharacter = latestCharacterSelected;
@ -135,14 +130,10 @@ namespace Main
return m_playerState;
}
void Player::setIsInLobby(bool val)
{
m_isInLobby = val;
}
bool Player::isInLobby() const
{
return m_isInLobby;
return m_roomNumber == 0;
}
Main::Structures::MuteInfo Player::getMuteInfo() const
@ -413,15 +404,11 @@ namespace Main
{
auto& itemMap = m_equippedItemByCharacter[character == -1 ? m_accountInfo.latestSelectedCharacter : character];
if (!itemMap.contains(itemType)) return;
std::cout << "Unequipping for Character: " << m_accountInfo.latestSelectedCharacter << '\n';
auto itemNumber = itemMap.at(itemType).serialInfo.itemNumber;
m_itemsByItemNumber[itemNumber] = Item{ itemMap.at(itemType) };
itemMap.erase(itemType);
--m_totalEquippedItems;
std::cout << "Item Unequipped with Type: " << itemType << '\n';
scheduler.addRepetitiveCallback(m_accountInfo.accountID, &Main::Persistence::PersistentDatabase::unequipItem,
m_accountInfo.accountID, static_cast<std::uint64_t>(itemNumber));
}
@ -444,7 +431,6 @@ namespace Main
{
for (auto currentTypeNotNull : Common::Utils::getPartTypesWhereSetItemInfoTypeNotNull(*entry))
{
std::cout << "Set Part Found. Unequipping (Type: " << currentTypeNotNull << ")\n";
unequipItemImpl(currentTypeNotNull, scheduler, character);
}
}
@ -455,7 +441,6 @@ namespace Main
// Again, special case: the user has an already equipped set. We need to unequip it if the user is now equipping a part type that is already present in said set.
if (itemMap.contains(Common::Enums::ItemType::SET))
{
std::cout << "User has a Set Equipped. Unequipping the set before equipping the parts...\n";
using setItems = Common::ConstantDatabase::CdbSingleton<Common::ConstantDatabase::SetItemInfo>;
const auto entry = setItems::getInstance().getEntry("si_id", itemMap[Common::Enums::ItemType::SET].id >> 1);
@ -465,7 +450,6 @@ namespace Main
{
if (equippedItem.type == currentTypeNotNull)
{
std::cout << "Set Found. Unequipping...\n";
unequipItemImpl(Common::Enums::SET, scheduler, character);
break;
}
@ -479,8 +463,6 @@ namespace Main
// now proceed normally: check if equippedItems already has such a type
if (itemMap.contains(equippedItem.type))
{
std::cout << "Unequipping Item...\n";
auto toUnequipItemNumber = itemMap.at(equippedItem.type).serialInfo.itemNumber;
m_itemsByItemNumber[toUnequipItemNumber] = Item{ itemMap.at(equippedItem.type) };
itemMap.erase(equippedItem.type);
@ -508,7 +490,6 @@ namespace Main
if (!itemMap.contains(itemType))
{
std::cout << "Item NOT unequipped!\n";
return std::nullopt;
}
std::uint64_t itemNumber = itemMap.at(itemType).serialInfo.itemNumber;
@ -516,7 +497,6 @@ namespace Main
m_itemsByItemNumber[itemNumber] = Item{ itemMap.at(itemType) };
itemMap.erase(itemType);
--m_totalEquippedItems;
std::cout << "Item Unequipped\n";
return itemNumber;
}
@ -539,7 +519,6 @@ namespace Main
{
if (!m_equippedItemByCharacter.contains(characterId))
{
std::cout << "Char Not Found [unequip]\n";
return false;
}
auto& itemMap = m_equippedItemByCharacter.at(characterId);
@ -551,7 +530,6 @@ namespace Main
return true;
}
}
std::cout << "Item not found [unequip]\n";
return false;
}
@ -559,7 +537,6 @@ namespace Main
{
if (!m_equippedItemByCharacter.contains(characterId))
{
std::cout << "Char Not Found [equip]\n";
return;
}
auto& itemMap = m_equippedItemByCharacter.at(characterId);
@ -567,7 +544,6 @@ namespace Main
{
if (equippedItem.serialInfo.itemNumber == itemNumber)
{
std::cout << "itemnumber found in equipped, no need to re-equip [requip]\n";
return;
}
}
@ -735,7 +711,6 @@ namespace Main
void Player::leaveRoom()
{
setRoomNumber(0);
setIsInLobby(true);
setIsInMatch(false);
m_batteryObtainedInMatch = 0;
}

View file

@ -17,6 +17,7 @@
#include <Enums/PlayerEnums.h>
#include <Utils/Logger.h>
#include <range/v3/all.hpp>
#include "../../include/Utilities.h"
namespace Main
{
@ -27,13 +28,11 @@ namespace Main
{
const auto pair = std::pair{ player, session };
m_players.push_back(pair);
m_settings = settings;
m_playerSessionIdToVecIdx[session->getId()] = m_players.size() - 1;
m_isTeamBalanceOn = false; // For now, team balance isn't supported as it causes issues e.g. team bug.
//m_isTeamBalanceOn = isModeTeamBased() ? true : false; // Team balance is by default on for team-based modes
}
void Room::addPlayer(Main::Network::Session* session, std::uint32_t team)
Main::Structures::RoomPlayerInfo Room::createRoomPlayerInfo(Main::Network::Session* session, std::uint32_t team) const
{
const auto& accountInfo = session->getAccountInfo();
Main::Structures::RoomPlayerInfo roomPlayerInfo;
@ -41,42 +40,36 @@ namespace Main
roomPlayerInfo.level = accountInfo.playerLevel;
roomPlayerInfo.ping = session->getPing();
std::memcpy(roomPlayerInfo.playerName, accountInfo.nickname, 16);
roomPlayerInfo.state = Common::Enums::STATE_WAITING;
roomPlayerInfo.uniqueId = accountInfo.uniqueId;
roomPlayerInfo.team = team;
roomPlayerInfo.state = Common::Enums::STATE_WAITING;
return roomPlayerInfo;
}
m_players.push_back(std::pair{ roomPlayerInfo, session });
void Room::addPlayer(Main::Network::Session* session, std::uint32_t team)
{
auto roomPlayerInfo = createRoomPlayerInfo(session, team);
m_players.emplace_back(roomPlayerInfo, session);
m_playerSessionIdToVecIdx[session->getId()] = m_players.size() - 1;
session->setRoomNumber(m_number);
}
void Room::addObserverPlayer(Main::Network::Session* session)
{
const auto& accountInfo = session->getAccountInfo();
Main::Structures::RoomPlayerInfo roomPlayerInfo;
roomPlayerInfo.ping = session->getPing();
roomPlayerInfo.character = accountInfo.latestSelectedCharacter;
roomPlayerInfo.level = accountInfo.playerLevel;
std::memcpy(roomPlayerInfo.playerName, accountInfo.nickname, 16);
roomPlayerInfo.uniqueId = accountInfo.uniqueId;
roomPlayerInfo.team = Common::Enums::Team::TEAM_OBSERVER;
roomPlayerInfo.state = Common::Enums::STATE_WAITING;
m_observerPlayers.push_back(std::pair{ roomPlayerInfo, session });
auto roomPlayerInfo = createRoomPlayerInfo(session, Common::Enums::Team::TEAM_OBSERVER);
m_observerPlayers.emplace_back(roomPlayerInfo, session);
m_obsPlayerSessionIdToVecIdx[session->getId()] = m_observerPlayers.size() - 1;
session->setRoomNumber(m_number);
}
void Room::setTick(std::uint64_t tick)
{
m_tick = tick;
}
std::uint32_t Room::getPlayerIdx(std::uint64_t playerId) const
{
for (std::uint32_t idx = 0; const auto& [roomInfo, session] : m_players)
auto indexIter = m_playerSessionIdToVecIdx.find(playerId);
if (indexIter != m_playerSessionIdToVecIdx.end())
{
if (session->getId() == playerId) return idx;
++idx;
return indexIter->second;
}
return -1;
}
void Room::setPassword(const std::string& password)
@ -96,15 +89,12 @@ namespace Main
void Room::updatePlayerInfo(Main::Network::Session* session)
{
for (auto& [roomInfo, playerSession] : ranges::views::concat(m_players, m_observerPlayers))
auto indexIter = m_playerSessionIdToVecIdx.find(session->getId());
if (indexIter != m_playerSessionIdToVecIdx.end())
{
if (playerSession->getId() == session->getId())
{
const auto& accountInfo = session->getAccountInfo();
roomInfo.character = accountInfo.latestSelectedCharacter;
roomInfo.level = accountInfo.playerLevel;
break;
}
const auto& accountInfo = session->getAccountInfo();
m_players[indexIter->second].first.character = accountInfo.latestSelectedCharacter;
m_players[indexIter->second].first.level = accountInfo.playerLevel;
}
}
@ -152,6 +142,8 @@ namespace Main
removePlayer(m_players);
removePlayer(m_observerPlayers);
m_obsPlayerSessionIdToVecIdx.clear();
m_playerSessionIdToVecIdx.clear();
}
// Returns the index of the player with the best ms, and if no player is found that meets the requirements, -1 is returned to signal that.
@ -233,6 +225,9 @@ namespace Main
hostChange.setExtra(Common::Enums::CHANGE_HOST_SUCCESS);
broadcastToRoom(hostChange);
// Unmap original host
m_playerSessionIdToVecIdx.erase(originalHostSessionId);
// Leave match + room packets.
m_players[bestMsPlayerIdxInMatch].second->asyncWrite(removePlayerFromRoomServerRequest);
m_players[bestMsPlayerIdxInMatch].second->leaveRoom();
@ -276,6 +271,9 @@ namespace Main
+ ", idx of new host: " + std::to_string(bestMsIndexPlayerOutsideMatch),
Utils::LogType::Normal, "Room::removeHostFromMatch");
// Unmap original host
m_playerSessionIdToVecIdx.erase(originalHostSessionId);
// If a new match-host has been taken, notify whole room about it.
hostChange.setOption(bestMsIndexPlayerOutsideMatch);
hostChange.setExtra(Common::Enums::CHANGE_HOST_SUCCESS);
@ -310,59 +308,6 @@ namespace Main
return true;
}
}
else // If the host was alone in the whole room (e.g. SquareMode, AI, BossBattle, and none outside the match), remove it from the room and close it.
{
logger.log("The host is leaving and no other host can be picked up. Leaving the room and closing it...",
Utils::LogType::Normal, "Room::removeHostFromMatch");
m_players[0].second->asyncWrite(removePlayerFromRoomServerRequest);
m_players[0].second->leaveRoom();
m_players.clear();
for (auto& [unused, obsSession] : m_observerPlayers)
{
obsSession->asyncWrite(removePlayerFromRoomServerRequest);
obsSession->leaveRoom();
}
m_observerPlayers.clear();
m_hasMatchStarted = false;
logger.log(getRoomInfoAsString(), Utils::LogType::Normal, "Room::removeHostFromMatch");
return true;
}
}
bool Room::changeHostByNickname(const std::string& newHostNickname)
{
// find player index inside the room through to their nickname
std::uint32_t targetIndex = 0;
std::uint32_t currentIndex = 0;
std::uint32_t sessionId = 0;
for (const auto& [roomInfo, session] : m_players)
{
if (std::strncmp(roomInfo.playerName, newHostNickname.c_str(), sizeof(roomInfo.playerName)) == 0)
{
targetIndex = currentIndex;
sessionId = roomInfo.uniqueId.session;
break;
}
else
{
++currentIndex;
}
}
if (currentIndex >= m_players.size()) return false; // player with target nickname not found
if (changeHost(targetIndex))
{
Common::Network::Packet hostChange;
hostChange.setTcpHeader(sessionId, Common::Enums::USER_LARGE_ENCRYPTION);
hostChange.setOrder(124);
hostChange.setOption(targetIndex);
hostChange.setExtra(Common::Enums::CHANGE_HOST_SUCCESS);
broadcastToRoom(hostChange);
return true;
}
return false;
}
// Returns true if the room must be also be closed (e.g. due to host-switch errors, or because no other player is inside the room), false otherwise.
@ -374,6 +319,7 @@ namespace Main
removePlayerFromRoomServerRequest.setTcpHeader(session->getId(), Common::Enums::USER_LARGE_ENCRYPTION);
removePlayerFromRoomServerRequest.setOrder(137);
removePlayerFromRoomServerRequest.setExtra(extra);
std::uint32_t originalSessionId = session->getId();
auto playerIter = std::find_if(m_players.begin(), m_players.end(), [session](const auto& currentSession) { return currentSession.second == session; });
@ -431,6 +377,9 @@ namespace Main
Main::Handlers::notifyRoomPlayerLeaves(playerIter->second->getAccountInfo().uniqueId, *this);
m_players.erase(playerIter);
// unmap original host
m_playerSessionIdToVecIdx.erase(originalSessionId);
logger.log("Removed player from room. " + playerIter->second->getPlayerInfoAsString(),
Utils::LogType::Normal, "Room::removePlayer");
logger.log(getRoomInfoAsString(), Utils::LogType::Normal, "Room::removePlayer");
@ -449,6 +398,7 @@ namespace Main
observerIter->second->leaveRoom();
Main::Handlers::notifyRoomPlayerLeaves(observerIter->second->getAccountInfo().uniqueId, *this);
m_observerPlayers.erase(observerIter);
m_obsPlayerSessionIdToVecIdx.erase(originalSessionId);
}
return false;
}
@ -494,7 +444,6 @@ namespace Main
return m_settings;
}
// Specific setting is missing here!
Main::Structures::RoomJoin Room::getRoomJoinInfo() const
{
Main::Structures::RoomJoin roomJoinInfo;
@ -558,6 +507,8 @@ namespace Main
}
m_players.clear();
m_observerPlayers.clear();
m_obsPlayerSessionIdToVecIdx.clear();
m_playerSessionIdToVecIdx.clear();
}
// Broadcasts to whole room (room + match)
@ -570,8 +521,6 @@ namespace Main
}
}
void Room::broadcastToRoomExceptSelf(Common::Network::Packet& packet, const Main::Structures::UniqueId& uniqueId)
{
for (auto& currentPlayer : ranges::views::concat(m_players, m_observerPlayers))
@ -584,21 +533,17 @@ namespace Main
void Room::broadcastToTeamExceptSelf(Common::Network::Packet& packet, const Main::Structures::UniqueId& uniqueId, bool checkInsideMatch)
{
Common::Enums::Team targetTeam = Common::Enums::Team::TEAM_ALL;
for (const auto& [roomInfo, session] : m_players)
auto indexIter = m_playerSessionIdToVecIdx.find(uniqueId.session);
if (indexIter != m_playerSessionIdToVecIdx.end())
{
if (roomInfo.uniqueId == uniqueId)
Common::Enums::Team targetTeam = static_cast<Common::Enums::Team>(m_players[indexIter->second].first.team);
for (auto& [roomInfo, session] : m_players)
{
targetTeam = static_cast<Common::Enums::Team>(roomInfo.team);
break;
}
}
for (auto& [roomInfo, session] : m_players)
{
if (roomInfo.uniqueId != uniqueId && roomInfo.team == targetTeam && ((checkInsideMatch && session->isInMatch()) || (!checkInsideMatch && !session->isInMatch())))
{
packet.setTcpHeader(session->getSessionId(), Common::Enums::USER_LARGE_ENCRYPTION);
session->asyncWrite(packet);
if (roomInfo.uniqueId != uniqueId && roomInfo.team == targetTeam && ((checkInsideMatch && session->isInMatch()) || (!checkInsideMatch && !session->isInMatch())))
{
packet.setTcpHeader(session->getSessionId(), Common::Enums::USER_LARGE_ENCRYPTION);
session->asyncWrite(packet);
}
}
}
}
@ -612,16 +557,18 @@ namespace Main
else
{
bool broadcastOnlyToObs = false;
auto indexIter = m_obsPlayerSessionIdToVecIdx.find(uniqueId.session);
if (indexIter != m_obsPlayerSessionIdToVecIdx.end())
{
// >= MOD grade messages are broadcast to whole room, even outside observer
if (m_observerPlayers[indexIter->second].second->getAccountInfo().playerGrade < Common::Enums::GRADE_MOD)
{
broadcastOnlyToObs = true;
}
}
for (auto& [roomInfo, session] : m_observerPlayers)
{
if (roomInfo.uniqueId == uniqueId)
{
if (session->getAccountInfo().playerGrade < Common::Enums::GRADE_MOD) // >= MOD grade messages are broadcast to whole room, even outside observer
{
broadcastOnlyToObs = true;
}
continue;
}
if (roomInfo.uniqueId == uniqueId) continue;
if (session->isInMatch())
{
packet.setTcpHeader(session->getSessionId(), Common::Enums::USER_LARGE_ENCRYPTION);
@ -680,23 +627,22 @@ namespace Main
// this is used by both (!) manual AND automatic host-changes
bool Room::changeHost(std::size_t newHostIdx)
{
Utils::Logger& logger = Utils::Logger::getInstance();
if (newHostIdx >= m_players.size())
{
logger.log("The newHostIdx is not found inside m_players! (newHostIdx: " + std::to_string(newHostIdx) + ", m_players.size(): " + std::to_string(m_players.size()),
Utils::LogType::Normal, "Room::changeHost");
return false;
}
std::swap(m_players[0], m_players[newHostIdx]);
m_playerSessionIdToVecIdx[m_players[0].second->getId()] = 0; // map the new host
m_playerSessionIdToVecIdx[m_players[newHostIdx].second->getId()] = newHostIdx;
return true;
}
Main::Network::Session* Room::getPlayer(const Main::Structures::UniqueId& uniqueId)
{
for (auto& [roomInfo, session] : m_players)
auto indexIter = m_playerSessionIdToVecIdx.find(uniqueId.session);
if (indexIter != m_playerSessionIdToVecIdx.end())
{
if (roomInfo.uniqueId == uniqueId) return session;
return m_players[indexIter->second].second;
}
return nullptr;
}
@ -717,69 +663,61 @@ namespace Main
}
// Returns new team for this player, to notify the client. Nullopt for failure.
std::optional<std::uint32_t> Room::changePlayerTeam(const Main::Structures::UniqueId& uniqueId, std::uint32_t newTeam)
{
Utils::Logger& logger = Utils::Logger::getInstance();
for (auto it = m_players.begin(); it != m_players.end(); ++it)
std::optional<std::uint32_t> Room::changePlayerTeam(const Main::Structures::UniqueId& uniqueId, std::uint32_t newTeam) {
auto playerIt = m_playerSessionIdToVecIdx.find(uniqueId.session);
if (playerIt != m_playerSessionIdToVecIdx.end())
{
if (it->first.uniqueId == uniqueId)
auto index = playerIt->second;
if (newTeam == Common::Enums::TEAM_OBSERVER)
{
if (newTeam == Common::Enums::TEAM_OBSERVER)
{
if (m_observerPlayers.size() >= 10) return std::nullopt;
auto playerInfo = std::move(*it);
playerInfo.first.team = Common::Enums::TEAM_OBSERVER;
m_observerPlayers.push_back(std::move(playerInfo));
m_players.erase(it);
if (m_observerPlayers.size() >= 10) return std::nullopt;
auto playerInfo = std::move(m_players[index]);
playerInfo.first.team = Common::Enums::TEAM_OBSERVER;
m_observerPlayers.push_back(std::move(playerInfo));
m_players.erase(m_players.begin() + index);
m_playerSessionIdToVecIdx.erase(uniqueId.session);
m_obsPlayerSessionIdToVecIdx[uniqueId.session] = m_observerPlayers.size() - 1;
}
else if (newTeam == Common::Enums::TEAM_ZOMBIE)
{
m_players[index].first.team = newTeam;
}
else
{
m_players[index].first.team = m_players[index].first.team == Common::Enums::TEAM_BLUE ? Common::Enums::TEAM_RED : Common::Enums::TEAM_BLUE;
}
return newTeam;
}
logger.log("The player " + playerInfo.second->getPlayerInfoAsString() + " changed team from Player to Observer",
Utils::LogType::Normal, "Room::switchPlayerTeam");
}
else if (newTeam == Common::Enums::TEAM_ZOMBIE)
auto observerIt = m_obsPlayerSessionIdToVecIdx.find(uniqueId.session);
if (observerIt != m_obsPlayerSessionIdToVecIdx.end())
{
auto index = observerIt->second;
if (newTeam == Common::Enums::TEAM_ALL || newTeam == Common::Enums::TEAM_RED || newTeam == Common::Enums::TEAM_BLUE)
{
if (m_players.size() >= m_settings.playersPerTeam * 2)
{
it->first.team = newTeam;
return std::nullopt;
}
else
else if (isModeTeamBased())
{
it->first.team = it->first.team == Common::Enums::TEAM_BLUE ? Common::Enums::TEAM_RED : Common::Enums::TEAM_BLUE;
m_observerPlayers[index].first.team = calculateNewPlayerTeam();
}
logger.log("The player " + it->second->getPlayerInfoAsString() + " changed team to: " + std::to_string(it->first.team),
Utils::LogType::Normal, "Room::switchPlayerTeam");
else
{
m_observerPlayers[index].first.team = Common::Enums::TEAM_ALL;
}
auto playerInfo = std::move(m_observerPlayers[index]);
std::uint32_t newTeam = playerInfo.first.team;
m_players.push_back(std::move(playerInfo));
m_observerPlayers.erase(m_observerPlayers.begin() + index);
m_obsPlayerSessionIdToVecIdx.erase(uniqueId.session);
m_playerSessionIdToVecIdx[uniqueId.session] = m_players.size() - 1;
return newTeam;
}
return std::nullopt; // Observer player cannot change to another team other than the first if...
}
for (auto it = m_observerPlayers.begin(); it != m_observerPlayers.end(); ++it)
{
if (it->first.uniqueId == uniqueId)
{
if (newTeam == Common::Enums::TEAM_ALL || newTeam == Common::Enums::TEAM_RED || newTeam == Common::Enums::TEAM_BLUE)
{
if (m_players.size() >= m_settings.playersPerTeam * 2)
{
logger.log("Could not switch from ObserverTeam => PlayerTeam because there are too many players in the room",
Utils::LogType::Warning, "Room::switchPlayerTeam");
return std::nullopt;
}
else if (isModeTeamBased())
{
it->first.team = calculateNewPlayerTeam();
}
else
{
it->first.team = Common::Enums::TEAM_ALL;
}
auto playerInfo = std::move(*it);
std::uint32_t newTeam = playerInfo.first.team;
m_players.push_back(std::move(playerInfo));
m_observerPlayers.erase(it);
return newTeam;
}
return std::nullopt; // Makes no sense: observer player cannot change to another team other than the first if...
}
}
return std::nullopt;
}
bool Room::isModeTeamBased() const
@ -793,16 +731,10 @@ namespace Main
// Called when non-team-based mode changed to team-based-mode, and thus all teams go from '0' to either '1' or '2'.
void Room::updatePlayersTeamToTeamBased()
{
Utils::Logger& logger = Utils::Logger::getInstance();
for (std::size_t i = 0; auto& [roomPlayerInfo, session] : m_players)
{
roomPlayerInfo.team = (i % 2 == 0) ? Common::Enums::TEAM_BLUE : Common::Enums::TEAM_RED;
++i;
logger.log(std::string(session->getAccountInfo().nickname) + " new team: " +
(roomPlayerInfo.team == Common::Enums::TEAM_BLUE ? "TEAM_BLUE" : "TEAM_RED"),
::Utils::LogType::Info, "Room::updatePlayersTeam");
}
}
@ -824,10 +756,6 @@ namespace Main
if (playerInfo.team == Common::Enums::Team::TEAM_BLUE) ++totalBlueTeam;
else if (playerInfo.team == Common::Enums::Team::TEAM_RED) ++totalRedTeam;
}
Utils::Logger& logger = Utils::Logger::getInstance();
logger.log("Total BLUE team: " + std::to_string(totalBlueTeam) + ", Total RED team: " + std::to_string(totalRedTeam),
Utils::LogType::Normal, "Room::calculateNewPlayerTeam");
if (totalRedTeam >= totalBlueTeam) return Common::Enums::TEAM_BLUE;
return Common::Enums::TEAM_RED;
}
@ -854,43 +782,36 @@ namespace Main
return static_cast<std::uint32_t>(m_players.size()) >= maxPossiblePlayers;
}
void Room::setStateFor(const Main::Structures::UniqueId& uniqueId, const Common::Enums::PlayerState& playerState)
void Room::setStateFor(const Main::Structures::UniqueId& uniqueId, const Common::Enums::PlayerState& playerState)
{
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
auto playerIt = m_playerSessionIdToVecIdx.find(uniqueId.session);
if (playerIt != m_playerSessionIdToVecIdx.end())
{
if (roomInfo.uniqueId == uniqueId)
{
roomInfo.state = playerState;
session->setPlayerState(playerState);
auto index = playerIt->second;
m_players[index].first.state = playerState;
m_players[index].second->setPlayerState(playerState);
}
return;
}
auto observerIt = m_obsPlayerSessionIdToVecIdx.find(uniqueId.session);
if (observerIt != m_obsPlayerSessionIdToVecIdx.end())
{
auto index = observerIt->second;
m_observerPlayers[index].first.state = playerState;
m_observerPlayers[index].second->setPlayerState(playerState);
}
}
void Room::startMatch(const Main::Structures::UniqueId& uniqueId)
{
auto allPlayers = ranges::views::concat(m_players, m_observerPlayers);
if (m_hasMatchStarted)
{
for (auto& [roomInfo, session] : allPlayers)
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
{
if (roomInfo.uniqueId == uniqueId)
{
roomInfo.state = 2;
session->setIsInMatch(true);
Common::Network::Packet response;
response.setTcpHeader(session->getId(), Common::Enums::USER_LARGE_ENCRYPTION);
/*
response.setOrder(312);
response.setOption(2);
response.setData(reinterpret_cast<std::uint8_t*>(&roomInfo.uniqueId), sizeof(uniqueId));
session->asyncWrite(response);
Main::Details::sendPlayerState(*session, uniqueId);
setStateFor(uniqueId, static_cast<Common::Enums::PlayerState>(2));
*/
session->setIsInMatch(true);
return;
}
}
@ -899,12 +820,12 @@ namespace Main
{
m_players[0].first.state = Common::Enums::STATE_PLAYING;
m_players[0].second->setIsInMatch(true);
for (auto& [roomInfo, session] : allPlayers)
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
{
if (roomInfo.state == Common::Enums::STATE_READY)
{
roomInfo.state = 2;
Main::Details::sendPlayerState(*session, uniqueId);
setStateFor(uniqueId, static_cast<Common::Enums::PlayerState>(2));
session->setIsInMatch(true);
}
}
@ -992,7 +913,6 @@ namespace Main
{
m_settings.hasPassword = true;
}
std::cout << "Password set: " << newPassword << '\n';
m_password = newPassword;
}
@ -1009,13 +929,17 @@ namespace Main
void Room::sendTo(const Main::Structures::UniqueId& uniqueId, const Common::Network::Packet& packet)
{
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
auto playerIter = m_playerSessionIdToVecIdx.find(uniqueId.session);
if (playerIter != m_playerSessionIdToVecIdx.end())
{
if (roomInfo.uniqueId == uniqueId)
{
session->asyncWrite(packet);
return;
}
m_players[playerIter->second].second->asyncWrite(packet);
return;
}
auto observerIter = m_obsPlayerSessionIdToVecIdx.find(uniqueId.session);
if (observerIter != m_obsPlayerSessionIdToVecIdx.end())
{
m_observerPlayers[observerIter->second].second->asyncWrite(packet);
}
}
@ -1026,7 +950,6 @@ namespace Main
{
if (roomInfo.uniqueId == uniqueId)
{
std::cout << "storeEndMatchStatsFor: UniqueID found\n";
Main::Enums::MatchEnd matchEnd;
if (redScore == blueScore)
{
@ -1049,12 +972,16 @@ namespace Main
Main::Network::Session::AccountInfo Room::getAccountInfoFor(const Main::Structures::UniqueId& uniqueId) const
{
for (auto& [roomInfo, session] : ranges::views::concat(m_players, m_observerPlayers))
auto playerIter = m_playerSessionIdToVecIdx.find(uniqueId.session);
if (playerIter != m_playerSessionIdToVecIdx.end())
{
if (roomInfo.uniqueId == uniqueId)
{
return session->getAccountInfo();
}
return m_players[playerIter->second].second->getAccountInfo();
}
auto observerIter = m_obsPlayerSessionIdToVecIdx.find(uniqueId.session);
if (observerIter != m_obsPlayerSessionIdToVecIdx.end())
{
return m_observerPlayers[observerIter->second].second->getAccountInfo();
}
}
}

View file

@ -13,13 +13,12 @@ namespace Main
m_roomByNumber.emplace(room.getRoomNumber(), room);
}
void RoomsManager::removeRoom(std::uint16_t roomNum)
void RoomsManager::removeRoom(std::uint16_t roomNum)
{
if (m_roomByNumber.contains(roomNum))
{
m_roomByNumber[roomNum].removeAllPlayers();
m_roomByNumber.erase(roomNum);
}
auto it = m_roomByNumber.find(roomNum);
if (it == m_roomByNumber.end()) return;
it->second.removeAllPlayers();
m_roomByNumber.erase(it);
}
std::size_t RoomsManager::getTotalRooms() const
@ -30,6 +29,7 @@ namespace Main
std::vector<Main::Structures::SingleRoom> RoomsManager::getRoomsList() const
{
std::vector<Main::Structures::SingleRoom> roomsList;
roomsList.reserve(m_roomByNumber.size());
for (const auto& [roomNumber, room] : m_roomByNumber)
{
roomsList.push_back(room.getRoomInfo());
@ -37,41 +37,43 @@ namespace Main
return roomsList;
}
std::optional<std::reference_wrapper<Main::Classes::Room>> RoomsManager::getRoomByNumber(std::uint16_t roomNumber)
Main::Classes::Room* RoomsManager::getRoomByNumber(std::uint16_t roomNumber)
{
if (m_roomByNumber.contains(roomNumber))
auto it = m_roomByNumber.find(roomNumber);
if (it != m_roomByNumber.end())
{
return std::ref(m_roomByNumber[roomNumber]);
return &it->second;
}
return std::nullopt;
return nullptr;
}
void RoomsManager::broadcastToRoom(std::uint16_t roomNumber, Common::Network::Packet& packet)
{
if (!m_roomByNumber.contains(roomNumber)) return;
auto& room = m_roomByNumber[roomNumber];
room.broadcastToRoom(packet);
auto it = m_roomByNumber.find(roomNumber);
if (it == m_roomByNumber.end()) return;
it->second.broadcastToRoom(packet);
}
void RoomsManager::broadcastToRoomExceptSelf(std::uint16_t roomNumber, const Main::Structures::UniqueId& selfUniqueId, Common::Network::Packet& packet)
{
if (!m_roomByNumber.contains(roomNumber)) return;
auto& room = m_roomByNumber[roomNumber];
room.broadcastToRoomExceptSelf(packet, selfUniqueId);
auto it = m_roomByNumber.find(roomNumber);
if (it == m_roomByNumber.end()) return;
it->second.broadcastToRoomExceptSelf(packet, selfUniqueId);
}
void RoomsManager::broadcastToMatchExceptSelf(std::uint16_t roomNumber, const Main::Structures::UniqueId& selfUniqueId, Common::Network::Packet& packet, std::uint32_t extra)
{
if (!m_roomByNumber.contains(roomNumber)) return;
auto& room = m_roomByNumber[roomNumber];
room.broadcastToMatchExceptSelf(packet, selfUniqueId, extra);
auto it = m_roomByNumber.find(roomNumber);
if (it == m_roomByNumber.end()) return;
it->second.broadcastToMatchExceptSelf(packet, selfUniqueId, extra);
}
void RoomsManager::broadcastOutsideMatchExceptSelf(std::uint16_t roomNumber, const Main::Structures::UniqueId& selfUniqueId, Common::Network::Packet& packet, std::uint32_t extra)
{
if (!m_roomByNumber.contains(roomNumber)) return;
auto& room = m_roomByNumber[roomNumber];
room.broadcastOutsideMatchExceptSelf(packet, selfUniqueId, extra);
auto it = m_roomByNumber.find(roomNumber);
if (it == m_roomByNumber.end()) return;
it->second.broadcastOutsideMatchExceptSelf(packet, selfUniqueId, extra);
}
};
}

View file

@ -67,15 +67,16 @@ namespace Main
Common::Network::Session::addCallback<Main::Network::Session>(52, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handlePlayerBlock(request, session, m_sessionsManager, m_database); });
Common::Network::Session::addCallback<Main::Network::Session>(53, Main::Handlers::handlePlayerUnblock);
Main::Network::Session& session) { Main::Handlers::handlePlayerBlock(request, session, m_sessionsManager, m_database, Details::parseData<std::array<char, 16>>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(53, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handlePlayerUnblock(request, session, Details::parseData<std::uint32_t>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(54, Main::Handlers::handleBlockedPlayerList);
Common::Network::Session::addCallback<Main::Network::Session>(57, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleLobbyClanList(request, session, m_sessionsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(61, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleGeneralFriendRequests(request, session, m_sessionsManager, m_database); });
Common::Network::Session::addCallback<Main::Network::Session>(62, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleFriendDeletion(request, session, m_sessionsManager); });
Main::Network::Session& session) { Main::Handlers::handleFriendDeletion(request, session, m_sessionsManager, Details::parseData<std::uint32_t>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(63, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleFriendList(request, session, m_sessionsManager, m_database); });
@ -85,28 +86,34 @@ namespace Main
Common::Network::Session::addCallback<Main::Network::Session>(68, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleInitialPlayerInfos(request, session, m_sessionsManager, m_database, m_timeSinceLastRestart, m_serverId); });
Common::Network::Session::addCallback<Main::Network::Session>(71, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handlePing(request, session, m_roomsManager, parseData<Main::ClientData::Ping>(request)); });
Main::Network::Session& session) { Main::Handlers::handlePing(request, session, m_roomsManager, Details::parseData<Main::ClientData::Ping>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(74, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleCharacterSelection(request, session, m_roomsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(84, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleLobbyUserList(request, session, m_sessionsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(85, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleLobbyAccountInfo(request, session, m_sessionsManager, m_serverId); });
Main::Network::Session& session) { Main::Handlers::handleLobbyAccountInfo(request, session, m_sessionsManager, m_serverId,
Details::parseData<Main::Structures::UniqueId>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(86, Main::Handlers::handleBoughtItem);
Common::Network::Session::addCallback<Main::Network::Session>(87, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleEquippedItemSwitch(request, session, m_roomsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(88, Main::Handlers::handleItemDelete);
Common::Network::Session::addCallback<Main::Network::Session>(88, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleItemDelete(request, session, Details::parseData<Main::Structures::ItemSerialInfo>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(89, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleBattery(request, session, m_roomsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(96, Main::Handlers::handleItemRefund);
Common::Network::Session::addCallback<Main::Network::Session>(97, Main::Handlers::handleItemUpgrade);
Main::Network::Session& session) { Main::Handlers::handleBattery(request, session, m_roomsManager, Details::parseData<Main::Structures::UniqueId>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(96, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleItemRefund(request, session, Details::parseData<Main::ClientData::ItemRefund>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(97, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleItemUpgrade(request, session, Details::parseData<Main::ClientData::ItemUpgrade>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(98, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleGeneralItem(request, session, m_database, m_boxes); });
Common::Network::Session::addCallback<Main::Network::Session>(99, Main::Handlers::handleMailboxDelete);
Main::Network::Session& session) { Main::Handlers::handleGeneralItem(request, session, m_database, m_boxes, Details::parseData<Main::Structures::ItemSerialInfo>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(99, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleMailboxDelete(request, session, Details::parseData<std::uint32_t>(request, 4)); });
Common::Network::Session::addCallback<Main::Network::Session>(100, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleMailboxCommunication(request, session, m_sessionsManager, m_database); });
Main::Network::Session& session) { Main::Handlers::handleMailboxCommunication(request, session, m_sessionsManager, m_database,
Details::parseData<Main::ClientData::MailboxMessage>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(101, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleReadMailbox(request, session, m_database); });
Main::Network::Session& session) { Main::Handlers::handleReadMailbox(request, session, m_database, Details::parseData<std::uint32_t>(request, 4)); });
Common::Network::Session::addCallback<Main::Network::Session>(102, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleMailboxDisplay(request, session, m_sessionsManager, m_database); });
Common::Network::Session::addCallback<Main::Network::Session>(103, [&](const Common::Network::Packet& request,
@ -138,11 +145,12 @@ namespace Main
Common::Network::Session::addCallback<Main::Network::Session>(131, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleSimpleRoomSetting<Main::Enums::SETTING_TIME>(request, session, m_roomsManager); }); // time
Common::Network::Session::addCallback<Main::Network::Session>(134, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleRoomCreation(request, session, m_roomsManager); });
Main::Network::Session& session) { Main::Handlers::handleRoomCreation(request, session, m_roomsManager, Details::parseData<Main::Structures::CompleteRoomInfo>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(136, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleRoomJoin(request, session, m_roomsManager); });
Main::Network::Session& session) { Main::Handlers::handleRoomJoin(request, session, m_roomsManager, Details::parseData<Main::ClientData::RoomInfo>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(137, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleRoomLeave(request, session, m_sessionsManager, m_roomsManager, m_serverId); });
Main::Network::Session& session) { Main::Handlers::handleRoomLeave(request, session, m_sessionsManager, m_roomsManager, m_serverId,
Details::parseData<Main::Structures::UniqueId>(request)); });
Common::Network::Session::addCallback<Main::Network::Session>(138, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleRoomsList(request, session, m_roomsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(154, [&](const Common::Network::Packet& request,
@ -153,6 +161,10 @@ namespace Main
Main::Network::Session& session) { Main::Handlers::handleLobbyChatMessage(request, session, m_sessionsManager, m_chatCommands, m_roomsManager, m_database); });
Common::Network::Session::addCallback<Main::Network::Session>(157, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleRoomChatMessage(request, session, m_sessionsManager, m_chatCommands, m_roomsManager, m_database); });
Common::Network::Session::addCallback<Main::Network::Session>(256, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleMatchLeave(request, session, m_sessionsManager, m_roomsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(259, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleEliminationNextRound(request, session, m_roomsManager); });
/*
Common::Network::Session::addCallback<Main::Network::Session>(202, [&](const Common::Network::Packet& request,
@ -160,14 +172,8 @@ namespace Main
Common::Network::Session::addCallback<Main::Network::Session>(232, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleMapEvents(request, session, m_database); });
*/
Common::Network::Session::addCallback<Main::Network::Session>(256, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleMatchLeave(request, session, m_sessionsManager, m_roomsManager); });
Common::Network::Session::addCallback<Main::Network::Session>(259, [&](const Common::Network::Packet& request,
Main::Network::Session& session) { Main::Handlers::handleEliminationNextRound(request, session, m_roomsManager); });
*/
// These 2 following handlers must be fully implemented still. Also check whether they're related to Bomb Battle (for host side)!
// Also requires to be refactored
Common::Network::Session::addCallback<Main::Network::Session>(156, [&](const Common::Network::Packet& request,

View file

@ -309,13 +309,6 @@ namespace Main
m_player.getAccountID(), mp, Main::Enums::ItemCurrencyType::ITEM_MP);
}
void Session::setAccountCoins(std::uint16_t coins)
{
m_player.setAccountCoins(coins);
m_scheduler.addCallback(m_player.getAccountID(), 3, &Main::Persistence::PersistentDatabase::updatePlayerCurrencyByType,
m_player.getAccountID(), coins, Main::Enums::ItemCurrencyType::ITEM_COIN);
}
void Session::setAccountLatestCharacterSelected(std::uint16_t latestCharacterSelected)
{
m_player.setAccountLatestCharacterSelected(latestCharacterSelected);
@ -344,7 +337,6 @@ namespace Main
return true;
}
void Session::addFriend(const Main::Structures::Friend& ffriend)
{
m_player.addOfflineFriend(ffriend);
@ -401,7 +393,6 @@ namespace Main
m_scheduler.addRepetitiveCallback(m_player.getAccountID(), &Main::Persistence::PersistentDatabase::removePlayerItem,
m_player.getAccountID(), static_cast<std::uint32_t>(itemSerialInfoToDelete.itemNumber));
}
std::cout << "Was removed? " << std::boolalpha << removed << '\n';
response.setExtra(removed ? 1 : 0);
asyncWrite(response);
return removed;
@ -421,7 +412,6 @@ namespace Main
Message message{ accountInfo.rockTotens, accountInfo.microPoints + mpToAdd };
response.setData(reinterpret_cast<std::uint8_t*>(&message), sizeof(message));
asyncWrite(response);
setAccountMicroPoints(accountInfo.microPoints + mpToAdd);
}
@ -447,17 +437,11 @@ namespace Main
return m_player.getEquippedItemsSeparated();
}
void Session::setIsInLobby(bool val)
{
m_player.setIsInLobby(val);
}
bool Session::isInLobby() const
{
return m_player.isInLobby();
}
void Session::switchItemEquip(std::uint32_t characterId, std::uint64_t itemNumber)
{
if (!m_player.unequipItemIfEquipped(itemNumber, characterId, m_scheduler))
@ -570,10 +554,6 @@ namespace Main
void Session::setRoomNumber(std::uint16_t roomNumber)
{
if (roomNumber)
{
m_player.setIsInLobby(false);
}
m_player.setRoomNumber(roomNumber);
}
@ -594,7 +574,6 @@ namespace Main
void Session::setIsInMatch(bool val)
{
std::cout << "Set Is In Match set to: " << val << '\n';
m_player.setIsInMatch(val);
}
@ -610,7 +589,7 @@ namespace Main
void Session::sendBattery(std::uint32_t battery)
{
// currently does not work:
// todo: recheck whether this works
Common::Network::Packet response;
response.setTcpHeader(getId(), Common::Enums::USER_LARGE_ENCRYPTION);
response.setOrder(89);
@ -638,7 +617,6 @@ namespace Main
previousAccountInfo.totalKills += stats.totalKills;
previousAccountInfo.deaths += stats.deaths;
previousAccountInfo.headshots += stats.headshots;
//previousAccountInfo.assists += stats.assists;
previousAccountInfo.experience = stats.newTotalEXP;
previousAccountInfo.microPoints = stats.newTotalMP;
if (matchEnd == Main::Enums::MATCH_WON) previousAccountInfo.wins += 1;

View file

@ -28,22 +28,18 @@ namespace Main
targetFriendSession.second->updateFriendSession(m_sessionsBySessionId[sessionId], true);
}
// Reset room state
if (m_sessionsBySessionId[sessionId]->getRoomNumber())
if (Main::Classes::Room* room = roomsManager->getRoomByNumber(m_sessionsBySessionId[sessionId]->getRoomNumber()))
{
auto roomOpt = roomsManager->getRoomByNumber(m_sessionsBySessionId[sessionId]->getRoomNumber());
if (roomOpt == std::nullopt) return;
auto& room = roomOpt.value().get();
if (m_sessionsBySessionId[sessionId]->isInMatch())
{
// if host, remove host from both match + room. removeHostFromMatch does that.
if (room.isHost(m_sessionsBySessionId[sessionId]->getAccountInfo().uniqueId))
if (room->isHost(m_sessionsBySessionId[sessionId]->getAccountInfo().uniqueId))
{
// This will also remove the host from the Room + notify the room that the host left the room
bool roomMustBeClosed = room.removeHostFromMatch(); // Also notifies cast whether the room must be broken
bool roomMustBeClosed = room->removeHostFromMatch(); // Also notifies cast whether the room must be broken
if (roomMustBeClosed)
{
roomsManager->removeRoom(room.getRoomNumber());
roomsManager->removeRoom(room->getRoomNumber());
}
}
else
@ -56,19 +52,19 @@ namespace Main
response.setExtra(0);
auto uniqueId = m_sessionsBySessionId[sessionId]->getAccountInfo().uniqueId;
response.setData(reinterpret_cast<std::uint8_t*>(&uniqueId), sizeof(uniqueId));
room.broadcastToRoom(response);
room->broadcastToRoom(response);
m_sessionsBySessionId[sessionId]->setIsInMatch(false);
room.removePlayer(m_sessionsBySessionId[sessionId], 1);
room->removePlayer(m_sessionsBySessionId[sessionId], 1);
}
}
else
{
bool roomMustBeClosed = room.removePlayer(m_sessionsBySessionId[sessionId], 1); // 1 = extra = leave room normally
bool roomMustBeClosed = room->removePlayer(m_sessionsBySessionId[sessionId], 1); // 1 = extra = leave room normally
// nb. removePlayer does NOT notify cast that the room must be removed.
if (roomMustBeClosed)
{
roomsManager->removeRoom(room.getRoomNumber());
roomsManager->removeRoom(room->getRoomNumber());
}
}
m_sessionsBySessionId[sessionId]->leaveRoom();
@ -82,8 +78,6 @@ namespace Main
{
m_sessionsVector.erase(it);
}
}
}