- Authoritative 30 Hz server (ENet, SQLite): accounts, characters, wild AI, tall grass / water / wandering spawns, fishing, captures, follower chains, clock + weather, LAN beacon - Client: title / join / character creator / play screens, prediction + reconciliation, interpolated players and parties, HD-2D UI (dialogue with Professor Henry, HUD, collection) - Shared deterministic zone generator, movement, protocol, roster, appearance - Paper-doll character art pipeline (PixelLab base walk + per-item animation edits) - Brandling roster from the company list (logo colors, jev types), Blender safari props - Headless test bot
82 lines
2.0 KiB
C++
82 lines
2.0 KiB
C++
#pragma once
|
|
// Thin ENet wrapper (reliable channel + unreliable channel) and a UDP
|
|
// broadcast beacon for finding servers on the LAN.
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
struct _ENetHost;
|
|
struct _ENetPeer;
|
|
|
|
namespace bs::net {
|
|
|
|
enum Channel : uint8_t { Reliable = 0, Unreliable = 1, kChannelCount = 2 };
|
|
|
|
struct Event {
|
|
enum Type { None, Connect, Disconnect, Receive } type = None;
|
|
uint32_t peer = 0;
|
|
std::vector<uint8_t> data;
|
|
};
|
|
|
|
bool initialize(); // once per process (enet_initialize); safe to call repeatedly
|
|
void shutdown();
|
|
|
|
class Host {
|
|
public:
|
|
Host() = default;
|
|
Host(const Host&) = delete;
|
|
Host& operator=(const Host&) = delete;
|
|
~Host();
|
|
|
|
bool listen(uint16_t port, size_t maxPeers);
|
|
// Starts connecting; a Connect (or Disconnect on failure) event follows.
|
|
bool connect(const std::string& address, uint16_t port);
|
|
// Next event; waits up to timeoutMs for the first one.
|
|
bool poll(Event& ev, uint32_t timeoutMs = 0);
|
|
void send(uint32_t peer, Channel ch, const std::vector<uint8_t>& data);
|
|
void disconnect(uint32_t peer);
|
|
void flush();
|
|
std::string address(uint32_t peer) const;
|
|
uint32_t roundTripMs(uint32_t peer) const;
|
|
bool valid() const { return host_ != nullptr; }
|
|
|
|
private:
|
|
_ENetHost* host_ = nullptr;
|
|
uint32_t nextId_ = 1;
|
|
std::unordered_map<uint32_t, _ENetPeer*> peers_;
|
|
};
|
|
|
|
struct ServerInfo {
|
|
std::string address; // ip the reply came from
|
|
uint16_t port = 0;
|
|
std::string name;
|
|
int players = 0;
|
|
};
|
|
|
|
// Server side: answers "BSAFARI?" broadcasts on kDiscoveryPort.
|
|
class Beacon {
|
|
public:
|
|
~Beacon();
|
|
bool open(uint16_t discoveryPort);
|
|
void poll(uint16_t gamePort, const std::string& serverName, int players);
|
|
|
|
private:
|
|
intptr_t sock_ = -1;
|
|
};
|
|
|
|
// Client side: broadcasts a query and collects replies.
|
|
class Scanner {
|
|
public:
|
|
~Scanner();
|
|
bool open();
|
|
void ping(uint16_t discoveryPort);
|
|
void poll(std::vector<ServerInfo>& found);
|
|
|
|
private:
|
|
intptr_t sock_ = -1;
|
|
};
|
|
|
|
} // namespace bs::net
|