#include "shared/pch.hh" #include "shared/protocol.hh" #include "core/io/buffer.hh" #include "shared/entity/head.hh" #include "shared/entity/player.hh" #include "shared/entity/transform.hh" #include "shared/entity/velocity.hh" #include "shared/world/chunk.hh" #include "shared/world/dimension.hh" #include "shared/globals.hh" static io::ReadBuffer read_buffer; static io::WriteBuffer write_buffer; ENetPacket* protocol::encode(const protocol::StatusRequest& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::StatusRequest::ID); write_buffer.write(packet.game_version_major); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::StatusResponse& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::StatusResponse::ID); write_buffer.write(packet.game_version_major); write_buffer.write(packet.max_players); write_buffer.write(packet.num_players); write_buffer.write(packet.motd); write_buffer.write(packet.game_version_minor); write_buffer.write(packet.game_version_patch); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::LoginRequest& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::LoginRequest::ID); write_buffer.write(packet.game_version_major); write_buffer.write(packet.voxel_registry_checksum); write_buffer.write(packet.item_registry_checksum); write_buffer.write(packet.password_hash); write_buffer.write(packet.username.substr(0, protocol::MAX_USERNAME)); write_buffer.write(packet.game_version_minor); write_buffer.write(packet.game_version_patch); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::LoginResponse& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::LoginResponse::ID); write_buffer.write(packet.client_index); write_buffer.write(packet.client_identity); write_buffer.write(packet.server_tickrate); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::Disconnect& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::Disconnect::ID); write_buffer.write(packet.reason); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::ChunkVoxels& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::ChunkVoxels::ID); write_buffer.write(packet.chunk.x); write_buffer.write(packet.chunk.y); write_buffer.write(packet.chunk.z); packet.voxels.serialize(write_buffer); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::EntityTransform& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::EntityTransform::ID); write_buffer.write(static_cast(packet.entity)); write_buffer.write(packet.chunk.x); write_buffer.write(packet.chunk.y); write_buffer.write(packet.chunk.z); write_buffer.write(packet.local.x); write_buffer.write(packet.local.y); write_buffer.write(packet.local.z); write_buffer.write(packet.angles.x); write_buffer.write(packet.angles.y); write_buffer.write(packet.angles.z); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::EntityHead& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::EntityHead::ID); write_buffer.write(static_cast(packet.entity)); write_buffer.write(packet.angles.x); write_buffer.write(packet.angles.y); write_buffer.write(packet.angles.z); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::EntityVelocity& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::EntityVelocity::ID); write_buffer.write(static_cast(packet.entity)); write_buffer.write(packet.value.x); write_buffer.write(packet.value.y); write_buffer.write(packet.value.z); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::SpawnPlayer& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::SpawnPlayer::ID); write_buffer.write(static_cast(packet.entity)); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::ChatMessage& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::ChatMessage::ID); write_buffer.write(packet.type); write_buffer.write(packet.sender.substr(0, protocol::MAX_USERNAME)); write_buffer.write(packet.message.substr(0, protocol::MAX_CHAT)); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::SetVoxel& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::SetVoxel::ID); write_buffer.write(packet.vpos.x); write_buffer.write(packet.vpos.y); write_buffer.write(packet.vpos.z); write_buffer.write(packet.voxel); write_buffer.write(packet.flags); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::RemoveEntity& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::RemoveEntity::ID); write_buffer.write(static_cast(packet.entity)); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::EntityPlayer& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::EntityPlayer::ID); write_buffer.write(static_cast(packet.entity)); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::ScoreboardUpdate& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::ScoreboardUpdate::ID); write_buffer.write(static_cast(packet.names.size())); for(const std::string& username : packet.names) write_buffer.write(username.substr(0, protocol::MAX_USERNAME)); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::RequestChunk& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::RequestChunk::ID); write_buffer.write(packet.cpos.x); write_buffer.write(packet.cpos.y); write_buffer.write(packet.cpos.z); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::GenericSound& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::GenericSound::ID); write_buffer.write(packet.sound.substr(0, protocol::MAX_SOUNDNAME)); write_buffer.write(packet.looping); write_buffer.write(packet.pitch); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::EntitySound& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::EntitySound::ID); write_buffer.write(static_cast(packet.entity)); write_buffer.write(packet.sound.substr(0, protocol::MAX_SOUNDNAME)); write_buffer.write(packet.looping); write_buffer.write(packet.pitch); return write_buffer.to_packet(flags); } ENetPacket* protocol::encode(const protocol::DimensionInfo& packet, enet_uint32 flags) { write_buffer.reset(); write_buffer.write(protocol::DimensionInfo::ID); write_buffer.write(packet.name); write_buffer.write(packet.gravity); return write_buffer.to_packet(flags); } void protocol::broadcast(ENetHost* host, ENetPacket* packet) { if(packet) { enet_host_broadcast(host, protocol::CHANNEL, packet); } } void protocol::broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except) { if(packet) { for(unsigned int i = 0U; i < host->peerCount; ++i) { if(host->peers[i].state == ENET_PEER_STATE_CONNECTED) { if(&host->peers[i] != except) { enet_peer_send(&host->peers[i], protocol::CHANNEL, packet); } } } } } void protocol::send(ENetPeer* peer, ENetPacket* packet) { if(packet) { enet_peer_send(peer, protocol::CHANNEL, packet); } } void protocol::decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer) { read_buffer.reset(packet); protocol::StatusRequest status_request; protocol::StatusResponse status_response; protocol::LoginRequest login_request; protocol::LoginResponse login_response; protocol::Disconnect disconnect; protocol::ChunkVoxels chunk_voxels; protocol::EntityTransform entity_transform; protocol::EntityHead entity_head; protocol::EntityVelocity entity_velocity; protocol::SpawnPlayer spawn_player; protocol::ChatMessage chat_message; protocol::SetVoxel set_voxel; protocol::RemoveEntity remove_entity; protocol::EntityPlayer entity_player; protocol::ScoreboardUpdate scoreboard_update; protocol::RequestChunk request_chunk; protocol::GenericSound generic_sound; protocol::EntitySound entity_sound; protocol::DimensionInfo dimension_info; auto id = read_buffer.read(); switch(id) { case protocol::StatusRequest::ID: status_request.peer = peer; status_request.game_version_major = read_buffer.read(); dispatcher.trigger(status_request); break; case protocol::StatusResponse::ID: status_response.peer = peer; status_response.game_version_major = read_buffer.read(); status_response.max_players = read_buffer.read(); status_response.num_players = read_buffer.read(); status_response.motd = read_buffer.read(); status_response.game_version_minor = read_buffer.read(); status_response.game_version_patch = read_buffer.read(); dispatcher.trigger(status_response); break; case protocol::LoginRequest::ID: login_request.peer = peer; login_request.game_version_major = read_buffer.read(); login_request.voxel_registry_checksum = read_buffer.read(); login_request.item_registry_checksum = read_buffer.read(); login_request.password_hash = read_buffer.read(); login_request.username = read_buffer.read(); login_request.game_version_minor = read_buffer.read(); login_request.game_version_patch = read_buffer.read(); dispatcher.trigger(login_request); break; case protocol::LoginResponse::ID: login_response.peer = peer; login_response.client_index = read_buffer.read(); login_response.client_identity = read_buffer.read(); login_response.server_tickrate = read_buffer.read(); dispatcher.trigger(login_response); break; case protocol::Disconnect::ID: disconnect.peer = peer; disconnect.reason = read_buffer.read(); dispatcher.trigger(disconnect); break; case protocol::ChunkVoxels::ID: chunk_voxels.peer = peer; chunk_voxels.chunk.x = read_buffer.read(); chunk_voxels.chunk.y = read_buffer.read(); chunk_voxels.chunk.z = read_buffer.read(); chunk_voxels.voxels.deserialize(read_buffer); dispatcher.trigger(chunk_voxels); break; case protocol::EntityTransform::ID: entity_transform.peer = peer; entity_transform.entity = static_cast(read_buffer.read()); entity_transform.chunk.x = read_buffer.read(); entity_transform.chunk.y = read_buffer.read(); entity_transform.chunk.z = read_buffer.read(); entity_transform.local.x = read_buffer.read(); entity_transform.local.y = read_buffer.read(); entity_transform.local.z = read_buffer.read(); entity_transform.angles.x = read_buffer.read(); entity_transform.angles.y = read_buffer.read(); entity_transform.angles.z = read_buffer.read(); dispatcher.trigger(entity_transform); break; case protocol::EntityHead::ID: entity_head.peer = peer; entity_head.entity = static_cast(read_buffer.read()); entity_head.angles[0] = read_buffer.read(); entity_head.angles[1] = read_buffer.read(); entity_head.angles[2] = read_buffer.read(); dispatcher.trigger(entity_head); break; case protocol::EntityVelocity::ID: entity_velocity.peer = peer; entity_velocity.entity = static_cast(read_buffer.read()); entity_velocity.value.x = read_buffer.read(); entity_velocity.value.y = read_buffer.read(); entity_velocity.value.z = read_buffer.read(); dispatcher.trigger(entity_velocity); break; case protocol::SpawnPlayer::ID: spawn_player.peer = peer; spawn_player.entity = static_cast(read_buffer.read()); dispatcher.trigger(spawn_player); break; case protocol::ChatMessage::ID: chat_message.peer = peer; chat_message.type = read_buffer.read(); chat_message.sender = read_buffer.read(); chat_message.message = read_buffer.read(); dispatcher.trigger(chat_message); break; case protocol::SetVoxel::ID: set_voxel.peer = peer; set_voxel.vpos.x = read_buffer.read(); set_voxel.vpos.y = read_buffer.read(); set_voxel.vpos.z = read_buffer.read(); set_voxel.voxel = read_buffer.read(); set_voxel.flags = read_buffer.read(); dispatcher.trigger(set_voxel); break; case protocol::RemoveEntity::ID: remove_entity.peer = peer; remove_entity.entity = static_cast(read_buffer.read()); dispatcher.trigger(remove_entity); break; case protocol::EntityPlayer::ID: entity_player.peer = peer; entity_player.entity = static_cast(read_buffer.read()); dispatcher.trigger(entity_player); break; case protocol::ScoreboardUpdate::ID: scoreboard_update.peer = peer; scoreboard_update.names.resize(read_buffer.read()); for(std::size_t i = 0; i < scoreboard_update.names.size(); ++i) scoreboard_update.names[i] = read_buffer.read(); dispatcher.trigger(scoreboard_update); break; case protocol::RequestChunk::ID: request_chunk.peer = peer; request_chunk.cpos.x = read_buffer.read(); request_chunk.cpos.y = read_buffer.read(); request_chunk.cpos.z = read_buffer.read(); dispatcher.trigger(request_chunk); break; case protocol::GenericSound::ID: generic_sound.peer = peer; generic_sound.sound = read_buffer.read(); generic_sound.looping = read_buffer.read(); generic_sound.pitch = read_buffer.read(); dispatcher.trigger(generic_sound); break; case protocol::EntitySound::ID: entity_sound.peer = peer; entity_sound.entity = static_cast(read_buffer.read()); entity_sound.sound = read_buffer.read(); entity_sound.looping = read_buffer.read(); entity_sound.pitch = read_buffer.read(); dispatcher.trigger(entity_sound); break; case protocol::DimensionInfo::ID: dimension_info.peer = peer; dimension_info.name = read_buffer.read(); dimension_info.gravity = read_buffer.read(); dispatcher.trigger(dimension_info); break; } } ENetPacket* protocol::utils::make_disconnect(std::string_view reason, enet_uint32 flags) { protocol::Disconnect packet; packet.reason = reason; return protocol::encode(packet, flags); } ENetPacket* protocol::utils::make_chat_message(std::string_view message, enet_uint32 flags) { protocol::ChatMessage packet; packet.type = protocol::ChatMessage::TEXT_MESSAGE; packet.message = message; return protocol::encode(packet, flags); } ENetPacket* protocol::utils::make_chunk_voxels(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) { if(auto component = dimension->chunks.try_get(entity)) { protocol::ChunkVoxels packet; packet.chunk = component->cpos; packet.voxels = component->chunk->get_voxels(); return protocol::encode(packet, flags); } return nullptr; } ENetPacket* protocol::utils::make_entity_head(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) { if(auto component = dimension->entities.try_get(entity)) { protocol::EntityHead packet; packet.entity = entity; packet.angles = component->angles; return protocol::encode(packet, flags); } return nullptr; } ENetPacket* protocol::utils::make_entity_transform(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) { if(auto component = dimension->entities.try_get(entity)) { protocol::EntityTransform packet; packet.entity = entity; packet.chunk = component->chunk; packet.local = component->local; packet.angles = component->angles; return protocol::encode(packet, flags); } return nullptr; } ENetPacket* protocol::utils::make_entity_velocity(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) { if(auto component = dimension->entities.try_get(entity)) { protocol::EntityVelocity packet; packet.entity = entity; packet.value = component->value; return protocol::encode(packet, flags); } return nullptr; } ENetPacket* protocol::utils::make_entity_player(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) { if(dimension->entities.any_of(entity)) { protocol::EntityPlayer packet; packet.entity = entity; return protocol::encode(packet, flags); } return nullptr; } ENetPacket* protocol::utils::make_dimension_info(const world::Dimension* dimension) { protocol::DimensionInfo packet; packet.name = dimension->get_name(); packet.gravity = dimension->get_gravity(); return protocol::encode(packet, ENET_PACKET_FLAG_RELIABLE); }