feat: add chunkOf and squaredDistance
This commit is contained in:
1 parent
db6bdb8dc2
commit
34191ca984
1 file changed
+160
@@ -0,0 +1,160 @@
|
||||
#include "vf/NetSession.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace vf {
|
||||
|
||||
namespace {
|
||||
|
||||
Vec3i chunkOf(const Vec3& position) {
|
||||
int gx = static_cast<int>(std::floor(position.x));
|
||||
int gy = static_cast<int>(std::floor(position.y));
|
||||
int gz = static_cast<int>(std::floor(position.z));
|
||||
return Vec3i{floorDiv(gx, chunkSize), floorDiv(gy, chunkSize), floorDiv(gz, chunkSize)};
|
||||
}
|
||||
|
||||
int64_t squaredDistance(const Vec3i& a, const Vec3i& b) {
|
||||
int64_t dx = a.x - b.x;
|
||||
int64_t dy = a.y - b.y;
|
||||
int64_t dz = a.z - b.z;
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ViewTracker::ViewTracker(int radius) : viewRadius(radius < 0 ? 0 : radius) {}
|
||||
|
||||
void ViewTracker::setRadius(int radius) { viewRadius = radius < 0 ? 0 : radius; }
|
||||
|
||||
void ViewTracker::clear() {
|
||||
resident.clear();
|
||||
centred = false;
|
||||
centreChunk = Vec3i{0, 0, 0};
|
||||
}
|
||||
|
||||
void ViewTracker::update(const Vec3i& newCentre, std::vector<Vec3i>& entered,
|
||||
std::vector<Vec3i>& left) {
|
||||
entered.clear();
|
||||
left.clear();
|
||||
|
||||
std::vector<Vec3i> wanted;
|
||||
int64_t limit = static_cast<int64_t>(viewRadius) * static_cast<int64_t>(viewRadius);
|
||||
for (int dy = -viewRadius; dy <= viewRadius; ++dy) {
|
||||
for (int dz = -viewRadius; dz <= viewRadius; ++dz) {
|
||||
for (int dx = -viewRadius; dx <= viewRadius; ++dx) {
|
||||
Vec3i coord{newCentre.x + dx, newCentre.y + dy, newCentre.z + dz};
|
||||
if (squaredDistance(coord, newCentre) > limit) continue;
|
||||
wanted.push_back(coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::stable_sort(wanted.begin(), wanted.end(),
|
||||
[&newCentre](const Vec3i& a, const Vec3i& b) {
|
||||
int64_t da = squaredDistance(a, newCentre);
|
||||
int64_t db = squaredDistance(b, newCentre);
|
||||
if (da != db) return da < db;
|
||||
if (a.y != b.y) return a.y < b.y;
|
||||
if (a.z != b.z) return a.z < b.z;
|
||||
return a.x < b.x;
|
||||
});
|
||||
|
||||
std::unordered_set<Vec3i, Vec3iHash> next;
|
||||
next.reserve(wanted.size() * 2);
|
||||
for (const Vec3i& coord : wanted) {
|
||||
next.insert(coord);
|
||||
if (resident.count(coord) == 0) entered.push_back(coord);
|
||||
}
|
||||
for (const Vec3i& coord : resident)
|
||||
if (next.count(coord) == 0) left.push_back(coord);
|
||||
|
||||
std::stable_sort(left.begin(), left.end(), [](const Vec3i& a, const Vec3i& b) {
|
||||
if (a.y != b.y) return a.y < b.y;
|
||||
if (a.z != b.z) return a.z < b.z;
|
||||
return a.x < b.x;
|
||||
});
|
||||
|
||||
resident.swap(next);
|
||||
centreChunk = newCentre;
|
||||
centred = true;
|
||||
}
|
||||
|
||||
void ClientView::queueChunk(const Vec3i& coord) {
|
||||
if (!queued.insert(coord).second) return;
|
||||
pending.push_back(coord);
|
||||
}
|
||||
|
||||
bool ClientView::takeNextPending(Vec3i& out) {
|
||||
while (!pending.empty()) {
|
||||
Vec3i coord = pending.front();
|
||||
pending.pop_front();
|
||||
if (queued.erase(coord) == 0) continue;
|
||||
out = coord;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientView::forget(const Vec3i& coord) {
|
||||
sent.erase(coord);
|
||||
queued.erase(coord);
|
||||
}
|
||||
|
||||
void ClientView::reset() {
|
||||
tracker.clear();
|
||||
pending.clear();
|
||||
queued.clear();
|
||||
sent.clear();
|
||||
centreChunk = Vec3i{0, 0, 0};
|
||||
position = Vec3{0.0f, 0.0f, 0.0f};
|
||||
}
|
||||
|
||||
NetSession::NetSession(Transport& transport, Role role, SessionConfig config)
|
||||
: transport(&transport), role(role), config(config), clientView(config.viewRadius) {}
|
||||
|
||||
std::size_t NetSession::queuedByteCount() const {
|
||||
std::size_t total = 0;
|
||||
for (const QueuedPacket& packet : outbound) total += packet.frame.size();
|
||||
return total;
|
||||
}
|
||||
|
||||
void NetSession::disconnect(const std::string& why) {
|
||||
if (currentPhase == SessionPhase::Disconnected) return;
|
||||
currentPhase = SessionPhase::Disconnected;
|
||||
reason = why;
|
||||
outbound.clear();
|
||||
}
|
||||
|
||||
void NetSession::enqueue(PacketId id, const PacketWriter& body, bool reliable) {
|
||||
ByteWriter stream;
|
||||
writeFramed(stream, id, body);
|
||||
QueuedPacket packet;
|
||||
packet.frame = stream.bytes();
|
||||
packet.reliable = reliable;
|
||||
statistics.bytesQueued += packet.frame.size();
|
||||
outbound.push_back(std::move(packet));
|
||||
}
|
||||
|
||||
void NetSession::beginHandshake(const std::string& playerName, uint64_t high, uint64_t low) {
|
||||
name = playerName;
|
||||
uuidHi = high;
|
||||
uuidLo = low;
|
||||
|
||||
Handshake hello;
|
||||
hello.protocolVersion = config.protocolVersion;
|
||||
hello.serverAddress = "loopback";
|
||||
hello.serverPort = 0;
|
||||
hello.nextState = 2;
|
||||
PacketWriter helloBody;
|
||||
hello.encode(helloBody);
|
||||
enqueue(PacketId::Handshake, helloBody, true);
|
||||
|
||||
LoginStart login;
|
||||
login.name = playerName;
|
||||
login.uuidHi = high;
|
||||
login.uuidLo = low;
|
||||
PacketWriter loginBody;
|
||||
login.encode(loginBody);
|
||||
enqueue(PacketId::LoginStart, loginBody, true);
|
||||
|
||||
Reference in new issue
Block a user