Network teleport
parent
d5118cda5b
commit
f7a19a7b26
55
TODO.md
55
TODO.md
|
@ -8,21 +8,18 @@
|
|||
|
||||
## Hello other
|
||||
|
||||
- [ ] Multiplayer
|
||||
- [ ] Chat
|
||||
- [~] Authentication
|
||||
- [x] Compression
|
||||
- [ ] Encryption
|
||||
- [x] Embedded
|
||||
- [x] Standalone
|
||||
- [ ] VK
|
||||
- [ ] Pipeline recreate
|
||||
- [ ] Pipeline cache
|
||||
- [ ] Reuse descriptors
|
||||
- [ ] Secondary buffers
|
||||
|
||||
## Hello world
|
||||
|
||||
- [~] Map stream
|
||||
- Local prediction
|
||||
- [ ] Contouring service
|
||||
- [~] Edit
|
||||
- Local prediction
|
||||
|
@ -30,29 +27,49 @@
|
|||
- [ ] Iterator ray
|
||||
- [ ] Cast from chunk center
|
||||
- [ ] Transparency
|
||||
- [ ] Entities
|
||||
|
||||
## Hello darkness
|
||||
## Hello universe
|
||||
|
||||
- [ ] ECS
|
||||
- [ ] Area
|
||||
- [ ] Rotation
|
||||
- [ ] Universe
|
||||
- [ ] Galaxy
|
||||
- [ ] 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
|
||||
- [ ] Area corrected CubeSphere
|
||||
- [ ] Corrected Normals
|
||||
- [ ] Surface curvature
|
||||
- [ ] Curvature avare frustum
|
||||
- [ ] Healpix
|
||||
- [ ] Surface features
|
||||
- [ ] Biomes
|
||||
- https://imgur.com/kM8b5Zq
|
||||
- https://imgur.com/a/bh2iy
|
||||
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
|
||||
- [ ] Galaxy
|
||||
|
||||
## Hello industry
|
||||
|
||||
- [ ] Multiblock
|
||||
|
||||
## Hello darkness
|
||||
|
||||
- [ ] Slash screen
|
||||
- [ ] QUIC protocal
|
||||
- [ ] Octree
|
||||
- SIMD
|
||||
- [ ] Dynamic SIMD libs
|
||||
- [ ] FastNoiseSIMD / HastyNoise double precision
|
||||
- [ ] https://github.com/Auburn/FastNoise2/releases
|
||||
- [ ] Better Lod
|
||||
- [ ] VK
|
||||
- [ ] Pipeline recreate
|
||||
- [ ] Pipeline cache
|
||||
- [ ] Reuse descriptors
|
||||
- [ ] Secondary buffers
|
||||
- [ ] ECS
|
||||
- [ ] Cross plateforme encoding
|
||||
- [ ] Config (yaml)
|
||||
- [ ] HDR
|
||||
|
|
|
@ -19,7 +19,6 @@ void Client::run(server_handle* const localHandle) {
|
|||
InputMap inputs(window.getPtr());
|
||||
Controllable player(window.getPtr(), inputs, options.control);
|
||||
Camera camera(&player, options.camera);
|
||||
state.position = player.position;
|
||||
|
||||
auto pipeline = render::Renderer::Get();
|
||||
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);
|
||||
state.contouring = world->getContouring();
|
||||
world->onTeleport = [&](voxel_pos pos) {
|
||||
state.position = player.position = pos;
|
||||
};
|
||||
|
||||
do {
|
||||
window.startFrame();
|
||||
|
@ -49,7 +51,7 @@ void Client::run(server_handle* const localHandle) {
|
|||
if(pos != state.position.as_voxel(options.voxel_density)) {
|
||||
world->emit(world::action::Move(pos));
|
||||
}
|
||||
state.position = player.position;
|
||||
state.position = pos;
|
||||
}
|
||||
camera.update();
|
||||
pipeline->lookFrom(camera);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#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::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 z = -queryDistance; z <= queryDistance; z++) {
|
||||
const auto dist2 = x * x + y * y + z * z;
|
||||
if (dist2 <= queryDistance * queryDistance) {
|
||||
const auto p = diff + chunk_pos(x, y, z);
|
||||
if (chunks.inRange(p) && chunks.find(p) == chunks.end()) {
|
||||
const auto p = diff + chunk_pos(x, y, z);
|
||||
if (dist2 <= queryDistance * queryDistance && chunks.inRange(p)) {
|
||||
if (chunks.find(p) != chunks.end()) {
|
||||
contouring->onNotify(std::make_pair(area.first, p), diff, chunks);
|
||||
} else {
|
||||
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);
|
||||
switch (type) {
|
||||
case server_packet_type::CAPABILITIES: {
|
||||
PacketReader(packet).read(serverDistance);
|
||||
emit(world::action::Move(pos));
|
||||
PacketReader(packet, true).read(serverDistance);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -95,6 +96,12 @@ void DistantUniverse::pullNetwork(voxel_pos pos) {
|
|||
break;
|
||||
}
|
||||
|
||||
case server_packet_type::TELEPORT: {
|
||||
PacketReader(packet).read(pos);
|
||||
onTeleport(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
case server_packet_type::AREAS: {
|
||||
auto reader = PacketReader(packet, true);
|
||||
while(!reader.isFull()) {
|
||||
|
|
|
@ -23,10 +23,14 @@ LocalUniverse::~LocalUniverse() {
|
|||
}
|
||||
|
||||
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 chunkChange = cur_chunk != last_chunk;
|
||||
if (last_chunk.x == INT_MAX)
|
||||
emit(world::action::Move(pos));
|
||||
last_chunk = cur_chunk;
|
||||
|
||||
if(chunkChange) {
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace world::client {
|
|||
|
||||
/// Send action to ServerUniverse
|
||||
virtual void emit(const action::packet &) = 0;
|
||||
/// When server teleport player
|
||||
std::function<void(voxel_pos)> onTeleport;
|
||||
|
||||
/// Get current contouring worker
|
||||
contouring::Abstract* getContouring() const {
|
||||
|
|
|
@ -26,15 +26,18 @@ using packet_t = ENetPacket;
|
|||
enum class server_packet_type: enet_uint8 {
|
||||
PERSONAL = 0,
|
||||
/// Get server salt
|
||||
/// realable
|
||||
/// reliable
|
||||
CHALLENGE = 0,
|
||||
/// Set client position
|
||||
/// voxel_pos reliable
|
||||
TELEPORT = 1,
|
||||
|
||||
BROADCASTED = 16,
|
||||
/// List all areas
|
||||
/// {area_id, world::Area::params}[] realable
|
||||
/// {area_id, world::Area::params}[] reliable
|
||||
AREAS = 16,
|
||||
/// Full chunk update
|
||||
/// {area_<chunk_pos>, zstd<chunk rle>} realable
|
||||
/// {area_<chunk_pos>, zstd<chunk rle>} reliable
|
||||
CHUNK = 17,
|
||||
/// Chunk changes
|
||||
/// {area_id, {chunk_pos, ushort(count), Chunk::Edit[]}[]} notify
|
||||
|
@ -42,19 +45,19 @@ enum class server_packet_type: enet_uint8 {
|
|||
EDITS = 18,
|
||||
|
||||
/// World compression dictionary
|
||||
/// zstd dict realable
|
||||
/// zstd dict reliable
|
||||
COMPRESSION = 24,
|
||||
/// Server capabilities
|
||||
/// ushort(loadDistance), MAYBE: more realable
|
||||
/// ushort(loadDistance), MAYBE: more reliable
|
||||
CAPABILITIES = 25,
|
||||
};
|
||||
enum class client_packet_type: enet_uint8 {
|
||||
/// Interact with voxels
|
||||
/// actions::FillCube realable
|
||||
/// actions::FillCube reliable
|
||||
FILL_CUBE = 0,
|
||||
|
||||
/// Request missing chunks
|
||||
/// area_id, chunk_pos[] realable
|
||||
/// area_id, chunk_pos[] reliable
|
||||
MISSING_CHUNKS = 8,
|
||||
|
||||
/// 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 world::action::packet &packet)> emit;
|
||||
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) {
|
||||
// Local player
|
||||
[[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);
|
||||
localHandle->teleport = spawnPoint;
|
||||
movedPlayers.push_back(id);
|
||||
|
||||
localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area
|
||||
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) {
|
||||
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) {
|
||||
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)});
|
||||
//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();
|
||||
}
|
||||
|
||||
|
@ -292,7 +293,10 @@ void Universe::update(float deltaTime) {
|
|||
#if TRACY_ENABLE
|
||||
size_t entity_count = 0;
|
||||
#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) {
|
||||
#if TRACY_ENABLE
|
||||
entity_count++;
|
||||
|
@ -334,7 +338,7 @@ void Universe::pullNetwork() {
|
|||
[&](peer_t *peer, salt_t salt) {
|
||||
ZoneScopedN("Connect");
|
||||
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;
|
||||
|
||||
const salt_t rnd = std::rand();
|
||||
|
@ -343,6 +347,11 @@ void Universe::pullNetwork() {
|
|||
|
||||
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);
|
||||
{
|
||||
auto player = findEntity(PLAYER_ENTITY_ID, client->instanceId);
|
||||
host.sendTo(peer, server_packet_type::TELEPORT, player->pos.as_voxel(), channel_type::RELIABLE);
|
||||
movedPlayers.push_back(client->instanceId);
|
||||
}
|
||||
broadcastAreas();
|
||||
},
|
||||
[](peer_t *peer, disconnect_reason reason) {
|
||||
|
@ -382,25 +391,27 @@ void Universe::pullNetwork() {
|
|||
break;
|
||||
}
|
||||
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);
|
||||
area_id id = *reader.read<area_id>();
|
||||
if(auto area = areas.find(id); area != areas.end()) {
|
||||
auto &chunks = area->second->getChunks();
|
||||
const chunk_pos diff = glm::divide(pos - area->second->getOffset().as_voxel());
|
||||
while(!reader.isFull()) {
|
||||
chunk_pos cpos = *reader.read<chunk_pos>();
|
||||
if(glm::length2(diff - cpos) <= glm::pow2(loadDistance) && chunks.inRange(cpos)) {
|
||||
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);
|
||||
auto reader = PacketReader(packet);
|
||||
area_id id = *reader.read<area_id>();
|
||||
if(auto area = areas.find(id); area != areas.end()) {
|
||||
auto &chunks = area->second->getChunks();
|
||||
const chunk_pos diff = glm::divide(pos - area->second->getOffset().as_voxel());
|
||||
while(!reader.isFull()) {
|
||||
chunk_pos cpos = *reader.read<chunk_pos>();
|
||||
if(glm::length2(diff - cpos) <= glm::pow2(loadDistance) && chunks.inRange(cpos)) {
|
||||
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);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
@ -531,21 +542,27 @@ entity_instance_id Universe::addEntity(entity_id type, const Entity::Instance &i
|
|||
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) {
|
||||
if(!entities.contains(PLAYER_ENTITY_ID))
|
||||
return false;
|
||||
if (auto player = findEntity(PLAYER_ENTITY_ID, id)) {
|
||||
if(player->pos.as_voxel() == pos.as_voxel())
|
||||
return true;
|
||||
|
||||
if(!entities.at(PLAYER_ENTITY_ID).instances.contains(id))
|
||||
return false;
|
||||
|
||||
auto &player = entities.at(PLAYER_ENTITY_ID).instances.at(id);
|
||||
if(player.pos.as_voxel() == pos.as_voxel())
|
||||
//TODO: check dist + collision from a to b
|
||||
movedPlayers.push_back(id);
|
||||
player->pos = pos;
|
||||
return true;
|
||||
|
||||
//TODO: check dist + collision from a to b
|
||||
movedPlayers.push_back(id);
|
||||
player.pos = pos;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);
|
||||
Entity::Instance* findEntity(entity_id type, entity_id id);
|
||||
|
||||
/// Move player
|
||||
bool movePlayer(data::generational::id id, glm::ifvec3 pos);
|
||||
|
@ -79,6 +80,7 @@ namespace world::server {
|
|||
virtual void loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &);
|
||||
|
||||
std::vector<data::generational::id> movedPlayers;
|
||||
voxel_pos spawnPoint;
|
||||
|
||||
/// Alive areas containing chunks
|
||||
area_map areas;
|
||||
|
|
Loading…
Reference in New Issue