mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
Compare commits
4 Commits
1acfeef9e6
...
6f39ff771d
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f39ff771d | |||
| 2953e8a233 | |||
| 678fc02998 | |||
| 4303c1cd32 |
@@ -19,6 +19,8 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(Protobuf REQUIRED)
|
||||
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(Freetype REQUIRED)
|
||||
@@ -28,8 +30,7 @@ if (UNIX AND NOT APPLE)
|
||||
find_package(glfw3 REQUIRED)
|
||||
endif()
|
||||
|
||||
add_library(glad STATIC third_party/glad/src/glad.c
|
||||
src/gameplay/network_client.cpp)
|
||||
add_library(glad STATIC third_party/glad/src/glad.c)
|
||||
target_include_directories(glad PUBLIC third_party/glad/include)
|
||||
|
||||
include(FetchContent)
|
||||
@@ -99,7 +100,7 @@ FetchContent_MakeAvailable(tomlplusplus)
|
||||
|
||||
add_subdirectory(third_party/imgui)
|
||||
|
||||
set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
src/main.cpp
|
||||
@@ -148,8 +149,17 @@ add_executable(${PROJECT_NAME}
|
||||
src/gameplay/server_player.cpp
|
||||
src/gameplay/client_player.cpp
|
||||
src/gameplay/session.cpp
|
||||
src/gameplay/network_client.cpp
|
||||
)
|
||||
file(GLOB_RECURSE PROTO_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/proto/*.proto
|
||||
)
|
||||
protobuf_generate(
|
||||
TARGET ${PROJECT_NAME}
|
||||
LANGUAGE cpp
|
||||
PROTOS ${PROTO_FILES}
|
||||
IMPORT_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/proto
|
||||
)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(STATUS "Building with AddressSanitizer enabled for target: ${PROJECT_NAME}")
|
||||
|
||||
@@ -175,10 +185,13 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/third_party/asio/include
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||
ASIO_STANDALONE
|
||||
ASIO_NO_DEPRECATED
|
||||
@@ -194,6 +207,7 @@ target_link_libraries(${PROJECT_NAME}
|
||||
tomlplusplus::tomlplusplus
|
||||
imgui
|
||||
tbb
|
||||
protobuf::libprotobuf
|
||||
)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <thread>
|
||||
namespace Cubed {
|
||||
@@ -10,11 +13,14 @@ public:
|
||||
void stop();
|
||||
void run();
|
||||
int port() const;
|
||||
std::unordered_map<std::string, std::shared_ptr<Session>> m_session;
|
||||
|
||||
private:
|
||||
asio::io_context m_io;
|
||||
std::thread m_server;
|
||||
int m_port = 25530;
|
||||
std::atomic<bool> m_stopped{false};
|
||||
ServerWorld m_world;
|
||||
asio::awaitable<void> listen();
|
||||
};
|
||||
} // namespace Cubed
|
||||
57
include/Cubed/gameplay/packet.hpp
Normal file
57
include/Cubed/gameplay/packet.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include "packet.pb.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <type_traits>
|
||||
namespace Cubed {
|
||||
constexpr int HEADER_LEN = 8;
|
||||
using Packet = std::shared_ptr<std::vector<uint8_t>>;
|
||||
template <typename> struct always_false : std::false_type {}; // NOLINT
|
||||
template <typename T> constexpr uint16_t get_packet_id() {
|
||||
|
||||
using std::is_same_v;
|
||||
using U = std::decay_t<T>;
|
||||
if constexpr (is_same_v<U, LoginReq>) {
|
||||
return 1001;
|
||||
} else if constexpr (is_same_v<U, LoginRsp>) {
|
||||
return 1002;
|
||||
} else if constexpr (is_same_v<U, PlayerInfo>) {
|
||||
return 2001;
|
||||
} else if constexpr (is_same_v<U, PlayerPos>) {
|
||||
return 2002;
|
||||
} else if constexpr (is_same_v<U, ChunkData>) {
|
||||
return 3001;
|
||||
} else if constexpr (is_same_v<U, Ping>) {
|
||||
return 9001;
|
||||
} else if (is_same_v<U, Pong>) {
|
||||
return 9002;
|
||||
} else {
|
||||
static_assert(always_false<U>::value, "Unkonw Type");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> Packet make_packet(const T& msg) {
|
||||
uint16_t cmd = get_packet_id<T>();
|
||||
|
||||
uint32_t body_len = static_cast<uint32_t>(msg.ByteSizeLong());
|
||||
|
||||
uint32_t total_len = HEADER_LEN + body_len;
|
||||
|
||||
auto packet = std::make_shared<std::vector<uint8_t>>(total_len);
|
||||
|
||||
uint32_t total_len_net = htonl(total_len);
|
||||
uint16_t cmd_net = htons(cmd);
|
||||
|
||||
std::memcpy(packet->data(), &total_len_net, sizeof(total_len_net));
|
||||
|
||||
std::memcpy(packet->data() + 4, &cmd_net, sizeof(cmd_net));
|
||||
|
||||
if (!msg.SerializeToArray(packet->data() + HEADER_LEN,
|
||||
static_cast<int>(body_len))) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -1,4 +1,17 @@
|
||||
#pragma once
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
namespace Cubed {
|
||||
class ServerPlayer {};
|
||||
class ServerPlayer {
|
||||
public:
|
||||
explicit ServerPlayer(std::string_view);
|
||||
const glm::vec3& get_pos() const;
|
||||
const std::string& get_name() const;
|
||||
void update_pos(float x, float y, float z);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
glm::vec3 m_pos{0.0f};
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -10,15 +10,19 @@
|
||||
|
||||
#include <future>
|
||||
#include <shared_mutex>
|
||||
#include <tbb/concurrent_hash_map.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
class Session;
|
||||
class ServerWorld {
|
||||
public:
|
||||
ServerWorld();
|
||||
~ServerWorld();
|
||||
void player_join();
|
||||
void player_join(const std::string& name);
|
||||
void player_exit(const std::string& name);
|
||||
void init_world();
|
||||
void need_gen();
|
||||
void update();
|
||||
@@ -60,6 +64,11 @@ public:
|
||||
|
||||
void set_block(const glm::ivec3& block_pos, unsigned id);
|
||||
|
||||
void sync_player_pos(const std::string& name, float x, float y, float z);
|
||||
void handle_player_login(const std::string& player_name,
|
||||
std::shared_ptr<Session> session);
|
||||
glm::vec3 get_player_pos(const std::string& name) const;
|
||||
|
||||
private:
|
||||
enum class ChunkLoadStyle { RANDOM, CENTER };
|
||||
struct PendingChunk {
|
||||
@@ -68,7 +77,7 @@ private:
|
||||
};
|
||||
using ChunkHashMap =
|
||||
std::unordered_map<ChunkPos, ServerChunk, ChunkPos::Hash>;
|
||||
using PlayerHashMap = std::unordered_map<std::size_t, ServerPlayer>;
|
||||
using PlayerHashMap = std::unordered_map<std::string, ServerPlayer>;
|
||||
using PendingChunkHashMap =
|
||||
std::unordered_map<ChunkPos, PendingChunk, ChunkPos::Hash>;
|
||||
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||
@@ -110,6 +119,11 @@ private:
|
||||
|
||||
std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::RANDOM};
|
||||
|
||||
std::optional<std::string> m_request_gen_name = std::nullopt;
|
||||
|
||||
tbb::concurrent_hash_map<std::string, std::shared_ptr<Session>>
|
||||
m_player_session;
|
||||
|
||||
void init_chunks();
|
||||
|
||||
void gen_chunks_internal();
|
||||
@@ -120,7 +134,5 @@ private:
|
||||
void submit_new_chunks();
|
||||
void poll_finished_chunks();
|
||||
void wait_all_chunk_tasks();
|
||||
|
||||
void sync_player_pos(glm::vec3& pos);
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/gameplay/packet.hpp"
|
||||
|
||||
#include <asio.hpp>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
namespace Cubed {
|
||||
using asio::ip::tcp;
|
||||
|
||||
using asio::ip::tcp;
|
||||
class ServerWorld;
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
|
||||
public:
|
||||
Session(tcp::socket socket);
|
||||
Session(tcp::socket socket, ServerWorld& server_world);
|
||||
~Session();
|
||||
void start();
|
||||
void send();
|
||||
void send(Packet packet);
|
||||
void close();
|
||||
const std::string& uuid() const;
|
||||
|
||||
private:
|
||||
static constexpr int HEADER_LEN = 8;
|
||||
static constexpr uint32_t MAX_PACKET_SIZE = 4 * 1024 * 1024;
|
||||
tcp::socket m_socket;
|
||||
std::vector<char> m_read_buffer;
|
||||
std::deque<std::vector<char>> m_write_queue;
|
||||
std::mutex m_write_mutex;
|
||||
|
||||
std::deque<Packet> m_write_queue;
|
||||
asio::strand<asio::io_context::executor_type> m_strand;
|
||||
std::string m_uuid;
|
||||
|
||||
asio::awaitable<void> read();
|
||||
asio::awaitable<void> write();
|
||||
ServerWorld& m_server_world;
|
||||
asio::awaitable<void> read_loop();
|
||||
std::atomic<bool> m_closed{false};
|
||||
void do_write();
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -9,7 +9,17 @@ NetworkServer::NetworkServer(int port) : m_port(port) {}
|
||||
NetworkServer::~NetworkServer() { stop(); }
|
||||
|
||||
void NetworkServer::stop() {
|
||||
if (m_stopped.exchange(true)) {
|
||||
return;
|
||||
}
|
||||
for (auto& [key, s] : m_session) {
|
||||
if (s) {
|
||||
s->close();
|
||||
}
|
||||
}
|
||||
|
||||
m_io.stop();
|
||||
m_session.clear();
|
||||
if (m_server.joinable()) {
|
||||
m_server.join();
|
||||
}
|
||||
@@ -19,10 +29,17 @@ void NetworkServer::stop() {
|
||||
asio::awaitable<void> NetworkServer::listen() {
|
||||
tcp::acceptor acceptor(m_io, tcp::endpoint(tcp::v4(), m_port));
|
||||
while (true) {
|
||||
|
||||
tcp::socket socket =
|
||||
co_await acceptor.async_accept(asio::use_awaitable);
|
||||
if (m_stopped) {
|
||||
break;
|
||||
}
|
||||
std::shared_ptr<Session> s =
|
||||
std::make_shared<Session>(std::move(socket), m_world);
|
||||
s->start();
|
||||
m_session.emplace(s->uuid(), s);
|
||||
}
|
||||
co_return;
|
||||
}
|
||||
|
||||
void NetworkServer::run() {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "Cubed/gameplay/server_player.hpp"
|
||||
|
||||
namespace Cubed {
|
||||
ServerPlayer::ServerPlayer(std::string_view name) : m_name(name) {}
|
||||
const glm::vec3& ServerPlayer::get_pos() const { return m_pos; }
|
||||
const std::string& ServerPlayer::get_name() const { return m_name; }
|
||||
void ServerPlayer::update_pos(float x, float y, float z) {
|
||||
m_pos = glm::vec3{x, y, z};
|
||||
}
|
||||
} // namespace Cubed
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/gameplay/packet.hpp"
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
@@ -83,12 +85,16 @@ void ServerWorld::gen_chunks_internal() {
|
||||
|
||||
submit_new_chunks();
|
||||
m_chunk_gen_finished = true;
|
||||
m_request_gen_name = std::nullopt;
|
||||
}
|
||||
|
||||
void ServerWorld::compute_required_chunks(ChunkPosSet& required_chunks) {
|
||||
glm::vec3 player_pos;
|
||||
// sync_player_pos(player_pos);
|
||||
ASSERT_MSG(false, "Player Pos");
|
||||
if (m_request_gen_name == std::nullopt) {
|
||||
player_pos = glm::vec3{0.0f};
|
||||
} else {
|
||||
player_pos = get_player_pos(m_request_gen_name.value());
|
||||
}
|
||||
int x = std::floor(player_pos.x);
|
||||
int z = std::floor(player_pos.z);
|
||||
auto [chunk_x, chunk_z] = get_chunk_pos(x, z);
|
||||
@@ -147,7 +153,11 @@ void ServerWorld::submit_new_chunks() {
|
||||
}
|
||||
}
|
||||
glm::vec3 player_pos;
|
||||
sync_player_pos(player_pos);
|
||||
if (m_request_gen_name == std::nullopt) {
|
||||
player_pos = glm::vec3{0.0f};
|
||||
} else {
|
||||
player_pos = get_player_pos(m_request_gen_name.value());
|
||||
}
|
||||
auto dist2 = [player_pos](ChunkPos chunk_pos) {
|
||||
ChunkPos player_chunk_pos =
|
||||
get_chunk_pos(player_pos.x, player_pos.z);
|
||||
@@ -339,6 +349,45 @@ void ServerWorld::rebuild_world() {
|
||||
|
||||
void ServerWorld::update() { poll_finished_chunks(); }
|
||||
|
||||
void ServerWorld::sync_player_pos(const std::string& name, float x, float y,
|
||||
float z) {
|
||||
auto it = m_players.find(name);
|
||||
if (it == m_players.end()) {
|
||||
Logger::warn("Player {} is not in this Server", it->first);
|
||||
return;
|
||||
}
|
||||
it->second.update_pos(x, y, z);
|
||||
}
|
||||
|
||||
void ServerWorld::handle_player_login(const std::string& name,
|
||||
std::shared_ptr<Session> session) {
|
||||
player_join(name);
|
||||
m_player_session.emplace(name, session);
|
||||
LoginRsp rsp;
|
||||
rsp.set_success(true);
|
||||
rsp.set_uuid(name);
|
||||
session->send(make_packet(name));
|
||||
}
|
||||
|
||||
void ServerWorld::player_join(const std::string& name) {
|
||||
m_players.emplace(name, name);
|
||||
}
|
||||
void ServerWorld::player_exit(const std::string& name) {
|
||||
auto it = m_players.find(name);
|
||||
if (it == m_players.end()) {
|
||||
Logger::error("Player {} isn't in Server", it->first);
|
||||
}
|
||||
m_players.erase(it);
|
||||
}
|
||||
|
||||
glm::vec3 ServerWorld::get_player_pos(const std::string& name) const {
|
||||
auto it = m_players.find(name);
|
||||
if (it == m_players.end()) {
|
||||
return glm::vec3{0.0f};
|
||||
}
|
||||
return it->second.get_pos();
|
||||
}
|
||||
|
||||
int ServerWorld::rendering_distance() const {
|
||||
return m_rendering_distance.load();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,39 @@
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/uuid.hpp"
|
||||
using asio::ip::tcp;
|
||||
|
||||
namespace Cubed {
|
||||
Session::Session(tcp::socket socket)
|
||||
: m_socket(std::move(socket)), m_uuid(generate_uuid()) {}
|
||||
Session::Session(tcp::socket socket, ServerWorld& server_world)
|
||||
: m_socket(std::move(socket)), m_uuid(generate_uuid()),
|
||||
m_server_world(server_world) {}
|
||||
|
||||
Session::~Session() {}
|
||||
|
||||
void Session::start() {
|
||||
auto self = shared_from_this();
|
||||
asio::co_spawn(
|
||||
m_socket.get_executor(),
|
||||
[self]() -> asio::awaitable<void> { co_await self->read(); },
|
||||
m_strand,
|
||||
[self]() -> asio::awaitable<void> { co_await self->read_loop(); },
|
||||
asio::detached);
|
||||
}
|
||||
|
||||
void Session::send(std::shared_ptr<std::vector<uint8_t>> packet) {
|
||||
asio::post(m_strand, [self = shared_from_this(),
|
||||
packet = std::move(packet)]() mutable {
|
||||
bool idle = self->m_write_queue.empty();
|
||||
self->m_write_queue.emplace_back(std::move(packet));
|
||||
if (idle) {
|
||||
self->do_write();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const std::string& Session::uuid() const { return m_uuid; }
|
||||
|
||||
asio::awaitable<void> Session::read() {
|
||||
asio::awaitable<void> Session::read_loop() {
|
||||
try {
|
||||
while (true) {
|
||||
std::array<char, HEADER_LEN> header;
|
||||
@@ -47,13 +60,47 @@ asio::awaitable<void> Session::read() {
|
||||
|
||||
if (cmd_id == 1001) {
|
||||
}
|
||||
if (cmd_id == 1002) {
|
||||
}
|
||||
}
|
||||
} catch (const asio::system_error& e) {
|
||||
Logger::warn("Catch Asio Error {}", e.what());
|
||||
close();
|
||||
} catch (...) {
|
||||
Logger::error("Unknow Error");
|
||||
close();
|
||||
}
|
||||
co_return;
|
||||
}
|
||||
|
||||
void Session::do_write() {
|
||||
|
||||
auto self = shared_from_this();
|
||||
asio::async_write(
|
||||
m_socket, asio::buffer(*(m_write_queue.front())),
|
||||
asio::bind_executor(m_strand, [self](std::error_code ec, size_t) {
|
||||
if (ec) {
|
||||
Logger::warn("Write Ec {}", ec.message());
|
||||
self->close();
|
||||
return;
|
||||
}
|
||||
self->m_write_queue.pop_front();
|
||||
if (!self->m_write_queue.empty()) {
|
||||
self->do_write();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void Session::close() {
|
||||
if (m_closed.exchange(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
|
||||
m_socket.shutdown(tcp::socket::shutdown_both, ec);
|
||||
|
||||
m_socket.close(ec);
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
11
src/proto/auth/auth.proto
Normal file
11
src/proto/auth/auth.proto
Normal file
@@ -0,0 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message LoginReq {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message LoginRsp {
|
||||
bool success = 1;
|
||||
string uuid = 2;
|
||||
}
|
||||
|
||||
6
src/proto/common/chunk_pos.proto
Normal file
6
src/proto/common/chunk_pos.proto
Normal file
@@ -0,0 +1,6 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message ChunkPos {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
}
|
||||
6
src/proto/common/error.proto
Normal file
6
src/proto/common/error.proto
Normal file
@@ -0,0 +1,6 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Error {
|
||||
int32 code = 1;
|
||||
string mes = 2;
|
||||
}
|
||||
5
src/proto/common/player_info.proto
Normal file
5
src/proto/common/player_info.proto
Normal file
@@ -0,0 +1,5 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message PlayerInfo {
|
||||
string name = 1;
|
||||
}
|
||||
7
src/proto/common/vector3.proto
Normal file
7
src/proto/common/vector3.proto
Normal file
@@ -0,0 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Vec3 {
|
||||
float x = 1;
|
||||
float y = 2;
|
||||
float z = 3;
|
||||
}
|
||||
11
src/proto/packet.proto
Normal file
11
src/proto/packet.proto
Normal file
@@ -0,0 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "common/chunk_pos.proto";
|
||||
import "common/error.proto";
|
||||
import "common/player_info.proto";
|
||||
import "common/vector3.proto";
|
||||
import "player/player.proto";
|
||||
import "auth/auth.proto";
|
||||
import "system/ping.proto";
|
||||
import "system/pong.proto";
|
||||
import "world/chunk_data.proto";
|
||||
8
src/proto/player/player.proto
Normal file
8
src/proto/player/player.proto
Normal file
@@ -0,0 +1,8 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "common/vector3.proto";
|
||||
|
||||
message PlayerPos {
|
||||
string uuid = 1;
|
||||
Vec3 pos = 2;
|
||||
}
|
||||
5
src/proto/system/ping.proto
Normal file
5
src/proto/system/ping.proto
Normal file
@@ -0,0 +1,5 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Ping {
|
||||
uint64 timestamp = 1;
|
||||
}
|
||||
5
src/proto/system/pong.proto
Normal file
5
src/proto/system/pong.proto
Normal file
@@ -0,0 +1,5 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message Pong {
|
||||
uint64 timestamp = 1;
|
||||
}
|
||||
13
src/proto/world/chunk_data.proto
Normal file
13
src/proto/world/chunk_data.proto
Normal file
@@ -0,0 +1,13 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "common/chunk_pos.proto";
|
||||
|
||||
message ChunkData {
|
||||
ChunkPos pos = 1;
|
||||
uint32 chunk_seed = 2;
|
||||
repeated uint32 chunk_blocks = 3 [packed=true];
|
||||
repeated uint32 neighbor_blocks_1 = 4 [packed=true];
|
||||
repeated uint32 neighbor_blocks_2 = 5 [packed=true];
|
||||
repeated uint32 neighbor_blocks_3 = 6 [packed=true];
|
||||
repeated uint32 neighbor_blocks_4 = 7 [packed=true];
|
||||
}
|
||||
Reference in New Issue
Block a user