Basic gravity using pseudo sphere collider
parent
96f4bbf11c
commit
7f8e249a18
|
@ -68,6 +68,8 @@ public:
|
|||
world.trustMajorant = config["world"]["trust_majorant"].value_or(world.trustMajorant);
|
||||
world.editPrediction = config["world"]["edit_prediction"].value_or(world.editPrediction);
|
||||
world.editHandling = config["world"]["edit_handling"].value_or(world.editHandling);
|
||||
world.movePrediction = config["world"]["move_prediction"].value_or(world.movePrediction);
|
||||
world.moveCollision = config["world"]["move_collision"].value_or(world.moveCollision);
|
||||
voxel_density = config["world"]["voxel_density"].value_or(voxel_density);
|
||||
|
||||
#ifndef STANDALONE
|
||||
|
@ -148,6 +150,8 @@ public:
|
|||
{"trust_majorant", world.trustMajorant},
|
||||
{"edit_prediction", world.editPrediction},
|
||||
{"edit_handling", world.editHandling},
|
||||
{"move_prediction", world.movePrediction},
|
||||
{"move_collision", world.moveCollision},
|
||||
{"voxel_density", voxel_density}
|
||||
}));
|
||||
if(connection.has_value()) {
|
||||
|
|
|
@ -128,6 +128,19 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (options.movePrediction) {
|
||||
entities.remove([&](size_t eId, Entity &entity) {
|
||||
entity.instances.remove([&](size_t iId, Universe::Entity::Instance &inst) {
|
||||
if (eId == PLAYER_ENTITY_ID.index && iId == playerId)
|
||||
return false;
|
||||
|
||||
// MAYBE: leap after entities packet
|
||||
inst.pos += inst.velocity * deltaTime;
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
contouring->update(pos, areas);
|
||||
}
|
||||
|
@ -172,7 +185,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
}
|
||||
|
||||
case server_packet_type::COMPRESSION: {
|
||||
const auto remain = packet.readAll();
|
||||
const auto remain = packet.readRemaining();
|
||||
dict.emplace(remain.data(), remain.size());
|
||||
LOG_T("Compression dictionnary loaded");
|
||||
mayQueryChunks = true;
|
||||
|
@ -187,13 +200,13 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
}
|
||||
|
||||
case server_packet_type::MESSAGE: {
|
||||
const auto remain = packet.readAll();
|
||||
const auto remain = packet.readRemaining();
|
||||
onMessage(std::string((const char*)remain.data(), remain.size()));
|
||||
break;
|
||||
}
|
||||
|
||||
case server_packet_type::AREAS: {
|
||||
while(!packet.isFull()) {
|
||||
while(!packet.isDone()) {
|
||||
area_id id;
|
||||
world::Area::params p;
|
||||
if(!packet.read(id) || !packet.read(p))
|
||||
|
@ -228,7 +241,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
// MAYBE: then create virtual or non chunk of single material
|
||||
uint16_t full = 0;
|
||||
uint16_t total = 0;
|
||||
while (!packet.isFull()) {
|
||||
while (!packet.isDone()) {
|
||||
region_chunk_pos cpos;
|
||||
Voxel voxel;
|
||||
if (!packet.read(cpos) || !packet.read(voxel))
|
||||
|
@ -247,7 +260,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
if (!dict.has_value())
|
||||
break;
|
||||
|
||||
if (packet.isFull()) {
|
||||
if (packet.isDone()) {
|
||||
mayQueryChunks = true;
|
||||
break;
|
||||
}
|
||||
|
@ -267,7 +280,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
}
|
||||
|
||||
std::vector<char> buffer;
|
||||
if(auto err = dict.value().decompress(packet.readAll(), buffer)) {
|
||||
if(auto err = dict.value().decompress(packet.readRemaining(), buffer)) {
|
||||
LOG_E("Corrupted chunk packet " << err.value());
|
||||
break;
|
||||
}
|
||||
|
@ -313,14 +326,14 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
break;
|
||||
}
|
||||
|
||||
while(!packet.isFull()) {
|
||||
while(!packet.isDone()) {
|
||||
chunk_pos pos = chunk_pos(INT_MAX);
|
||||
packet.read(pos);
|
||||
chunk_voxel_idx count = 0;
|
||||
packet.read(count);
|
||||
if (auto ptr = it->second->setChunks().findInRange(pos)) {
|
||||
auto chunk = std::dynamic_pointer_cast<Chunk>(ptr.value());
|
||||
for (auto i = 0; i < count && !packet.isFull(); i++) {
|
||||
for (auto i = 0; i < count && !packet.isDone(); i++) {
|
||||
Chunk::Edit edit;
|
||||
packet.read(edit);
|
||||
chunk->apply(edit);
|
||||
|
@ -334,7 +347,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
|
||||
case server_packet_type::ENTITY_TYPES: {
|
||||
entities.clear();
|
||||
while(!packet.isFull()) {
|
||||
while(!packet.isDone()) {
|
||||
size_t index;
|
||||
glm::usvec3 size;
|
||||
glm::vec3 scale;
|
||||
|
@ -351,7 +364,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
|
||||
case server_packet_type::ENTITIES: {
|
||||
entities.remove([](size_t, Entity &entity) { entity.instances.clear(); return false; });
|
||||
while(!packet.isFull()) {
|
||||
while(!packet.isDone()) {
|
||||
size_t entity_idx;
|
||||
size_t count;
|
||||
if (!(packet.read(entity_idx) && packet.read(count)))
|
||||
|
@ -360,7 +373,7 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
if (auto entity = entities.get(entity_idx)) {
|
||||
if (count == 0)
|
||||
continue;
|
||||
for (size_t i = 0; i < count && !packet.isFull(); i++) {
|
||||
for (size_t i = 0; i < count && !packet.isDone(); i++) {
|
||||
size_t idx;
|
||||
glm::ifvec3 pos;
|
||||
glm::vec3 vel;
|
||||
|
@ -410,15 +423,9 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
auto area = std::get_if<Universe::Entity::area_t>(&it->shape);
|
||||
assert(area);
|
||||
area->clear();
|
||||
glm::i64 i = 0;
|
||||
while (!packet.isFull()) {
|
||||
i++;
|
||||
size_t size = 0;
|
||||
if (!packet.read(size))
|
||||
break;
|
||||
|
||||
while (!packet.isDone()) {
|
||||
std::vector<char> buffer;
|
||||
if(auto err = dict.value().decompress(packet.readPart(size), buffer)) {
|
||||
if(auto err = dict.value().decompress(packet.readSizedPart(), buffer)) {
|
||||
LOG_E("Corrupted entity chunk packet " << err.value());
|
||||
break;
|
||||
}
|
||||
|
@ -427,15 +434,15 @@ bool DistantUniverse::onPacket(const data::out_view& buf, net::PacketFlags) {
|
|||
area->push_back(std::make_shared<Chunk>(iss));
|
||||
}
|
||||
auto scale = glm::lvec3(1) + glm::divide(it->size);
|
||||
if (i != scale.x * scale.y * scale.z) {
|
||||
LOG_E("Corrupted entity area");
|
||||
if ((long)area->size() != scale.x * scale.y * scale.z) {
|
||||
LOG_E("Corrupted entity area " << area->size() << "!=" << (scale.x * scale.y * scale.z));
|
||||
break;
|
||||
}
|
||||
contouring->onEntityLoad(id, scale, *area);
|
||||
} else {
|
||||
auto model = std::get_if<Universe::Entity::model_t>(&it->shape);
|
||||
assert(model);
|
||||
auto remain = packet.readAll();
|
||||
auto remain = packet.readRemaining();
|
||||
model->resize(remain.size());
|
||||
//MAYBE: avoid storing model
|
||||
memcpy(model->data(), remain.data(), remain.size());
|
||||
|
|
|
@ -29,6 +29,10 @@ namespace world::client {
|
|||
bool editPrediction = true;
|
||||
/// Get only edits commands and compute locally
|
||||
bool editHandling = true;
|
||||
/// Apply velocity locally. Smooth entities positions
|
||||
bool movePrediction = true;
|
||||
/// Check for entities collisions
|
||||
bool moveCollision = false;
|
||||
};
|
||||
struct connection: net::address {
|
||||
connection(): net::address{"127.0.0.1", 4242} { }
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace glm {
|
|||
}
|
||||
inline ifvec3 operator+(const offset_t& v) const { return ifvec3(raw, offset + v); }
|
||||
inline ifvec3 operator-(const offset_t &v) const { return ifvec3(raw, offset - v); }
|
||||
inline ifvec3 operator-(const ifvec3 &v) const { return ifvec3(raw - v.raw, offset - v.offset); }
|
||||
inline ifvec3 operator/(int i) const { return ifvec3(raw / i, offset / (i * 1.f), false); }
|
||||
inline ifvec3 operator*(int i) const { return ifvec3(raw * i, offset * (i * 1.f)); }
|
||||
};
|
||||
|
|
|
@ -76,7 +76,8 @@ namespace glm {
|
|||
constexpr T inline max_axis(const vec<3, T> &v) {
|
||||
return std::max({v.x, v.y, v.z});
|
||||
}
|
||||
ivec3 inline inormalize(const ivec3 &v) {
|
||||
template <typename T>
|
||||
ivec3 inline inormalize(const vec<3, T> &v) {
|
||||
const auto a = glm::abs(v);
|
||||
return a.x >= a.y ? (a.x >= a.z ? ivec3(glm::sign(v.x), 0, 0) : ivec3(0, 0, glm::sign(v.z))) :
|
||||
(a.y >= a.z ? ivec3(0, glm::sign(v.y), 0) : ivec3(0, 0, glm::sign(v.z)));
|
||||
|
|
|
@ -24,6 +24,131 @@ struct view {
|
|||
constexpr size_t size() const { return siz; }
|
||||
constexpr bool isDone() const { return cur >= siz; }
|
||||
};
|
||||
// Abstract data writer
|
||||
struct in_view: view {
|
||||
in_view(uint8_t *ptr, size_t size): view(size), ptr(ptr) {
|
||||
assert(ptr != nullptr);
|
||||
}
|
||||
|
||||
uint8_t* ptr;
|
||||
uint8_t* writeTo(size_t len) {
|
||||
assert(cur + len <= siz);
|
||||
auto p = ptr + cur;
|
||||
cur += len;
|
||||
return p;
|
||||
}
|
||||
void write(const uint8_t* data, size_t len) {
|
||||
memcpy(writeTo(len), data, len);
|
||||
}
|
||||
};
|
||||
/// Writer with Dynamic allocation and subparts
|
||||
struct in_writer: public in_view {
|
||||
private:
|
||||
static constexpr auto EMPTY_OFFSET = 0x1000;
|
||||
static uint8_t* alloc(size_t size) { return (uint8_t*)(size > 0 ? ::malloc(size) : reinterpret_cast<uint8_t*>(EMPTY_OFFSET)); }
|
||||
static uint8_t* realloc(uint8_t* ptr, size_t size) { return (uint8_t*)::realloc(ptr, size); }
|
||||
static void free(uint8_t* ptr) { ::free(ptr); }
|
||||
|
||||
inline void auto_size(size_t len) {
|
||||
if (cur + len > siz)
|
||||
resize(cur + len);
|
||||
}
|
||||
|
||||
public:
|
||||
in_writer(size_t init_size = 0): in_view(alloc(init_size), init_size), vis_siz(init_size) { }
|
||||
~in_writer() { if (ptr != reinterpret_cast<uint8_t*>(EMPTY_OFFSET)) free(ptr); }
|
||||
|
||||
size_t vis_siz = 0;
|
||||
|
||||
uint8_t* data() { return ptr; }
|
||||
constexpr size_t size() const { return vis_siz; }
|
||||
|
||||
void write(const void* data, size_t len) {
|
||||
in_view::write((uint8_t*)data, len);
|
||||
}
|
||||
/// Write without resize
|
||||
template<typename D>
|
||||
void write(const D& d) {
|
||||
write(&d, sizeof(d));
|
||||
}
|
||||
|
||||
uint8_t* pushTo(size_t len) {
|
||||
auto_size(len);
|
||||
return writeTo(len);
|
||||
}
|
||||
void push(const void* data, size_t len) {
|
||||
auto_size(len);
|
||||
in_view::write((uint8_t*)data, len);
|
||||
}
|
||||
template<typename D>
|
||||
void push(const D& d) {
|
||||
push(&d, sizeof(d));
|
||||
}
|
||||
|
||||
size_t getCursor() const { return cur; }
|
||||
void writeAt(size_t pos, const void* data, size_t len) {
|
||||
assert(pos + len <= vis_siz);
|
||||
memcpy(ptr + pos, data, len);
|
||||
}
|
||||
template<typename D>
|
||||
void writeAt(size_t pos, const D& d) {
|
||||
writeAt(pos, &d, sizeof(d));
|
||||
}
|
||||
|
||||
void reserve(size_t target) {
|
||||
if (target >= siz) {
|
||||
ptr = realloc(ptr, target);
|
||||
siz = target;
|
||||
}
|
||||
}
|
||||
void resize(size_t target) {
|
||||
reserve(target);
|
||||
vis_siz = target;
|
||||
}
|
||||
|
||||
bool isFull() const {
|
||||
return cur >= vis_siz;
|
||||
}
|
||||
|
||||
// Must take ptr ownership before
|
||||
void reset() {
|
||||
ptr = reinterpret_cast<uint8_t*>(EMPTY_OFFSET);
|
||||
cur = 0;
|
||||
siz = 0;
|
||||
vis_siz = 0;
|
||||
}
|
||||
|
||||
struct part {
|
||||
part(in_writer* parent): up(parent), start(parent->cur) { }
|
||||
in_writer* up;
|
||||
size_t start;
|
||||
|
||||
uint8_t* data() { return up->data() + start; }
|
||||
constexpr size_t size() const { return up->size() - start; }
|
||||
|
||||
void reserve(size_t size) {
|
||||
up->reserve(start + size);
|
||||
}
|
||||
void resize(size_t size) {
|
||||
up->resize(start + size);
|
||||
}
|
||||
};
|
||||
template<typename CB>
|
||||
size_t pushPart(const CB& callback) {
|
||||
const auto prev = cur;
|
||||
callback(part(this));
|
||||
cur = vis_siz;
|
||||
return cur - prev;
|
||||
}
|
||||
template<typename CB>
|
||||
size_t pushSizedPart(const CB& callback) {
|
||||
const auto size_cur = cur;
|
||||
push<size_t>(0);
|
||||
const size_t size = pushPart(callback);
|
||||
writeAt(size_cur, size);
|
||||
return size;
|
||||
}
|
||||
};
|
||||
/// Vector with in_view interface
|
||||
struct in_vector {
|
||||
/// 512 Mébibits
|
||||
|
@ -44,23 +169,6 @@ struct in_vector {
|
|||
memcpy(writeTo(len), data, len);
|
||||
}
|
||||
};
|
||||
// Abstract data writer
|
||||
struct in_view: view {
|
||||
in_view(uint8_t *ptr, size_t size): view(size), ptr(ptr) {
|
||||
assert(ptr != nullptr);
|
||||
}
|
||||
|
||||
uint8_t* ptr;
|
||||
uint8_t* writeTo(size_t len) {
|
||||
assert(cur + len <= siz);
|
||||
auto p = ptr + cur;
|
||||
cur += len;
|
||||
return p;
|
||||
}
|
||||
void write(const uint8_t* data, size_t len) {
|
||||
memcpy(writeTo(len), data, len);
|
||||
}
|
||||
};
|
||||
/// Abstract data reader
|
||||
struct out_view: view {
|
||||
out_view(): out_view(nullptr, 0) { }
|
||||
|
@ -80,6 +188,42 @@ struct out_view: view {
|
|||
constexpr const uint8_t* data() const { return ptr; }
|
||||
constexpr size_t remaining() const { return size() - cur; }
|
||||
};
|
||||
/// Helper to read from out_view
|
||||
struct out_reader: public out_view {
|
||||
out_reader(const out_view& buf): out_view(buf.ptr, buf.siz) { cur = buf.cur; }
|
||||
|
||||
template<typename D>
|
||||
const D* read() {
|
||||
return cur + sizeof(D) <= size() ?
|
||||
(const D*)readFrom(sizeof(D)) : nullptr;
|
||||
}
|
||||
template<typename D>
|
||||
bool read(D& out) {
|
||||
const auto ptr = read<D>();
|
||||
if (ptr == nullptr)
|
||||
return false;
|
||||
|
||||
out = *ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skip(size_t size) {
|
||||
readFrom(size);
|
||||
return !isDone();
|
||||
}
|
||||
|
||||
data::out_view readPart(size_t size) {
|
||||
return data::out_view(readFrom(size), size);
|
||||
}
|
||||
data::out_view readSizedPart() {
|
||||
size_t size = 0;
|
||||
read(size);
|
||||
return readPart(size);
|
||||
}
|
||||
data::out_view readRemaining() {
|
||||
return readPart(remaining());
|
||||
}
|
||||
};
|
||||
/// Pointer to opaque owned memory
|
||||
using handle_t = std::shared_ptr<const void>;
|
||||
/// out_view with owned data
|
||||
|
@ -92,6 +236,9 @@ struct out_buffer: out_view {
|
|||
out_buffer(view, std::shared_ptr<const void>(view.ptr)) { }
|
||||
/// Take ptr ownership
|
||||
out_buffer(const uint8_t *ptr, size_t size): out_buffer(out_view(ptr, size)) { }
|
||||
/// Take ptr ownership (release writer)
|
||||
out_buffer(in_writer& writer):
|
||||
out_buffer(writer.data(), writer.size()) { writer.reset(); }
|
||||
|
||||
handle_t handle = nullptr;
|
||||
};
|
||||
|
|
|
@ -8,100 +8,19 @@ namespace net {
|
|||
//TODO: preallocate static data pool
|
||||
|
||||
/// Helper to write allocated packets
|
||||
class PacketWriter final {
|
||||
class PacketWriter final: public data::in_writer {
|
||||
public:
|
||||
PacketWriter(size_t size): buffer((uint8_t*)malloc(size), size), visible_size(size) { }
|
||||
PacketWriter(size_t size): data::in_writer(size) { }
|
||||
PacketWriter(uint8_t type, size_t data_size): PacketWriter(sizeof(type) + data_size) {
|
||||
write(type);
|
||||
}
|
||||
PacketWriter(net::client_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { }
|
||||
PacketWriter(net::server_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { }
|
||||
~PacketWriter() {
|
||||
if (buffer.ptr != nullptr)
|
||||
free(buffer.ptr);
|
||||
}
|
||||
|
||||
void write(const void* data, size_t len) {
|
||||
buffer.write((uint8_t*)data, len);
|
||||
}
|
||||
template<typename D>
|
||||
void write(const D& d) {
|
||||
write(&d, sizeof(d));
|
||||
}
|
||||
|
||||
constexpr size_t getCursor() const { return buffer.cur; }
|
||||
void writeAt(size_t pos, const void* data, size_t len) {
|
||||
assert(pos + len <= buffer.siz);
|
||||
memcpy(buffer.ptr + pos, data, len);
|
||||
}
|
||||
template<typename D>
|
||||
void writeAt(size_t pos, const D& d) {
|
||||
writeAt(pos, &d, sizeof(d));
|
||||
}
|
||||
|
||||
void reserve(size_t target) {
|
||||
if (target >= buffer.siz - buffer.cur) {
|
||||
const auto size = target + buffer.cur;
|
||||
buffer.ptr = (uint8_t *)realloc(buffer.ptr, size);
|
||||
buffer.siz = size;
|
||||
}
|
||||
}
|
||||
void resize(size_t target) {
|
||||
reserve(target);
|
||||
visible_size = target;
|
||||
}
|
||||
|
||||
void writePush(const void* data, size_t len) {
|
||||
if (buffer.cur + len > buffer.siz)
|
||||
resize(buffer.cur + len);
|
||||
write(data, len);
|
||||
}
|
||||
template<typename D>
|
||||
void writePush(const D& d) {
|
||||
writePush(&d, sizeof(d));
|
||||
}
|
||||
|
||||
struct varying_part {
|
||||
varying_part(data::in_view &buffer, size_t& p_size): buffer(buffer), parent_size(p_size), visible_size(0) { }
|
||||
~varying_part() {
|
||||
buffer.cur += visible_size;
|
||||
parent_size += visible_size;
|
||||
}
|
||||
|
||||
data::in_view &buffer;
|
||||
size_t &parent_size;
|
||||
size_t visible_size;
|
||||
|
||||
constexpr size_t size() const { return visible_size; }
|
||||
void* data() { return buffer.writeTo(0); }
|
||||
void reserve(size_t target) {
|
||||
if (target >= buffer.siz - buffer.cur) {
|
||||
const auto size = target + buffer.cur;
|
||||
buffer.ptr = (uint8_t *)realloc(buffer.ptr, size);
|
||||
buffer.siz = size;
|
||||
}
|
||||
}
|
||||
void resize(size_t target) {
|
||||
reserve(target);
|
||||
visible_size = target;
|
||||
}
|
||||
};
|
||||
/// Only from resize, write, resize down
|
||||
varying_part varying() {
|
||||
return varying_part(buffer, visible_size);
|
||||
}
|
||||
|
||||
bool isFull() const {
|
||||
return buffer.cur >= visible_size;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
data::out_buffer finish() {
|
||||
assert(isFull());
|
||||
data::out_buffer cpy(buffer.ptr, visible_size);
|
||||
buffer.ptr = nullptr;
|
||||
buffer.siz = 0;
|
||||
return cpy;
|
||||
return data::out_buffer(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
|
@ -126,50 +45,12 @@ public:
|
|||
static data::out_buffer Of(net::server_packet_type type, const D& data) {
|
||||
return Of(type, &data, sizeof(data));
|
||||
}
|
||||
|
||||
private:
|
||||
data::in_view buffer;
|
||||
size_t visible_size;
|
||||
};
|
||||
|
||||
/// Helper to read out_view
|
||||
class PacketReader final {
|
||||
class PacketReader final: public data::out_reader {
|
||||
public:
|
||||
PacketReader(const data::out_view& buf): buffer(buf) { }
|
||||
|
||||
template<typename D>
|
||||
const D* read() {
|
||||
return buffer.cur + sizeof(D) <= buffer.size() ?
|
||||
(const D*)buffer.readFrom(sizeof(D)) : nullptr;
|
||||
}
|
||||
template<typename D>
|
||||
bool read(D& out) {
|
||||
const auto ptr = read<D>();
|
||||
if (ptr == nullptr)
|
||||
return false;
|
||||
|
||||
out = *ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skip(size_t size) {
|
||||
buffer.readFrom(size);
|
||||
return !isFull();
|
||||
}
|
||||
|
||||
data::out_view readPart(size_t size) {
|
||||
return data::out_view(buffer.readFrom(size), size);
|
||||
}
|
||||
data::out_view readAll() {
|
||||
return readPart(buffer.size() - buffer.cur);
|
||||
}
|
||||
|
||||
bool isFull() const {
|
||||
return buffer.isDone();
|
||||
}
|
||||
|
||||
private:
|
||||
data::out_view buffer;
|
||||
PacketReader(const data::out_view& buf): data::out_reader(buf) { }
|
||||
};
|
||||
|
||||
}
|
|
@ -30,6 +30,8 @@ namespace world::server {
|
|||
std::optional<double> getCurvature() const override { return GetCurvature(generator_properties); }
|
||||
static std::optional<double> GetCurvature(const generator::params &);
|
||||
|
||||
inline const glm::vec3 getGravity(const voxel_pos& p) const { return generator->getGravity(p); }
|
||||
|
||||
private:
|
||||
shared_guarded<regions_t> regions;
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@ void Universe::update(float deltaTime) {
|
|||
const auto areaDiff = glm::divide(it->second->getOffset().as_voxel());
|
||||
|
||||
std::vector<chunk_pos> inAreaPlayers;
|
||||
players.iter([&](entity_id, Entity::Instance player) {
|
||||
players.iter([&](const entity_id&, const 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);
|
||||
|
@ -414,6 +414,9 @@ void Universe::update(float deltaTime) {
|
|||
ZoneScopedN("Entities");
|
||||
size_t item_count = 0;
|
||||
entities.remove([&](entity_id type, Entity &val) {
|
||||
//TODO: find mass center
|
||||
const auto OFFSET = glm::vec3(val.size) * val.scale / 2.f;
|
||||
const auto DIST2 = glm::pow2(loadDistance); //NOTE: must be < keepDistance + glm::length(OFFSET) to avoid collision miss
|
||||
val.instances.remove([&](entity_id, Entity::Instance &inst) {
|
||||
if (type == PLAYER_ENTITY_ID) {
|
||||
//MAYBE: update players ?
|
||||
|
@ -421,14 +424,25 @@ void Universe::update(float deltaTime) {
|
|||
return false;
|
||||
}
|
||||
|
||||
inst.pos += inst.velocity * deltaTime;
|
||||
if (true /*FIXME: remove far entities ? glm::length2(glm::divide(pos - inst.pos.as_voxel())) <= glm::pow2(keepDistance);*/) {
|
||||
//TODO: partition space
|
||||
auto pos = inst.pos + OFFSET;
|
||||
for(const auto& area: areas) {
|
||||
//NOTE: consider entity mass negligible
|
||||
inst.velocity += area.second->getGravity((pos - area.second->getOffset()).as_voxel()) * deltaTime;
|
||||
}
|
||||
//MAYBE: friction
|
||||
if (move(pos, inst.velocity, 1, glm::max_axis(OFFSET))) {
|
||||
inst.velocity = glm::vec3(0);
|
||||
}
|
||||
inst.pos = pos - OFFSET;
|
||||
if (entities.at(PLAYER_ENTITY_ID).instances.contains([&](const entity_id&, const Entity::Instance& player) {
|
||||
return glm::length2(glm::divide((player.pos - inst.pos).as_voxel())) <= DIST2;
|
||||
})) {
|
||||
item_count++;
|
||||
return false;
|
||||
}
|
||||
//TODO: Save to files if !temporary
|
||||
return true;
|
||||
//MAYBE: Store in region ?
|
||||
//MAYBE: Save to files
|
||||
});
|
||||
return !val.permanant && val.instances.empty();
|
||||
});
|
||||
|
@ -558,7 +572,7 @@ bool Universe::onPacket(net::server::Peer *peer, const data::out_view &buf, net:
|
|||
break;
|
||||
}
|
||||
case client_packet_type::MESSAGE: {
|
||||
const auto ref = packet.readAll();
|
||||
const auto ref = packet.readRemaining();
|
||||
broadcastMessage("Player" + std::to_string(peer->getCtx<net_client>()->instanceId.index)
|
||||
+ ": " + std::string((const char*)ref.data(), ref.size()));
|
||||
break;
|
||||
|
@ -573,7 +587,7 @@ bool Universe::onPacket(net::server::Peer *peer, const data::out_view &buf, net:
|
|||
break;
|
||||
if (auto area = areas.find(id); area != areas.end()) {
|
||||
const chunk_pos areaOffset = glm::divide(pos - area->second->getOffset().as_voxel());
|
||||
while (!packet.isFull()) {
|
||||
while (!packet.isDone()) {
|
||||
region_pos rpos;
|
||||
if (!packet.read(rpos))
|
||||
break;
|
||||
|
@ -582,10 +596,8 @@ bool Universe::onPacket(net::server::Peer *peer, const data::out_view &buf, net:
|
|||
if (glm::length2(areaOffset - glm::lvec3(it_r->first) * glm::lvec3(REGION_LENGTH)) <= glm::pow2(loadDistance + REGION_LENGTH * 2)) {
|
||||
auto packet = PacketWriter(server_packet_type::REGION, sizeof(area_<region_pos>));
|
||||
packet.write<area_<region_pos>>(std::make_pair(id, rpos));
|
||||
{
|
||||
auto vec = packet.varying();
|
||||
it_r->second->averages(vec);
|
||||
}
|
||||
packet.pushPart([&](PacketWriter::part part) {
|
||||
it_r->second->averages(part); });
|
||||
peer->send(packet.finish(), net::server::CHUNK);
|
||||
} else {
|
||||
LOG_T("Request out of range region");
|
||||
|
@ -611,7 +623,7 @@ bool Universe::onPacket(net::server::Peer *peer, const data::out_view &buf, net:
|
|||
auto &chunks = area->second->getChunks();
|
||||
const chunk_pos areaOffset = glm::divide(pos - area->second->getOffset().as_voxel());
|
||||
|
||||
for (size_t i = 0; !packet.isFull() && i < MAX_PENDING_CHUNK_COUNT; i++) {
|
||||
for (size_t i = 0; !packet.isDone() && i < MAX_PENDING_CHUNK_COUNT; i++) {
|
||||
chunk_pos cpos;
|
||||
if (!packet.read(cpos))
|
||||
break;
|
||||
|
@ -642,15 +654,8 @@ bool Universe::onPacket(net::server::Peer *peer, const data::out_view &buf, net:
|
|||
for (auto it = area->begin(); it != area->end(); ++it) {
|
||||
std::ostringstream out;
|
||||
std::dynamic_pointer_cast<Chunk>(*it)->write(out);
|
||||
auto size_pos = packet.getCursor();
|
||||
size_t size = 0;
|
||||
packet.writePush(size);
|
||||
{
|
||||
auto vec = packet.varying();
|
||||
dict_write_ctx.compress(out.str(), vec);
|
||||
size = vec.size();
|
||||
}
|
||||
packet.writeAt(size_pos, size);
|
||||
packet.pushSizedPart([&](PacketWriter::part part) {
|
||||
dict_write_ctx.compress(out.str(), part); });
|
||||
}
|
||||
peer->send(packet.finish(), net::server::CHUNK);
|
||||
} else {
|
||||
|
@ -691,10 +696,8 @@ data::out_buffer Universe::serializeChunk(area_<chunk_pos> id, const std::shared
|
|||
data->write(out);
|
||||
auto packet = net::PacketWriter(net::server_packet_type::CHUNK, sizeof(id));
|
||||
packet.write(id);
|
||||
{
|
||||
auto vec = packet.varying();
|
||||
dict_write_ctx.compress(out.str(), vec);
|
||||
}
|
||||
packet.pushPart([&](net::PacketWriter::part part){
|
||||
dict_write_ctx.compress(out.str(), part); });
|
||||
return packet.finish();
|
||||
}
|
||||
void Universe::broadcastMessage(const std::string& text) {
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace world::generator {
|
|||
/// Generate chunk voxels
|
||||
/// MAYBE: use template to avoid virtual
|
||||
virtual void generate(const chunk_pos &at, std::array<Voxel, CHUNK_SIZE> &out) = 0;
|
||||
/// Get gravity vector at given point
|
||||
virtual glm::vec3 getGravity(const voxel_pos& point) const = 0;
|
||||
};
|
||||
|
||||
// Generate empty space
|
||||
|
@ -24,6 +26,7 @@ namespace world::generator {
|
|||
void generate(const chunk_pos &, std::array<Voxel, CHUNK_SIZE> &out) override {
|
||||
out.fill(Voxel());
|
||||
}
|
||||
glm::vec3 getGravity(const voxel_pos&) const override { return glm::vec3(0); }
|
||||
};
|
||||
|
||||
/// Endless cave network
|
||||
|
@ -51,6 +54,7 @@ namespace world::generator {
|
|||
out[i] = Voxel(material, density);
|
||||
}
|
||||
}
|
||||
glm::vec3 getGravity(const voxel_pos&) const override { return glm::vec3(-1, 0, 0); }
|
||||
private:
|
||||
Params params;
|
||||
Noise density;
|
||||
|
@ -110,6 +114,12 @@ namespace world::generator {
|
|||
}();
|
||||
}
|
||||
}
|
||||
glm::vec3 getGravity(const voxel_pos& pos) const override {
|
||||
const auto heightRatio = static_cast<float>((getHeight(pos) - params.height) / params.height);
|
||||
const auto scale = params.height >> 7;
|
||||
const auto mass = scale * scale * scale; //FIXME: average material density
|
||||
return -getSurfaceDir(pos) * std::max(0.f, 1.f - heightRatio * heightRatio) * glm::vec3(mass);
|
||||
}
|
||||
private:
|
||||
static constexpr PlanetShape shape = PS;
|
||||
static constexpr glm::f64 getHeight(const voxel_pos &p) {
|
||||
|
@ -119,6 +129,15 @@ namespace world::generator {
|
|||
return glm::length(glm::dvec3(p));
|
||||
}
|
||||
}
|
||||
/// Centre inverse direction
|
||||
// NOTE: So center point is consider mass center
|
||||
static constexpr glm::vec3 getSurfaceDir(const voxel_pos &p) {
|
||||
if constexpr(shape == PlanetShape::Cube) {
|
||||
return glm::inormalize(p);
|
||||
} else {
|
||||
return glm::normalize(glm::dvec3(p));
|
||||
}
|
||||
}
|
||||
Params params;
|
||||
Noise density;
|
||||
Noise displacement;
|
||||
|
|
Loading…
Reference in New Issue