mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
perf(gameplay): optimize protobuf message allocation with Arena and limit thread pool size
Switch to Arena allocation for protobuf messages to reduce heap allocations. Pass ChunkDataRsp by value to enable move semantics. Cap thread pool size to hardware concurrency with max 4 threads.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include "Cubed/gameplay/packet.hpp"
|
||||
using namespace std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace google::protobuf;
|
||||
namespace Cubed {
|
||||
|
||||
namespace {
|
||||
@@ -170,14 +171,15 @@ void ClientWorld::push_delete_vao(GLuint vao) {
|
||||
|
||||
void ClientWorld::report_block_change(const glm::ivec3& pos,
|
||||
unsigned id) const {
|
||||
BlockChangeReq req;
|
||||
req.set_uuid(m_player.get_uuid());
|
||||
req.set_block(id);
|
||||
auto* p = req.mutable_pos();
|
||||
Arena arena;
|
||||
auto* req = Arena::Create<BlockChangeReq>(&arena);
|
||||
req->set_uuid(m_player.get_uuid());
|
||||
req->set_block(id);
|
||||
auto* p = req->mutable_pos();
|
||||
p->set_x(pos.x);
|
||||
p->set_y(pos.y);
|
||||
p->set_z(pos.z);
|
||||
m_client->send(make_packet(req));
|
||||
m_client->send(make_packet(*req));
|
||||
}
|
||||
|
||||
void ClientWorld::receive_block_change(const BlockChangeRsp& rsp) {
|
||||
@@ -254,7 +256,11 @@ void ClientWorld::stop_client_thread() {
|
||||
}
|
||||
m_game_running = false;
|
||||
}
|
||||
void ClientWorld::start_thread_pool() { change_pool_threads(1); }
|
||||
void ClientWorld::start_thread_pool() {
|
||||
int max_threads = std::thread::hardware_concurrency();
|
||||
int threads = std::min<size_t>(max_threads, 4);
|
||||
change_pool_threads(threads);
|
||||
}
|
||||
void ClientWorld::stop_thread_pool() {
|
||||
auto pool_ptr = m_thread_pool.load();
|
||||
if (pool_ptr) {
|
||||
@@ -301,14 +307,15 @@ void ClientWorld::report_player_pos() {
|
||||
if (!m_client) {
|
||||
return;
|
||||
}
|
||||
PlayerPos pos;
|
||||
pos.set_uuid(m_player.get_uuid());
|
||||
Arena arena;
|
||||
auto* pos = Arena::Create<PlayerPos>(&arena);
|
||||
pos->set_uuid(m_player.get_uuid());
|
||||
glm::vec3 player_pos = m_player.get_player_pos();
|
||||
auto* v3 = pos.mutable_pos();
|
||||
auto* v3 = pos->mutable_pos();
|
||||
v3->set_x(player_pos.x);
|
||||
v3->set_y(player_pos.y);
|
||||
v3->set_z(player_pos.z);
|
||||
m_client->send(make_packet(pos));
|
||||
m_client->send(make_packet(*pos));
|
||||
}
|
||||
|
||||
void ClientWorld::request_chunk() {
|
||||
@@ -379,18 +386,19 @@ void ClientWorld::request_chunk() {
|
||||
}
|
||||
}
|
||||
auto uuid = m_player.get_uuid();
|
||||
ChunkDataReq req;
|
||||
Arena arena;
|
||||
auto* req = Arena::Create<ChunkDataReq>(&arena);
|
||||
for (const auto& pos : need_send_pos) {
|
||||
req.set_uuid(uuid);
|
||||
auto* p = req.mutable_pos();
|
||||
req->set_uuid(uuid);
|
||||
auto* p = req->mutable_pos();
|
||||
p->set_x(pos.x);
|
||||
p->set_z(pos.z);
|
||||
m_client->send(make_packet(req));
|
||||
m_client->send(make_packet(*req));
|
||||
}
|
||||
m_requesting_chunk = false;
|
||||
}
|
||||
|
||||
void ClientWorld::receive_chunk(const ChunkDataRsp& data) {
|
||||
void ClientWorld::receive_chunk(ChunkDataRsp data) {
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_chunks_mutex);
|
||||
@@ -418,9 +426,10 @@ void ClientWorld::receive_chunk(const ChunkDataRsp& data) {
|
||||
}
|
||||
|
||||
void ClientWorld::exit() {
|
||||
LogoutReq req;
|
||||
req.set_uuid(m_player.get_uuid());
|
||||
m_client->send(make_packet(req));
|
||||
Arena arena;
|
||||
auto* req = Arena::Create<LogoutReq>(&arena);
|
||||
req->set_uuid(m_player.get_uuid());
|
||||
m_client->send(make_packet(*req));
|
||||
}
|
||||
|
||||
void ClientWorld::update(float delta_time) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Cubed/gameplay/client_world.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
using namespace google::protobuf;
|
||||
namespace Cubed {
|
||||
NetworkClient::NetworkClient(ClientWorld& world)
|
||||
: m_socket(m_io), m_strand(asio::make_strand(m_io)), m_world(world) {}
|
||||
@@ -62,13 +63,14 @@ asio::awaitable<void> NetworkClient::read_loop() {
|
||||
}
|
||||
|
||||
constexpr auto& to_num = std::to_underlying<PacketEnum>;
|
||||
Arena arena;
|
||||
switch (header.cmd) {
|
||||
case to_num(PacketEnum::LOGIN_RSP): {
|
||||
LoginRsp rsp;
|
||||
auto* rsp = Arena::Create<LoginRsp>(&arena);
|
||||
Logger::info("Client: Receive Login rsp");
|
||||
if (decode_packet(rsp, body_data, header)) {
|
||||
if (rsp.success()) {
|
||||
m_world.start_client_thread(rsp.uuid());
|
||||
if (decode_packet(*rsp, body_data, header)) {
|
||||
if (rsp->success()) {
|
||||
m_world.start_client_thread(rsp->uuid());
|
||||
} else {
|
||||
Logger::error("Connected Server Fail");
|
||||
}
|
||||
@@ -79,32 +81,32 @@ asio::awaitable<void> NetworkClient::read_loop() {
|
||||
Logger::info("Client: Receive Chunk Data rsp, size {}mb",
|
||||
body_data.size() / 1024.0f / 1024);
|
||||
if (decode_packet(rsp, body_data, header)) {
|
||||
m_world.receive_chunk(rsp);
|
||||
m_world.receive_chunk(std::move(rsp));
|
||||
}
|
||||
} break;
|
||||
case to_num(PacketEnum::BLOCK_CHANGE_RSP): {
|
||||
BlockChangeRsp rsp;
|
||||
auto* rsp = Arena::Create<BlockChangeRsp>(&arena);
|
||||
Logger::info("Client: Receive Block Change rsp");
|
||||
if (decode_packet(rsp, body_data, header)) {
|
||||
m_world.receive_block_change(rsp);
|
||||
if (decode_packet(*rsp, body_data, header)) {
|
||||
m_world.receive_block_change(*rsp);
|
||||
}
|
||||
} break;
|
||||
case to_num(PacketEnum::UPDATE_TIME): {
|
||||
UpdateTime rsp;
|
||||
if (decode_packet(rsp, body_data, header)) {
|
||||
m_world.receive_time(rsp);
|
||||
auto* rsp = Arena::Create<UpdateTime>(&arena);
|
||||
if (decode_packet(*rsp, body_data, header)) {
|
||||
m_world.receive_time(*rsp);
|
||||
}
|
||||
} break;
|
||||
case to_num(PacketEnum::PLAYER_INFO_RSP): {
|
||||
PlayerInfoRsp rsp;
|
||||
if (decode_packet(rsp, body_data, header)) {
|
||||
m_world.receive_other_player(rsp);
|
||||
auto* rsp = Arena::Create<PlayerInfoRsp>(&arena);
|
||||
if (decode_packet(*rsp, body_data, header)) {
|
||||
m_world.receive_other_player(*rsp);
|
||||
}
|
||||
} break;
|
||||
case to_num(PacketEnum::LOGOUT_RSP): {
|
||||
LogoutRsp rsp;
|
||||
if (decode_packet(rsp, body_data, header)) {
|
||||
m_world.receive_player_logout(rsp);
|
||||
auto* rsp = Arena::Create<LogoutRsp>(&arena);
|
||||
if (decode_packet(*rsp, body_data, header)) {
|
||||
m_world.receive_player_logout(*rsp);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <utility>
|
||||
using namespace std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace google::protobuf;
|
||||
|
||||
namespace Cubed {
|
||||
ServerWorld::ServerWorld() {}
|
||||
@@ -36,12 +37,14 @@ void ServerWorld::wait_all_chunk_tasks() {
|
||||
}
|
||||
|
||||
void ServerWorld::send_time() {
|
||||
UpdateTime rsp;
|
||||
rsp.set_day_tick(m_day_tick);
|
||||
rsp.set_game_tick(m_game_ticks);
|
||||
Arena arena;
|
||||
auto* rsp = Arena::Create<UpdateTime>(&arena);
|
||||
|
||||
rsp->set_day_tick(m_day_tick);
|
||||
rsp->set_game_tick(m_game_ticks);
|
||||
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
player.get_session()->send(make_packet(rsp));
|
||||
player.get_session()->send(make_packet(*rsp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,14 +442,15 @@ void ServerWorld::sync_player_pos(const std::string& uuid, float x, float y,
|
||||
}
|
||||
|
||||
for (auto& session : other) {
|
||||
PlayerInfoRsp rsp;
|
||||
rsp.set_uuid(uuid);
|
||||
rsp.set_name(name);
|
||||
auto* pos = rsp.mutable_pos();
|
||||
Arena arena;
|
||||
auto* rsp = Arena::Create<PlayerInfoRsp>(&arena);
|
||||
rsp->set_uuid(uuid);
|
||||
rsp->set_name(name);
|
||||
auto* pos = rsp->mutable_pos();
|
||||
pos->set_x(x);
|
||||
pos->set_y(y);
|
||||
pos->set_z(z);
|
||||
session->send(make_packet(rsp));
|
||||
session->send(make_packet(*rsp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,10 +465,11 @@ void ServerWorld::handle_player_login(const std::string& name,
|
||||
std::forward_as_tuple(name, uuid, *this, session, m_game_ticks));
|
||||
}
|
||||
m_uuid_to_name.emplace(uuid, name);
|
||||
LoginRsp rsp;
|
||||
rsp.set_success(true);
|
||||
rsp.set_uuid(uuid);
|
||||
session->send(make_packet(rsp));
|
||||
Arena arena;
|
||||
auto* rsp = Arena::Create<LoginRsp>(&arena);
|
||||
rsp->set_success(true);
|
||||
rsp->set_uuid(uuid);
|
||||
session->send(make_packet(*rsp));
|
||||
}
|
||||
|
||||
void ServerWorld::handle_player_exit(const std::string& uuid) {
|
||||
@@ -491,9 +496,10 @@ void ServerWorld::handle_player_exit(const std::string& uuid) {
|
||||
}
|
||||
|
||||
for (auto& s : sessions) {
|
||||
LogoutRsp rsp;
|
||||
rsp.set_uuid(uuid);
|
||||
s->send(make_packet(rsp));
|
||||
Arena arena;
|
||||
auto* rsp = Arena::Create<LogoutRsp>(&arena);
|
||||
rsp->set_uuid(uuid);
|
||||
s->send(make_packet(*rsp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,8 +514,10 @@ glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
|
||||
}
|
||||
|
||||
void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) {
|
||||
ChunkDataRsp rsq;
|
||||
auto* rsq_pos = rsq.mutable_pos();
|
||||
|
||||
Arena arean;
|
||||
ChunkDataRsp* rsp = Arena::Create<ChunkDataRsp>(&arean);
|
||||
auto* rsq_pos = rsp->mutable_pos();
|
||||
rsq_pos->set_x(pos.x);
|
||||
rsq_pos->set_z(pos.z);
|
||||
{
|
||||
@@ -518,9 +526,9 @@ void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) {
|
||||
if (it == m_chunks.end()) {
|
||||
return;
|
||||
}
|
||||
rsq.set_chunk_seed(it->second.seed());
|
||||
rsq.set_biome_type(std::to_underlying(it->second.biome()));
|
||||
auto* blocks = rsq.mutable_chunk_blocks();
|
||||
rsp->set_chunk_seed(it->second.seed());
|
||||
rsp->set_biome_type(std::to_underlying(it->second.biome()));
|
||||
auto* blocks = rsp->mutable_chunk_blocks();
|
||||
auto& chunk_blocks = it->second.get_chunk_blocks();
|
||||
blocks->Assign(chunk_blocks.begin(), chunk_blocks.end());
|
||||
auto& neighbor_blocks = it->second.get_neightbor_blocks();
|
||||
@@ -534,10 +542,10 @@ void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) {
|
||||
}
|
||||
nb->Assign(blocks->begin(), blocks->end());
|
||||
};
|
||||
auto* nb1 = rsq.mutable_neighbor_blocks_1();
|
||||
auto* nb2 = rsq.mutable_neighbor_blocks_2();
|
||||
auto* nb3 = rsq.mutable_neighbor_blocks_3();
|
||||
auto* nb4 = rsq.mutable_neighbor_blocks_4();
|
||||
auto* nb1 = rsp->mutable_neighbor_blocks_1();
|
||||
auto* nb2 = rsp->mutable_neighbor_blocks_2();
|
||||
auto* nb3 = rsp->mutable_neighbor_blocks_3();
|
||||
auto* nb4 = rsp->mutable_neighbor_blocks_4();
|
||||
assign(nb1, neighbor_blocks[0]);
|
||||
assign(nb2, neighbor_blocks[1]);
|
||||
assign(nb3, neighbor_blocks[2]);
|
||||
@@ -557,7 +565,7 @@ void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->send(make_packet(rsq));
|
||||
s->send(make_packet(*rsp));
|
||||
}
|
||||
|
||||
void ServerWorld::handle_block_change(const BlockChangeReq& req) {
|
||||
@@ -567,18 +575,20 @@ void ServerWorld::handle_block_change(const BlockChangeReq& req) {
|
||||
if (!set_block(glm::ivec3(x, y, z), req.block())) {
|
||||
return;
|
||||
}
|
||||
BlockChangeRsp rsp;
|
||||
auto* pos = rsp.mutable_pos();
|
||||
|
||||
Arena arena;
|
||||
BlockChangeRsp* rsp = Arena::Create<BlockChangeRsp>(&arena);
|
||||
auto* pos = rsp->mutable_pos();
|
||||
pos->set_x(x);
|
||||
pos->set_y(y);
|
||||
pos->set_z(z);
|
||||
rsp.set_block(req.block());
|
||||
rsp->set_block(req.block());
|
||||
{
|
||||
std::shared_lock lock(m_player_mutex);
|
||||
for (auto& [uuid, player] : m_players) {
|
||||
auto session = player.get_session();
|
||||
if (session) {
|
||||
session->send(make_packet(rsp));
|
||||
session->send(make_packet(*rsp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/uuid.hpp"
|
||||
using asio::ip::tcp;
|
||||
|
||||
using namespace google::protobuf;
|
||||
namespace Cubed {
|
||||
Session::Session(tcp::socket socket, ServerWorld& server_world,
|
||||
asio::io_context& io)
|
||||
@@ -55,41 +55,42 @@ asio::awaitable<void> Session::read_loop() {
|
||||
}
|
||||
constexpr auto& to_num = std::to_underlying<PacketEnum>;
|
||||
auto cmd_id = header.cmd;
|
||||
Arena arena;
|
||||
if (cmd_id == to_num(PacketEnum::LOGIN_REQ)) {
|
||||
LoginReq req;
|
||||
auto* req = Arena::Create<LoginReq>(&arena);
|
||||
Logger::info("Session: Receive Login req");
|
||||
if (decode_packet(req, body_data, header)) {
|
||||
m_server_world.handle_player_login(req.name(),
|
||||
if (decode_packet(*req, body_data, header)) {
|
||||
m_server_world.handle_player_login(req->name(),
|
||||
shared_from_this());
|
||||
}
|
||||
}
|
||||
if (cmd_id == to_num(PacketEnum::PLAYER_POS)) {
|
||||
PlayerPos pos;
|
||||
if (decode_packet(pos, body_data, header)) {
|
||||
m_server_world.sync_player_pos(pos.uuid(), pos.pos().x(),
|
||||
pos.pos().y(),
|
||||
pos.pos().z());
|
||||
auto* pos = Arena::Create<PlayerPos>(&arena);
|
||||
if (decode_packet(*pos, body_data, header)) {
|
||||
m_server_world.sync_player_pos(pos->uuid(), pos->pos().x(),
|
||||
pos->pos().y(),
|
||||
pos->pos().z());
|
||||
}
|
||||
}
|
||||
if (cmd_id == to_num(PacketEnum::CHUNK_DATA_REQ)) {
|
||||
ChunkDataReq req;
|
||||
auto* req = Arena::Create<ChunkDataReq>(&arena);
|
||||
// Logger::info("Session: Receive Chunk Data req");
|
||||
if (decode_packet(req, body_data, header)) {
|
||||
if (decode_packet(*req, body_data, header)) {
|
||||
m_server_world.handle_chunk_req(
|
||||
req.uuid(), ChunkPos(req.pos().x(), req.pos().z()));
|
||||
req->uuid(), ChunkPos(req->pos().x(), req->pos().z()));
|
||||
}
|
||||
}
|
||||
if (cmd_id == to_num(PacketEnum::BLOCK_CHANGE_REQ)) {
|
||||
BlockChangeReq req;
|
||||
auto* req = Arena::Create<BlockChangeReq>(&arena);
|
||||
Logger::info("Session: Receive Block Change req");
|
||||
if (decode_packet(req, body_data, header)) {
|
||||
m_server_world.handle_block_change(req);
|
||||
if (decode_packet(*req, body_data, header)) {
|
||||
m_server_world.handle_block_change(*req);
|
||||
}
|
||||
}
|
||||
if (cmd_id == to_num(PacketEnum::LOGOUT_REQ)) {
|
||||
LogoutReq req;
|
||||
if (decode_packet(req, body_data, header)) {
|
||||
m_server_world.handle_player_exit(req.uuid());
|
||||
auto* req = Arena::Create<LogoutReq>(&arena);
|
||||
if (decode_packet(*req, body_data, header)) {
|
||||
m_server_world.handle_player_exit(req->uuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user