Compare commits
2 Commits
d5118cda5b
...
9f213f1a7f
Author | SHA1 | Date |
---|---|---|
May B. | 9f213f1a7f | |
May B. | f7a19a7b26 |
55
TODO.md
55
TODO.md
|
@ -8,21 +8,18 @@
|
||||||
|
|
||||||
## Hello other
|
## Hello other
|
||||||
|
|
||||||
|
- [ ] Multiplayer
|
||||||
- [ ] Chat
|
- [ ] Chat
|
||||||
- [~] Authentication
|
- [~] Authentication
|
||||||
- [x] Compression
|
- [x] Compression
|
||||||
- [ ] Encryption
|
- [ ] Encryption
|
||||||
- [x] Embedded
|
- [x] Embedded
|
||||||
- [x] Standalone
|
- [x] Standalone
|
||||||
- [ ] VK
|
|
||||||
- [ ] Pipeline recreate
|
|
||||||
- [ ] Pipeline cache
|
|
||||||
- [ ] Reuse descriptors
|
|
||||||
- [ ] Secondary buffers
|
|
||||||
|
|
||||||
## Hello world
|
## Hello world
|
||||||
|
|
||||||
- [~] Map stream
|
- [~] Map stream
|
||||||
|
- Local prediction
|
||||||
- [ ] Contouring service
|
- [ ] Contouring service
|
||||||
- [~] Edit
|
- [~] Edit
|
||||||
- Local prediction
|
- Local prediction
|
||||||
|
@ -30,29 +27,49 @@
|
||||||
- [ ] Iterator ray
|
- [ ] Iterator ray
|
||||||
- [ ] Cast from chunk center
|
- [ ] Cast from chunk center
|
||||||
- [ ] Transparency
|
- [ ] Transparency
|
||||||
|
- [ ] Entities
|
||||||
|
|
||||||
## Hello darkness
|
## Hello universe
|
||||||
|
|
||||||
- [ ] ECS
|
- [ ] Universe
|
||||||
- [ ] Area
|
- [ ] Galaxy
|
||||||
- [ ] Rotation
|
- [ ] Rotation
|
||||||
|
- [ ] Orbit system
|
||||||
|
- [ ] Gravity referential
|
||||||
|
- [ ] Better generation
|
||||||
|
- SIMD
|
||||||
|
- [ ] Dynamic SIMD libs
|
||||||
|
- [ ] FastNoiseSIMD / HastyNoise double precision
|
||||||
|
- [ ] https://github.com/Auburn/FastNoise2/releases
|
||||||
|
- [ ] Surface features
|
||||||
|
- [ ] Biomes
|
||||||
|
- https://imgur.com/kM8b5Zq
|
||||||
|
- https://imgur.com/a/bh2iy
|
||||||
|
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
|
||||||
|
- Curvature
|
||||||
- [~] CubeSphere
|
- [~] CubeSphere
|
||||||
- [ ] Area corrected CubeSphere
|
- [ ] Area corrected CubeSphere
|
||||||
- [ ] Corrected Normals
|
- [ ] Corrected Normals
|
||||||
- [ ] Surface curvature
|
- [ ] Surface curvature
|
||||||
- [ ] Curvature avare frustum
|
- [ ] Curvature avare frustum
|
||||||
- [ ] Healpix
|
- [ ] Healpix
|
||||||
- [ ] Surface features
|
|
||||||
- [ ] Biomes
|
## Hello industry
|
||||||
- https://imgur.com/kM8b5Zq
|
|
||||||
- https://imgur.com/a/bh2iy
|
- [ ] Multiblock
|
||||||
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
|
|
||||||
- [ ] Galaxy
|
## Hello darkness
|
||||||
|
|
||||||
|
- [ ] Slash screen
|
||||||
|
- [ ] QUIC protocal
|
||||||
- [ ] Octree
|
- [ ] Octree
|
||||||
- SIMD
|
- [ ] Better Lod
|
||||||
- [ ] Dynamic SIMD libs
|
- [ ] VK
|
||||||
- [ ] FastNoiseSIMD / HastyNoise double precision
|
- [ ] Pipeline recreate
|
||||||
- [ ] https://github.com/Auburn/FastNoise2/releases
|
- [ ] Pipeline cache
|
||||||
|
- [ ] Reuse descriptors
|
||||||
|
- [ ] Secondary buffers
|
||||||
|
- [ ] ECS
|
||||||
- [ ] Cross plateforme encoding
|
- [ ] Cross plateforme encoding
|
||||||
- [ ] Config (yaml)
|
- [ ] Config (yaml)
|
||||||
- [ ] HDR
|
- [ ] HDR
|
||||||
|
|
|
@ -19,7 +19,6 @@ void Client::run(server_handle* const localHandle) {
|
||||||
InputMap inputs(window.getPtr());
|
InputMap inputs(window.getPtr());
|
||||||
Controllable player(window.getPtr(), inputs, options.control);
|
Controllable player(window.getPtr(), inputs, options.control);
|
||||||
Camera camera(&player, options.camera);
|
Camera camera(&player, options.camera);
|
||||||
state.position = player.position;
|
|
||||||
|
|
||||||
auto pipeline = render::Renderer::Get();
|
auto pipeline = render::Renderer::Get();
|
||||||
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
|
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
|
||||||
|
@ -27,6 +26,9 @@ void Client::run(server_handle* const localHandle) {
|
||||||
|
|
||||||
auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring);
|
auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring);
|
||||||
state.contouring = world->getContouring();
|
state.contouring = world->getContouring();
|
||||||
|
world->onTeleport = [&](voxel_pos pos) {
|
||||||
|
state.position = player.position = pos;
|
||||||
|
};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
window.startFrame();
|
window.startFrame();
|
||||||
|
@ -49,7 +51,7 @@ void Client::run(server_handle* const localHandle) {
|
||||||
if(pos != state.position.as_voxel(options.voxel_density)) {
|
if(pos != state.position.as_voxel(options.voxel_density)) {
|
||||||
world->emit(world::action::Move(pos));
|
world->emit(world::action::Move(pos));
|
||||||
}
|
}
|
||||||
state.position = player.position;
|
state.position = pos;
|
||||||
}
|
}
|
||||||
camera.update();
|
camera.update();
|
||||||
pipeline->lookFrom(camera);
|
pipeline->lookFrom(camera);
|
||||||
|
@ -178,7 +180,7 @@ void Client::run(server_handle* const localHandle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
window.waitTargetFPS();
|
window.waitTargetFPS();
|
||||||
} while (!(inputs.isDown(Input::Quit) || window.shouldClose()));
|
} while (!(inputs.isDown(Input::Quit) || window.shouldClose() || world->isDisconnected()));
|
||||||
|
|
||||||
options.contouring = state.contouring->getOptions();
|
options.contouring = state.contouring->getOptions();
|
||||||
world.reset();
|
world.reset();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "Controllable.hpp"
|
#include "Controllable.hpp"
|
||||||
|
|
||||||
Controllable::Controllable(GLFWwindow *window, const InputMap& inputs, const Controllable::options& opt): position(voxel_pos(100, 0, 0), 1), window(window), inputs(inputs), o(opt){ }
|
Controllable::Controllable(GLFWwindow *window, const InputMap& inputs, const Controllable::options& opt): position(), window(window), inputs(inputs), o(opt){ }
|
||||||
Controllable::~Controllable() { }
|
Controllable::~Controllable() { }
|
||||||
|
|
||||||
Controllable::axis Controllable::getAxis() const {
|
Controllable::axis Controllable::getAxis() const {
|
||||||
|
|
|
@ -51,9 +51,11 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) {
|
||||||
for (int y = -queryDistance; y <= queryDistance; y++) {
|
for (int y = -queryDistance; y <= queryDistance; y++) {
|
||||||
for (int z = -queryDistance; z <= queryDistance; z++) {
|
for (int z = -queryDistance; z <= queryDistance; z++) {
|
||||||
const auto dist2 = x * x + y * y + z * z;
|
const auto dist2 = x * x + y * y + z * z;
|
||||||
if (dist2 <= queryDistance * queryDistance) {
|
const auto p = diff + chunk_pos(x, y, z);
|
||||||
const auto p = diff + chunk_pos(x, y, z);
|
if (dist2 <= queryDistance * queryDistance && chunks.inRange(p)) {
|
||||||
if (chunks.inRange(p) && chunks.find(p) == chunks.end()) {
|
if (chunks.find(p) != chunks.end()) {
|
||||||
|
contouring->onNotify(std::make_pair(area.first, p), diff, chunks);
|
||||||
|
} else {
|
||||||
missing.push_back(p);
|
missing.push_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,8 +83,7 @@ void DistantUniverse::pullNetwork(voxel_pos pos) {
|
||||||
const server_packet_type type = static_cast<server_packet_type>(*packet->data);
|
const server_packet_type type = static_cast<server_packet_type>(*packet->data);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case server_packet_type::CAPABILITIES: {
|
case server_packet_type::CAPABILITIES: {
|
||||||
PacketReader(packet).read(serverDistance);
|
PacketReader(packet, true).read(serverDistance);
|
||||||
emit(world::action::Move(pos));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +96,12 @@ void DistantUniverse::pullNetwork(voxel_pos pos) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case server_packet_type::TELEPORT: {
|
||||||
|
PacketReader(packet).read(pos);
|
||||||
|
onTeleport(pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case server_packet_type::AREAS: {
|
case server_packet_type::AREAS: {
|
||||||
auto reader = PacketReader(packet, true);
|
auto reader = PacketReader(packet, true);
|
||||||
while(!reader.isFull()) {
|
while(!reader.isFull()) {
|
||||||
|
@ -191,7 +198,13 @@ void DistantUniverse::pullNetwork(voxel_pos pos) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[](disconnect_reason){ });
|
[](disconnect_reason reason){
|
||||||
|
if (reason == disconnect_reason::UNEXPECTED) {
|
||||||
|
LOG_E("Connection to server lost");
|
||||||
|
} else {
|
||||||
|
LOG_W("Disconnected from server with " << (int)reason);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DistantUniverse::emit(const action::packet &action) {
|
void DistantUniverse::emit(const action::packet &action) {
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace world::client {
|
||||||
|
|
||||||
ray_result raycast(const geometry::Ray &) const override;
|
ray_result raycast(const geometry::Ray &) const override;
|
||||||
|
|
||||||
|
bool isDisconnected() const override { return peer.isDisconnected(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void pullNetwork(voxel_pos);
|
void pullNetwork(voxel_pos);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ LocalUniverse::LocalUniverse(server_handle *const handle, const std::string& con
|
||||||
Window::wait();
|
Window::wait();
|
||||||
}
|
}
|
||||||
handle->onUpdate = std::function([&](const area_<chunk_pos> &pos, const chunk_pos &offset, const world::ChunkContainer &data, geometry::Faces neighbors) {
|
handle->onUpdate = std::function([&](const area_<chunk_pos> &pos, const chunk_pos &offset, const world::ChunkContainer &data, geometry::Faces neighbors) {
|
||||||
contouring->onUpdate(pos, offset, data, neighbors);
|
contouring->onUpdate(pos, this->last_chunk - offset, data, neighbors);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
LocalUniverse::~LocalUniverse() {
|
LocalUniverse::~LocalUniverse() {
|
||||||
|
@ -23,10 +23,14 @@ LocalUniverse::~LocalUniverse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalUniverse::update(voxel_pos pos, float) {
|
void LocalUniverse::update(voxel_pos pos, float) {
|
||||||
|
if (handle->teleport.has_value() && onTeleport) {
|
||||||
|
pos = handle->teleport.value();
|
||||||
|
onTeleport(pos);
|
||||||
|
handle->teleport = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
const auto cur_chunk = glm::divide(pos);
|
const auto cur_chunk = glm::divide(pos);
|
||||||
const auto chunkChange = cur_chunk != last_chunk;
|
const auto chunkChange = cur_chunk != last_chunk;
|
||||||
if (last_chunk.x == INT_MAX)
|
|
||||||
emit(world::action::Move(pos));
|
|
||||||
last_chunk = cur_chunk;
|
last_chunk = cur_chunk;
|
||||||
|
|
||||||
if(chunkChange) {
|
if(chunkChange) {
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace world::client {
|
||||||
|
|
||||||
ray_result raycast(const geometry::Ray &ray) const override;
|
ray_result raycast(const geometry::Ray &ray) const override;
|
||||||
|
|
||||||
|
bool isDisconnected() const override { return !handle->running; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
server_handle *const handle;
|
server_handle *const handle;
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,16 @@ namespace world::client {
|
||||||
|
|
||||||
/// Send action to ServerUniverse
|
/// Send action to ServerUniverse
|
||||||
virtual void emit(const action::packet &) = 0;
|
virtual void emit(const action::packet &) = 0;
|
||||||
|
/// When server teleport player
|
||||||
|
std::function<void(voxel_pos)> onTeleport;
|
||||||
|
|
||||||
/// Get current contouring worker
|
/// Get current contouring worker
|
||||||
contouring::Abstract* getContouring() const {
|
contouring::Abstract* getContouring() const {
|
||||||
return contouring.get();
|
return contouring.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isDisconnected() const = 0;
|
||||||
|
|
||||||
//TODO: move to ClientUniverse
|
//TODO: move to ClientUniverse
|
||||||
//void getEntitiesModels(const std::function<void(const std::vector<glm::mat4> &, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density);
|
//void getEntitiesModels(const std::function<void(const std::vector<glm::mat4> &, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density);
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,17 @@ namespace data::generational {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename predicate>
|
||||||
|
bool contains(predicate fn) const {
|
||||||
|
for (size_t i = 0; i < entries.size(); i++) {
|
||||||
|
const auto &entry = entries[i];
|
||||||
|
if(entry.value.has_value() && fn(id(i, entry.generation), entry.value.value())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename extractor>
|
template<typename extractor>
|
||||||
void extract(extractor fn) {
|
void extract(extractor fn) {
|
||||||
for (size_t i = 0; i < entries.size(); i++) {
|
for (size_t i = 0; i < entries.size(); i++) {
|
||||||
|
|
|
@ -97,8 +97,6 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TracyPlot("CltNetUp", (int64_t)host->outgoingBandwidth);
|
|
||||||
TracyPlot("CltNetDown", (int64_t)host->incomingBandwidth);
|
|
||||||
TracyPlot("CltNetRTT", (int64_t)peer->roundTripTime);
|
TracyPlot("CltNetRTT", (int64_t)peer->roundTripTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +122,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool isReady() const { return ready; }
|
constexpr bool isReady() const { return ready; }
|
||||||
|
constexpr bool isDisconnected() const { return peer->state == ENET_PEER_STATE_DISCONNECTED; }
|
||||||
constexpr salt_t getSalt() const { return salt; }
|
constexpr salt_t getSalt() const { return salt; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -7,20 +7,25 @@ namespace net {
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
public:
|
public:
|
||||||
Server(const connection& ct, size_t connections) {
|
Server(const connection& ct, int connections) {
|
||||||
auto addr = [&] {
|
if(connections > 0) {
|
||||||
if (auto addr = ct.toAddress())
|
auto addr = [&] {
|
||||||
return addr.value();
|
if (auto addr = ct.toAddress())
|
||||||
|
return addr.value();
|
||||||
|
|
||||||
FATAL("Invalid ip address format");
|
FATAL("Invalid ip address format");
|
||||||
}();
|
}();
|
||||||
|
|
||||||
host = enet_host_create(&addr, connections, CHANNEL_COUNT, 0, 0);
|
host = enet_host_create(&addr, connections, CHANNEL_COUNT, 1 << 13, 1 << 13);
|
||||||
if(host == nullptr) {
|
if(host == nullptr) {
|
||||||
FATAL("Network server creation failed");
|
FATAL("Network server creation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I("Listening on " << ct);
|
||||||
|
} else {
|
||||||
|
host = nullptr;
|
||||||
|
LOG_D("Local only server");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_I("Listening on " << ct);
|
|
||||||
}
|
}
|
||||||
~Server() {
|
~Server() {
|
||||||
enet_host_destroy(host);
|
enet_host_destroy(host);
|
||||||
|
@ -28,6 +33,9 @@ public:
|
||||||
|
|
||||||
template<typename C, typename D, typename R>
|
template<typename C, typename D, typename R>
|
||||||
void pull(C onConnect, D onDisconnect, R onData, int delay = 10, int count = 10) {
|
void pull(C onConnect, D onDisconnect, R onData, int delay = 10, int count = 10) {
|
||||||
|
if (host == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
for(int i = 0; i < count && enet_host_service(host, &event, delay) > 0; i++) {
|
for(int i = 0; i < count && enet_host_service(host, &event, delay) > 0; i++) {
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
|
@ -49,8 +57,14 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TracyPlot("SrvNetUp", (int64_t)host->outgoingBandwidth);
|
TracyPlot("SrvNetUpData", (int64_t)host->totalSentData);
|
||||||
TracyPlot("SrvNetDown", (int64_t)host->incomingBandwidth);
|
host->totalSentData = 0;
|
||||||
|
TracyPlot("SrvNetUpPackets", (int64_t)host->totalSentPackets);
|
||||||
|
host->totalSentPackets = 0;
|
||||||
|
TracyPlot("SrvNetDownData", (int64_t)host->totalReceivedData);
|
||||||
|
host->totalReceivedData = 0;
|
||||||
|
TracyPlot("SrvNetDownPackets", (int64_t)host->totalReceivedPackets);
|
||||||
|
host->totalReceivedPackets = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnect(peer_t *peer, disconnect_reason reason) const {
|
void disconnect(peer_t *peer, disconnect_reason reason) const {
|
||||||
|
@ -91,7 +105,8 @@ public:
|
||||||
|
|
||||||
/// Send to all connected peers
|
/// Send to all connected peers
|
||||||
void broadcast(packet_t* packet, channel_type channel) {
|
void broadcast(packet_t* packet, channel_type channel) {
|
||||||
enet_host_broadcast(host, (enet_uint8)channel, packet);
|
if (host != nullptr)
|
||||||
|
enet_host_broadcast(host, (enet_uint8)channel, packet);
|
||||||
}
|
}
|
||||||
void broadcast(server_packet_type type, const void *data, size_t size, channel_type channel, std::optional<enet_uint32> flags = {}) {
|
void broadcast(server_packet_type type, const void *data, size_t size, channel_type channel, std::optional<enet_uint32> flags = {}) {
|
||||||
broadcast(makePacket(type, data, size, flags.value_or(channel == channel_type::RELIABLE ? ENET_PACKET_FLAG_RELIABLE : 0)).get(), channel);
|
broadcast(makePacket(type, data, size, flags.value_or(channel == channel_type::RELIABLE ? ENET_PACKET_FLAG_RELIABLE : 0)).get(), channel);
|
||||||
|
|
|
@ -26,15 +26,18 @@ using packet_t = ENetPacket;
|
||||||
enum class server_packet_type: enet_uint8 {
|
enum class server_packet_type: enet_uint8 {
|
||||||
PERSONAL = 0,
|
PERSONAL = 0,
|
||||||
/// Get server salt
|
/// Get server salt
|
||||||
/// realable
|
/// reliable
|
||||||
CHALLENGE = 0,
|
CHALLENGE = 0,
|
||||||
|
/// Set client position
|
||||||
|
/// voxel_pos reliable
|
||||||
|
TELEPORT = 1,
|
||||||
|
|
||||||
BROADCASTED = 16,
|
BROADCASTED = 16,
|
||||||
/// List all areas
|
/// List all areas
|
||||||
/// {area_id, world::Area::params}[] realable
|
/// {area_id, world::Area::params}[] reliable
|
||||||
AREAS = 16,
|
AREAS = 16,
|
||||||
/// Full chunk update
|
/// Full chunk update
|
||||||
/// {area_<chunk_pos>, zstd<chunk rle>} realable
|
/// {area_<chunk_pos>, zstd<chunk rle>} reliable
|
||||||
CHUNK = 17,
|
CHUNK = 17,
|
||||||
/// Chunk changes
|
/// Chunk changes
|
||||||
/// {area_id, {chunk_pos, ushort(count), Chunk::Edit[]}[]} notify
|
/// {area_id, {chunk_pos, ushort(count), Chunk::Edit[]}[]} notify
|
||||||
|
@ -42,19 +45,19 @@ enum class server_packet_type: enet_uint8 {
|
||||||
EDITS = 18,
|
EDITS = 18,
|
||||||
|
|
||||||
/// World compression dictionary
|
/// World compression dictionary
|
||||||
/// zstd dict realable
|
/// zstd dict reliable
|
||||||
COMPRESSION = 24,
|
COMPRESSION = 24,
|
||||||
/// Server capabilities
|
/// Server capabilities
|
||||||
/// ushort(loadDistance), MAYBE: more realable
|
/// ushort(loadDistance), MAYBE: more reliable
|
||||||
CAPABILITIES = 25,
|
CAPABILITIES = 25,
|
||||||
};
|
};
|
||||||
enum class client_packet_type: enet_uint8 {
|
enum class client_packet_type: enet_uint8 {
|
||||||
/// Interact with voxels
|
/// Interact with voxels
|
||||||
/// actions::FillCube realable
|
/// actions::FillCube reliable
|
||||||
FILL_CUBE = 0,
|
FILL_CUBE = 0,
|
||||||
|
|
||||||
/// Request missing chunks
|
/// Request missing chunks
|
||||||
/// area_id, chunk_pos[] realable
|
/// area_id, chunk_pos[] reliable
|
||||||
MISSING_CHUNKS = 8,
|
MISSING_CHUNKS = 8,
|
||||||
|
|
||||||
/// Position update
|
/// Position update
|
||||||
|
|
|
@ -10,4 +10,5 @@ struct server_handle {
|
||||||
std::function<void(const area_<chunk_pos> &pos, const chunk_pos &offset, const world::ChunkContainer &data, geometry::Faces neighbors)> onUpdate;
|
std::function<void(const area_<chunk_pos> &pos, const chunk_pos &offset, const world::ChunkContainer &data, geometry::Faces neighbors)> onUpdate;
|
||||||
std::function<void(const world::action::packet &packet)> emit;
|
std::function<void(const world::action::packet &packet)> emit;
|
||||||
std::function<world::Universe::ray_result(const geometry::Ray &ray)> raycast;
|
std::function<world::Universe::ray_result(const geometry::Ray &ray)> raycast;
|
||||||
|
std::optional<voxel_pos> teleport;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,8 +6,10 @@ using namespace world::server;
|
||||||
SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandle): Universe(o), localHandle(localHandle) {
|
SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandle): Universe(o), localHandle(localHandle) {
|
||||||
// Local player
|
// Local player
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const auto id = entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{});
|
const auto id = entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint});
|
||||||
assert(id == PLAYER_ENTITY_ID);
|
assert(id == PLAYER_ENTITY_ID);
|
||||||
|
localHandle->teleport = spawnPoint;
|
||||||
|
movedPlayers.insert(id);
|
||||||
|
|
||||||
localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area
|
localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area
|
||||||
localHandle->emit = std::function([&](const world::action::packet &packet) {
|
localHandle->emit = std::function([&](const world::action::packet &packet) {
|
||||||
|
@ -33,7 +35,8 @@ SharedUniverse::~SharedUniverse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedUniverse::loadChunk(area_<chunk_pos> area, chunk_pos diff, const world::ChunkContainer& chunks) {
|
void SharedUniverse::loadChunk(area_<chunk_pos> area, chunk_pos diff, const world::ChunkContainer& chunks) {
|
||||||
localHandle->onUpdate(area, diff, chunks, Faces::All);
|
if(localHandle->onUpdate)
|
||||||
|
localHandle->onUpdate(area, diff, chunks, Faces::All);
|
||||||
}
|
}
|
||||||
void SharedUniverse::updateChunk(area_map::iterator &it, world::ChunkContainer::iterator &it_c, chunk_pos diff, float deltaTime) {
|
void SharedUniverse::updateChunk(area_map::iterator &it, world::ChunkContainer::iterator &it_c, chunk_pos diff, float deltaTime) {
|
||||||
if (const auto neighbors = std::dynamic_pointer_cast<SharedChunk>(it_c->second)->update(deltaTime, true)) {
|
if (const auto neighbors = std::dynamic_pointer_cast<SharedChunk>(it_c->second)->update(deltaTime, true)) {
|
||||||
|
|
|
@ -52,6 +52,7 @@ Universe::Universe(const Universe::options &options): host(options.connection, o
|
||||||
generator::params(std::in_place_type<generator::RoundPlanet::Params>, radius * CHUNK_LENGTH * 3 / 4, 42)});
|
generator::params(std::in_place_type<generator::RoundPlanet::Params>, radius * CHUNK_LENGTH * 3 / 4, 42)});
|
||||||
//far_areas.emplace(Area::params{voxel_pos(0), 1 << 20, generator::params(std::in_place_type<generator::Cave::Params>, 42)});
|
//far_areas.emplace(Area::params{voxel_pos(0), 1 << 20, generator::params(std::in_place_type<generator::Cave::Params>, 42)});
|
||||||
}
|
}
|
||||||
|
spawnPoint = voxel_pos(100, 0, 0); //TODO: save in index
|
||||||
index.close();
|
index.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,29 +175,36 @@ void Universe::update(float deltaTime) {
|
||||||
|
|
||||||
pullNetwork();
|
pullNetwork();
|
||||||
|
|
||||||
if(entities.at(PLAYER_ENTITY_ID).instances.empty())
|
std::vector<voxel_pos> moves;
|
||||||
return;
|
{
|
||||||
|
moves.reserve(movedPlayers.size());
|
||||||
|
for (const auto& id: movedPlayers) {
|
||||||
|
if (auto player = findEntity(PLAYER_ENTITY_ID, id))
|
||||||
|
moves.push_back(player->pos.as_voxel());
|
||||||
|
}
|
||||||
|
movedPlayers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
const auto pos = entities.at(PLAYER_ENTITY_ID).instances.at(PLAYER_ENTITY_ID).pos.as_voxel();
|
if (!moves.empty()) {
|
||||||
const auto chunkChange = !movedPlayers.empty();
|
|
||||||
movedPlayers.clear();
|
|
||||||
|
|
||||||
if(chunkChange) {
|
|
||||||
ZoneScopedN("Far");
|
ZoneScopedN("Far");
|
||||||
bool extracted = false;
|
bool extracted = false;
|
||||||
far_areas.extract([&](area_id id, Area::params params) {
|
far_areas.extract([&](area_id id, Area::params params) {
|
||||||
if (const chunk_pos diff = glm::divide(pos - params.center);
|
for(const auto& move: moves) {
|
||||||
glm::length2(diff) > glm::pow2(loadDistance + params.radius))
|
if(const chunk_pos diff = glm::divide(move - params.center);
|
||||||
return false;
|
glm::length2(diff) <= glm::pow2(loadDistance + params.radius)) {
|
||||||
|
|
||||||
LOG_I("Load area " << id.index);
|
LOG_I("Load area " << id.index);
|
||||||
areas.emplace(id, std::make_shared<Area>(params));
|
areas.emplace(id, std::make_shared<Area>(params));
|
||||||
extracted = true;
|
extracted = true;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
if(extracted)
|
if(extracted)
|
||||||
broadcastAreas();
|
broadcastAreas();
|
||||||
}
|
}
|
||||||
|
const auto &players = entities.at(PLAYER_ENTITY_ID).instances;
|
||||||
{ // Update alive areas
|
{ // Update alive areas
|
||||||
ZoneScopedN("World");
|
ZoneScopedN("World");
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
|
@ -208,10 +216,19 @@ void Universe::update(float deltaTime) {
|
||||||
auto it = areas.begin();
|
auto it = areas.begin();
|
||||||
while (it != areas.end()) {
|
while (it != areas.end()) {
|
||||||
ZoneScopedN("Area");
|
ZoneScopedN("Area");
|
||||||
const bool chunkChangeArea = (false && it->first == 1 && it->second->move(glm::vec3(deltaTime))) || chunkChange; // TODO: area.velocity
|
//FIXME: const auto areaChunkChange = it->second->move(glm::vec3(deltaTime));
|
||||||
const chunk_pos diff = glm::divide(pos - it->second->getOffset().as_voxel());
|
const auto areaRange = glm::pow2(keepDistance + it->second->getChunks().getRadius());
|
||||||
|
const auto areaDiff = glm::divide(it->second->getOffset().as_voxel());
|
||||||
|
|
||||||
|
std::vector<chunk_pos> inAreaPlayers;
|
||||||
|
players.iter([&](entity_id, Entity::Instance player) {
|
||||||
|
const chunk_pos diff = glm::divide(player.pos.as_voxel() - it->second->getOffset().as_voxel());
|
||||||
|
if (glm::length2(diff) <= areaRange)
|
||||||
|
inAreaPlayers.push_back(diff);
|
||||||
|
});
|
||||||
|
|
||||||
auto &chunks = it->second->setChunks();
|
auto &chunks = it->second->setChunks();
|
||||||
if (glm::length2(diff) > glm::pow2(keepDistance + it->second->getChunks().getRadius())) {
|
if (inAreaPlayers.empty()) {
|
||||||
auto it_c = chunks.begin();
|
auto it_c = chunks.begin();
|
||||||
while(it_c != chunks.end()) {
|
while(it_c != chunks.end()) {
|
||||||
saveQueue.emplace(*it, std::make_pair(it_c->first, std::dynamic_pointer_cast<Chunk>(it_c->second)));
|
saveQueue.emplace(*it, std::make_pair(it_c->first, std::dynamic_pointer_cast<Chunk>(it_c->second)));
|
||||||
|
@ -229,35 +246,48 @@ void Universe::update(float deltaTime) {
|
||||||
ZoneScopedN("Alive");
|
ZoneScopedN("Alive");
|
||||||
auto it_c = chunks.begin();
|
auto it_c = chunks.begin();
|
||||||
while(it_c != chunks.end()) {
|
while(it_c != chunks.end()) {
|
||||||
if (glm::length2(diff - it_c->first) > glm::pow2(keepDistance)) {
|
if ([&] {
|
||||||
saveQueue.emplace(*it, std::make_pair(it_c->first, std::dynamic_pointer_cast<Chunk>(it_c->second))); //MAYBE: take look
|
const auto keepDist = glm::pow2(keepDistance);
|
||||||
lazyArea = false;
|
for(const auto& diff: inAreaPlayers) {
|
||||||
it_c = chunks.erase(it_c);
|
if (glm::length2(diff - it_c->first) < keepDist)
|
||||||
}else {
|
return true;
|
||||||
updateChunk(it, it_c, diff, deltaTime);
|
}
|
||||||
|
return false;
|
||||||
|
}()) {
|
||||||
|
updateChunk(it, it_c, areaDiff, deltaTime);
|
||||||
++it_c;
|
++it_c;
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
chunk_count++;
|
chunk_count++;
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
saveQueue.emplace(*it, std::make_pair(it_c->first, std::dynamic_pointer_cast<Chunk>(it_c->second))); //MAYBE: take look
|
||||||
|
lazyArea = false;
|
||||||
|
it_c = chunks.erase(it_c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chunkChangeArea) { // Enqueue missing chunks
|
{ // Enqueue missing chunks
|
||||||
ZoneScopedN("Missing");
|
ZoneScopedN("Missing");
|
||||||
auto handle = loadQueue.inserter();
|
auto handle = loadQueue.inserter();
|
||||||
//TODO: need dist so no easy sphere fill
|
for (const auto& to: moves) {
|
||||||
for (int x = -loadDistance; x <= loadDistance; x++) {
|
const chunk_pos diff = glm::divide(to - it->second->getOffset().as_voxel());
|
||||||
for (int y = -loadDistance; y <= loadDistance; y++) {
|
if (glm::length2(diff) > areaRange)
|
||||||
for (int z = -loadDistance; z <= loadDistance; z++) {
|
continue;
|
||||||
const auto dist2 = x * x + y * y + z * z;
|
|
||||||
if (dist2 <= loadDistance * loadDistance) {
|
//TODO: need dist so no easy sphere fill
|
||||||
const auto p = diff + chunk_pos(x, y, z);
|
for (int x = -loadDistance; x <= loadDistance; x++) {
|
||||||
if (chunks.inRange(p) && chunks.find(p) == chunks.end()) {
|
for (int y = -loadDistance; y <= loadDistance; y++) {
|
||||||
handle.first(std::make_pair(it->first, p), it->second, -dist2);
|
for (int z = -loadDistance; z <= loadDistance; z++) {
|
||||||
lazyArea = false;
|
const auto dist2 = x * x + y * y + z * z;
|
||||||
|
if (dist2 <= loadDistance * loadDistance) {
|
||||||
|
const auto p = diff + chunk_pos(x, y, z);
|
||||||
|
if (chunks.inRange(p) && chunks.find(p) == chunks.end()) {
|
||||||
|
handle.first(std::make_pair(it->first, p), it->second, -dist2);
|
||||||
|
lazyArea = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}}}
|
||||||
}}}
|
}
|
||||||
if(!lazyArea)
|
if(!lazyArea)
|
||||||
loadQueue.notify_all();
|
loadQueue.notify_all();
|
||||||
}
|
}
|
||||||
|
@ -269,7 +299,14 @@ void Universe::update(float deltaTime) {
|
||||||
region_count += unique->size();
|
region_count += unique->size();
|
||||||
#endif
|
#endif
|
||||||
for (auto it_r = unique->begin(); it_r != unique->end(); ++it_r) {
|
for (auto it_r = unique->begin(); it_r != unique->end(); ++it_r) {
|
||||||
if (glm::length2(diff - glm::lvec3(it_r->first) * glm::lvec3(REGION_LENGTH)) > glm::pow2(keepDistance + REGION_LENGTH * 2)) {
|
if([&] {
|
||||||
|
const auto keepDist = glm::pow2(keepDistance + REGION_LENGTH * 2);
|
||||||
|
for(const auto& diff: inAreaPlayers) {
|
||||||
|
if (glm::length2(diff - glm::lvec3(it_r->first) * glm::lvec3(REGION_LENGTH)) <= keepDist)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}()) {
|
||||||
unique->erase(it_r); //FIXME: may wait for os file access (long)
|
unique->erase(it_r); //FIXME: may wait for os file access (long)
|
||||||
break; //NOTE: save one only max per frame
|
break; //NOTE: save one only max per frame
|
||||||
}
|
}
|
||||||
|
@ -287,24 +324,29 @@ void Universe::update(float deltaTime) {
|
||||||
TracyPlot("ChunkUnload", static_cast<int64_t>(saveQueue.size()));
|
TracyPlot("ChunkUnload", static_cast<int64_t>(saveQueue.size()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
{ // Update entities
|
/* FIXME: { // Update entities
|
||||||
ZoneScopedN("Entities");
|
ZoneScopedN("Entities");
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
size_t entity_count = 0;
|
size_t entity_count = 0;
|
||||||
#endif
|
#endif
|
||||||
entities.for_each([&](entity_id, Entity &val) {
|
entities.for_each([&](entity_id type, Entity &val) {
|
||||||
|
if (type == PLAYER_ENTITY_ID) //FIXME: update players
|
||||||
|
return;
|
||||||
|
|
||||||
val.instances.remove([&](entity_id, Entity::Instance &inst) {
|
val.instances.remove([&](entity_id, Entity::Instance &inst) {
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
entity_count++;
|
entity_count++;
|
||||||
#endif
|
#endif
|
||||||
inst.pos += inst.velocity * deltaTime;
|
inst.pos += inst.velocity * deltaTime;
|
||||||
return glm::length2(glm::divide(pos - inst.pos.as_voxel())) > glm::pow2(keepDistance);
|
return glm::length2(glm::divide(pos - inst.pos.as_voxel())) > glm::pow2(keepDistance);
|
||||||
|
//MAYBE: Store in region ?
|
||||||
|
//MAYBE: Save to files
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
TracyPlot("EntityCount", static_cast<int64_t>(entity_count));
|
TracyPlot("EntityCount", static_cast<int64_t>(entity_count));
|
||||||
#endif
|
#endif
|
||||||
}
|
}*/
|
||||||
|
|
||||||
{ // Store loaded chunks
|
{ // Store loaded chunks
|
||||||
ZoneScopedN("Load");
|
ZoneScopedN("Load");
|
||||||
|
@ -312,8 +354,7 @@ void Universe::update(float deltaTime) {
|
||||||
for (auto handle = loadedQueue.extractor(); handle.first(loaded);) {
|
for (auto handle = loadedQueue.extractor(); handle.first(loaded);) {
|
||||||
if (const auto it = areas.find(loaded.first.first); it != areas.end()) {
|
if (const auto it = areas.find(loaded.first.first); it != areas.end()) {
|
||||||
it->second->setChunks().emplace(loaded.first.second, loaded.second);
|
it->second->setChunks().emplace(loaded.first.second, loaded.second);
|
||||||
const chunk_pos diff = glm::divide(pos - it->second->getOffset().as_voxel());
|
loadChunk(loaded.first, glm::divide(it->second->getOffset().as_voxel()), it->second->getChunks());
|
||||||
loadChunk(loaded.first, diff, it->second->getChunks());
|
|
||||||
// MAYBE: limit chunks per update
|
// MAYBE: limit chunks per update
|
||||||
host.broadcast(serializeChunk(loaded), net::channel_type::RELIABLE);
|
host.broadcast(serializeChunk(loaded), net::channel_type::RELIABLE);
|
||||||
}
|
}
|
||||||
|
@ -334,7 +375,7 @@ void Universe::pullNetwork() {
|
||||||
[&](peer_t *peer, salt_t salt) {
|
[&](peer_t *peer, salt_t salt) {
|
||||||
ZoneScopedN("Connect");
|
ZoneScopedN("Connect");
|
||||||
LOG_I("Client connect from " << peer->address);
|
LOG_I("Client connect from " << peer->address);
|
||||||
net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{ }));
|
net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint}));
|
||||||
peer->data = client;
|
peer->data = client;
|
||||||
|
|
||||||
const salt_t rnd = std::rand();
|
const salt_t rnd = std::rand();
|
||||||
|
@ -343,13 +384,20 @@ void Universe::pullNetwork() {
|
||||||
|
|
||||||
host.send(peer, server_packet_type::CAPABILITIES, loadDistance, channel_type::RELIABLE);
|
host.send(peer, server_packet_type::CAPABILITIES, loadDistance, channel_type::RELIABLE);
|
||||||
host.send(peer, server_packet_type::COMPRESSION, dict_content.data(), dict_content.size(), channel_type::RELIABLE);
|
host.send(peer, server_packet_type::COMPRESSION, dict_content.data(), dict_content.size(), channel_type::RELIABLE);
|
||||||
|
{
|
||||||
|
auto player = findEntity(PLAYER_ENTITY_ID, client->instanceId);
|
||||||
|
host.sendTo(peer, server_packet_type::TELEPORT, player->pos.as_voxel(), channel_type::RELIABLE);
|
||||||
|
movedPlayers.insert(client->instanceId);
|
||||||
|
}
|
||||||
broadcastAreas();
|
broadcastAreas();
|
||||||
},
|
},
|
||||||
[](peer_t *peer, disconnect_reason reason) {
|
[&](peer_t *peer, disconnect_reason reason) {
|
||||||
ZoneScopedN("Disconnect");
|
ZoneScopedN("Disconnect");
|
||||||
LOG_I("Client disconnect from " << peer->address << " with " << (enet_uint32)reason);
|
LOG_I("Client disconnect from " << peer->address << " with " << (enet_uint32)reason);
|
||||||
if (const auto data = Server::GetPeerData<net_client>(peer); data != nullptr)
|
if (const auto data = Server::GetPeerData<net_client>(peer)) {
|
||||||
|
entities.at(PLAYER_ENTITY_ID).instances.free(data->instanceId);
|
||||||
delete data;
|
delete data;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[&](peer_t *peer, packet_t* packet, channel_type) {
|
[&](peer_t *peer, packet_t* packet, channel_type) {
|
||||||
ZoneScopedN("Data");
|
ZoneScopedN("Data");
|
||||||
|
@ -382,25 +430,27 @@ void Universe::pullNetwork() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case client_packet_type::MISSING_CHUNKS: {
|
case client_packet_type::MISSING_CHUNKS: {
|
||||||
const auto pos = entities.at(PLAYER_ENTITY_ID).instances.at(Server::GetPeerData<net_client>(peer)->instanceId).pos.as_voxel();
|
if (auto player = findEntity(PLAYER_ENTITY_ID,Server::GetPeerData<net_client>(peer)->instanceId )) {
|
||||||
|
const auto pos = player->pos.as_voxel();
|
||||||
|
|
||||||
auto reader = PacketReader(packet);
|
auto reader = PacketReader(packet);
|
||||||
area_id id = *reader.read<area_id>();
|
area_id id = *reader.read<area_id>();
|
||||||
if(auto area = areas.find(id); area != areas.end()) {
|
if(auto area = areas.find(id); area != areas.end()) {
|
||||||
auto &chunks = area->second->getChunks();
|
auto &chunks = area->second->getChunks();
|
||||||
const chunk_pos diff = glm::divide(pos - area->second->getOffset().as_voxel());
|
const chunk_pos diff = glm::divide(pos - area->second->getOffset().as_voxel());
|
||||||
while(!reader.isFull()) {
|
while(!reader.isFull()) {
|
||||||
chunk_pos cpos = *reader.read<chunk_pos>();
|
chunk_pos cpos = *reader.read<chunk_pos>();
|
||||||
if(glm::length2(diff - cpos) <= glm::pow2(loadDistance) && chunks.inRange(cpos)) {
|
if(glm::length2(diff - cpos) <= glm::pow2(loadDistance) && chunks.inRange(cpos)) {
|
||||||
if(auto chunk = chunks.find(cpos); chunk != chunks.end()) {
|
if(auto chunk = chunks.find(cpos); chunk != chunks.end()) {
|
||||||
host.send(peer, serializeChunk({std::make_pair(id, cpos), std::dynamic_pointer_cast<Chunk>(chunk->second)}), net::channel_type::RELIABLE);
|
host.send(peer, serializeChunk({std::make_pair(id, cpos), std::dynamic_pointer_cast<Chunk>(chunk->second)}), net::channel_type::RELIABLE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_T("Request out of range chunk");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
LOG_T("Request out of range chunk");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LOG_T("Bad chunk request");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
LOG_T("Bad chunk request");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -531,21 +581,28 @@ entity_instance_id Universe::addEntity(entity_id type, const Entity::Instance &i
|
||||||
return std::make_pair(type, entities.at(type).instances.push(instance));
|
return std::make_pair(type, entities.at(type).instances.push(instance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Universe::Entity::Instance* Universe::findEntity(entity_id type, entity_id id) {
|
||||||
|
if(!entities.contains(type))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if(!entities.at(type).instances.contains(id))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &entities.at(type).instances.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
bool Universe::movePlayer(data::generational::id id, glm::ifvec3 pos) {
|
bool Universe::movePlayer(data::generational::id id, glm::ifvec3 pos) {
|
||||||
if(!entities.contains(PLAYER_ENTITY_ID))
|
if (auto player = findEntity(PLAYER_ENTITY_ID, id)) {
|
||||||
return false;
|
const auto initialPos = player->pos.as_voxel();
|
||||||
|
if (initialPos == pos.as_voxel())
|
||||||
|
return true;
|
||||||
|
|
||||||
if(!entities.at(PLAYER_ENTITY_ID).instances.contains(id))
|
//TODO: check dist + collision from a to b
|
||||||
return false;
|
movedPlayers.insert(id);
|
||||||
|
player->pos = pos;
|
||||||
auto &player = entities.at(PLAYER_ENTITY_ID).instances.at(id);
|
|
||||||
if(player.pos.as_voxel() == pos.as_voxel())
|
|
||||||
return true;
|
return true;
|
||||||
|
} else
|
||||||
//TODO: check dist + collision from a to b
|
return false;
|
||||||
movedPlayers.push_back(id);
|
|
||||||
player.pos = pos;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Chunk> Universe::createChunk(const chunk_pos &pos, const std::unique_ptr<generator::Abstract> &rnd) const {
|
std::shared_ptr<Chunk> Universe::createChunk(const chunk_pos &pos, const std::unique_ptr<generator::Abstract> &rnd) const {
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace world::server {
|
||||||
|
|
||||||
/// Instante entity
|
/// Instante entity
|
||||||
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);
|
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);
|
||||||
|
Entity::Instance* findEntity(entity_id type, entity_id id);
|
||||||
|
|
||||||
/// Move player
|
/// Move player
|
||||||
bool movePlayer(data::generational::id id, glm::ifvec3 pos);
|
bool movePlayer(data::generational::id id, glm::ifvec3 pos);
|
||||||
|
@ -78,7 +79,8 @@ namespace world::server {
|
||||||
virtual void updateChunk(area_map::iterator&, world::ChunkContainer::iterator&, chunk_pos, float deltaTime);
|
virtual void updateChunk(area_map::iterator&, world::ChunkContainer::iterator&, chunk_pos, float deltaTime);
|
||||||
virtual void loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &);
|
virtual void loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &);
|
||||||
|
|
||||||
std::vector<data::generational::id> movedPlayers;
|
robin_hood::unordered_set<data::generational::id> movedPlayers;
|
||||||
|
voxel_pos spawnPoint;
|
||||||
|
|
||||||
/// Alive areas containing chunks
|
/// Alive areas containing chunks
|
||||||
area_map areas;
|
area_map areas;
|
||||||
|
|
Loading…
Reference in New Issue