bigger commits
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace {
|
||||
constexpr uint32_t NET_MAGIC = 0x45494946; // "EIIF"
|
||||
constexpr uint16_t NET_VERSION = 2;
|
||||
constexpr uint16_t NET_VERSION = 3;
|
||||
constexpr unsigned short NET_PORT = 27015;
|
||||
constexpr double NET_TIMEOUT = 2.0; // seconds of silence before a player is dropped
|
||||
|
||||
@@ -67,6 +67,30 @@ namespace {
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr uint32_t NET_MAGIC_SPAWN = 0x45494953; // "EIIS"
|
||||
constexpr uint32_t NET_MAGIC_CUBES = 0x45494943; // "EIIC"
|
||||
constexpr int CUBES_PER_PACKET = 36;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SpawnPacket {
|
||||
uint32_t magic;
|
||||
uint16_t version;
|
||||
uint8_t sender;
|
||||
uint32_t id;
|
||||
float pos[3];
|
||||
};
|
||||
struct CubesHeader {
|
||||
uint32_t magic;
|
||||
uint16_t version;
|
||||
uint8_t count;
|
||||
};
|
||||
struct CubeEntry {
|
||||
uint32_t id;
|
||||
float pos[3];
|
||||
float rot[4]; // x, y, z, w
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
constexpr int MAX_ENTRIES = Lan::MaxPlayers;
|
||||
constexpr int MAX_DATAGRAM = (int)sizeof(Header) + MAX_ENTRIES * (int)sizeof(Entry);
|
||||
|
||||
@@ -127,6 +151,11 @@ struct Lan::Impl {
|
||||
uint32_t blastSeq = 0;
|
||||
std::vector<uint64_t> seenBlasts; // (type, sender, id) of recent blasts/hits, for de-duplication
|
||||
|
||||
struct PendingSpawn { SpawnPacket pkt; int copiesLeft; };
|
||||
std::vector<PendingSpawn> pendingSpawns;
|
||||
uint32_t spawnSeq = 0;
|
||||
size_t cubeCursor = 0; // host: where the next slice of cubes starts
|
||||
|
||||
struct PendingHit { HitPacket pkt; int copiesLeft; };
|
||||
std::vector<PendingHit> pendingHits;
|
||||
uint32_t hitSeq = 0;
|
||||
@@ -232,6 +261,7 @@ void Lan::Stop() {
|
||||
impl->peers.clear();
|
||||
impl->pendingBlasts.clear();
|
||||
impl->pendingHits.clear();
|
||||
impl->pendingSpawns.clear();
|
||||
impl->seenBlasts.clear();
|
||||
impl->anyRecv = false;
|
||||
active = false;
|
||||
@@ -266,9 +296,60 @@ void Lan::SendHit(uint8_t target, const NetHit& h) {
|
||||
impl->pendingHits.push_back(ph);
|
||||
}
|
||||
|
||||
void Lan::SendCubeSpawn(const glm::vec3& position) {
|
||||
if (!active || mode != Mode::Client) return;
|
||||
Impl::PendingSpawn ps;
|
||||
ps.pkt.magic = NET_MAGIC_SPAWN;
|
||||
ps.pkt.version = NET_VERSION;
|
||||
ps.pkt.sender = 0; // the host stamps the real id
|
||||
ps.pkt.id = ++impl->spawnSeq;
|
||||
ps.pkt.pos[0] = position.x; ps.pkt.pos[1] = position.y; ps.pkt.pos[2] = position.z;
|
||||
ps.copiesLeft = BLAST_COPIES;
|
||||
impl->pendingSpawns.push_back(ps);
|
||||
}
|
||||
|
||||
void Lan::SendCubes(const std::vector<NetCube>& cubes) {
|
||||
if (!active || mode != Mode::Host || cubes.empty() || impl->peers.empty()) return;
|
||||
|
||||
const size_t n = cubes.size();
|
||||
const size_t count = std::min(n, (size_t)CUBES_PER_PACKET);
|
||||
if (impl->cubeCursor >= n) impl->cubeCursor = 0;
|
||||
|
||||
char buf[sizeof(CubesHeader) + CUBES_PER_PACKET * sizeof(CubeEntry)];
|
||||
CubesHeader h;
|
||||
h.magic = NET_MAGIC_CUBES;
|
||||
h.version = NET_VERSION;
|
||||
h.count = (uint8_t)count;
|
||||
std::memcpy(buf, &h, sizeof(h));
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const NetCube& c = cubes[(impl->cubeCursor + i) % n];
|
||||
CubeEntry e;
|
||||
e.id = c.id;
|
||||
e.pos[0] = c.position.x; e.pos[1] = c.position.y; e.pos[2] = c.position.z;
|
||||
e.rot[0] = c.rotation.x; e.rot[1] = c.rotation.y; e.rot[2] = c.rotation.z; e.rot[3] = c.rotation.w;
|
||||
std::memcpy(buf + sizeof(h) + i * sizeof(e), &e, sizeof(e));
|
||||
}
|
||||
impl->cubeCursor = (impl->cubeCursor + count) % n;
|
||||
|
||||
const int len = (int)(sizeof(h) + count * sizeof(CubeEntry));
|
||||
for (const Impl::Peer& to : impl->peers)
|
||||
sendto(impl->sock, buf, len, 0, (const sockaddr*)&to.addr, (int)sizeof(to.addr));
|
||||
}
|
||||
|
||||
void Lan::Send(const NetState& s) {
|
||||
if (!active) return;
|
||||
|
||||
// One more copy of every pending cube spawn request (client -> host)
|
||||
for (Impl::PendingSpawn& ps : impl->pendingSpawns) {
|
||||
sendto(impl->sock, (const char*)&ps.pkt, (int)sizeof(ps.pkt), 0,
|
||||
(const sockaddr*)&impl->hostAddr, (int)sizeof(impl->hostAddr));
|
||||
ps.copiesLeft--;
|
||||
}
|
||||
impl->pendingSpawns.erase(
|
||||
std::remove_if(impl->pendingSpawns.begin(), impl->pendingSpawns.end(),
|
||||
[](const Impl::PendingSpawn& ps) { return ps.copiesLeft <= 0; }),
|
||||
impl->pendingSpawns.end());
|
||||
|
||||
// One more copy of every pending hit: clients send to the host, the host to the target only
|
||||
for (Impl::PendingHit& ph : impl->pendingHits) {
|
||||
if (mode == Mode::Client) impl->SendHitPacket(impl->hostAddr, ph.pkt);
|
||||
@@ -309,10 +390,11 @@ void Lan::Send(const NetState& s) {
|
||||
}
|
||||
}
|
||||
|
||||
void Lan::Receive(std::vector<NetUpdate>& out, std::vector<NetBlast>* blasts, std::vector<NetHit>* hits) {
|
||||
void Lan::Receive(std::vector<NetUpdate>& out, std::vector<NetBlast>* blasts, std::vector<NetHit>* hits,
|
||||
std::vector<NetCubeRequest>* spawns, std::vector<NetCube>* cubes) {
|
||||
if (!active) return;
|
||||
|
||||
char buf[MAX_DATAGRAM + 64];
|
||||
char buf[1500];
|
||||
for (int i = 0; i < 512; i++) { // bounded so a flood can't stall the frame
|
||||
sockaddr_in from{};
|
||||
int fromLen = (int)sizeof(from);
|
||||
@@ -355,6 +437,50 @@ void Lan::Receive(std::vector<NetUpdate>& out, std::vector<NetBlast>* blasts, st
|
||||
continue;
|
||||
}
|
||||
|
||||
if (magic == NET_MAGIC_SPAWN) {
|
||||
if (mode != Mode::Host || r != (int)sizeof(SpawnPacket)) continue;
|
||||
SpawnPacket sp;
|
||||
std::memcpy(&sp, buf, sizeof(sp));
|
||||
if (sp.version != NET_VERSION) continue;
|
||||
|
||||
// Only known players may spawn cubes
|
||||
const Impl::Peer* sender = nullptr;
|
||||
for (const Impl::Peer& pe : impl->peers)
|
||||
if (SameAddress(pe.addr, from)) { sender = &pe; break; }
|
||||
if (!sender) continue;
|
||||
|
||||
if (spawns && impl->FirstSighting(2, sender->id, sp.id)) {
|
||||
NetCubeRequest req;
|
||||
req.sender = sender->id;
|
||||
req.id = sp.id;
|
||||
req.position = glm::vec3(sp.pos[0], sp.pos[1], sp.pos[2]);
|
||||
spawns->push_back(req);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (magic == NET_MAGIC_CUBES) {
|
||||
if (mode != Mode::Client || !SameAddress(from, impl->hostAddr)) continue;
|
||||
CubesHeader ch;
|
||||
if (r < (int)sizeof(ch)) continue;
|
||||
std::memcpy(&ch, buf, sizeof(ch));
|
||||
if (ch.version != NET_VERSION || ch.count > CUBES_PER_PACKET) continue;
|
||||
if (r != (int)(sizeof(ch) + ch.count * sizeof(CubeEntry))) continue;
|
||||
|
||||
if (cubes) {
|
||||
for (int k = 0; k < ch.count; k++) {
|
||||
CubeEntry e;
|
||||
std::memcpy(&e, buf + sizeof(ch) + k * sizeof(e), sizeof(e));
|
||||
NetCube c;
|
||||
c.id = e.id;
|
||||
c.position = glm::vec3(e.pos[0], e.pos[1], e.pos[2]);
|
||||
c.rotation = glm::quat(e.rot[3], e.rot[0], e.rot[1], e.rot[2]);
|
||||
cubes->push_back(c);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (magic == NET_MAGIC_HIT) {
|
||||
if (r != (int)sizeof(HitPacket)) continue;
|
||||
HitPacket hp;
|
||||
|
||||
Reference in New Issue
Block a user