#ifndef NET_CLASS #define NET_CLASS #include #include #include #include #include // Multiplayer UDP link for a LAN pit. One player hosts (UDP port 27015), everyone else joins by IP. // Clients send their own transform to the host every frame; the host relays everyone's // transform to everyone else. The host is player id 0, joiners get ids 1, 2, 3, ... // All Winsock code lives in Net.cpp so windows.h never leaks into the rest of the engine. struct NetState { glm::vec3 position = glm::vec3(0.0f); glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); bool sliding = false; }; // A state received for some other player. struct NetUpdate { uint8_t id = 0; NetState state; }; // A shockwave explosion. Every machine applies the launch to its own player, since remote // players are only puppets here. Blasts are re-sent a few times (UDP) and de-duplicated on receive. struct NetBlast { uint8_t sender = 0; // filled in by the host; ignored on send uint32_t id = 0; // filled in by SendBlast glm::vec3 center = glm::vec3(0.0f); float radius = 0.0f; float power = 0.0f; }; // Damage dealt to another player. Each machine owns its own player's health, so the shooter // aims locally and sends this to the victim, who applies it. Re-sent a few times and de-duplicated. struct NetHit { uint8_t sender = 0; // filled in by the host uint32_t id = 0; // filled in by SendHit int damage = 0; glm::vec3 knockback = glm::vec3(0.0f); // added to the victim's velocity }; class Lan { public: enum class Mode { Off, Host, Client }; // Total players in the pit, host included. static constexpr int MaxPlayers = 8; Lan(); ~Lan(); // Opens the socket. For Client, hostIp is the host's IPv4 address. Returns false on failure. bool Start(Mode mode, const std::string& hostIp); void Stop(); Mode GetMode() const { return mode; } bool IsActive() const { return active; } // Call once per frame with our own state. void Send(const NetState& state); // Drains all waiting packets and appends the other players' newest states to 'out'. // If 'blasts' is given, new (de-duplicated) shockwave blasts from other players are appended to it. // 'hits' gets damage aimed at us (de-duplicated). void Receive(std::vector& out, std::vector* blasts = nullptr, std::vector* hits = nullptr); // Damage another player. 'target' is the id from their NetUpdate (the host is 0). void SendHit(uint8_t target, const NetHit& hit); // Tell the other players about a blast we caused. Sent over the next few Send() calls. void SendBlast(const NetBlast& blast); // Host: at least one player has joined. Client: the host has been heard from in the last 2 s. bool IsConnected() const; // Host only: number of joined players, not counting the host. int PeerCount() const; // This machine's IPv4 addresses (for the host to read out to the joiners). static std::string LocalAddresses(); private: struct Impl; Impl* impl; Mode mode = Mode::Off; bool active = false; }; inline Lan* lan = nullptr; #endif