Files
brandling-safari/shared/Net.h
Gabe 238cd9c6c3 Brandling Safari: LAN safari-zone creature catching on the HD-2D engine
- 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
2026-10-02 15:20:27 -05:00

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