diff --git a/Flakkari/Engine/EntityComponentSystem/Factory.cpp b/Flakkari/Engine/EntityComponentSystem/Factory.cpp index 25af87f4..522a80a9 100644 --- a/Flakkari/Engine/EntityComponentSystem/Factory.cpp +++ b/Flakkari/Engine/EntityComponentSystem/Factory.cpp @@ -182,7 +182,7 @@ void RegistryEntityByTemplate(Registry ®istry, Entity entity, const nl_templa Engine::Math::Vector3f(componentContent["position"]["x"], componentContent["position"]["y"], componentContent["position"]["z"]); transform._rotation = - Engine::Math::Vector3f(componentContent["rotation"]["x"], componentContent["rotation"]["y"], + Engine::Math::Vector3d(componentContent["rotation"]["x"], componentContent["rotation"]["y"], componentContent["rotation"]["z"]); transform._scale = Engine::Math::Vector3f(componentContent["scale"]["x"], componentContent["scale"]["y"], componentContent["scale"]["z"]); diff --git a/Flakkari/Engine/Math/Vector.hpp b/Flakkari/Engine/Math/Vector.hpp index 1dcea0d0..dae10750 100644 --- a/Flakkari/Engine/Math/Vector.hpp +++ b/Flakkari/Engine/Math/Vector.hpp @@ -82,6 +82,12 @@ template struct Vector { return Vector(v[0] * other.v[0], v[1] * other.v[1], v[2] * other.v[2], v[3] * other.v[3]); } + Vector multiplyWithFloatVector(const Vector &other) const + { + return Vector((float) v[0] * other.v[0], (float) v[1] * other.v[1], (float) v[2] * other.v[2], + (float) v[3] * other.v[3]); + } + Vector operator/(const Vector &other) const { return Vector(v[0] / other.v[0], v[1] / other.v[1], v[2] / other.v[2], v[3] / other.v[3]); @@ -193,9 +199,7 @@ template struct Vector { Type operator[](const int &index) const { return v[index]; } - Type length() const { return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]); } - - Type lengthSquared() const { return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; } + Type length() const { return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } Vector &normalize() { @@ -205,7 +209,6 @@ template struct Vector { v[0] /= len; v[1] /= len; v[2] /= len; - v[3] /= len; return *this; } @@ -214,7 +217,7 @@ template struct Vector { Type len = length(); if (len == 0) return *this; - return Vector(v[0] / len, v[1] / len, v[2] / len, v[3] / len); + return Vector(v[0] / len, v[1] / len, v[2] / len); } Type dot(const Vector &other) const @@ -307,19 +310,28 @@ template struct Vector { v[1] = y; } - void rotate(const Vector &axis, double angleRadians) + void quaternionRotate(Type x, Type y, Type z, Type w) { - Type c = cos(angleRadians); - Type s = sin(angleRadians); - Type x = v[0] * (c + axis.x * axis.x * (1 - c)) + v[1] * (axis.x * axis.y * (1 - c) - axis.z * s) + - v[2] * (axis.x * axis.z * (1 - c) + axis.y * s); - Type y = v[0] * (axis.y * axis.x * (1 - c) + axis.z * s) + v[1] * (c + axis.y * axis.y * (1 - c)) + - v[2] * (axis.y * axis.z * (1 - c) - axis.x * s); - Type z = v[0] * (axis.z * axis.x * (1 - c) - axis.y * s) + v[1] * (axis.z * axis.y * (1 - c) + axis.x * s) + - v[2] * (c + axis.z * axis.z * (1 - c)); - v[0] = x; - v[1] = y; - v[2] = z; + v[0] = v[3] * x + v[0] * w + v[1] * z - v[2] * y; + v[1] = v[3] * y - v[0] * z + v[1] * w + v[2] * x; + v[2] = v[3] * z + v[0] * y - v[1] * x + v[2] * w; + v[3] = v[3] * w - v[0] * x - v[1] * y - v[2] * z; + } + + /** + * @brief Rotate the vector around an axis by an angle in radians. + * + * @param axis The axis to rotate around. + * @param angleRadians The angle in radians. + */ + void rotate(const Vector &axis, float angleDegrees) + { + double _pi = 3.14159265358979323846; + double angleRadians = (angleDegrees * _pi / 180) / 2.0; + double sinHalfAngle = sin(angleRadians); + auto normalizedAxis = axis.normalized(); + quaternionRotate(normalizedAxis.v[0] * sinHalfAngle, normalizedAxis.v[1] * sinHalfAngle, + normalizedAxis.v[2] * sinHalfAngle, cos(angleRadians)); } }; @@ -335,7 +347,7 @@ using Vector4f = Vector; using Vector4d = Vector; using Vector4i = Vector; using Vector4u = Vector; -using Quaternion = Vector4f; +using Quaternion = Vector4d; using Color = Vector4f; template std::ostream &operator<<(std::ostream &os, const Vector &vector); diff --git a/Flakkari/Protocol/Commands.hpp b/Flakkari/Protocol/Commands.hpp index d0a1f358..553dddc2 100644 --- a/Flakkari/Protocol/Commands.hpp +++ b/Flakkari/Protocol/Commands.hpp @@ -195,10 +195,8 @@ enum class CommandId : uint8_t { REQ_ENTITY_SHOOT = 28, // Server -> Client [Shoot entity]: (id)(component (position, rotation, velocity, etc)) REP_ENTITY_SHOOT = 29, // Client -> Server [Entity shot]: () // 30 - 39: User - REQ_USER_UPDATE = 30, // Client -> Server [Update user]: (event_id, state) - REP_USER_UPDATE = 31, // Server -> Client [User updated]: () - REQ_USER_UPDATES = 32, // Client -> Server [Update user multi-events]: (event_id, state|event_id, float) - REP_USER_UPDATES = 33, // Server -> Client [User updated]: () + REQ_USER_UPDATES = 30, // Client -> Server [Update user multi-events]: (event_id, state|event_id, float) + REP_USER_UPDATES = 31, // Server -> Client [User updated]: () // 40 - 49: Chat // 50 - 59: Matchmaking REQ_CREATE_ROOM = 50, // Client -> Server [Create room]: (user_id) @@ -244,8 +242,6 @@ class Commands final { case CommandId::REP_ENTITY_MOVED: return "REP_ENTITY_MOVED"; case CommandId::REQ_ENTITY_SHOOT: return "REQ_ENTITY_SHOOT"; case CommandId::REP_ENTITY_SHOOT: return "REP_ENTITY_SHOOT"; - case CommandId::REQ_USER_UPDATE: return "REQ_USER_UPDATE"; - case CommandId::REP_USER_UPDATE: return "REP_USER_UPDATE"; case CommandId::REQ_USER_UPDATES: return "REQ_USER_UPDATES"; case CommandId::REP_USER_UPDATES: return "REP_USER_UPDATES"; case CommandId::REQ_CREATE_ROOM: return "REQ_CREATE_ROOM"; diff --git a/Flakkari/Protocol/Events.hpp b/Flakkari/Protocol/Events.hpp index 1b224353..21e74897 100644 --- a/Flakkari/Protocol/Events.hpp +++ b/Flakkari/Protocol/Events.hpp @@ -67,19 +67,14 @@ enum class EventId : uint8_t { MOVE_DOWN = 3, MOVE_FRONT = 4, MOVE_BACK = 5, + LOOK_LEFT = 6, + LOOK_RIGHT = 7, + LOOK_UP = 8, + LOOK_DOWN = 9, SHOOT = 10, MAX_EVENT }; -enum class EventAxisId : uint8_t { - LOOK_LEFT = 1, - LOOK_RIGHT = 2, - LOOK_UP = 3, - LOOK_DOWN = 4, - SHOOT = 5, - MAX_EVENT -}; - enum class EventState : uint8_t { PRESSED = 0, RELEASED = 1, @@ -91,11 +86,15 @@ LPL_PACKED_START struct Event { V_1::EventId id; V_1::EventState state; + + void print() const { std::cout << "Event: " << int(id) << " " << int(state) << std::endl; } }; struct EventAxis { - V_1::EventAxisId id; + V_1::EventId id; float value; + + void print() const { std::cout << "EventAxis: " << int(id) << " " << value << std::endl; } }; LPL_PACKED_END diff --git a/Flakkari/Protocol/Header.hpp b/Flakkari/Protocol/Header.hpp index 8e31b937..e67212a5 100644 --- a/Flakkari/Protocol/Header.hpp +++ b/Flakkari/Protocol/Header.hpp @@ -84,7 +84,7 @@ LPL_PACKED_START * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Priority|Api V.| CommandId | ContentLength | + * |Priority| Api V.| CommandId | ContentLength | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SequenceNumber | * | | diff --git a/Flakkari/Protocol/Packet.hpp b/Flakkari/Protocol/Packet.hpp index 49ac8af7..7cca2bdd 100644 --- a/Flakkari/Protocol/Packet.hpp +++ b/Flakkari/Protocol/Packet.hpp @@ -47,7 +47,7 @@ template struct Packet { { std::string str = "Packet"; return str; } diff --git a/Flakkari/Protocol/PacketFactory.hpp b/Flakkari/Protocol/PacketFactory.hpp index d2da0262..b5b43ddd 100644 --- a/Flakkari/Protocol/PacketFactory.hpp +++ b/Flakkari/Protocol/PacketFactory.hpp @@ -217,10 +217,10 @@ class PacketFactory { packet << transform->_position.vec.x; packet << transform->_position.vec.y; packet << transform->_position.vec.z; - packet << transform->_rotation.vec.x; - packet << transform->_rotation.vec.y; - packet << transform->_rotation.vec.z; - packet << transform->_rotation.vec.w; + packet << (float) transform->_rotation.vec.x; + packet << (float) transform->_rotation.vec.y; + packet << (float) transform->_rotation.vec.z; + packet << (float) transform->_rotation.vec.w; packet << transform->_scale.vec.x; packet << transform->_scale.vec.y; packet << transform->_scale.vec.z; diff --git a/Flakkari/Server/Client/Client.cpp b/Flakkari/Server/Client/Client.cpp index 6b00719f..7f9996ce 100644 --- a/Flakkari/Server/Client/Client.cpp +++ b/Flakkari/Server/Client/Client.cpp @@ -23,7 +23,7 @@ Client::~Client() { _isConnected = false; } bool Client::isConnected(float timeout) { - if (!_isConnected) + if (!this || !_isConnected) return false; return std::chrono::duration_cast(std::chrono::steady_clock::now() - _lastActivity).count() < timeout; diff --git a/Flakkari/Server/Client/ClientManager.cpp b/Flakkari/Server/Client/ClientManager.cpp index 2ef131d5..fed43307 100644 --- a/Flakkari/Server/Client/ClientManager.cpp +++ b/Flakkari/Server/Client/ClientManager.cpp @@ -84,7 +84,7 @@ void ClientManager::checkInactiveClients() void ClientManager::sendPacketToClient(const std::shared_ptr &client, const Network::Buffer &packet) { - std::thread([this, client, packet] { _socket->sendTo(client, packet); }).detach(); + _socket->sendTo(client, packet); } void ClientManager::sendPacketToAllClients(const Network::Buffer &packet) @@ -110,7 +110,7 @@ void ClientManager::sendPacketToAllClientsExcept(const std::shared_ptr>> +std::optional>> ClientManager::receivePacketFromClient(const std::shared_ptr &client, const Network::Buffer &buffer) { auto clientName = client->toString().value_or(""); @@ -130,6 +130,13 @@ ClientManager::receivePacketFromClient(const std::shared_ptr & if (packet.deserialize(buffer)) { FLAKKARI_LOG_LOG("Client " + clientName + " sent a valid packet: " + packet.to_string()); + + if (packet.header._commandId == Protocol::CommandId::REQ_DISCONNECT) + { + FLAKKARI_LOG_LOG("Client " + clientName + " disconnected"); + return std::make_pair(tmp_client->getGameName(), tmp_client); + } + tmp_client->addPacketToReceiveQueue(packet); return std::nullopt; } @@ -143,7 +150,6 @@ ClientManager::receivePacketFromClient(const std::shared_ptr & _bannedClients.push_back(ip); FLAKKARI_LOG_LOG("Client " + clientName + " banned"); - _clients.erase(clientName); return std::make_pair(tmp_client->getGameName(), tmp_client); } diff --git a/Flakkari/Server/Client/ClientManager.hpp b/Flakkari/Server/Client/ClientManager.hpp index e3d1ef02..57e34037 100644 --- a/Flakkari/Server/Client/ClientManager.hpp +++ b/Flakkari/Server/Client/ClientManager.hpp @@ -137,9 +137,9 @@ class ClientManager : public Singleton { * @param client The client's address * @param packet The packet received * @return std::optional> - * The client's name and the client object + * A pair of the client's game name and the client object */ - std::optional>> + std::optional>> receivePacketFromClient(const std::shared_ptr &client, const Network::Buffer &packet); /** diff --git a/Flakkari/Server/Game/Game.cpp b/Flakkari/Server/Game/Game.cpp index bed84004..355dcc75 100644 --- a/Flakkari/Server/Game/Game.cpp +++ b/Flakkari/Server/Game/Game.cpp @@ -48,7 +48,7 @@ void Game::loadSystems(Engine::ECS::Registry ®istry, const std::string &scene registry.add_system( [this](Engine::ECS::Registry &r) { Engine::ECS::Systems::_3D::apply_movable(r, _deltaTime); }); - else if (sysName == "spawn_enemy") + if (sysName == "spawn_enemy") registry.add_system([this, sceneName](Engine::ECS::Registry &r) { std::string templateName; Engine::ECS::Entity entity; @@ -182,6 +182,30 @@ void Game::sendOnSameSceneExcept(const std::string &sceneName, Protocol::Packet< } } +void Game::sendAllEntitiesToPlayer(std::shared_ptr player, const std::string &sceneGame) +{ + auto ®istry = _scenes[sceneGame]; + auto &transforms = registry.getComponents(); + auto &tags = registry.getComponents(); + + for (Engine::ECS::Entity i(0); i < transforms.size(); ++i) + { + if (!transforms[i].has_value() || !tags[i].has_value() || i == player->getEntity()) + continue; + if (tags[i]->tag == "Skybox") + continue; + Protocol::Packet packet; + packet.header._apiVersion = player->getApiVersion(); + packet.header._commandId = Protocol::CommandId::REQ_ENTITY_SPAWN; + packet << i; + packet.injectString(tags[i]->tag); + + Protocol::PacketFactory::addComponentsToPacketByEntity(packet, registry, i); + + player->addPacketToSendQueue(packet); + } +} + void Game::checkDisconnect() { for (auto &player : _players) @@ -206,10 +230,10 @@ void Game::sendUpdatePosition(std::shared_ptr player, Engine::ECS::Compo packet << pos._position.vec.x; packet << pos._position.vec.y; packet << pos._position.vec.z; - packet << pos._rotation.vec.x; - packet << pos._rotation.vec.y; - packet << pos._rotation.vec.z; - packet << pos._rotation.vec.w; + packet << (float) pos._rotation.vec.x; + packet << (float) pos._rotation.vec.y; + packet << (float) pos._rotation.vec.z; + packet << (float) pos._rotation.vec.w; packet << pos._scale.vec.x; packet << pos._scale.vec.y; packet << pos._scale.vec.z; @@ -236,7 +260,7 @@ static bool handleMoveEvent(Protocol::Event &event, Engine::ECS::Components::_3D Engine::ECS::Components::_3D::Movable &vel, Engine::ECS::Components::_3D::Transform &pos) { auto setAcceleration = [&](const Engine::Math::Vector3f &acceleration) { - vel._acceleration = pos._rotation * acceleration; + vel._acceleration = pos._rotation.multiplyWithFloatVector(acceleration); }; switch (event.id) @@ -332,30 +356,22 @@ void Game::handleEvents(std::shared_ptr player, Protocol::Packet_look_right) - { - pos->_rotation.vec.y += event.value * 100 * _deltaTime; - continue; - } - else if (event.id == Protocol::EventAxisId::LOOK_LEFT && ctrl->_look_left) - { - pos->_rotation.vec.y -= event.value * 100 * _deltaTime; - continue; - } - else if (event.id == Protocol::EventAxisId::LOOK_UP && ctrl->_look_up) + if (event.id == Protocol::EventId::LOOK_RIGHT && ctrl->_look_right) { - pos->_rotation.vec.x += event.value * 100 * _deltaTime; + pos->_rotation.rotate(Engine::Math::Vector3d(0, 0, 1), -event.value); + sendUpdatePosition(player, pos.value(), vel.value()); continue; } - else if (event.id == Protocol::EventAxisId::LOOK_DOWN && ctrl->_look_down) + else if (event.id == Protocol::EventId::LOOK_UP && ctrl->_look_up) { - pos->_rotation.vec.x -= event.value * 100 * _deltaTime; + pos->_rotation.rotate(Engine::Math::Vector3d(1, 0, 0), -event.value); + sendUpdatePosition(player, pos.value(), vel.value()); continue; } } @@ -408,6 +424,9 @@ void Game::updateOutcomingPackets(unsigned char maxMessagePerFrame) messageCount--; buffer += packet.serialize(); + } + if (buffer.size() > 0) + { ClientManager::GetInstance().sendPacketToClient(player->getAddress(), buffer); ClientManager::UnlockInstance(); } @@ -487,6 +506,8 @@ bool Game::addPlayer(std::shared_ptr player) packet2.injectString(p_Template); sendOnSameSceneExcept(sceneGame, packet2, player); + + sendAllEntitiesToPlayer(player, sceneGame); return true; } diff --git a/Flakkari/Server/Game/Game.hpp b/Flakkari/Server/Game/Game.hpp index c372accb..03d822d1 100644 --- a/Flakkari/Server/Game/Game.hpp +++ b/Flakkari/Server/Game/Game.hpp @@ -89,6 +89,8 @@ class Game { void sendOnSameSceneExcept(const std::string &sceneName, Protocol::Packet &packet, std::shared_ptr except); + void sendAllEntitiesToPlayer(std::shared_ptr player, const std::string &sceneGame); + /** * @brief Check if a player is disconnected. * diff --git a/Flakkari/Server/Game/GameManager.cpp b/Flakkari/Server/Game/GameManager.cpp index 30ca84cc..e33a53ac 100644 --- a/Flakkari/Server/Game/GameManager.cpp +++ b/Flakkari/Server/Game/GameManager.cpp @@ -171,7 +171,7 @@ void GameManager::removeClientFromGame(const std::string &gameName, const std::s { _gamesInstances[gameName].pop_back(); FLAKKARI_LOG_INFO("game \"" + gameName + "\" removed"); - break; + return; } else if (instance->getPlayers().size() > minPlayers) { diff --git a/Flakkari/Server/UDPServer.cpp b/Flakkari/Server/UDPServer.cpp index e36e672b..46d94930 100644 --- a/Flakkari/Server/UDPServer.cpp +++ b/Flakkari/Server/UDPServer.cpp @@ -62,6 +62,8 @@ bool UDPServer::handleInput(int fd) void UDPServer::handlePacket() { auto packet = _socket->receiveFrom(); + if (!packet.has_value()) + return; auto resultAddClient = ClientManager::GetInstance().addClient(packet->first, packet->second); ClientManager::UnlockInstance(); if (!resultAddClient.has_value())