Standalone exe & missing chunks request
This commit is contained in:
parent
c760edb0a4
commit
ba8405e51f
|
@ -22,33 +22,8 @@ add_subdirectory("include/glfw")
|
|||
add_subdirectory("include/glm")
|
||||
add_subdirectory("include/enet")
|
||||
add_subdirectory("include/zstd")
|
||||
set(LINKED_LIBS glfw pthread dl
|
||||
glm::glm_static enet::enet_static zstd::zstd_static)
|
||||
|
||||
file(GLOB_RECURSE SOURCES "src/*/*.cpp")
|
||||
file(GLOB INCLUDE_SOURCES
|
||||
"include/imgui/*.cpp"
|
||||
"include/FastNoiseSIMD/*.cpp"
|
||||
"include/tracy/TracyClient.cpp"
|
||||
"include/meshoptimizer/*.cpp"
|
||||
"include/gl3w/gl3w.c"
|
||||
)
|
||||
set(INCLUDE_LIBS
|
||||
"include/imgui"
|
||||
"include/FastNoiseSIMD"
|
||||
"include/toml++"
|
||||
"include/robin_hood"
|
||||
"include/libguarded"
|
||||
"include/tracy"
|
||||
"include/meshoptimizer"
|
||||
"include/gl3w"
|
||||
)
|
||||
|
||||
add_executable(univerxel "src/main.cpp" ${SOURCES} ${INCLUDE_SOURCES})
|
||||
target_compile_features(univerxel PUBLIC cxx_std_17)
|
||||
target_link_libraries(univerxel ${LINKED_LIBS})
|
||||
target_include_directories(univerxel PRIVATE ${INCLUDE_LIBS})
|
||||
target_compile_definitions(univerxel PRIVATE FIXED_WINDOW=${FIXED_WINDOW} HN_USE_FILESYSTEM=1)
|
||||
add_compile_definitions(FIXED_WINDOW=${FIXED_WINDOW} HN_USE_FILESYSTEM=1)
|
||||
if(PROFILING)
|
||||
add_compile_definitions(TRACY_ENABLE=1)
|
||||
endif(PROFILING)
|
||||
|
@ -62,7 +37,37 @@ if(USE_FMA)
|
|||
add_definitions(-mfma)
|
||||
endif(USE_FMA)
|
||||
|
||||
file(GLOB_RECURSE CORE_SOURCES "src/core/*.cpp" "include/tracy/TracyClient.cpp")
|
||||
set(CORE_HEADERS "include/toml++" "include/robin_hood" "include/libguarded" "include/tracy")
|
||||
set(CORE_LIBS pthread dl glm::glm_static enet::enet_static zstd::zstd_static)
|
||||
|
||||
file(GLOB_RECURSE CLIENT_SOURCES "src/client/*.cpp" "include/imgui/*.cpp" "include/meshoptimizer/*.cpp" "include/gl3w/gl3w.c")
|
||||
set(CLIENT_HEADERS "include/imgui" "include/meshoptimizer" "include/gl3w")
|
||||
set(CLIENT_LIBS glfw)
|
||||
|
||||
file(GLOB_RECURSE SERVER_SOURCES "src/server/*.cpp" "include/FastNoiseSIMD/*.cpp")
|
||||
set(SERVER_HEADERS "include/FastNoiseSIMD")
|
||||
set(SERVER_LINKED)
|
||||
|
||||
# All in one exec
|
||||
add_executable(univerxel "src/main.cpp" ${CORE_SOURCES} ${CLIENT_SOURCES} ${SERVER_SOURCES})
|
||||
target_compile_features(univerxel PUBLIC cxx_std_17)
|
||||
target_link_libraries(univerxel ${CORE_LIBS} ${CLIENT_LIBS} ${SERVER_LIBS})
|
||||
target_include_directories(univerxel PRIVATE ${CORE_HEADERS} ${CLIENT_HEADERS} ${SERVER_HEADERS})
|
||||
|
||||
# Standalone server
|
||||
add_executable(univerxel-server EXCLUDE_FROM_ALL "src/server.cpp" ${CORE_SOURCES} ${SERVER_SOURCES})
|
||||
target_compile_features(univerxel-server PUBLIC cxx_std_17)
|
||||
target_link_libraries(univerxel-server ${CORE_LIBS} ${SERVER_LIBS})
|
||||
target_include_directories(univerxel-server PRIVATE ${CORE_HEADERS} ${SERVER_HEADERS})
|
||||
|
||||
# Dumb client
|
||||
add_executable(univerxel-client EXCLUDE_FROM_ALL "src/client.cpp" ${CORE_SOURCES} ${CLIENT_SOURCES})
|
||||
target_compile_features(univerxel-client PUBLIC cxx_std_17)
|
||||
target_link_libraries(univerxel-client ${CORE_LIBS} ${CLIENT_LIBS})
|
||||
target_include_directories(univerxel-client PRIVATE ${CORE_HEADERS} ${CLIENT_HEADERS})
|
||||
|
||||
# Resource client files + default zstd.dict
|
||||
file(COPY resource/content DESTINATION ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Docs
|
||||
|
@ -71,14 +76,3 @@ add_custom_target(docs
|
|||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
COMMENT "Build doc."
|
||||
)
|
||||
|
||||
# Builtin models
|
||||
file(GLOB_RECURSE MCT_SOURCES "src/model_contouring.cpp" "src/*/*.cpp")
|
||||
add_executable(model_contouring EXCLUDE_FROM_ALL ${MCT_SOURCES} ${INCLUDE_SOURCES})
|
||||
target_compile_features(model_contouring PUBLIC cxx_std_17)
|
||||
target_link_libraries(model_contouring ${LINKED_LIBS})
|
||||
target_include_directories(model_contouring PRIVATE ${INCLUDE_LIBS})
|
||||
|
||||
add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/content/model.ivb"
|
||||
COMMAND "${CMAKE_BINARY_DIR}/model_contouring" DEPENDS model_contouring)
|
||||
add_custom_target(render_models DEPENDS "${CMAKE_BINARY_DIR}/content/model.ivb")
|
||||
|
|
2
TODO.md
2
TODO.md
|
@ -14,7 +14,7 @@
|
|||
- [x] Compression
|
||||
- [ ] Encryption
|
||||
- [x] Embedded
|
||||
- [ ] Standalone
|
||||
- [x] Standalone
|
||||
|
||||
## Hello world
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ endif()
|
|||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
||||
option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF)
|
||||
option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF)
|
||||
option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF)
|
||||
option(GLFW_INSTALL "Generate installation target" OFF)
|
||||
option(GLFW_VULKAN_STATIC "Assume the Vulkan loader is linked with the application" OFF)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(GLFW_BUILD_EXAMPLES OFF)
|
||||
set(GLFW_BUILD_TESTS OFF)
|
||||
set(GLFW_BUILD_DOCS OFF)
|
||||
set(GLFW_INSTALL OFF)
|
||||
set(GLFW_VULKAN_STATIC OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakeDependentOption)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#define TOML_HEADER_ONLY 0
|
||||
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
|
||||
//# Copyright (c) 2019-2020 Mark Gillard <mark.gillard@outlook.com.au>
|
||||
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* \file server.cpp
|
||||
* \brief Univerxel client
|
||||
* \author Maelys Bois
|
||||
* \version 0.0.1
|
||||
*
|
||||
* Univerxel standalone client program.
|
||||
*/
|
||||
|
||||
#define STANDALONE 1
|
||||
#include "client/Client.hpp"
|
||||
#include "core/standalone_config.hpp"
|
||||
#include "core/utils/tracy.hpp"
|
||||
|
||||
/// Entry point
|
||||
int main(int argc, char *argv[]){
|
||||
LOG("Univerxel client");
|
||||
|
||||
#if TRACY_ENABLE
|
||||
LOG("Profiling !");
|
||||
#endif
|
||||
|
||||
auto options = config::standalone_options<config::client::options>(argc > 1 ? argv[1] : config::DEFAULT_FILE);
|
||||
options.save();
|
||||
|
||||
#if TRACY_ENABLE
|
||||
tracy::SetThreadName("Main");
|
||||
#endif
|
||||
|
||||
net::Setup();
|
||||
|
||||
auto client = Client(options.get());
|
||||
client.run(nullptr);
|
||||
|
||||
net::Destroy();
|
||||
|
||||
options.save();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -180,7 +180,7 @@ void Client::run(server_handle* const localHandle) {
|
|||
ZoneScopedN("Swap");
|
||||
pipeline->swapBuffer(window.getPtr());
|
||||
inputs.poll();
|
||||
FrameMark;
|
||||
FrameMarkNamed("Client");
|
||||
}
|
||||
|
||||
window.waitTargetFPS();
|
||||
|
|
|
@ -65,7 +65,13 @@ public:
|
|||
world.keepDistance = config["world"]["keep_distance"].value_or(world.keepDistance);
|
||||
voxel_density = config["world"]["voxel_density"].value_or(voxel_density);
|
||||
|
||||
if(!config["connection"]["use_local"].value_or(true)) {
|
||||
#ifndef STANDALONE
|
||||
const auto useLocal = config["connection"]["use_local"].value_or(true);
|
||||
#else
|
||||
const auto useLocal = false;
|
||||
#endif
|
||||
|
||||
if(!useLocal) {
|
||||
world::client::Universe::connection ct;
|
||||
ct.address = config["connection"]["address"].value_or(ct.address);
|
||||
ct.port = config["connection"]["port"].value_or(ct.port);
|
||||
|
@ -138,9 +144,11 @@ public:
|
|||
if(connection.has_value()) {
|
||||
const auto &ct = connection.value();
|
||||
config.insert_or_assign("connection", toml::table({
|
||||
#ifndef STANDALONE
|
||||
{"use_local", false},
|
||||
#endif
|
||||
{"address", ct.address},
|
||||
{"start_port", ct.port}
|
||||
{"port", ct.port}
|
||||
}));
|
||||
} else {
|
||||
config.insert_or_assign("connection", toml::table({{"use_local", true}}));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "UI.hpp"
|
||||
|
||||
#include <GL/gl3w.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include "Texture.hpp"
|
||||
|
|
|
@ -20,7 +20,7 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) {
|
|||
const auto chunkChange = cur_chunk != last_chunk;
|
||||
last_chunk = cur_chunk;
|
||||
|
||||
pullNetwork();
|
||||
pullNetwork(pos);
|
||||
|
||||
{ // Update alive areas
|
||||
ZoneScopedN("World");
|
||||
|
@ -38,19 +38,39 @@ void DistantUniverse::update(voxel_pos pos, float deltaTime) {
|
|||
} else {
|
||||
if(const auto neighbors = std::dynamic_pointer_cast<world::client::EdittableChunk>(it_c->second)->update(deltaTime, true /*FIXME: rnd from contouring*/)) {
|
||||
contouring->onUpdate(std::make_pair(area.first, it_c->first), diff, chunks, neighbors.value());
|
||||
} else if(chunkChangeArea) {
|
||||
contouring->onNotify(std::make_pair(area.first, it_c->first), diff, chunks);
|
||||
}
|
||||
++it_c;
|
||||
}
|
||||
}
|
||||
if (chunkChangeArea) { // Request missing chunks
|
||||
ZoneScopedN("Missing");
|
||||
std::vector<chunk_pos> missing;
|
||||
//TODO: use easy sphere fill
|
||||
for (int x = -loadDistance; x <= loadDistance; x++) {
|
||||
for (int y = -loadDistance; y <= loadDistance; y++) {
|
||||
for (int z = -loadDistance; z <= loadDistance; z++) {
|
||||
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()) {
|
||||
missing.push_back(p);
|
||||
}
|
||||
}
|
||||
}}}
|
||||
if(!missing.empty()) {
|
||||
auto packet = net::Client::makePacket(net::client_packet_type::MISSING_CHUNKS, NULL, sizeof(area_id) + missing.size() * sizeof(chunk_pos), ENET_PACKET_FLAG_RELIABLE, peer.getSalt());
|
||||
packet.write(area.first);
|
||||
packet.write(missing.data(), missing.size() * sizeof(chunk_pos));
|
||||
peer.send(packet.get(), net::channel_type::RELIABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contouring->update(pos, areas);
|
||||
}
|
||||
void DistantUniverse::pullNetwork() {
|
||||
void DistantUniverse::pullNetwork(voxel_pos pos) {
|
||||
ZoneScopedN("Pull");
|
||||
|
||||
using namespace net;
|
||||
|
@ -82,7 +102,6 @@ void DistantUniverse::pullNetwork() {
|
|||
} else {
|
||||
areas.emplace(id, std::make_shared<Area>(p));
|
||||
}
|
||||
LOG_D("Area " << id.index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace world::client {
|
|||
ray_result raycast(const geometry::Ray &) const override;
|
||||
|
||||
protected:
|
||||
void pullNetwork();
|
||||
void pullNetwork(voxel_pos);
|
||||
|
||||
/// Alive areas containing chunks
|
||||
area_map areas;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "index.hpp"
|
||||
#ifndef STANDALONE
|
||||
#include "LocalUniverse.hpp"
|
||||
#endif
|
||||
#include "DistantUniverse.hpp"
|
||||
#include "../../core/utils/logger.hpp"
|
||||
|
||||
|
@ -7,12 +9,12 @@ namespace world::client {
|
|||
std::unique_ptr<Universe> Load(const std::optional<Universe::connection>& ct, server_handle *const localHandle, const Universe::options &distOpts) {
|
||||
if(ct.has_value()) {
|
||||
return std::make_unique<DistantUniverse>(ct.value(), distOpts);
|
||||
#ifndef STANDALONE
|
||||
} else if(localHandle != nullptr) {
|
||||
return std::make_unique<LocalUniverse>(localHandle);
|
||||
#endif
|
||||
} else {
|
||||
if(localHandle != nullptr) {
|
||||
return std::make_unique<LocalUniverse>(localHandle);
|
||||
} else {
|
||||
FATAL("Must enable server.allow_local or define client.connection");
|
||||
}
|
||||
FATAL("Must enable server.allow_local or define client.connection");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,16 +4,16 @@
|
|||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include "../client/config.hpp"
|
||||
#include "../server/config.hpp"
|
||||
|
||||
namespace config {
|
||||
|
||||
constexpr auto DEFAULT_FILE = "config.toml";
|
||||
|
||||
/// Savable game options
|
||||
struct options {
|
||||
public:
|
||||
/// Load from path
|
||||
options(const std::string &path = "config.toml"): path(path) {
|
||||
options(const std::string &path): path(path) {
|
||||
auto config = [&] {
|
||||
if(std::filesystem::exists(path))
|
||||
return toml::parse_file(path);
|
||||
|
@ -51,4 +51,5 @@ private:
|
|||
std::optional<server::options> _server;
|
||||
std::optional<client::options> _client;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#define TOML_HEADER_ONLY 0
|
||||
#include <toml.h>
|
|
@ -123,6 +123,7 @@ public:
|
|||
}
|
||||
|
||||
constexpr bool isReady() const { return ready; }
|
||||
constexpr salt_t getSalt() const { return salt; }
|
||||
|
||||
protected:
|
||||
ENetHost *host;
|
||||
|
|
|
@ -50,6 +50,10 @@ enum class client_packet_type: enet_uint8 {
|
|||
/// actions::FillCube realable
|
||||
FILL_CUBE = 0,
|
||||
|
||||
/// Request missing chunks
|
||||
/// area_id, chunk_pos[] realable
|
||||
MISSING_CHUNKS = 8,
|
||||
|
||||
/// Position update
|
||||
/// voxel_pos notify
|
||||
MOVE = 16,
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <toml.h>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
|
||||
namespace config {
|
||||
|
||||
constexpr auto DEFAULT_FILE = "config.toml";
|
||||
|
||||
/// Standalone options
|
||||
template<typename O>
|
||||
struct standalone_options {
|
||||
public:
|
||||
/// Load from path
|
||||
standalone_options(const std::string &path): path(path) {
|
||||
auto config = toml::table({{"c", [&] {
|
||||
if(std::filesystem::exists(path))
|
||||
return toml::parse_file(path);
|
||||
|
||||
LOG_E("Config file " << path << " not found. Creating default");
|
||||
return toml::table();
|
||||
}()}});
|
||||
val = new O(config["c"]);
|
||||
}
|
||||
~standalone_options() {
|
||||
delete val;
|
||||
}
|
||||
/// Write to path
|
||||
void save() {
|
||||
std::ofstream out;
|
||||
out.open(path, std::ios::out | std::ios::trunc);
|
||||
out << val->save() << "\n\n";
|
||||
out.close();
|
||||
}
|
||||
|
||||
O &get() { return *val; }
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
O* val;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <Tracy.hpp>
|
||||
|
||||
#if TRACY_MEMORY
|
||||
void *operator new(std::size_t count)
|
||||
{
|
||||
auto ptr = malloc(count);
|
||||
TracyAlloc(ptr, count);
|
||||
return ptr;
|
||||
}
|
||||
void operator delete(void *ptr) noexcept
|
||||
{
|
||||
TracyFree(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
|
@ -26,5 +26,5 @@ bool Universe::collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density
|
|||
const auto dir = glm::normalize(vel);
|
||||
const auto velocity = vel * glm::vec3(density);
|
||||
const auto from = pos * density + dir;
|
||||
return std::holds_alternative<ray_target>(raycast(Ray(from, dir, glm::length(velocity) + radius)));
|
||||
return !std::holds_alternative<std::monostate>(raycast(Ray(from, dir, glm::length(velocity) + radius)));
|
||||
}
|
20
src/main.cpp
20
src/main.cpp
|
@ -10,22 +10,7 @@
|
|||
#include "client/Client.hpp"
|
||||
#include "server/Server.hpp"
|
||||
#include "core/config.hpp"
|
||||
#include "core/net/data.hpp"
|
||||
#include <Tracy.hpp>
|
||||
|
||||
#if TRACY_MEMORY
|
||||
void *operator new(std::size_t count)
|
||||
{
|
||||
auto ptr = malloc(count);
|
||||
TracyAlloc(ptr, count);
|
||||
return ptr;
|
||||
}
|
||||
void operator delete(void *ptr) noexcept
|
||||
{
|
||||
TracyFree(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
#include "core/utils/tracy.hpp"
|
||||
|
||||
/// Entry point
|
||||
int main(int argc, char *argv[]){
|
||||
|
@ -35,7 +20,7 @@ int main(int argc, char *argv[]){
|
|||
LOG("Profiling !");
|
||||
#endif
|
||||
|
||||
config::options options = config::options(argc > 1 ? argv[1] : "config.toml");
|
||||
auto options = config::options(argc > 1 ? argv[1] : config::DEFAULT_FILE);
|
||||
options.save();
|
||||
|
||||
std::optional<Server> server = options.hasServer() ? std::make_optional<Server>(options.getServer()) : std::nullopt;
|
||||
|
@ -69,7 +54,6 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
} else {
|
||||
if (client.has_value()) {
|
||||
//MAYBE: check not local
|
||||
clientTask(nullptr);
|
||||
} else {
|
||||
options.save();
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* \file server.cpp
|
||||
* \brief Univerxel server
|
||||
* \author Maelys Bois
|
||||
* \version 0.0.1
|
||||
*
|
||||
* Univerxel standalone server program.
|
||||
*/
|
||||
|
||||
#define STANDALONE 1
|
||||
#include "server/Server.hpp"
|
||||
#include "core/standalone_config.hpp"
|
||||
#include "core/utils/tracy.hpp"
|
||||
|
||||
/// Entry point
|
||||
int main(int argc, char *argv[]){
|
||||
LOG("Univerxel server");
|
||||
|
||||
#if TRACY_ENABLE
|
||||
LOG("Profiling !");
|
||||
#endif
|
||||
|
||||
auto options = config::standalone_options<config::server::options>(argc > 1 ? argv[1] : config::DEFAULT_FILE);
|
||||
options.save();
|
||||
|
||||
#if TRACY_ENABLE
|
||||
tracy::SetThreadName("Main");
|
||||
#endif
|
||||
|
||||
net::Setup();
|
||||
|
||||
auto server = Server(options.get());
|
||||
server.run();
|
||||
|
||||
net::Destroy();
|
||||
|
||||
options.save();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
#include "Server.hpp"
|
||||
#include "world/StandaloneUniverse.hpp"
|
||||
#ifndef STANDALONE
|
||||
#include "world/SharedUniverse.hpp"
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
Server::Server(config::server::options& options): options(options) {
|
||||
|
@ -16,8 +18,10 @@ void handle_signal(int) { running = false; }
|
|||
|
||||
void Server::run() {
|
||||
universe = [&]() -> std::unique_ptr<world::server::Universe> {
|
||||
#ifndef STANDALONE
|
||||
if(options.allowLocal)
|
||||
return std::make_unique<world::server::SharedUniverse>(options.world, localHandle);
|
||||
#endif
|
||||
|
||||
return std::make_unique<world::server::StandaloneUniverse>(options.world);
|
||||
}();
|
||||
|
@ -27,6 +31,7 @@ void Server::run() {
|
|||
|
||||
while(running && (localHandle == nullptr || localHandle->running)) {
|
||||
universe->update(1. / TPS); //FIXME: use chrono
|
||||
FrameMarkNamed("Server");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / TPS));
|
||||
}
|
||||
}
|
|
@ -7,9 +7,17 @@ namespace config::server {
|
|||
|
||||
struct options {
|
||||
public:
|
||||
options(toml::node_view<toml::node> config) {
|
||||
options(toml::node_view<toml::node> config): world() {
|
||||
assert(config["enabled"]);
|
||||
#ifndef STANDALONE
|
||||
allowLocal = config["allow_local"].value_or(allowLocal);
|
||||
#else
|
||||
allowLocal = false;
|
||||
#endif
|
||||
|
||||
world.connection.address = config["connection"]["address"].value_or(world.connection.address);
|
||||
world.connection.port = config["connection"]["port"].value_or(world.connection.port);
|
||||
world.maxPlayers = config["max_players"].value_or(world.maxPlayers);
|
||||
|
||||
world.loadDistance = config["world"]["load_distance"].value_or(world.loadDistance);
|
||||
world.keepDistance = config["world"]["keep_distance"].value_or(world.keepDistance);
|
||||
|
@ -19,7 +27,14 @@ public:
|
|||
toml::table save() {
|
||||
return toml::table({
|
||||
{"enabled", true},
|
||||
#ifndef STANDALONE
|
||||
{"allow_local", allowLocal},
|
||||
#endif
|
||||
{"connection", toml::table({
|
||||
{"address", world.connection.address},
|
||||
{"port", world.connection.port}
|
||||
})},
|
||||
{"max_players", world.maxPlayers},
|
||||
{"world", toml::table({
|
||||
{"load_distance", world.loadDistance},
|
||||
{"keep_distance", world.keepDistance},
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace world::server;
|
|||
|
||||
const auto AREAS_FILE = "/areas.idx";
|
||||
|
||||
Universe::Universe(const Universe::options &options): host(net::connection{"localhost", 4242}, 4),
|
||||
Universe::Universe(const Universe::options &options): host(options.connection, options.maxPlayers),
|
||||
dict_content({options.folderPath + "/zstd.dict", "content/zstd.dict"}), dicts(dict_content), dict_write_ctx(dicts.make_writer()) {
|
||||
setOptions(options);
|
||||
folderPath = options.folderPath;
|
||||
|
@ -314,7 +314,8 @@ void Universe::update(float deltaTime) {
|
|||
it->second->setChunks().emplace(loaded.first.second, loaded.second);
|
||||
const chunk_pos diff = glm::divide(pos - it->second->getOffset().as_voxel());
|
||||
loadChunk(loaded.first, diff, it->second->getChunks());
|
||||
broadcastChunk(loaded);
|
||||
// MAYBE: limit chunks per update
|
||||
host.broadcast(serializeChunk(loaded), net::channel_type::RELIABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,6 +376,29 @@ 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();
|
||||
|
||||
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_D("Request out of range chunk");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_D("Bad chunk request");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_D("Bad packet from " << peer->address);
|
||||
break;
|
||||
|
@ -394,8 +418,7 @@ void Universe::broadcastAreas() {
|
|||
assert(packet.isFull());
|
||||
host.broadcast(packet.get(), net::channel_type::RELIABLE);
|
||||
}
|
||||
void Universe::broadcastChunk(const robin_hood::pair<area_<chunk_pos>, std::shared_ptr<Chunk>> &pair) {
|
||||
// MAYBE: limit chunks per update
|
||||
net::packet_t* Universe::serializeChunk(const robin_hood::pair<area_<chunk_pos>, std::shared_ptr<Chunk>> &pair) {
|
||||
std::ostringstream out;
|
||||
pair.second->write(out);
|
||||
std::vector<char> buffer;
|
||||
|
@ -404,7 +427,7 @@ void Universe::broadcastChunk(const robin_hood::pair<area_<chunk_pos>, std::shar
|
|||
packet.write(pair.first);
|
||||
packet.write(buffer.data(), buffer.size());
|
||||
assert(packet.isFull());
|
||||
host.broadcast(packet.get(), net::channel_type::RELIABLE);
|
||||
return packet.get();
|
||||
}
|
||||
|
||||
void Universe::updateChunk(area_map::iterator &, world::ChunkContainer::iterator &, chunk_pos, float deltaTime) {}
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace world::server {
|
|||
struct options: world::Universe::options {
|
||||
/// Storage path
|
||||
std::string folderPath = "world";
|
||||
|
||||
net::connection connection = net::connection{"localhost", 4242};
|
||||
int maxPlayers = 1;
|
||||
};
|
||||
|
||||
Universe(const options &);
|
||||
|
@ -64,7 +67,7 @@ namespace world::server {
|
|||
/// Handle networking requests
|
||||
void pullNetwork();
|
||||
void broadcastAreas();
|
||||
void broadcastChunk(const robin_hood::pair<area_<chunk_pos>, std::shared_ptr<Chunk>> &);
|
||||
net::packet_t* serializeChunk(const robin_hood::pair<area_<chunk_pos>, std::shared_ptr<Chunk>> &);
|
||||
|
||||
using area_map = robin_hood::unordered_map<area_id, std::shared_ptr<Area>>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue