get*Ex -> getLoad*, (re)implement networked block updates

Light data and extdata not yet handled.

Fixes some signedness inconsistencies in Chunk.{cpp,hpp}

Server now holds some chunks in memory.
This commit is contained in:
Dorian Wouters 2016-07-03 15:16:50 +02:00
parent 212896a18b
commit 2868fa82df
No known key found for this signature in database
GPG Key ID: 6E9DA8063322434B
13 changed files with 205 additions and 80 deletions

View File

@ -1,14 +1,20 @@
#include "Chunk.hpp"
#include "Platform.hpp"
#include <cstring>
#include <cstddef>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <lzfx.h>
#include <fasthash.h>
#include "GlobalProperties.hpp"
#include "Game.hpp"
#include "content/Registry.hpp"
#include <cstring>
#include <cstddef>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <lzfx.h>
#include <fasthash.h>
#include "network/msgtypes/BlockUpdate.hpp"
#if CHUNK_INMEM_COMPRESS
#include <cstdlib>
@ -18,7 +24,7 @@
namespace Diggler {
Chunk::Renderer Chunk::R = {0};
Chunk::Renderer Chunk::R = {};
const Texture *Chunk::TextureAtlas = nullptr;
struct GLCoord {
@ -51,15 +57,17 @@ void Chunk::ChangeHelper::add(int x, int y, int z) {
m_changes.emplace_back(x, y, z);
}
void Chunk::ChangeHelper::flush(Net::OutMessage &msg) {
msg.writeU8(m_changes.size());
using Net::MsgTypes::BlockUpdateNotify;
void Chunk::ChangeHelper::flush(BlockUpdateNotify &bun) {
for (glm::ivec3 &c : m_changes) {
msg.writeU8(c.x);
msg.writeU8(c.y);
msg.writeU8(c.z);
msg.writeU16(C.data->id[I(c.x, c.y, c.z)]);
msg.writeU16(C.data->data[I(c.x, c.y, c.z)]);
msg.writeU16(C.data->light[I(c.x, c.y, c.z)]);
bun.updates.emplace_back();
BlockUpdateNotify::UpdateData &upd = bun.updates.back();
upd.worldId = C.W->id;
upd.pos = glm::ivec3(C.wcx * CX + c.x, C.wcy * CY + c.y, C.wcz * CZ + c.z);
upd.id = C.data->id[I(c.x, c.y, c.z)];
upd.data = C.data->data[I(c.x, c.y, c.z)];
upd.light = C.data->light[I(c.x, c.y, c.z)];
upd.cause = BlockUpdateNotify::UpdateData::Cause::Unspecified;
}
m_changes.clear();
}
@ -191,6 +199,8 @@ void Chunk::notifyChange(int x, int y, int z) {
if (state != State::Ready)
return;
markAsDirty();
CH.add(x, y, z);
if (GlobalProperties::IsClient) {
int u = x==CX-1?1:(x==0)?-1:0,
@ -324,7 +334,7 @@ void Chunk::updateClient() {
GLCoord vertex[CX * CY * CZ * 6 /* faces */ * 4 /* vertices */ / 2 /* face removing (HSR) makes a lower vert max */];
GLushort idxOpaque[CX * CY * CZ * 6 /* faces */ * 6 /* indices */ / 2 /* HSR */],
idxTransp[CX*CY*CZ*6*6/2];
int v = 0, io = 0, it = 0;
uint v = 0, io = 0, it = 0;
bool hasWaves = G->RP->wavingLiquids;
BlockId bt, bu /*BlockUp*/, bn /*BlockNear*/;
@ -383,7 +393,7 @@ void Chunk::updateClient() {
mayDisp = false;
}
GLushort *index; int i; bool transp = ContentRegistry::isTransparent(bt);
GLushort *index; uint i; bool transp = ContentRegistry::isTransparent(bt);
if (transp) {
index = idxTransp;
i = it;
@ -568,7 +578,7 @@ void Chunk::read(InStream &is) {
}
delete[] compressedData;
markAsDirty();
state = State::Ready;
{ ChunkRef nc;
nc = W->getChunk(wcx+1, wcy, wcz); if (nc) nc->markAsDirty();

View File

@ -23,6 +23,12 @@ class Game;
class World;
using WorldRef = std::shared_ptr<World>;
namespace Net {
namespace MsgTypes {
struct BlockUpdateNotify;
}
}
constexpr int CX = 16, CY = 16, CZ = 16;
class Chunk {
@ -69,7 +75,7 @@ public:
private:
Game *G; WorldRef W;
Render::gl::VBO *vbo, *ibo;
int vertices, indicesOpq, indicesTpt;
uint vertices, indicesOpq, indicesTpt;
Data *data, *data2;
//std::map<uint16, msgpack::object> extdataStore;
@ -82,8 +88,8 @@ private:
void calcMemUsage();
#if CHUNK_INMEM_COMPRESS
union {
int imcSize;
int imcUnusedSince;
uint imcSize;
uint64 imcUnusedSince;
};
void *imcData;
void imcCompress();
@ -95,7 +101,7 @@ public:
(CZ > (CX > CY ? CX : CY) ? CZ : (CX > CY ? CX : CY));
// * 1.4142135623f; but we're already at 2x the radius (i.e. diameter)
constexpr static float MidX = CX/2.f, MidY = CY/2.f, MidZ = CZ/2.f;
int blkMem;
uint blkMem;
State getState();
class ChangeHelper {
@ -110,7 +116,7 @@ public:
void add(int x, int y, int z);
bool empty() const;
int count() const;
void flush(Net::OutMessage&);
void flush(Net::MsgTypes::BlockUpdateNotify&);
void discard();
} CH;

View File

@ -20,6 +20,7 @@
#include "network/NetHelper.hpp"
#include "Particles.hpp"
#include "network/msgtypes/BlockUpdate.hpp"
#include "content/Registry.hpp"
using std::unique_ptr;
@ -298,20 +299,14 @@ void GameState::onMouseButton(int key, int action, int mods) {
if (action == GLFW_PRESS) {
glm::ivec3 pointed, face;
if (G->LP->raytracePointed(32, &pointed, &face)) {
Net::OutMessage msg(Net::MessageType::BlockUpdate);
msg.writeI32(G->LP->W->id);
Net::OutMessage msg;
if (key == GLFW_MOUSE_BUTTON_LEFT) {
msg.writeI32(pointed.x);
msg.writeI32(pointed.y);
msg.writeI32(pointed.z);
msg.writeU16(Content::BlockAirId);
msg.writeU16(0);
Net::MsgTypes::BlockUpdateBreak bub;
bub.worldId = G->LP->W->id;
bub.pos = pointed;
bub.writeToMsg(msg);
} else {
msg.writeI32(face.x);
msg.writeI32(face.y);
msg.writeI32(face.z);
msg.writeU16(Content::BlockUnknownId);//m_builderGun.currentBlock);
msg.writeU16(0);
// TODO stubbed
}
sendMsg(msg, Net::Tfer::Rel, Net::Channels::MapUpdate);
}

View File

@ -122,7 +122,7 @@ private:
void lockMouse();
void unlockMouse();
// TODO: FIXME!!! Ugly as fuck
// TODO: REMOVEME!!!
std::list<ChunkRef> holdChunksInMem;
public:

View File

@ -1,5 +1,6 @@
#include "Server.hpp"
#include "Game.hpp"
#include "network/msgtypes/BlockUpdate.hpp"
#include "network/msgtypes/Chat.hpp"
#include "network/msgtypes/ChunkTransfer.hpp"
#include "network/Network.hpp"
@ -59,7 +60,7 @@ void Server::handlePlayerJoin(InMessage &msg, Peer &peer) {
plr.name = name;
plr.id = FastRand();
plr.P = peer;
plr.W = G.U->getWorldEx(0);
plr.W = G.U->getLoadWorld(0);
// Confirm successful join
OutMessage join(MessageType::PlayerJoin);
@ -90,7 +91,7 @@ void Server::handlePlayerJoin(InMessage &msg, Peer &peer) {
for (int x = -2; x < 2; ++x)
for (int y = -2; y < 2; ++y)
for (int z = -2; z < 2; ++z)
schedSendChunk(G.U->getWorld(0)->getChunkEx(x, y, z), plr);
schedSendChunk(G.U->getWorld(0)->getLoadChunk(x, y, z), plr);
}
void Server::handlePlayerQuit(Peer &peer, QuitReason reason) {
@ -214,7 +215,7 @@ void Server::handlePlayerChunkRequest(InMessage &msg, Player &plr) {
for (const ChunkTransferRequest::ChunkData &cd : ctr.chunks) {
WorldRef wld = G.U->getWorld(cd.worldId);
if (wld) {
schedSendChunk(wld->getChunkEx(cd.chunkPos.x, cd.chunkPos.y, cd.chunkPos.z), plr);
schedSendChunk(wld->getLoadChunk(cd.chunkPos.x, cd.chunkPos.y, cd.chunkPos.z), plr);
}
}
} break;
@ -227,21 +228,35 @@ void Server::handlePlayerChunkRequest(InMessage &msg, Player &plr) {
void Server::handlePlayerMapUpdate(InMessage &msg, Player &plr) {
// TODO: distance & tool check, i.e. legitimate update
WorldId wid = msg.readI32();
int x = msg.readI32(), y = msg.readI32(), z = msg.readI32();
BlockId id = msg.readU16();
BlockData data = msg.readU16();
ChunkRef c = G.U->getWorld(wid)->getChunkAtCoords(x, y, z);
if (c) {
c->setBlock(x, y, z, id, data);
if (!c->CH.empty()) {
OutMessage msg(MessageType::BlockUpdate, 1);
msg.writeI32(wid);
const glm::ivec3 wcpos = c->getWorldChunkPos();
msg.writeIVec3(wcpos);
c->CH.flush(msg);
NetHelper::Broadcast(G, msg, Tfer::Rel, Channels::MapUpdate);
}
using namespace Net::MsgTypes;
using S = BlockUpdateSubtype;
switch (static_cast<S>(msg.getSubtype())) {
case S::Notify: {
; // No-op
} break;
case S::Place: {
BlockUpdatePlace bup;
bup.readFromMsg(msg);
//TODO
} break;
case S::Break: {
BlockUpdateBreak bub;
bub.readFromMsg(msg);
WorldRef w = G.U->getWorld(bub.worldId);
if (w) {
ChunkRef c = w->getChunkAtCoords(bub.pos);
if (c) {
c->setBlock(rmod(bub.pos.x, CX), rmod(bub.pos.y, CY), rmod(bub.pos.z, CZ), 0, 0);
if (!c->CH.empty()) {
BlockUpdateNotify bun;
c->CH.flush(bun);
OutMessage omsg;
bun.writeToMsg(omsg);
NetHelper::Broadcast(G, omsg, Tfer::Rel, Channels::MapUpdate);
}
}
}
} break;
}
}
@ -312,6 +327,11 @@ void Server::start() {
WorldRef wr = G.U->createWorld(0);
World0Ref = wr;
for (int x = -2; x < 2; ++x)
for (int y = -2; y < 2; ++y)
for (int z = -2; z < 2; ++z)
holdChunksInMem.emplace_back(G.U->getWorld(0)->getLoadChunk(x, y, z));
}
void Server::stop() {
@ -338,12 +358,10 @@ void Server::chunkUpdater(WorldRef WR, bool &continueUpdate) {
for (auto pair : W) {
if ((c = pair.second.lock()) && !c->CH.empty()) {
// TODO: view range
OutMessage msg(MessageType::BlockUpdate, 0);
glm::ivec3 pos = c->getWorldChunkPos();
msg.writeI16(pos.x);
msg.writeI16(pos.y);
msg.writeI16(pos.z);
c->CH.flush(msg);
Net::MsgTypes::BlockUpdateNotify bun;
c->CH.flush(bun);
OutMessage msg;
bun.writeToMsg(msg);
NetHelper::Broadcast(G, msg, Tfer::Rel, Channels::MapUpdate);
}
}

View File

@ -16,6 +16,9 @@ private:
Game &G;
lua_State *L;
// TODO: REMOVEME!!!
std::list<ChunkRef> holdChunksInMem;
void handleCommand(Player*, const std::string &command, const std::vector<std::string> &args);
void handlePlayerJoin(Net::InMessage&, Net::Peer&);

View File

@ -16,7 +16,7 @@ WorldRef Universe::getWorld(WorldId id) {
return it->second.lock();
}
WorldRef Universe::getWorldEx(WorldId id) {
WorldRef Universe::getLoadWorld(WorldId id) {
// TODO World loading
iterator it = find(id);
if (it == end()) {

View File

@ -34,7 +34,7 @@ public:
/// *synchronously* loads it.
/// @returns Reference to the world.
///
WorldRef getWorldEx(WorldId id);
WorldRef getLoadWorld(WorldId id);
///
/// @brief Creates a world.

View File

@ -87,7 +87,7 @@ ChunkRef World::getChunk(int cx, int cy, int cz) {
return ChunkRef();
}
ChunkRef World::getChunkEx(int cx, int cy, int cz) {
ChunkRef World::getLoadChunk(int cx, int cy, int cz) {
iterator it = find(glm::ivec3(cx, cy, cz));
if (it != end()) {
if (!it->second.expired())
@ -412,7 +412,7 @@ void World::read(InStream &M) {
byte *compressedData = new byte[compressedSize];
M.readData(compressedData, compressedSize);
bytesRead += compressedSize;
Chunk &c = *getChunkEx(x, y, z);
Chunk &c = *getLoadChunk(x, y, z);
uint outLen = targetDataSize;
int rz = lzfx_decompress(compressedData, compressedSize, c.data, &outLen);
if (rz < 0 || outLen != targetDataSize) {

View File

@ -82,6 +82,9 @@ public:
inline ChunkRef getChunkAtCoords(int x, int y, int z) {
return getChunk(divrd(x, CX), divrd(y, CY), divrd(z, CZ));
}
inline ChunkRef getChunkAtCoords(const glm::ivec3 &v) {
return getChunk(divrd(v.x, CX), divrd(v.y, CY), divrd(v.z, CZ));
}
///
/// @brief Gets a chunk.
@ -89,9 +92,12 @@ public:
/// and add said chunk to the load queue.
/// @returns `ChunkRef` to the chunk.
///
ChunkRef getChunkEx(int cx, int cy, int cz);
inline ChunkRef getChunkExAtCoords(int x, int y, int z) {
return getChunkEx(divrd(x, CX), divrd(y, CY), divrd(z, CZ));
ChunkRef getLoadChunk(int cx, int cy, int cz);
inline ChunkRef getLoadChunkAtCoords(int x, int y, int z) {
return getLoadChunk(divrd(x, CX), divrd(y, CY), divrd(z, CZ));
}
inline ChunkRef getLoadChunkAtCoords(const glm::ivec3 &v) {
return getLoadChunk(divrd(v.x, CX), divrd(v.y, CY), divrd(v.z, CZ));
}
///

View File

@ -3,6 +3,7 @@
#include "../Chatbox.hpp"
#include "../Game.hpp"
#include "../GameState.hpp"
#include "msgtypes/BlockUpdate.hpp"
#include "msgtypes/Chat.hpp"
#include "msgtypes/ChunkTransfer.hpp"
@ -30,7 +31,7 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
ChunkTransferResponse ctr;
ctr.readFromMsg(msg);
for (const ChunkTransferResponse::ChunkData &cd : ctr.chunks) {
ChunkRef c = GS.G->U->getWorldEx(cd.worldId)->getNewEmptyChunk(
ChunkRef c = GS.G->U->getLoadWorld(cd.worldId)->getNewEmptyChunk(
cd.chunkPos.x, cd.chunkPos.y, cd.chunkPos.z);
InMemoryStream ims(cd.data, cd.dataLength);
c->read(ims);
@ -115,18 +116,28 @@ bool ClientMessageHandler::handleMessage(InMessage &msg) {
}
} break;
case MessageType::BlockUpdate: {
// TODO proper count
// TODO handle that in Chunk's ChangeHelper
int count = msg.getSubtype();
for (int i=0; i < count; ++i) {
const glm::ivec3 wcpos = msg.readIVec3();
uint8 x = msg.readU8(),
y = msg.readU8(),
z = msg.readU8();
WorldId wid = msg.readI16();
uint16 id = msg.readU16();
uint16 data = msg.readU16();
GS.G->U->getWorld(wid)->setBlock(x, y, z, id, data);
using S = BlockUpdateSubtype;
switch (static_cast<S>(msg.getSubtype())) {
case S::Notify: {
BlockUpdateNotify bun;
bun.readFromMsg(msg);
for (const BlockUpdateNotify::UpdateData &upd : bun.updates) {
WorldRef w = GS.G->U->getWorld(upd.worldId);
if (w) {
ChunkRef c = w->getChunkAtCoords(upd.pos);
if (c) {
c->setBlock(rmod(upd.pos.x, CX), rmod(upd.pos.y, CY), rmod(upd.pos.z, CZ),
upd.id, upd.data);
// TODO extdata & light
}
}
}
} break;
case S::Place:
case S::Break: {
; // No-op
} break;
}
} break;
case MessageType::Event: {

View File

@ -1,10 +1,77 @@
#include "Chat.hpp"
#include "BlockUpdate.hpp"
namespace Diggler {
namespace Net {
namespace MsgTypes {
void BlockUpdateNotify::writeToMsg(OutMessage &msg) const {
msg.setType(MessageType::BlockUpdate, BlockUpdateSubtype::Notify);
msg.writeU16(updates.size());
for (const UpdateData &upd : updates) {
msg.writeU8(*reinterpret_cast<const uint8*>(&upd.updated));
msg.writeI32(upd.worldId);
msg.writeIVec3(upd.pos);
msg.writeU16(upd.id);
msg.writeU16(upd.data);
msgpack::pack(msg, upd.extdata);
msg.writeU16(upd.light);
msg.writeU8(upd.cause);
}
}
void BlockUpdateNotify::readFromMsg(InMessage &msg) {
uint16 count = msg.readU16();
updates.clear();
updates.reserve(count);
for (uint8 i = 0; i < count; ++i) {
updates.emplace_back();
UpdateData &upd = updates.back();
*reinterpret_cast<uint8*>(&upd.updated) = msg.readU8();
upd.worldId = msg.readI32();
upd.pos = msg.readIVec3();
upd.id = msg.readU16();
upd.data = msg.readU16();
Stream::PosT offset = msg.tell();
upd.extdata = msgpack::unpack(z, static_cast<const char*>(msg.data()), msg.length(), offset);
msg.seek(static_cast<Stream::OffT>(offset));
upd.light = msg.readU16();
upd.cause = static_cast<UpdateData::Cause>(msg.readU8());
}
}
void BlockUpdatePlace::writeToMsg(OutMessage &msg) const {
msg.setType(MessageType::BlockUpdate, BlockUpdateSubtype::Place);
msg.writeI32(worldId);
msg.writeIVec3(pos);
msg.writeU16(id);
msg.writeU16(data);
msgpack::pack(msg, extdata);
}
void BlockUpdatePlace::readFromMsg(InMessage &msg) {
worldId = msg.readI32();
pos = msg.readIVec3();
id = msg.readU16();
data = msg.readU16();
Stream::PosT offset = msg.tell();
extdata = msgpack::unpack(z, static_cast<const char*>(msg.data()), msg.length(), offset);
}
void BlockUpdateBreak::writeToMsg(OutMessage &msg) const {
msg.setType(MessageType::BlockUpdate, BlockUpdateSubtype::Break);
msg.writeI32(worldId);
msg.writeIVec3(pos);
}
void BlockUpdateBreak::readFromMsg(InMessage &msg) {
worldId = msg.readI32();
pos = msg.readIVec3();
}
}
}

View File

@ -6,6 +6,7 @@
#include <msgpack.hpp>
#include "../../content/Content.hpp"
#include "../../World.hpp"
namespace Diggler {
namespace Net {
@ -24,11 +25,17 @@ struct BlockUpdateNotify : public MsgType {
bool : 4, light : 1, extdata : 1, data : 1, id : 1;
} updated;
static_assert(sizeof(updated) == 1, "Bitfields aren't packed");
WorldId worldId;
glm::ivec3 pos;
BlockId id;
BlockData data;
msgpack::object extdata;
LightData light;
enum Cause : uint8 {
Unspecified = 0,
PlayerPlace,
PlayerBreak
} cause;
};
std::vector<UpdateData> updates;
@ -38,6 +45,7 @@ struct BlockUpdateNotify : public MsgType {
struct BlockUpdatePlace : public MsgType {
msgpack::zone z;
WorldId worldId;
glm::ivec3 pos;
BlockId id;
BlockData data;
@ -48,6 +56,7 @@ struct BlockUpdatePlace : public MsgType {
};
struct BlockUpdateBreak : public MsgType {
WorldId worldId;
glm::ivec3 pos;
void writeToMsg(OutMessage&) const override;