diff --git a/docs/network-protocol.md b/docs/network-protocol.md index 45c4c285..d57bb43f 100644 --- a/docs/network-protocol.md +++ b/docs/network-protocol.md @@ -91,6 +91,8 @@ _This packet has no field._ | Player Z | double | Player Z coordinate | | Dimension | u16 | Dimension ID | | Username | std::string | Name of the player | +| Camera Yaw | float | Horizontal camera view angle | +| Camera Pitch | float | Vertical camera view angle | #### PlayerChangeDimension diff --git a/source/client/network/ClientCommandHandler.cpp b/source/client/network/ClientCommandHandler.cpp index b3e1bc2a..972eea69 100644 --- a/source/client/network/ClientCommandHandler.cpp +++ b/source/client/network/ClientCommandHandler.cpp @@ -231,12 +231,15 @@ void ClientCommandHandler::setupCallbacks() { gk::Vector3d pos; u16 dimension; std::string username; - packet >> clientId >> pos.x >> pos.y >> pos.z >> dimension >> username; + float cameraYaw, cameraPitch; + packet >> clientId >> pos.x >> pos.y >> pos.z >> dimension + >> username >> cameraYaw >> cameraPitch; if (clientId != m_client.id()) { m_playerBoxes.emplace(clientId, PlayerBox{m_player.camera()}); Player &player = m_playerBoxes.at(clientId); player.setPosition(pos.x, pos.y, pos.z); + player.setRotation(cameraYaw, cameraPitch); player.setDimension(dimension); player.setClientID(clientId); player.setName(username); @@ -244,6 +247,8 @@ void ClientCommandHandler::setupCallbacks() { } else { m_player.setPosition(pos.x, pos.y, pos.z); + m_player.setRotation(cameraYaw, cameraPitch); + m_player.updateCamera(); } }); diff --git a/source/client/world/ClientPlayer.cpp b/source/client/world/ClientPlayer.cpp index 7f1f7b95..b0d721ba 100644 --- a/source/client/world/ClientPlayer.cpp +++ b/source/client/world/ClientPlayer.cpp @@ -43,7 +43,7 @@ ClientPlayer::ClientPlayer(gk::Camera &camera) : m_camera(camera) { m_viewAngleV = 0.f; m_viewAngleRoll = 0.f; - updateDir(); + updateCamera(); m_camera.setDPosition(m_x + m_cameraLocalPos.x, m_y + m_cameraLocalPos.y, m_z + m_cameraLocalPos.z); } @@ -53,16 +53,16 @@ void ClientPlayer::turnH(float angle) { if (m_viewAngleH >= 180.f) m_viewAngleH -= 360.f; if (m_viewAngleH < -180.f) m_viewAngleH += 360.f; - updateDir(); + updateCamera(); } void ClientPlayer::turnViewV(float angle) { m_viewAngleV = std::max(std::min(m_viewAngleV + angle, 90.f), -90.f); - updateDir(); + updateCamera(); } -void ClientPlayer::updateDir() { +void ClientPlayer::updateCamera() { float ch = cosf(m_viewAngleH * RADIANS_PER_DEGREES); float sh = sinf(m_viewAngleH * RADIANS_PER_DEGREES); float cv = cosf(m_viewAngleV * RADIANS_PER_DEGREES); diff --git a/source/client/world/ClientPlayer.hpp b/source/client/world/ClientPlayer.hpp index e2d48746..9789881f 100644 --- a/source/client/world/ClientPlayer.hpp +++ b/source/client/world/ClientPlayer.hpp @@ -52,6 +52,8 @@ class ClientPlayer : public Player { void turnH(float angle); void turnViewV(float angle); + void updateCamera(); + void move(float direction); void processInputs(); @@ -67,13 +69,12 @@ class ClientPlayer : public Player { static void setInstance(ClientPlayer *instance) { s_instance = instance; } void setPosition(double x, double y, double z); - void setCameraRoll(float angle) { m_viewAngleRoll = angle; updateDir(); }; + void setCameraRoll(float angle) { m_viewAngleRoll = angle; updateCamera(); }; gk::Camera &camera() { return m_camera; } private: void testPoint(const ClientWorld &world, double x, double y, double z, glm::vec3 &vel); - void updateDir(); static ClientPlayer *s_instance; diff --git a/source/common/world/Player.cpp b/source/common/world/Player.cpp index 5760c086..0bf9e964 100644 --- a/source/common/world/Player.cpp +++ b/source/common/world/Player.cpp @@ -42,11 +42,11 @@ u8 Player::getOppositeDirection() const { } void Player::serialize(sf::Packet &packet) const { - packet << m_x << m_y << m_z << m_dimension << m_inventory << m_name; + packet << m_x << m_y << m_z << m_dimension << m_viewAngleH << m_viewAngleV << m_viewAngleRoll << m_inventory; } void Player::deserialize(sf::Packet &packet) { - packet >> m_x >> m_y >> m_z >> m_dimension >> m_inventory >> m_name; + packet >> m_x >> m_y >> m_z >> m_dimension >> m_viewAngleH >> m_viewAngleV >> m_viewAngleRoll >> m_inventory; } // Please update 'docs/lua-api-cpp.md' if you change this diff --git a/source/server/core/PlayerList.cpp b/source/server/core/PlayerList.cpp index d67bef2d..9985c832 100644 --- a/source/server/core/PlayerList.cpp +++ b/source/server/core/PlayerList.cpp @@ -26,30 +26,61 @@ */ #include "PlayerList.hpp" -ServerPlayer &PlayerList::addPlayer(ClientInfo &client) { - m_players.emplace(client.id, client); - return m_players.at(client.id); +ServerPlayer &PlayerList::addPlayer(const std::string &name, bool isNewPlayer) { + m_players.emplace(name, ServerPlayer{name, isNewPlayer}); + return m_players.at(name); } -void PlayerList::removePlayer(u16 id) { - auto it = m_players.find(id); - if (it != m_players.end()) - m_players.erase(it); +ServerPlayer &PlayerList::connectPlayer(const std::string &name, ClientInfo &client) { + ServerPlayer *player = nullptr; + auto it = m_players.find(name); + if (it != m_players.end()) { + player = &it->second; + gkInfo() << name << "is online"; + } + else { + player = &addPlayer(name, true); + gkInfo() << name << "is online (first connection)"; + } + + player->setClient(&client); + player->setClientID(client.id); + + client.playerName = name; + + return *player; } -const ServerPlayer *PlayerList::getPlayer(u16 id) const { - auto it = m_players.find(id); +void PlayerList::disconnectPlayer(const std::string &name) { + auto it = m_players.find(name); + if (it != m_players.end()) { + it->second.setClient(nullptr); + it->second.setNewPlayer(false); + } +} + +const ServerPlayer *PlayerList::getPlayer(const std::string &name) const { + auto it = m_players.find(name); if (it == m_players.end()) return nullptr; return &it->second; } -ServerPlayer *PlayerList::getPlayer(u16 id) { - auto it = m_players.find(id); +ServerPlayer *PlayerList::getPlayer(const std::string &name) { + auto it = m_players.find(name); if (it == m_players.end()) return nullptr; return &it->second; } +ServerPlayer *PlayerList::getPlayerFromClientID(u16 clientID) { + for (auto &it : m_players) { + if (it.second.clientID() == clientID) + return &it.second; + } + + return nullptr; +} + diff --git a/source/server/core/PlayerList.hpp b/source/server/core/PlayerList.hpp index 2dd9c9e2..8779a1d0 100644 --- a/source/server/core/PlayerList.hpp +++ b/source/server/core/PlayerList.hpp @@ -32,16 +32,19 @@ #include "ServerPlayer.hpp" class PlayerList { - using PlayerMap = std::unordered_map; + using PlayerMap = std::unordered_map; using Iterator = PlayerMap::iterator; using ConstIterator = PlayerMap::const_iterator; public: - ServerPlayer &addPlayer(ClientInfo &client); - void removePlayer(u16 id); + ServerPlayer &addPlayer(const std::string &name, bool isNewPlayer); + ServerPlayer &connectPlayer(const std::string &name, ClientInfo &client); + void disconnectPlayer(const std::string &name); - const ServerPlayer *getPlayer(u16 id) const; - ServerPlayer *getPlayer(u16 id); + const ServerPlayer *getPlayer(const std::string &name) const; + ServerPlayer *getPlayer(const std::string &name); + + ServerPlayer *getPlayerFromClientID(u16 clientID); Iterator begin() { return m_players.begin(); } Iterator end() { return m_players.end(); } @@ -49,6 +52,8 @@ class PlayerList { ConstIterator begin() const { return m_players.begin(); } ConstIterator end() const { return m_players.end(); } + std::size_t size() const { return m_players.size(); } + private: PlayerMap m_players; }; diff --git a/source/server/core/ServerApplication.cpp b/source/server/core/ServerApplication.cpp index 5782ce6e..fa5eb126 100644 --- a/source/server/core/ServerApplication.cpp +++ b/source/server/core/ServerApplication.cpp @@ -179,8 +179,10 @@ void ServerApplication::update() { if (m_clock.getTicks() % 100 < 10) { for (auto &it : m_players) { - m_serverCommandHandler.sendPlayerPosUpdate(it.first); - m_serverCommandHandler.sendPlayerRotUpdate(it.first); + if (it.second.isOnline()) { + m_serverCommandHandler.sendPlayerPosUpdate(it.second.clientID()); + m_serverCommandHandler.sendPlayerRotUpdate(it.second.clientID()); + } } } } diff --git a/source/server/lua/LuaMod.cpp b/source/server/lua/LuaMod.cpp index 935076c6..4d57a660 100644 --- a/source/server/lua/LuaMod.cpp +++ b/source/server/lua/LuaMod.cpp @@ -109,7 +109,7 @@ void LuaMod::despawnEntity(EntityWrapper &entity) { void LuaMod::giveItemStack(ServerPlayer &player, ItemStack *itemStack) { if (itemStack) { player.inventory().addStack(itemStack->item().stringID(), itemStack->amount()); - m_worldController.server()->sendPlayerInvUpdate(player.clientID(), &player.client()); + m_worldController.server()->sendPlayerInvUpdate(player.clientID(), player.client()); } else gkError() << "In mod '" + m_id + "': Failed to add stack to player"; diff --git a/source/server/network/ClientInfo.hpp b/source/server/network/ClientInfo.hpp index 543c1d98..4bf747c2 100644 --- a/source/server/network/ClientInfo.hpp +++ b/source/server/network/ClientInfo.hpp @@ -46,6 +46,8 @@ class ClientInfo { std::shared_ptr tcpSocket; NetworkInputHandler inputHandler; + + std::string playerName; }; #endif // CLIENTINFO_HPP_ diff --git a/source/server/network/ServerCommandHandler.cpp b/source/server/network/ServerCommandHandler.cpp index fa126563..0e0a86af 100644 --- a/source/server/network/ServerCommandHandler.cpp +++ b/source/server/network/ServerCommandHandler.cpp @@ -68,7 +68,7 @@ void ServerCommandHandler::sendBlockInvUpdate(s32 x, s32 y, s32 z, const Invento } void ServerCommandHandler::sendPlayerPosUpdate(u16 clientID, bool isTeleportation, const ClientInfo *client) const { - const ServerPlayer *player = m_players.getPlayer(clientID); + const ServerPlayer *player = m_players.getPlayerFromClientID(clientID); if (player) { Network::Packet packet; packet << Network::Command::PlayerPosUpdate; @@ -86,7 +86,7 @@ void ServerCommandHandler::sendPlayerPosUpdate(u16 clientID, bool isTeleportatio } void ServerCommandHandler::sendPlayerRotUpdate(u16 clientID, const ClientInfo *client) const { - const ServerPlayer *player = m_players.getPlayer(clientID); + const ServerPlayer *player = m_players.getPlayerFromClientID(clientID); if (player) { Network::Packet packet; packet << Network::Command::PlayerRotUpdate; @@ -103,7 +103,7 @@ void ServerCommandHandler::sendPlayerRotUpdate(u16 clientID, const ClientInfo *c } void ServerCommandHandler::sendPlayerInvUpdate(u16 clientID, const ClientInfo *client) const { - ServerPlayer *player = m_players.getPlayer(clientID); + ServerPlayer *player = m_players.getPlayerFromClientID(clientID); if (player) { Network::Packet packet; packet << Network::Command::PlayerInvUpdate; @@ -170,9 +170,9 @@ void ServerCommandHandler::setupCallbacks() { std::string username; connectionPacket >> username; - auto &player = m_players.addPlayer(client); - player.setPosition(m_spawnPosition.x, m_spawnPosition.y, m_spawnPosition.z); - player.setName(username); + auto &player = m_players.connectPlayer(username, client); + if (player.isNewPlayer()) + player.setPosition(m_spawnPosition.x, m_spawnPosition.y, m_spawnPosition.z); Network::Packet packet; packet << Network::Command::RegistryData; @@ -183,11 +183,13 @@ void ServerCommandHandler::setupCallbacks() { for (auto &it : m_players) { Network::Packet spawnPacket; spawnPacket << Network::Command::PlayerSpawn << it.first; - spawnPacket << it.second.x() << it.second.y() << it.second.z(); + spawnPacket << it.second.x() << it.second.y() << it.second.z() << it.second.dimension() << it.second.name(); + spawnPacket << it.second.cameraYaw() << it.second.cameraPitch(); client.tcpSocket->send(spawnPacket); } - m_scriptEngine.luaCore().onEvent(LuaEventType::PlayerConnected, glm::ivec3{m_spawnPosition.x, m_spawnPosition.y, m_spawnPosition.z}, player, client, *this); + if (player.isNewPlayer()) + m_scriptEngine.luaCore().onEvent(LuaEventType::PlayerConnected, glm::ivec3{player.x(), player.y(), player.z()}, player, client, *this); Network::Packet invPacket; invPacket << Network::Command::PlayerInvUpdate << client.id; @@ -198,6 +200,7 @@ void ServerCommandHandler::setupCallbacks() { Network::Packet spawnPacket; spawnPacket << Network::Command::PlayerSpawn << client.id; spawnPacket << player.x() << player.y() << player.z() << player.dimension() << player.name(); + spawnPacket << player.cameraYaw() << player.cameraPitch(); m_server.sendToAllClients(spawnPacket); // Send entities to the client @@ -205,7 +208,7 @@ void ServerCommandHandler::setupCallbacks() { }); m_server.setCommandCallback(Network::Command::ClientDisconnect, [this](ClientInfo &client, Network::Packet &) { - m_players.removePlayer(client.id); + m_players.disconnectPlayer(client.playerName); }); m_server.setCommandCallback(Network::Command::ChunkRequest, [this](ClientInfo &client, Network::Packet &packet) { @@ -216,7 +219,7 @@ void ServerCommandHandler::setupCallbacks() { }); m_server.setCommandCallback(Network::Command::PlayerInvUpdate, [this](ClientInfo &client, Network::Packet &packet) { - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { packet >> player->inventory(); } @@ -228,7 +231,7 @@ void ServerCommandHandler::setupCallbacks() { double x, y, z; packet >> x >> y >> z; - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { player->setPosition(x, y, z); } @@ -240,7 +243,7 @@ void ServerCommandHandler::setupCallbacks() { float yaw, pitch; packet >> yaw >> pitch; - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { player->setRotation(yaw, pitch); } @@ -249,7 +252,7 @@ void ServerCommandHandler::setupCallbacks() { }); m_server.setCommandCallback(Network::Command::PlayerPlaceBlock, [this](ClientInfo &client, Network::Packet &packet) { - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { s32 x, y, z; u32 block; @@ -271,7 +274,7 @@ void ServerCommandHandler::setupCallbacks() { }); m_server.setCommandCallback(Network::Command::PlayerDigBlock, [this](ClientInfo &client, Network::Packet &packet) { - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { s32 x, y, z; packet >> x >> y >> z; @@ -291,7 +294,7 @@ void ServerCommandHandler::setupCallbacks() { }); m_server.setCommandCallback(Network::Command::PlayerHeldItemChanged, [this](ClientInfo &client, Network::Packet &packet) { - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { u8 hotbarSlot; u16 itemID; @@ -306,7 +309,7 @@ void ServerCommandHandler::setupCallbacks() { }); m_server.setCommandCallback(Network::Command::BlockActivated, [this](ClientInfo &client, Network::Packet &packet) { - ServerPlayer *player = m_players.getPlayer(client.id); + ServerPlayer *player = m_players.getPlayerFromClientID(client.id); if (player) { s32 x, y, z; u16 screenWidth, screenHeight; @@ -372,7 +375,7 @@ void ServerCommandHandler::setupCallbacks() { } void ServerCommandHandler::setPlayerPosition(u16 clientID, s32 x, s32 y, s32 z) { - ServerPlayer *player = m_players.getPlayer(clientID); + ServerPlayer *player = m_players.getPlayerFromClientID(clientID); if (player) player->setPosition(x, y, z); else @@ -380,7 +383,7 @@ void ServerCommandHandler::setPlayerPosition(u16 clientID, s32 x, s32 y, s32 z) } inline ServerWorld &ServerCommandHandler::getWorldForClient(u16 clientID) { - ServerPlayer *player = m_players.getPlayer(clientID); + ServerPlayer *player = m_players.getPlayerFromClientID(clientID); if (!player) throw EXCEPTION("Player instance not found for client", clientID); diff --git a/source/server/world/ServerPlayer.cpp b/source/server/world/ServerPlayer.cpp index 9f8f4cab..662a7b65 100644 --- a/source/server/world/ServerPlayer.cpp +++ b/source/server/world/ServerPlayer.cpp @@ -26,10 +26,6 @@ */ #include "ServerPlayer.hpp" -ServerPlayer::ServerPlayer(ClientInfo &client) : m_client(client) { - m_clientID = client.id; -} - // Please update 'docs/lua-api-cpp.md' if you change this void ServerPlayer::initUsertype(sol::state &lua) { lua.new_usertype("ServerPlayer", diff --git a/source/server/world/ServerPlayer.hpp b/source/server/world/ServerPlayer.hpp index 8971003d..3bc57f0c 100644 --- a/source/server/world/ServerPlayer.hpp +++ b/source/server/world/ServerPlayer.hpp @@ -34,24 +34,30 @@ class ServerPlayer : public Player { public: - ServerPlayer(ClientInfo &client); + ServerPlayer(const std::string &name, bool isNewPlayer) { + m_name = name; + m_isNewPlayer = isNewPlayer; + } - const ClientInfo &client() const { return m_client; } + const ClientInfo *client() const { return m_client; } + void setClient(ClientInfo *client) { m_client = client; } const ItemStack &heldItemStack() { return m_inventory.getStack(m_heldItemSlot, 0); } void setHeldItemSlot(u8 heldItemSlot) { m_heldItemSlot = heldItemSlot; } - bool isOnline() const { return m_isOnline; } - void setOnline(bool isOnline) { m_isOnline = isOnline; } + bool isOnline() const { return m_client != nullptr; } + bool isNewPlayer() const { return m_isNewPlayer; } + void setNewPlayer(bool isNewPlayer) { m_isNewPlayer = isNewPlayer; } static void initUsertype(sol::state &lua); private: - ClientInfo &m_client; + ClientInfo *m_client = nullptr; u8 m_heldItemSlot = 0; bool m_isOnline = false; + bool m_isNewPlayer = false; }; #endif // SERVERPLAYER_HPP_ diff --git a/source/server/world/ServerWorld.cpp b/source/server/world/ServerWorld.cpp index ece04271..7492119c 100644 --- a/source/server/world/ServerWorld.cpp +++ b/source/server/world/ServerWorld.cpp @@ -48,7 +48,7 @@ void ServerWorld::update() { if (it.second->isInitialized() && !it.second->isSent()) { for (auto &client : m_server->server().info().clients()) - if (m_players.getPlayer(client.id)->dimension() == m_dimension.id()) + if (m_players.getPlayer(client.playerName)->dimension() == m_dimension.id()) sendChunkData(client, *it.second.get()); // gkDebug() << "Chunk updated at" << it.second->x() << it.second->y() << it.second->z(); diff --git a/source/server/world/WorldController.cpp b/source/server/world/WorldController.cpp index 8ee6b937..e378da21 100644 --- a/source/server/world/WorldController.cpp +++ b/source/server/world/WorldController.cpp @@ -34,7 +34,7 @@ void WorldController::init(PlayerList &players) { m_worldList.back().setServer(m_server); } - m_worldSaveBackend.reset(new WorldSaveBasicBackend{m_worldList}); + m_worldSaveBackend.reset(new WorldSaveBasicBackend{m_worldList, players}); } void WorldController::clearEntities() { diff --git a/source/server/world/save/WorldSaveBasicBackend.cpp b/source/server/world/save/WorldSaveBasicBackend.cpp index f7d4a35e..a1f6f34f 100644 --- a/source/server/world/save/WorldSaveBasicBackend.cpp +++ b/source/server/world/save/WorldSaveBasicBackend.cpp @@ -101,6 +101,16 @@ void WorldSaveBasicBackend::load(const std::string &name) { loadEntities(save, world); } + + u16 playerCount; + save >> playerCount; + for (u16 i = 0 ; i < playerCount ; ++i) { + std::string username; + save >> username; + + auto &player = m_playerList.addPlayer(username, false); + player.deserialize(save); + } } // gkInfo() << "Loading done."; @@ -150,6 +160,13 @@ void WorldSaveBasicBackend::save(const std::string &name) { saveEntities(save, world); } + save << (u16)m_playerList.size(); + + for (auto &it : m_playerList) { + save << it.second.name(); + save << it.second; + } + file.write((const char *)save.getData(), save.getDataSize()); // gkInfo() << "Saving done."; diff --git a/source/server/world/save/WorldSaveBasicBackend.hpp b/source/server/world/save/WorldSaveBasicBackend.hpp index b10f5acd..99684e30 100644 --- a/source/server/world/save/WorldSaveBasicBackend.hpp +++ b/source/server/world/save/WorldSaveBasicBackend.hpp @@ -32,6 +32,7 @@ #include +#include "PlayerList.hpp" #include "WorldSaveBackend.hpp" namespace sf { class Packet; } @@ -40,8 +41,8 @@ class ServerWorld; class WorldSaveBasicBackend : public WorldSaveBackend { public: - WorldSaveBasicBackend(std::deque &worldList) - : m_worldList(worldList) {} + WorldSaveBasicBackend(std::deque &worldList, PlayerList &playerList) + : m_worldList(worldList), m_playerList(playerList) {} void load(const std::string &worldName) override; void save(const std::string &worldName) override; @@ -52,6 +53,8 @@ class WorldSaveBasicBackend : public WorldSaveBackend { std::deque &m_worldList; + PlayerList &m_playerList; + std::unordered_map m_entityMap; };