From 1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df Mon Sep 17 00:00:00 2001 From: Nicolas James Date: Wed, 12 Feb 2025 18:05:18 +1100 Subject: initial commit --- src/client/client.cc | 515 ++ src/client/client.hh | 28 + src/client/draw.cc | 432 ++ src/client/draw.hh | 59 + src/client/input.cc | 111 + src/client/input.hh | 48 + src/client/math.cc | 26 + src/client/math.hh | 22 + src/client/movement.cc | 165 + src/client/movement.hh | 23 + src/client/player.cc | 58 + src/client/player.hh | 64 + src/client/render/camera.cc | 96 + src/client/render/camera.hh | 38 + src/client/render/lib/stb_image/stb_image.cc | 2 + src/client/render/lib/stb_image/stb_image.hh | 7774 ++++++++++++++++++++++++++ src/client/render/model.cc | 1 + src/client/render/model.hh | 247 + src/client/render/program.cc | 55 + src/client/render/program.hh | 29 + src/client/render/render.cc | 602 ++ src/client/render/render.hh | 62 + src/client/render/texture.cc | 1 + src/client/render/texture.hh | 37 + src/client/settings.cc | 139 + src/client/settings.hh | 52 + src/client/shared.cc | 1 + src/client/shared.hh | 29 + src/client/window.cc | 449 ++ src/client/window.hh | 30 + src/client/world.cc | 429 ++ src/client/world.hh | 90 + src/main.cc | 193 + src/main.hh | 25 + src/server/chunk_data.cc | 1 + src/server/chunk_data.hh | 30 + src/server/client.cc | 1 + src/server/client.hh | 67 + src/server/database.cc | 238 + src/server/database.hh | 39 + src/server/movement.cc | 87 + src/server/movement.hh | 19 + src/server/resources.cc | 59 + src/server/resources.hh | 119 + src/server/server.cc | 640 +++ src/server/server.hh | 37 + src/server/shared.cc | 1 + src/server/shared.hh | 19 + src/server/world.cc | 53 + src/server/world.hh | 59 + src/shared/math.cc | 23 + src/shared/math.hh | 53 + src/shared/movement.cc | 490 ++ src/shared/movement.hh | 67 + src/shared/net/connection.cc | 1 + src/shared/net/connection.hh | 212 + src/shared/net/lib/protobuf/net.pb.cc | 5548 ++++++++++++++++++ src/shared/net/lib/protobuf/net.pb.h | 6386 +++++++++++++++++++++ src/shared/net/lib/protobuf/net.proto | 123 + src/shared/net/net.cc | 138 + src/shared/net/net.hh | 56 + src/shared/net/proto.cc | 55 + src/shared/net/proto.hh | 28 + src/shared/player.cc | 1 + src/shared/player.hh | 46 + src/shared/shared.cc | 57 + src/shared/shared.hh | 120 + src/shared/world.cc | 932 +++ src/shared/world.hh | 224 + 69 files changed, 27961 insertions(+) create mode 100644 src/client/client.cc create mode 100644 src/client/client.hh create mode 100644 src/client/draw.cc create mode 100644 src/client/draw.hh create mode 100644 src/client/input.cc create mode 100644 src/client/input.hh create mode 100644 src/client/math.cc create mode 100644 src/client/math.hh create mode 100644 src/client/movement.cc create mode 100644 src/client/movement.hh create mode 100644 src/client/player.cc create mode 100644 src/client/player.hh create mode 100644 src/client/render/camera.cc create mode 100644 src/client/render/camera.hh create mode 100644 src/client/render/lib/stb_image/stb_image.cc create mode 100644 src/client/render/lib/stb_image/stb_image.hh create mode 100644 src/client/render/model.cc create mode 100644 src/client/render/model.hh create mode 100644 src/client/render/program.cc create mode 100644 src/client/render/program.hh create mode 100644 src/client/render/render.cc create mode 100644 src/client/render/render.hh create mode 100644 src/client/render/texture.cc create mode 100644 src/client/render/texture.hh create mode 100644 src/client/settings.cc create mode 100644 src/client/settings.hh create mode 100644 src/client/shared.cc create mode 100644 src/client/shared.hh create mode 100644 src/client/window.cc create mode 100644 src/client/window.hh create mode 100644 src/client/world.cc create mode 100644 src/client/world.hh create mode 100644 src/main.cc create mode 100644 src/main.hh create mode 100644 src/server/chunk_data.cc create mode 100644 src/server/chunk_data.hh create mode 100644 src/server/client.cc create mode 100644 src/server/client.hh create mode 100644 src/server/database.cc create mode 100644 src/server/database.hh create mode 100644 src/server/movement.cc create mode 100644 src/server/movement.hh create mode 100644 src/server/resources.cc create mode 100644 src/server/resources.hh create mode 100644 src/server/server.cc create mode 100644 src/server/server.hh create mode 100644 src/server/shared.cc create mode 100644 src/server/shared.hh create mode 100644 src/server/world.cc create mode 100644 src/server/world.hh create mode 100644 src/shared/math.cc create mode 100644 src/shared/math.hh create mode 100644 src/shared/movement.cc create mode 100644 src/shared/movement.hh create mode 100644 src/shared/net/connection.cc create mode 100644 src/shared/net/connection.hh create mode 100644 src/shared/net/lib/protobuf/net.pb.cc create mode 100644 src/shared/net/lib/protobuf/net.pb.h create mode 100644 src/shared/net/lib/protobuf/net.proto create mode 100644 src/shared/net/net.cc create mode 100644 src/shared/net/net.hh create mode 100644 src/shared/net/proto.cc create mode 100644 src/shared/net/proto.hh create mode 100644 src/shared/player.cc create mode 100644 src/shared/player.hh create mode 100644 src/shared/shared.cc create mode 100644 src/shared/shared.hh create mode 100644 src/shared/world.cc create mode 100644 src/shared/world.hh (limited to 'src') diff --git a/src/client/client.cc b/src/client/client.cc new file mode 100644 index 0000000..b4cacdc --- /dev/null +++ b/src/client/client.cc @@ -0,0 +1,515 @@ +#include "client.hh" + +namespace { +bool should_send_move = false; // Ratelimit move packets by player packets. + +shared::world::block last_block = shared::world::block::type::dirt; + +client::world::chunk::map chunks{4096, shared::world::chunk::hash, + shared::world::chunk::equal}; + +client::players players; +} // namespace + +namespace client { + +static auto get_player_it(const std::uint32_t index) { + return std::ranges::find_if( + ::players, [&](const auto& player) { return player.index == index; }); +} + +static proto::packet +make_get_chunk_packet(const shared::math::coords& coords) noexcept { + proto::packet packet; + + const auto chunk_packet = packet.mutable_request_chunk_packet(); + shared::net::set_coords(*chunk_packet->mutable_chunk_pos(), coords); + + return packet; +} + +static proto::packet make_auth_packet(const std::string& username, + const std::string& password) noexcept { + proto::packet packet; + + const auto auth_packet = packet.mutable_auth_packet(); + auth_packet->set_username(username); + auth_packet->set_password(password); + + return packet; +} + +static proto::packet make_add_block_packet(const shared::math::coords& coords, + const glm::ivec3& pos) noexcept { + proto::packet packet; + + const auto interact_packet = packet.mutable_add_block_packet(); + shared::net::set_coords(*interact_packet->mutable_chunk_pos(), coords); + shared::net::set_ivec3(*interact_packet->mutable_block_pos(), pos); + interact_packet->set_block(static_cast(::last_block.type)); + + return packet; +} + +static proto::packet +make_remove_block_packet(const shared::math::coords& coords, + const glm::ivec3& pos) noexcept { + proto::packet packet; + + const auto interact_packet = packet.mutable_remove_block_packet(); + shared::net::set_coords(*interact_packet->mutable_chunk_pos(), coords); + shared::net::set_ivec3(*interact_packet->mutable_block_pos(), pos); + + return packet; +} + +[[maybe_unused]] // [[actually_used]] +static proto::packet +make_remove_chunk_packet(const shared::math::coords& coords) noexcept { + proto::packet packet; + + const auto remove_chunk_packet = packet.mutable_remove_chunk_packet(); + shared::net::set_coords(*remove_chunk_packet->mutable_chunk_pos(), coords); + + return packet; +} + +static void handle_init_packet(const proto::init& packet) noexcept { + client::state.seed = packet.seed(); + client::state.draw_distance = + std::min(packet.draw_distance(), + client::settings::get({"video", "draw_distance"}, 32)); + + auto& localplayer = packet.localplayer(); + client::state.localplayer = localplayer.index(); + + ::players.emplace_back(shared::net::get_player(localplayer)); +} + +static void handle_player_packet(const proto::player& packet) noexcept { + if (std::size(::players) <= 0) { + return; + } + + const auto player_it = get_player_it(packet.index()); + + shared::player player = shared::net::get_player(packet); + + if (player_it == std::end(::players)) { + ::players.emplace_back(player); + return; + } + // If the player packet refers to us, we do not override our localplayer's + // commands or viewangles. Also, we should send a new move packet. + if (auto& lp = get_localplayer(::players); lp.index == packet.index()) { + + player.viewangles = lp.viewangles; + player.commands = 0u; + ::should_send_move = true; + } + player_it->update(player); +} + +// Remove the client whose element is equal to pkt.index. +static void handle_remove_packet(const proto::remove_player& packet) noexcept { + const auto player_it = get_player_it(packet.index()); + if (player_it == std::end(::players)) { + return; + } + ::players.erase(player_it); +} + +static void handle_hear_packet(const proto::hear_player& packet) noexcept { + const auto player_it = get_player_it(packet.index()); + if (player_it == std::end(::players)) { + return; + } + player_it->message.emplace(packet.text()); +} + +static void handle_chunk_packet(const proto::chunk& packet) noexcept { + const shared::math::coords pos{.x = packet.chunk_pos().x(), + .z = packet.chunk_pos().z()}; + const auto find_it = ::chunks.find(pos); + if (find_it == std::end(::chunks)) { + return; + } + find_it->second.emplace( + client::state.seed, pos, + shared::world::chunk::make_blocks_from_chunk(packet)); + // Force the surrounding chunks to regenerate their vbos. + // It's possible we could only generate the ones that we actually need to + // generate, but that's not really a priority atm. + for (auto x = -1; x <= 1; ++x) { + for (auto z = -1; z <= 1; ++z) { + if (std::abs(x) == 1 && std::abs(z) == 1) { + continue; + } + const auto find_update_it = + ::chunks.find(pos + shared::math::coords{x, z}); + if (find_update_it == std::end(::chunks)) { + continue; + } + if (!find_update_it->second.has_value()) { + continue; + } + find_update_it->second->should_regenerate_vbo = true; + } + } +} + +static void +handle_server_message_packet(const proto::server_message& packet) noexcept { + const bool fatal = packet.fatal(); + const std::string message = + "client: received " + std::string{fatal ? "fatal" : ""} + + " message from the server \"" + packet.message() + "\"\n"; + if (!fatal) { + shared::print::notify(message); + return; + } + + shared::print::warn(message); + shared::should_exit = true; +} + +static void parse_packet(const proto::packet& packet) noexcept { + + if (packet.has_init_packet()) { + handle_init_packet(packet.init_packet()); + } else if (packet.has_player_packet()) { + handle_player_packet(packet.player_packet()); + } else if (packet.has_remove_player_packet()) { + handle_remove_packet(packet.remove_player_packet()); + } else if (packet.has_hear_player_packet()) { + handle_hear_packet(packet.hear_player_packet()); + } else if (packet.has_chunk_packet()) { + handle_chunk_packet(packet.chunk_packet()); + } else if (packet.has_server_message_packet()) { + handle_server_message_packet(packet.server_message_packet()); + } +#ifndef NDEBUG + else { + shared::print::warn("client: unhandled packet type\n"); + } +#endif +} + +static shared::net::connection make_connection(const std::string_view address, + const std::string_view port) { + constexpr addrinfo hints = {.ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM}; + const auto info = shared::net::get_addr_info(address, port, &hints); + const auto sock = shared::net::make_socket(info.get()); + shared::net::connect_socket(sock, info.get()); + return shared::net::connection(sock); +} + +static void update_chunks(shared::net::connection& connection) noexcept { + + const auto draw_distance = client::state.draw_distance; + const shared::math::coords& lp_pos = get_localplayer(::players).chunk_pos; + + // Remove bad chunks. + std::erase_if(::chunks, [&](const auto& chunk) { + const bool should_erase = + !shared::math::is_inside_draw(chunk.first, lp_pos, draw_distance); + if (should_erase) { + connection.rsend_packet(make_remove_chunk_packet(chunk.first)); + } + return should_erase; + }); + + for (int dist = 0; dist <= client::state.draw_distance; ++dist) { + + const auto maybe_add_chunk = [&](const int x, const int z) -> bool { + const auto pos = shared::math::coords{x + lp_pos.x, z + lp_pos.z}; + if (!is_inside_draw(pos, lp_pos, draw_distance)) { + return false; + } + if (::chunks.contains(pos)) { + return false; + } + connection.rsend_packet(make_get_chunk_packet(pos)); + ::chunks.emplace(pos, std::nullopt); + return true; + }; + + int x = -dist; + int z = dist; + + // Does a spiral pattern, but it's basically unnoticable :( + for (int i = 0; i < dist * 2 + 1; ++i) { + if (maybe_add_chunk(x, z)) { + return; + } + x += (i < dist * 2); + } + for (int i = 0; i < dist * 2; ++i) { + --z; + if (maybe_add_chunk(x, z)) { + return; + } + } + for (int i = 0; i < dist * 2; ++i) { + --x; + if (maybe_add_chunk(x, z)) { + return; + } + } + for (int i = 0; i < dist * 2 - 1; ++i) { + ++z; + if (maybe_add_chunk(x, z)) { + return; + } + } + } +} + +static void update_state() noexcept { + client::state.player_count = ::players.size(); + client::state.requested_chunk_count = + static_cast(std::ranges::count_if( + ::chunks, [](const auto& c) { return !c.second.has_value(); })); + client::state.networked_chunk_count = + std::size(::chunks) - client::state.requested_chunk_count; +} + +static proto::packet make_say_packet(const std::string& text) noexcept { + proto::packet packet; + + const auto sub_say_packet = packet.mutable_say_packet(); + sub_say_packet->set_text(text); + + return packet; +} + +// unfortunate non-static :( +void send_say_packet(const std::string& text) noexcept { + client::state.connection->rsend_packet(make_say_packet(text)); +} + +static void handle_button_input() noexcept { + if (input::is_key_pressed(SDLK_z)) { + client::render::camera::get_xfov() = 30.0f; + } else { + client::render::camera::get_xfov() = + client::settings::get({"gameplay", "fov"}, 100.0f); + } + + // Don't build our movement commands if we're inputting text. + if (input::state.typing) { + return; + } + + auto& lp = get_localplayer(::players); + + using spm = shared::player::mask; + lp.commands |= spm::forward * input::is_key_pressed(SDLK_w); + lp.commands |= spm::left * input::is_key_pressed(SDLK_a); + lp.commands |= spm::backward * input::is_key_pressed(SDLK_s); + lp.commands |= spm::right * input::is_key_pressed(SDLK_d); + lp.commands |= spm::jump * input::is_key_pressed(SDLK_SPACE); + lp.commands |= spm::crouch * input::is_key_pressed(SDLK_LCTRL); + lp.commands |= spm::sprint * input::is_key_pressed(SDLK_LSHIFT); + lp.commands |= spm::attack * input::is_key_pressed(SDL_BUTTON_LEFT); +} + +static void update_input() noexcept { + client::input::update(); + + if (!client::window::is_open()) { + handle_button_input(); + } + + if (client::input::state.quit) { + shared::should_exit = true; + } +} + +static proto::packet +make_move_packet(const shared::player& localplayer) noexcept { + proto::packet packet; + + const auto move_packet = packet.mutable_move_packet(); + move_packet->set_commands(localplayer.commands); + shared::net::set_angles(*move_packet->mutable_viewangles(), + localplayer.viewangles); + + return packet; +} + +static void send_move_packet(shared::net::connection& connection) noexcept { + const auto& localplayer = get_localplayer(::players); + connection.usend_packet(make_move_packet(localplayer)); +} + +static void update_players() noexcept { + const auto lp_index = get_localplayer(::players).index; + // pvs, remove clients outside of chunks we own + std::erase_if(::players, [&](const auto& player) { + if (player.index == lp_index) { + return false; + } + + // Players should be removed if the chunk can't draw. + const auto chunk_it = ::chunks.find(player.chunk_pos); + if (chunk_it == std::end(::chunks)) { + return true; + } + const auto& chunk = chunk_it->second; + if (!chunk.has_value()) { + return false; + } + + if (!chunk->can_draw()) { + return true; + } + return false; + }); +} + +// requires SDL_MOUSEMOTION +static void handle_mousemotion(const SDL_Event& event) noexcept { + const float sens = + settings::get({"gameplay", "mouse_sensitivity"}, 0.0235f); + + auto& lp = get_localplayer(::players); + auto& angles = lp.viewangles; + + const float pitch_offset = static_cast(event.motion.yrel) * sens; + const float yaw_offset = static_cast(event.motion.xrel) * sens; + + angles.pitch = std::clamp(angles.pitch - glm::radians(pitch_offset), + glm::radians(-89.0f), glm::radians(89.0f)); + angles.yaw = + std::fmod(angles.yaw + glm::radians(yaw_offset), glm::radians(360.0f)) + + (angles.yaw < 0.0f) * glm::radians(360.0f); +} + +// requires SDL_MOUSEBUTTONDOWN +static void handle_mousebuttons(const SDL_Event& event) noexcept { + if (event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) { + return; + } + + const auto mode = event.button.button == SDL_BUTTON_LEFT + ? client::movement::interact_mode::remove + : client::movement::interact_mode::add; + + const auto position = + client::movement::interact(get_localplayer(::players), mode, ::chunks); + + if (!position.has_value()) { + return; + } + + const auto& [chunk_pos, block_pos] = *position; + + auto& connection = *client::state.connection; + switch (mode) { + case client::movement::interact_mode::add: + connection.usend_packet(make_add_block_packet(chunk_pos, block_pos)); + break; + case client::movement::interact_mode::remove: + connection.usend_packet(make_remove_block_packet(chunk_pos, block_pos)); + ::last_block = ::chunks[chunk_pos]->get_block(block_pos); + break; + } +} + +static void handle_events(const SDL_Event& event) noexcept { + if (client::window::is_open()) { + return; + } + + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + handle_mousebuttons(event); + break; + case SDL_MOUSEMOTION: + handle_mousemotion(event); + break; + default: + break; + } +} + +static void authenticate_client(shared::net::connection& connection) noexcept { + const auto rand_alphanum_string = [](const int size) -> std::string { + static const std::string allowed = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "1234567890"; + std::string ret; + for (int i = 0; i < size; ++i) { + std::ranges::sample(allowed, std::back_inserter(ret), 1, + std::random_device{}); + } + + return ret; + }; + + const std::string username = settings::get( + {"auth", "username"}, + rand_alphanum_string(shared::MAX_USER_PASS_LENGTH)); + const std::string password = settings::get( + {"auth", "password"}, + rand_alphanum_string(shared::MAX_USER_PASS_LENGTH)); + + connection.rsend_packet(make_auth_packet(username, password)); +} + +void main(const std::string_view address, const std::string_view port) { + client::state.address = address; + client::state.port = port; + + shared::net::connection connection = make_connection(address, port); + shared::print::notify("client: connected to " + std::string{address} + ':' + + std::string{port} + '\n'); + client::state.connection = &connection; + + client::render::init(); + client::input::register_event_handler(&handle_events); + + authenticate_client(connection); + + while (!shared::should_exit) { + // Parse all new packets. + while (const auto packet = connection.recv_packet()) { + parse_packet(packet.value()); + } + + // Wait for localplayer to be constructed before doing anything. + if (::players.empty()) { + continue; + } + + // Handle input, which may prime text input -> send it to the + // server. + update_input(); + // Send our localplayer to the server. + if (::should_send_move) { + send_move_packet(connection); + ::should_send_move = false; + } + update_chunks(connection); + update_state(); + update_players(); + + client::draw::draw(::players, ::chunks); + + if (!connection.good()) { + shared::print::notify("client: disconnected for \"" + + connection.get_bad_reason() + "\"\n"); + shared::should_exit = true; + } + } + shared::print::notify("client: disconnecting from server\n"); + + client::render::quit(); + client::settings::save(); +} + +} // namespace client diff --git a/src/client/client.hh b/src/client/client.hh new file mode 100644 index 0000000..6dbabc1 --- /dev/null +++ b/src/client/client.hh @@ -0,0 +1,28 @@ +#ifndef CLIENT_CLIENT_HH_ +#define CLIENT_CLIENT_HH_ + +#include +#include +#include +#include + +#include "client/draw.hh" +#include "client/input.hh" +#include "client/movement.hh" +#include "client/player.hh" +#include "client/render/camera.hh" +#include "client/settings.hh" +#include "client/shared.hh" +#include "client/window.hh" +#include "client/world.hh" +#include "shared/math.hh" +#include "shared/net/net.hh" +#include "shared/net/proto.hh" + +namespace client { +void send_say_packet(const std::string& text) noexcept; + +void main(const std::string_view address, const std::string_view port); +} // namespace client + +#endif diff --git a/src/client/draw.cc b/src/client/draw.cc new file mode 100644 index 0000000..c549ffe --- /dev/null +++ b/src/client/draw.cc @@ -0,0 +1,432 @@ +#include "draw.hh" + +namespace client { +namespace draw { + +void draw_rectangle(const rectangle_args& ra) noexcept { + const glm::vec2 pos = ra.pos.to_vec2(); + const glm::vec2 size = ra.size.to_vec2(); + + // We want to render from the bottom left corner. + render::render_rectangle(pos + (size / 2.0f), size, ra.colour); +} + +void draw_colour(const glm::vec4& colour) noexcept { + const rectangle_args args = { + .pos = {.extent = {0.0f, 0.0f}}, + .size = {.extent = {1.0f, 1.0f}}, + .colour = colour, + }; + draw_rectangle(args); +} + +void draw_text(const std::string_view text, const text_args& args) noexcept { + const glm::vec2& window = render::get_window_size(); + const float x = floorf(window.x * args.pos.extent.x + args.pos.offset.x); + const float y = floorf(window.y * args.pos.extent.y + args.pos.offset.y); + const unsigned height = static_cast( + args.extent_height * window.y + args.offset_height); + + const auto make_matrix = [&](const float xo, const float yo) -> glm::mat4 { + constexpr auto identity = glm::mat4(1.0f); + const auto proj = glm::ortho(0.f, window.x, 0.f, window.y); + const auto tran = + glm::translate(identity, glm::vec3{x + xo, y + yo, 0.0f}); + return proj * tran; + }; + + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + if (args.has_backing) { + constexpr glm::vec4 black{0.0f, 0.0f, 0.0f, 1.0f}; + render::render_text(text, height, args.is_centered, args.is_vcentered, + black, make_matrix(1.0f, -2.0f)); + } + glEnable(GL_BLEND); + + render::render_text(text, height, args.is_centered, args.is_vcentered, + args.colour, make_matrix(0, 0)); + glEnable(GL_DEPTH_TEST); +} + +static void draw_state_info(const shared::player& lp) noexcept { + + constexpr auto nstr = [](const auto d) -> std::string { + auto str = std::to_string(d); + str.erase(std::prev(std::end(str), 4), std::end(str)); + return str; + }; + + const auto make_position = [&]() -> std::string { + const auto chunk_x = lp.chunk_pos.x; + const auto chunk_z = lp.chunk_pos.z; + const auto x = static_cast(lp.local_pos.x); + const auto y = static_cast(lp.local_pos.y); + const auto z = static_cast(lp.local_pos.z); + constexpr auto WIDTH = shared::world::chunk::WIDTH; + const auto abs_x = static_cast(lp.chunk_pos.x) * WIDTH + x; + const auto abs_z = static_cast(lp.chunk_pos.z) * WIDTH + z; + + constexpr auto nstr = [](const double d) -> std::string { + auto str = std::to_string(d); + str.erase(std::prev(std::end(str), 4), std::end(str)); + return str; + }; + const std::string chk_str = '[' + std::to_string(chunk_x) + ", " + + std::to_string(chunk_z) + ']'; + const std::string abs_str = + '(' + nstr(abs_x) + ", " + nstr(y) + ", " + nstr(abs_z) + ')'; + return "position: " + abs_str + chk_str; + }; + + const auto make_direction = [&]() -> std::string { + const float yaw = glm::degrees(lp.viewangles.yaw); + const float pitch = glm::degrees(lp.viewangles.pitch); + + const std::string bearing = [&]() -> std::string { + if (yaw >= 315.0f || yaw < 45.0f) { + return "North"; + } else if (yaw >= 45.0f && yaw < 135.0f) { + return "East"; + } else if (yaw >= 135.0f && yaw < 225.0f) { + return "South"; + } else { + return "West"; + } + }(); + const std::string face_str = '(' + nstr(pitch) + ", " + nstr(yaw) + ')'; + // Yaw is between 0 and 360. + return "perspective: " + face_str + " -> " + bearing; + }; + + const auto make_address = []() -> std::string { + const std::string address = std::string(client::state.address); + const std::string port = std::string(client::state.port); + return "address: " + address + ":" + port; + }; + + const auto make_seed = []() -> std::string { + return "seed: " + std::to_string(client::state.seed); + }; + + const auto make_players = []() -> std::string { + const auto index = std::to_string(client::state.localplayer); + return "index: " + index; + }; + + const auto make_chunks = []() -> std::string { + return "chunks [req, rcv]: " + + std::to_string(client::state.requested_chunk_count) + ", " + + std::to_string(client::state.networked_chunk_count) + " @ " + + std::to_string(client::state.draw_distance) + " draw distance"; + }; + + const auto make_speed = [&]() -> std::string { + return "speed: " + nstr(glm::length(lp.velocity)) + " b/s"; + }; + + const auto make_velocity = [&]() -> std::string { + return "velocity: (" + nstr(lp.velocity.x) + ", " + + nstr(lp.velocity.y) + ", " + nstr(lp.velocity.z) + ")"; + }; + + // Draws all of our strings and works its way down the top of the screen. + text_args args{.pos = {.extent = {0.0f, 1.0f - 0.015f}}, + .extent_height = 0.0165f, + .colour = {1.0f, 1.0f, 1.0f, 1.0f}, + .has_backing = true}; + const auto draw_str_trail = [&args](const std::string& str) { + draw_text(str, args); + args.pos.extent.y -= 0.02f; + }; + draw_str_trail("blockgame_linux v0.20"); + draw_str_trail(make_address()); + draw_str_trail(make_seed()); + draw_str_trail(make_players()); + draw_str_trail(make_chunks()); + draw_str_trail(make_position()); + draw_str_trail(make_direction()); + draw_str_trail(make_speed()); + draw_str_trail(make_velocity()); +} + +static void draw_fps() noexcept { + const auto get_fps_colour = [](const int fps) -> glm::vec4 { + if (fps == 0) { + return {1.0f, 1.0f, 1.0f, 1.0f}; + } else if (fps < 30) { + return {1.0f, 0.0f, 0.0f, 1.0f}; + } else if (fps < 60) { + return {1.0f, 0.5f, 0.0f, 1.0f}; + } else if (fps < 120) { + return {0.0f, 1.0f, 0.0f, 1.0f}; + } + return {0.0f, 1.0f, 1.0f, 1.0f}; + }; + + const int fps = client::render::get_fps(); + const std::string fps_str = fps != 0 ? std::to_string(fps) : "~"; + draw_text("FPS: " + fps_str, {.pos = relative_arg{.offset = {0.0f, 2.0f}}, + .extent_height = 0.0165f, + .colour = get_fps_colour(fps), + .has_backing = true}); +} + +// Player position, version, fps etc +// Just don't read past this point, doing this is unbelievably ugly. +// I don't know why I write this like someone else will read it. +static void draw_overlay(const shared::player& lp) noexcept { + draw_state_info(lp); + draw_fps(); +} + +static void draw_main_pass(const shared::player& localplayer, + client::players& players, + client::world::chunk::map& chunks) noexcept { + for (auto& chunk : chunks) { + if (!chunk.second.has_value()) { + continue; + } + chunk.second->draw(chunks, localplayer, + client::world::chunk::pass::solid); + } + + // Draw players while ignoring the localplayer, which is always 0'th! + // This also handles drawing messages. + for (auto i = 1u; i < std::size(players); ++i) { + players[i].draw_playermodel(localplayer); + } +} + +static void draw_water_pass(const shared::player& localplayer, + client::world::chunk::map& chunks) noexcept { + for (auto& chunk : chunks) { + if (!chunk.second.has_value()) { + continue; + } + chunk.second->draw(chunks, localplayer, + client::world::chunk::pass::water); + } +} + +static void draw_wts_text(const shared::player& localplayer, + client::players& players) noexcept { + for (auto i = 1u; i < std::size(players); ++i) { + players[i].draw_message(localplayer); + } +} + +static void draw_hud(const client::player& localplayer, + const client::world::chunk::map& chunks) noexcept { + if (client::input::is_key_toggled(SDLK_F3)) { + draw_overlay(localplayer); + } + + if (const auto& msg = localplayer.get_message(); msg.has_value()) { + if (msg->receive_time + player::MSG_SHOW_TIME >= + std::chrono::steady_clock::now()) { + draw_text(msg->text, {.pos = relative_arg{.extent = {0.5f, 0.0f}, + .offset = {0.0f, 2.0f}}, + .extent_height = 0.0165f, + .colour = {1.0f, 1.0f, 1.0f, 1.0f}, + .has_backing = true, + .is_centered = true}); + } + } + + if (client::window::is_open()) { + return; + } + + // crosshair + client::draw::draw_rectangle( + {.pos = {.extent = {0.5f, 0.5f}, .offset = {-3.0f, -3.0f}}, + .size = {.offset = {6.0f, 6.0f}}, + .colour = {1.0f, 1.0f, 1.0f, 1.0f}}); + + // Draw the outline of the block we're aiming at. + if (const auto interact = client::movement::interact( + localplayer, movement::interact_mode::remove, chunks); + interact.has_value()) { + + const auto [world_x, world_z] = [&]() -> std::pair { + const float offset_x = + static_cast(interact->first.x - localplayer.chunk_pos.x); + const float offset_z = + static_cast(interact->first.z - localplayer.chunk_pos.z); + return {offset_x * shared::world::chunk::WIDTH, + offset_z * shared::world::chunk::WIDTH}; + }(); + + const glm::vec3 render_pos = { + world_x + static_cast(interact->second.x), + interact->second.y, + world_z + static_cast(interact->second.z)}; + + client::render::render_cube_outline(render_pos + 0.5f, + {0.8f, 0.8f, 0.8f, 1.0f}); + } +} + +static void update_camera(const shared::player& localplayer) noexcept { + // approximately encompasses everything we could possibly see + + // if our zfar is too low, our fog breaks + // bit of maths for calculating the max distance we could can see + client::render::camera::get_zfar() = std::hypot( + static_cast(world::chunk::HEIGHT), + float(client::state.draw_distance) * std::hypot(16.0f, 16.0f)); + client::render::camera::get_pos() = + localplayer.local_pos + + glm::vec3{0.0f, shared::player::EYE_HEIGHT, 0.0f}; + client::render::camera::get_front() = + shared::math::angle_to_dir(localplayer.viewangles); + client::render::camera::update(); +} + +// We create framebuffer here to enable postprocessing and solve some +// rendering problems. +static void draw_buffers(const shared::player& localplayer, + client::players& players, + client::world::chunk::map& chunks) noexcept { + const auto make_vbo = [](const auto& vertices) -> GLuint { + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), std::data(vertices), + GL_STATIC_DRAW); + return vbo; + }; + const auto make_vao = []() -> GLuint { + GLuint vao = 0; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // position + glVertexAttribPointer(0, sizeof(glm::vec2) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(glm::vec2), nullptr); + glEnableVertexAttribArray(0); + return vao; + }; + const auto make_ebo = [](const auto& indices) -> GLuint { + GLuint ebo = 0; + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, + GL_STATIC_DRAW); + return ebo; + }; + const auto make_fbo = []() -> GLuint { + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + return fbo; + }; + const auto make_texture = [](const auto& internal_format, + const auto& format, + const int texture_offset) -> GLuint { + GLuint texture; + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE2 + texture_offset); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + + const glm::vec2& window = client::render::get_window_size(); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, window.x, window.y, 0, + internal_format, GL_UNSIGNED_BYTE, nullptr); + glFramebufferTexture2D(GL_FRAMEBUFFER, format, GL_TEXTURE_2D, texture, + 0); + return texture; + }; + + static constexpr std::array vertices = { + glm::vec2{-1.0f, -1.0f}, glm::vec2{1.0f, -1.0f}, glm::vec2{1.0f, 1.0f}, + glm::vec2{-1.0f, 1.0f}}; + static constexpr std::array indices = {0, 1, 2, 2, 3, 0}; + static const client::render::program framebuffer_program{ + "res/shaders/framebuffer.vs", "res/shaders/framebuffer.fs"}; + static const GLuint vbo [[maybe_unused]] = make_vbo(vertices); + static const GLuint vao = make_vao(); + static const GLuint ebo [[maybe_unused]] = make_ebo(indices); + // Main frame buffer object. + static const GLuint fbo_main = make_fbo(); + static const GLuint main_colour [[maybe_unused]] = + make_texture(GL_RGB, GL_COLOR_ATTACHMENT0, 0); + static const GLuint main_depth [[maybe_unused]] = + make_texture(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT, 1); + // Water frame buffer object. + static const GLuint fbo_water = make_fbo(); + static const GLuint water_colour [[maybe_unused]] = + make_texture(GL_RGB, GL_COLOR_ATTACHMENT0, 2); + static const GLuint water_depth [[maybe_unused]] = + make_texture(GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT, 3); + static const GLint u_is_underwater = + glGetUniformLocation(framebuffer_program, "_u_is_underwater"); + + // We render our main scene on the main framebuffer. + glBindFramebuffer(GL_FRAMEBUFFER, fbo_main); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + draw_main_pass(localplayer, players, chunks); + + // We render our water scene on the water framebuffer. + glBindFramebuffer(GL_FRAMEBUFFER, fbo_water); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + const bool is_underwater = [&]() -> bool { + const glm::ivec3 pos{client::render::camera::get_pos()}; + + const auto find_it = chunks.find(localplayer.chunk_pos); + if (find_it == std::end(chunks) || !find_it->second.has_value()) { + return false; + } + if (shared::world::chunk::is_outside_chunk(pos)) { + return false; + } + + const auto block = find_it->second->get_block(pos); + return block.type == shared::world::block::type::water; + }(); + if (is_underwater) { + glFrontFace(GL_CW); + draw_water_pass(localplayer, chunks); + glFrontFace(GL_CCW); + } else { + draw_water_pass(localplayer, chunks); + } + + glBindFramebuffer(GL_FRAMEBUFFER, main_colour); + glDisable(GL_DEPTH_TEST); + glUseProgram(framebuffer_program); + glBindVertexArray(vao); + + glUniform1i(u_is_underwater, is_underwater); + + glDrawElements(GL_TRIANGLES, std::size(indices), GL_UNSIGNED_INT, nullptr); + + static client::render::program postprocess_program{ + "res/shaders/framebuffer.vs", "res/shaders/postprocess.fs"}; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glUseProgram(postprocess_program); + glDrawElements(GL_TRIANGLES, std::size(indices), GL_UNSIGNED_INT, nullptr); + + glEnable(GL_DEPTH_TEST); +} + +void draw(client::players& players, + client::world::chunk::map& chunks) noexcept { + const auto& localplayer = client::get_localplayer(players); + + update_camera(localplayer); + client::render::update_uniforms(); + + draw_buffers(localplayer, players, chunks); + draw_hud(localplayer, chunks); + draw_wts_text(localplayer, players); + + client::window::draw(); + + client::render::swap_window(); +} + +} // namespace draw +} // namespace client diff --git a/src/client/draw.hh b/src/client/draw.hh new file mode 100644 index 0000000..821d67b --- /dev/null +++ b/src/client/draw.hh @@ -0,0 +1,59 @@ +#ifndef CLIENT_DRAW_HH_ +#define CLIENT_DRAW_HH_ + +#include + +#include + +#include "client/movement.hh" +#include "client/player.hh" +#include "client/render/camera.hh" +#include "client/render/render.hh" +#include "client/render/program.hh" +#include "client/shared.hh" +#include "client/window.hh" +#include "client/world.hh" + +namespace client { +namespace draw { + +// Scale takes the range [0, 1] and represents an amount of the screen. +// Offset is any value that is added after scale. +struct relative_arg { + glm::vec2 extent; + glm::vec2 offset; + + glm::vec2 to_vec2() const noexcept { + const glm::vec2& window = render::get_window_size(); + const float x = this->extent.x * window.x + this->offset.x; + const float y = this->extent.y * window.y + this->offset.y; + return {x, y}; + } +}; + +struct rectangle_args { + relative_arg pos; + relative_arg size; + glm::vec4 colour; +}; + +struct text_args { + relative_arg pos; + float extent_height; // we don't get width here, + float offset_height; + glm::vec4 colour; + bool has_backing; + bool is_centered; + bool is_vcentered; +}; + +void draw_rectangle(const rectangle_args& args) noexcept; +void draw_colour(const glm::vec4& colour) noexcept; +void draw_text(const std::string_view text, const text_args& args) noexcept; + +void draw(client::players& players, client::world::chunk::map& chunks) noexcept; + +} // namespace draw +} // namespace client + +#endif diff --git a/src/client/input.cc b/src/client/input.cc new file mode 100644 index 0000000..4a16a9e --- /dev/null +++ b/src/client/input.cc @@ -0,0 +1,111 @@ +#include "client/input.hh" + +namespace { +std::vector event_callbacks; + +struct keystate { + bool pressed; + bool toggled; // !'ed each keypress. +}; +std::unordered_map keystates; +} // namespace + +namespace client { +namespace input { + +void set_mouse_position(const glm::ivec2& d) noexcept { + SDL_WarpMouseInWindow(client::render::get_sdl_window(), d.x, d.y); +} + +void set_text_input(const bool should_start) noexcept { + if (should_start) { + SDL_StartTextInput(); + } else { + SDL_StopTextInput(); + state.text_input.clear(); + } + state.typing = should_start; +} + +void set_mouse_relative(const bool b) noexcept { + if (const int status = SDL_SetRelativeMouseMode(b ? SDL_TRUE : SDL_FALSE); + status != 0) { + + throw std::runtime_error(SDL_GetError()); + } +} + +static void handle_press(const SDL_Event& event) noexcept { + keystate& ks = ::keystates[event.key.keysym.sym]; + + ks.pressed = true; + if (!event.key.repeat) { + ks.toggled = !ks.toggled; + } +} + +static void handle_lift(const SDL_Event& event) noexcept { + keystate& ks = ::keystates[event.key.keysym.sym]; + ks.pressed = false; +} + +static void handle_windowevent(const SDL_Event& event) noexcept { + switch (event.window.event) { + case SDL_WINDOWEVENT_FOCUS_GAINED: + state.focused = true; + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + state.focused = false; + break; + } +} + +static void handle_textinput(const SDL_Event& event) noexcept { + state.text_input += event.text.text; +} + +static void handle_quit(const SDL_Event&) noexcept { state.quit = true; } + +bool is_key_pressed(const SDL_Keycode& key) noexcept { + return ::keystates[key].pressed; +} + +bool is_key_toggled(const SDL_Keycode& key) noexcept { + return ::keystates[key].toggled; +} + +void register_event_handler(const event_callback& ec) noexcept { + ::event_callbacks.push_back(ec); +} + +// definition of a fun function (not as fun anymore) +void update() noexcept { + SDL_Event event; + while (SDL_PollEvent(&event)) { + + switch (event.type) { + case SDL_WINDOWEVENT: + handle_windowevent(event); + break; + case SDL_TEXTINPUT: + handle_textinput(event); + break; + case SDL_QUIT: + handle_quit(event); + break; + case SDL_KEYDOWN: + handle_press(event); + break; + case SDL_KEYUP: + handle_lift(event); + break; + } + + for (auto& callback : ::event_callbacks) { + callback(event); + } + } +} + +} // namespace input +} // namespace client diff --git a/src/client/input.hh b/src/client/input.hh new file mode 100644 index 0000000..d5287a7 --- /dev/null +++ b/src/client/input.hh @@ -0,0 +1,48 @@ +#ifndef CLIENT_INPUT_HH_ +#define CLIENT_INPUT_HH_ + +#include +#include +#include +#include + +#include +#include + +#include "client/render/render.hh" + +namespace client { + +namespace input { + +// Called on every event during update, supports multiple handlers. +// using event_callback = void (*)(const SDL_Event&); +using event_callback = std::function; +void register_event_handler(const event_callback&) noexcept; + +// Empties our event queue while updating our inlines - also calls our +// registered callback functions per event. +void update() noexcept; + +void set_text_input(const bool should_start) noexcept; +void set_mouse_relative(const bool is_relative) noexcept; +void set_mouse_position(const glm::ivec2& d) noexcept; + +bool is_key_pressed(const SDL_Keycode& key) noexcept; +bool is_key_toggled(const SDL_Keycode& key) noexcept; + +struct state { + std::string text_input; + bool quit; + bool focused = true; + bool typing; + glm::vec2 mouse_pos; +}; + +inline state state; + +} // namespace input + +} // namespace client + +#endif diff --git a/src/client/math.cc b/src/client/math.cc new file mode 100644 index 0000000..01fc68b --- /dev/null +++ b/src/client/math.cc @@ -0,0 +1,26 @@ +#include "client/math.hh" + +namespace client { +namespace math { + +std::optional world_to_screen(const glm::vec3& pos, + const glm::mat4& m, + const glm::vec2& window) noexcept { + // clang-format off + const float w = m[0][3] * pos.x + m[1][3] * pos.y + m[2][3] * pos.z + m[3][3]; + + if (w < 0.0f) { + return std::nullopt; + } + + const float inv_w = std::fabs(1.0f / w); + + const float x = window.x * 0.5f + (0.5f * (m[0][0] * pos.x + m[1][0] * pos.y + m[2][0] * pos.z + m[3][0]) * inv_w * window.x + 0.5f); + const float y = window.y * 0.5f + (0.5f * (m[0][1] * pos.x + m[1][1] * pos.y + m[2][1] * pos.z + m[3][1]) * inv_w * window.y + 0.5f); + // clang-format on + + return glm::vec2{x, y}; +} + +} // namespace math +} // namespace client diff --git a/src/client/math.hh b/src/client/math.hh new file mode 100644 index 0000000..da89d25 --- /dev/null +++ b/src/client/math.hh @@ -0,0 +1,22 @@ +#ifndef CLIENT_MATH_HH_ +#define CLIENT_MATH_HH_ + +#include + +#include + +#include "client/render/camera.hh" + +namespace client { +namespace math { + +std::optional world_to_screen( + const glm::vec3& pos, + const glm::mat4& matrix = client::render::camera::get_proj() * + client::render::camera::get_view(), + const glm::vec2& window = client::render::get_window_size()) noexcept; + +} // namespace math +} // namespace client + +#endif diff --git a/src/client/movement.cc b/src/client/movement.cc new file mode 100644 index 0000000..e5898eb --- /dev/null +++ b/src/client/movement.cc @@ -0,0 +1,165 @@ +#include "client/movement.hh" + +namespace client { +namespace movement { + +static std::optional +maybe_get_block(const shared::math::coords& pos, + const client::world::chunk::map& chunks, + const glm::ivec3& block_pos) noexcept { + const auto find_it = chunks.find(pos); + + if (find_it == std::end(chunks)) { + return std::nullopt; + } + + if (!find_it->second.has_value()) { + return std::nullopt; + } + + return find_it->second->get_block(block_pos); +} + +static std::optional> +make_blockinfos(const shared::player& player, + const client::world::chunk::map& chunks, const int width, + const int height) noexcept { + + std::vector blockinfos; + + for (int x = -width; x <= width; ++x) { + for (int y = -height; y <= height; ++y) { + for (int z = -width; z <= width; ++z) { + + const glm::ivec3 rel_pos = + glm::ivec3{x, y, z} + glm::ivec3{player.local_pos}; + + if (rel_pos.y < 0 || + rel_pos.y >= shared::world::chunk::HEIGHT) { + continue; + } + + const shared::math::coords norm_chunk_pos = + shared::world::chunk::get_normalised_chunk( + player.chunk_pos, rel_pos.x, rel_pos.z); + const glm::ivec3 norm_pos = + shared::world::chunk::get_normalised_coords(rel_pos); + + const auto block = + maybe_get_block(norm_chunk_pos, chunks, norm_pos); + + if (!block.has_value()) { + return std::nullopt; + } + + const glm::vec3 pos = glm::vec3{rel_pos} - player.local_pos; + + const shared::movement::aabb aabb = { + .min = glm::vec3{0.0f, 0.0f, 0.0f} + pos, + .max = glm::vec3{1.0f, 1.0f, 1.0f} + pos}; + blockinfos.push_back( + shared::movement::blockinfo{.block = block.value(), + .aabb = aabb, + .chunk_pos = norm_chunk_pos, + .pos = norm_pos}); + } + } + } + + return blockinfos; +} + +void move(shared::player& player, client::world::chunk::map& chunks, + const float deltatime) noexcept { + const auto blockinfos = + make_blockinfos(player, chunks, shared::movement::move_width, + shared::movement::move_height); + if (!blockinfos.has_value()) { + return; + } + + shared::movement::move(player, blockinfos.value(), deltatime); +} + +std::optional> +interact(const shared::player& player, const interact_mode& mode, + const client::world::chunk::map& chunks) noexcept { + const auto blockinfos = make_blockinfos(player, chunks, 5, 5); + if (!blockinfos.has_value()) { + return std::nullopt; + } + + constexpr float epsilon = 0.001f; + constexpr shared::movement::aabb player_aabb = { + .min = {-shared::player::HALFWIDTH + epsilon, 0.0f + epsilon, + -shared::player::HALFWIDTH + epsilon}, + .max = {shared::player::HALFWIDTH - epsilon, + shared::player::HEIGHT - epsilon, + shared::player::HALFWIDTH - epsilon}}; + constexpr shared::movement::aabb ray_aabb = { + .min = {-epsilon, shared::player::EYE_HEIGHT - epsilon, -epsilon}, + .max = {epsilon, shared::player::EYE_HEIGHT + epsilon, epsilon}}; + + const shared::movement::moving_aabb ray_moving_aabb{ + .aabb = ray_aabb, + .velocity = shared::math::angle_to_dir(player.viewangles)}; + + std::optional> + best; + for (const auto& blockinfo : *blockinfos) { + if (blockinfo.block == shared::world::block::type::air) { + continue; + } + if (!shared::world::block::is_removable(blockinfo.block)) { + continue; + } + + const auto intersect = shared::movement::intersect_moving_aabbs( + ray_moving_aabb, + shared::movement::moving_aabb{.aabb = blockinfo.aabb, + .velocity = {0.0f, 0.0f, 0.0f}}); + + constexpr float MAX_REACH = 3.8f; + if (!intersect.has_value() || intersect->time > MAX_REACH) { + continue; + } + if (best.has_value() && intersect->time > best->first.time) { + continue; + } + + best = std::make_pair(*intersect, blockinfo); + } + + if (!best.has_value()) { + return std::nullopt; + } + + const auto& [intersect, blockinfo] = *best; + + const glm::ivec3 position = blockinfo.pos; + if (mode == interact_mode::remove) { + return std::make_pair(blockinfo.chunk_pos, position); + } + + const glm::ivec3 normal_i = -intersect.normal; + const glm::ivec3 normalised_pos = + shared::world::chunk::get_normalised_coords(normal_i + position); + + const auto find_it = + std::find_if(std::begin(*blockinfos), std::end(*blockinfos), + [&](const auto b) { return b.pos == normalised_pos; }); + if (find_it == std::end(*blockinfos)) { + return std::nullopt; + } + if (!shared::world::block::is_replaceable(find_it->block)) { + return std::nullopt; + } + if (shared::movement::intersect_aabbs(player_aabb, find_it->aabb)) { + return std::nullopt; + } + return std::make_pair(find_it->chunk_pos, normalised_pos); +} + +} // namespace movement +} // namespace client diff --git a/src/client/movement.hh b/src/client/movement.hh new file mode 100644 index 0000000..82b56b1 --- /dev/null +++ b/src/client/movement.hh @@ -0,0 +1,23 @@ +#ifndef CLIENT_MOVEMENT_HH_ +#define CLIENT_MOVEMENT_HH_ + +#include "client/world.hh" +#include "shared/movement.hh" +#include "shared/net/net.hh" +#include "shared/player.hh" + +namespace client { +namespace movement { + +void move(shared::player& player, client::world::chunk::map& chunks, + const float deltatime) noexcept; + +enum class interact_mode { add, remove }; +std::optional> +interact(const shared::player& player, const interact_mode& mode, + const client::world::chunk::map& chunks) noexcept; + +} // namespace movement +} // namespace client + +#endif diff --git a/src/client/player.cc b/src/client/player.cc new file mode 100644 index 0000000..5ff4118 --- /dev/null +++ b/src/client/player.cc @@ -0,0 +1,58 @@ +#include "player.hh" + +glm::vec3 client::player::get_world_pos(const shared::player& lp) noexcept { + // clang-format off + const float world_x = static_cast(this->chunk_pos.x - lp.chunk_pos.x) * shared::world::chunk::WIDTH + this->local_pos.x; + const float world_y = static_cast(this->local_pos.y) + shared::player::HEIGHT / 2.0f; + const float world_z = static_cast(this->chunk_pos.z - lp.chunk_pos.z) * shared::world::chunk::WIDTH + this->local_pos.z; + // clang-format on + return {world_x, world_y, world_z}; +} + +void client::player::draw_playermodel( + const shared::player& localplayer) noexcept { + + static client::render::model playermodel{"res/models/player/player.obj"}; + static client::render::program program{"res/shaders/model.vs", + "res/shaders/model.fs"}; + + const glm::vec3 world_pos = this->get_world_pos(localplayer); + const glm::mat4 rotate = glm::rotate(glm::mat4(1.0f), -this->viewangles.yaw, + glm::vec3(0.0f, 1.0f, 0.0f)); + const glm::mat4 translate = glm::translate(glm::mat4(1.0f), world_pos); + const glm::mat4& view = client::render::camera::get_view(); + const glm::mat4& proj = client::render::camera::get_proj(); + + playermodel.draw(program, proj * view * translate * rotate); +} + +void client::player::draw_message(const shared::player& localplayer) noexcept { + // Clear the message if it's too old. + if (this->message.has_value()) { + const auto now = std::chrono::steady_clock::now(); + if (now > this->message->receive_time + player::MSG_SHOW_TIME) { + this->message.reset(); + } + } + + if (!this->message.has_value()) { + return; + } + + const glm::vec3 world_pos = this->get_world_pos(localplayer); + const auto pos = client::math::world_to_screen(world_pos); + + if (!pos.has_value()) { + return; + } + + const glm::vec2& window = client::render::get_window_size(); + const glm::mat4 proj = glm::ortho(0.0f, window.x, 0.0f, window.y); + const glm::mat4 tran = + glm::translate(glm::mat4(1.0f), + glm::vec3{std::floor(pos->x), std::floor(pos->y), 0.0f}); + + constexpr glm::vec4 white{1.0f, 1.0f, 1.0f, 1.0f}; + client::render::render_text(this->message->text, 30.0f, true, true, white, + proj * tran); +} diff --git a/src/client/player.hh b/src/client/player.hh new file mode 100644 index 0000000..c41ba23 --- /dev/null +++ b/src/client/player.hh @@ -0,0 +1,64 @@ +#ifndef CLIENT_PLAYER_HH_ +#define CLIENT_PLAYER_HH_ + +#include +#include +#include +#include + +#include "client/math.hh" +#include "client/render/camera.hh" +#include "client/render/model.hh" +#include "client/render/program.hh" +#include "shared/player.hh" + +namespace client { + +// Renderable player, similar to client::chunk. We also store the message the +// player wants to say. +class player : public shared::player { +public: + static constexpr auto MSG_SHOW_TIME = std::chrono::seconds(15); + struct message { + std::string text; + std::chrono::time_point receive_time; + message(const std::string& message) noexcept { + this->text = message; + this->receive_time = std::chrono::steady_clock::now(); + } + }; + std::optional message; + +private: + glm::vec3 get_world_pos(const shared::player& lp) noexcept; + +public: + player(shared::player&& p) noexcept + : shared::player(std::forward(p)) {} + player(const shared::player& p) noexcept : shared::player(p) {} + + void update(const shared::player& p) noexcept { + this->index = p.index; // there is no syntax for doing this in one line + this->commands = p.commands; + this->chunk_pos = p.chunk_pos; + this->local_pos = p.local_pos; + this->viewangles = p.viewangles; + this->velocity = p.velocity; + } + + void draw_playermodel(const shared::player& localplayer) noexcept; + void draw_message(const shared::player& localplayer) noexcept; + + const std::optional& get_message() const noexcept { + return this->message; + } +}; + +using players = std::vector; +static inline client::player& get_localplayer(players& players) noexcept { + return players[0]; +} + +} // namespace client + +#endif diff --git a/src/client/render/camera.cc b/src/client/render/camera.cc new file mode 100644 index 0000000..1ea4dfb --- /dev/null +++ b/src/client/render/camera.cc @@ -0,0 +1,96 @@ +#include "client/render/camera.hh" + +namespace client { +namespace render { +namespace camera { + +float& get_xfov() noexcept { + static float xfov = 100.0f; + return xfov; +} + +glm::vec3& get_pos() noexcept { + static glm::vec3 pos{0.0f, 0.0f, 0.0f}; + return pos; +} + +glm::vec3& get_front() noexcept { + static glm::vec3 front{0.0f, 0.0f, 0.0f}; + return front; +} + +glm::vec3& get_up() noexcept { + static glm::vec3 front{0.0f, 1.0f, 0.0f}; + return front; +} + +static glm::mat4 make_view() noexcept { + const glm::vec3& pos = get_pos(); + return glm::lookAt(pos, pos + get_front(), get_up()); +} + +glm::mat4& get_view() noexcept { + static glm::mat4 view = make_view(); + return view; +} + +static glm::mat4 make_proj() noexcept { + const glm::vec2& window = client::render::get_window_size(); + return glm::perspective(glm::radians(get_yfov()), window.x / window.y, + get_znear(), get_zfar()); +} + +glm::mat4& get_proj() noexcept { + static glm::mat4 proj = make_proj(); + return proj; +} + +static frustum make_frustum() noexcept { + const glm::mat4 matrix = get_proj() * get_view(); + const glm::vec4 row_x = glm::row(matrix, 0); + const glm::vec4 row_y = glm::row(matrix, 1); + const glm::vec4 row_z = glm::row(matrix, 2); + const glm::vec4 row_w = glm::row(matrix, 3); + + frustum ret{row_w + row_x, row_w - row_x, row_w + row_y, + row_w - row_y, row_w + row_z, row_w - row_z}; + std::ranges::transform(ret, std::begin(ret), [](const auto& matrix) { + return glm::normalize(matrix); + }); + return ret; +} + +frustum& get_frustum() noexcept { + static frustum ret = make_frustum(); + return ret; +} + +float& get_znear() noexcept { + static float znear = 0.1f; + return znear; +} + +float& get_zfar() noexcept { + static float zfar = 1024.0f; + return zfar; +} + +float get_yfov() noexcept { + const glm::vec2& window = client::render::get_window_size(); + const float yfov = + 2.0f * std::atan((window.y / window.x) * + std::tan(glm::radians(get_xfov()) / 2.0f)); + return glm::degrees(yfov); +} + +void update() noexcept { + get_view() = make_view(); // specific order here! + get_proj() = make_proj(); + get_frustum() = make_frustum(); +} + +} // namespace camera + +} // namespace render + +} // namespace client diff --git a/src/client/render/camera.hh b/src/client/render/camera.hh new file mode 100644 index 0000000..018f54f --- /dev/null +++ b/src/client/render/camera.hh @@ -0,0 +1,38 @@ +#ifndef CLIENT_RENDER_CAMERA_HH_ +#define CLIENT_RENDER_CAMERA_HH_ + +#include + +#include +#include +#include + +#include "client/render/render.hh" + +namespace client { +namespace render { +namespace camera { + +// Call update after modifying references to camera objects. +void update() noexcept; + +// modifying +float& get_xfov() noexcept; +glm::vec3& get_pos() noexcept; +glm::vec3& get_front() noexcept; +glm::vec3& get_up() noexcept; +glm::mat4& get_view() noexcept; +glm::mat4& get_proj() noexcept; +using frustum = std::array; +frustum& get_frustum() noexcept; +float& get_znear() noexcept; +float& get_zfar() noexcept; + +// non-modifying +float get_yfov() noexcept; + +} // namespace camera +} // namespace render +} // namespace client + +#endif diff --git a/src/client/render/lib/stb_image/stb_image.cc b/src/client/render/lib/stb_image/stb_image.cc new file mode 100644 index 0000000..baf937a --- /dev/null +++ b/src/client/render/lib/stb_image/stb_image.cc @@ -0,0 +1,2 @@ +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.hh" \ No newline at end of file diff --git a/src/client/render/lib/stb_image/stb_image.hh b/src/client/render/lib/stb_image/stb_image.hh new file mode 100644 index 0000000..41a2fda --- /dev/null +++ b/src/client/render/lib/stb_image/stb_image.hh @@ -0,0 +1,7774 @@ +//#define STBI_ONLY_JPEG +#define STBI_NO_FAILURE_STRINGS +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wsign-compare" +#pragma clang diagnostic ignored "-Wunused" +#pragma clang diagnostic ignored "-Wimplicit-int-conversion" +#pragma clang diagnostic ignored "-Wdouble-promotion" + + +/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko [reserved] + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); + if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (NULL == tmp) { + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + return stbi__errpuc("outofmem", "Out of memory"); + } + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + *delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + +#pragma clang diagnostic pop diff --git a/src/client/render/model.cc b/src/client/render/model.cc new file mode 100644 index 0000000..6a2641b --- /dev/null +++ b/src/client/render/model.cc @@ -0,0 +1 @@ +#include "client/render/model.hh" diff --git a/src/client/render/model.hh b/src/client/render/model.hh new file mode 100644 index 0000000..42d3b0a --- /dev/null +++ b/src/client/render/model.hh @@ -0,0 +1,247 @@ +#ifndef CLIENT_RENDER_MODEL_HH_ +#define CLIENT_RENDER_MODEL_HH_ + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include "client/render/program.hh" +#include "client/render/texture.hh" + +namespace client { +namespace render { + +struct vertex { + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texture; +}; +struct texture_info { + unsigned id; + std::string type; + std::string path; +}; + +class model { +private: + struct mesh { + private: + GLuint vao; + GLuint vbo; + GLuint ebo; + + public: + std::vector vertices; + std::vector indices; + std::vector textures; + + private: + void setup() noexcept { + glGenVertexArrays(1, &this->vao); + glGenBuffers(1, &this->vbo); + glGenBuffers(1, &this->ebo); + + glBindVertexArray(vao); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, + std::size(this->vertices) * sizeof(vertex), + std::data(this->vertices), GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + std::size(this->indices) * sizeof(GLuint), + std::data(this->indices), GL_STATIC_DRAW); + + // The reinterpret casts might be wrong here. + // positions + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), + nullptr); + // normals LMAO + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), + reinterpret_cast(sizeof(glm::vec3))); + // texture + glEnableVertexAttribArray(2); + glVertexAttribPointer( + 2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), + reinterpret_cast(sizeof(glm::vec3) + sizeof(glm::vec3))); + } + + public: + mesh(const std::vector& v, const std::vector& i, + const std::vector& t) noexcept + : vertices(v), indices(i), textures(t) { + setup(); + } + + // Not going to bother with textures yet. + void draw(const client::render::program& program, + const glm::mat4& matrix) const noexcept { + + glUseProgram(program); + static const GLint u_matrix{ + glGetUniformLocation(program, "_u_matrix")}; + glBindVertexArray(this->vao); + + glUniformMatrix4fv(u_matrix, 1, GL_FALSE, glm::value_ptr(matrix)); + + glDrawElements(GL_TRIANGLES, std::size(this->indices), + GL_UNSIGNED_INT, nullptr); + } + }; + +private: + std::vector meshes; + std::string directory; + +private: + unsigned int texture_from_file(const std::string& path, + const std::string& dir) noexcept { + const std::string filename = dir + '/' + path; + + const client::render::texture texture{filename}; + + unsigned int tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, + 0, texture.channels == 3 ? GL_RGB : GL_RGBA, + GL_UNSIGNED_BYTE, texture.image); + glGenerateMipmap(GL_TEXTURE_2D); + + return tex; + } + + std::vector + load_material_textures(const aiMaterial* const material, + const aiTextureType type, + const std::string& name) noexcept { + std::vector textures; + for (unsigned i = 0; i < material->GetTextureCount(type); ++i) { + aiString str; + material->GetTexture(type, i, &str); + + struct texture_info texture; + texture.id = texture_from_file(str.C_Str(), directory); + texture.type = name; + texture.path = str.data; + + textures.push_back(std::move(texture)); + } + return textures; + } + mesh process_mesh(const aiMesh* mesh, const aiScene* scene) noexcept { + std::vector vertices; + std::vector indices; + std::vector textures; + + for (unsigned i = 0; i < mesh->mNumVertices; ++i) { + vertex v; + + glm::vec3 vector; + vector.x = mesh->mVertices[i].x; + vector.y = mesh->mVertices[i].y; + vector.z = mesh->mVertices[i].z; + + v.position = vector; + + vector.x = mesh->mNormals[i].x; + vector.y = mesh->mNormals[i].y; + vector.z = mesh->mNormals[i].z; + + v.normal = vector; + + if (mesh->mTextureCoords[0]) { + glm::vec2 vec; + vec.x = mesh->mTextureCoords[0][i].x; + vec.y = mesh->mTextureCoords[0][i].x; + v.texture = vec; + } else { + v.texture = glm::vec2{0.0f}; + } + + vector.x = mesh->mNormals[i].x; + vector.y = mesh->mNormals[i].y; + vector.z = mesh->mNormals[i].z; + + vertices.push_back(std::move(v)); + } + + for (unsigned i = 0; i < mesh->mNumFaces; ++i) { + aiFace face = mesh->mFaces[i]; + for (unsigned j = 0; j < face.mNumIndices; ++j) { + indices.push_back(face.mIndices[j]); + } + } + + if (mesh->mMaterialIndex >= 0) { + const aiMaterial* const material = + scene->mMaterials[mesh->mMaterialIndex]; + std::ranges::copy(load_material_textures(material, + aiTextureType_DIFFUSE, + "texture_diffuse"), + std::back_inserter(textures)); + std::ranges::copy(load_material_textures(material, + aiTextureType_SPECULAR, + "texture_specular"), + std::back_inserter(textures)); + } + + return {vertices, indices, textures}; + } + void process_node(const aiNode* node, const aiScene* scene) noexcept { + for (unsigned i = 0; i < node->mNumMeshes; ++i) { + const aiMesh* const mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(process_mesh(mesh, scene)); + } + for (unsigned i = 0; i < node->mNumChildren; ++i) { + process_node(node->mChildren[i], scene); + } + } + void load(const std::string& path) noexcept { + Assimp::Importer importer; + + const aiScene* scene = + importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); + if (scene == nullptr || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || + scene->mRootNode == nullptr) { + throw std::runtime_error("assimp error: " + + std::string(importer.GetErrorString())); + } + + directory = path; // AHHHHHHHhh + process_node(scene->mRootNode, scene); + } + +public: + model(const std::string& path) noexcept { load(path); } + void draw(const client::render::program& program, + const glm::mat4& matrix) noexcept { + for (const auto& mesh : meshes) { + mesh.draw(program, matrix); + } + } +}; + +} // namespace render + +} // namespace client + +#endif diff --git a/src/client/render/program.cc b/src/client/render/program.cc new file mode 100644 index 0000000..d658b68 --- /dev/null +++ b/src/client/render/program.cc @@ -0,0 +1,55 @@ +#include "client/render/program.hh" + +namespace client { +namespace render { + +static void check_shader(const GLuint shader) { + int status = 0; + char info[512]; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader, 512, nullptr, info); + throw std::runtime_error(std::string("failed to compile shader: ") + + info); + } +} + +static void check_program(const GLuint program) { + int status = 0; + char info[512]; + glGetProgramiv(program, GL_LINK_STATUS, &status); + + if (!status) { + glGetProgramInfoLog(program, 512, nullptr, info); + throw std::runtime_error(std::string("failed to link program: ") + + info); + } +} + +program::program(const std::string_view vpath, const std::string_view fpath) { + const auto make_shader = [](const auto& path, const auto type) -> GLuint { + const std::string source = shared::read_file(path.data()); + const char* const src_ptr = source.c_str(); + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src_ptr, nullptr); + glCompileShader(shader); + check_shader(shader); + return shader; + }; + + GLuint vertex = make_shader(vpath, GL_VERTEX_SHADER); + GLuint fragment = make_shader(fpath, GL_FRAGMENT_SHADER); + + this->index = glCreateProgram(); + glAttachShader(this->index, vertex); + glAttachShader(this->index, fragment); + glLinkProgram(this->index); + check_program(this->index); + + glDeleteShader(vertex); + glDeleteShader(fragment); +} + +} // namespace render +} // namespace client diff --git a/src/client/render/program.hh b/src/client/render/program.hh new file mode 100644 index 0000000..10ae19c --- /dev/null +++ b/src/client/render/program.hh @@ -0,0 +1,29 @@ +#ifndef CLIENT_RENDER_PROGRAM_HH_ +#define CLIENT_RENDER_PROGRAM_HH_ + +#include +#include + +#include + +#include "shared/shared.hh" + +namespace client { +namespace render { + +class program { +private: + GLuint index; + +public: + program(const std::string_view vpath, const std::string_view fpath); + program(const program&) = delete; + program(program&&) = delete; + + operator unsigned int() const noexcept { return this->index; }; +}; + +} // namespace render +} // namespace client + +#endif diff --git a/src/client/render/render.cc b/src/client/render/render.cc new file mode 100644 index 0000000..18aa32a --- /dev/null +++ b/src/client/render/render.cc @@ -0,0 +1,602 @@ +#include "render.hh" + +namespace client { +namespace render { + +static void check_sdl_call(const auto& sdl_call) { + if (sdl_call()) { + throw std::runtime_error{SDL_GetError()}; + } +} + +static void check_sdl_pointer(const void* const ptr) { + if (ptr == nullptr) { + throw std::runtime_error{SDL_GetError()}; + } +} + +SDL_Window* const& get_sdl_window() noexcept { + static SDL_Window* const window = []() -> SDL_Window* { + check_sdl_call(std::bind(SDL_Init, SDL_INIT_VIDEO)); + check_sdl_call(std::bind(SDL_GL_SetAttribute, + SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_CORE)); + check_sdl_call( + std::bind(SDL_GL_SetAttribute, SDL_GL_CONTEXT_MAJOR_VERSION, 4)); + check_sdl_call( + std::bind(SDL_GL_SetAttribute, SDL_GL_CONTEXT_MINOR_VERSION, 2)); + + SDL_Window* const ret = + SDL_CreateWindow("blockgame_linux", 0, 0, 0, 0, + SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP | + SDL_WINDOW_BORDERLESS); + check_sdl_pointer(ret); + return ret; + }(); + return window; +} + +static SDL_GLContext& get_sdl_glcontext() noexcept { + static SDL_GLContext context = []() -> SDL_GLContext { + const SDL_GLContext ret = SDL_GL_CreateContext(get_sdl_window()); + check_sdl_pointer(ret); + check_sdl_call(std::bind(SDL_GL_SetSwapInterval, 0)); + check_sdl_call(std::bind(SDL_SetRelativeMouseMode, SDL_TRUE)); + + // Default gl attributes. + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glEnable(GL_BLEND); + glEnable(GL_DEBUG_OUTPUT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDebugMessageCallback( + [](GLenum, GLenum, GLuint, GLenum severity, GLsizei, + const GLchar* message, const void*) { + if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) { + return; + } + throw std::runtime_error{std::string{"gl severe error: "} + + message}; + }, + nullptr); + + glClear(GL_COLOR_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT); // anti ub first frame + return ret; + }(); + return context; +} + +// When we support window resizing, just make this non const etc. +const glm::ivec2& get_window_size() noexcept { + static glm::ivec2 window_size = []() -> glm::ivec2 { + int width, height; + SDL_GetWindowSize(get_sdl_window(), &width, &height); + return {width, height}; + }(); + return window_size; +} + +static int& get_framecount() noexcept { + static int framecount = 0; + return framecount; +} + +int get_fps() noexcept { + constexpr auto rate = std::chrono::milliseconds(500); // rate of updates + + static auto prev = std::chrono::steady_clock::now(); + static int fps = []() { + get_framecount() = 0; // so we don't report absurdly high numbers @ init + return 0; + }(); + + if (const auto now = std::chrono::steady_clock::now(); now >= prev + rate) { + const auto ms_elapsed = (now - prev) / std::chrono::milliseconds(1); + + int& framecount = get_framecount(); + fps = int(float(framecount) * (1000.0f / float(ms_elapsed))); + framecount = 0; + + prev = now; + } + return fps; +} + +void init() { + // Creates the glcontext, traverses the tree of sdl calls required for our + // window to initialise. + get_sdl_glcontext(); +} + +void quit() noexcept { + // Epoxy doesn't like this, so we're commenting it out for now. + /* + SDL_GL_DeleteContext(get_sdl_glcontext()); + SDL_DestroyWindow(get_sdl_window()); + SDL_Quit(); + */ +} + +void swap_window() noexcept { + SDL_GL_SwapWindow(get_sdl_window()); + ++get_framecount(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void render_cube_outline(const glm::vec3& pos, + const glm::vec4& colour) noexcept { + const auto generate_vbo = [](const auto& vertices) -> GLuint { + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), std::data(vertices), + GL_STATIC_DRAW); + return vbo; + }; + const auto generate_vao = []() -> GLuint { + GLuint vao = 0; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // position + glVertexAttribPointer(0, sizeof(glm::vec3) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(glm::vec3), nullptr); + glEnableVertexAttribArray(0); + return vao; + }; + const auto generate_ebo = [](const auto& indices) -> GLuint { + GLuint ebo = 0; + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, + GL_STATIC_DRAW); + return ebo; + }; + const auto make_matrix = [&]() -> glm::mat4 { + constexpr auto identity = glm::mat4(1.0f); + const auto proj = camera::get_proj(); + const auto trans = glm::translate(identity, pos); + const auto& view = camera::get_view(); + return proj * view * trans; + }; + + static constexpr std::array vertices = { + glm::vec3{-0.5f, -0.5f, -0.5f}, glm::vec3{0.5f, -0.5f, -0.5f}, + glm::vec3{-0.5f, -0.5f, 0.5f}, glm::vec3{0.5f, -0.5f, 0.5f}, + glm::vec3{-0.5f, 0.5f, -0.5f}, glm::vec3{0.5f, 0.5f, -0.5f}, + glm::vec3{-0.5f, 0.5f, 0.5f}, glm::vec3{0.5f, 0.5f, 0.5f}}; + static constexpr std::array indices = { + 0, 1, 0, 2, 0, 4, 6, 4, 6, 7, 6, 2, 5, 4, 5, 1, 5, 7, 3, 2, 3, 1, 3, 7}; + static const program program{"res/shaders/line.vs", "res/shaders/line.fs"}; + static const GLuint vbo [[maybe_unused]] = generate_vbo(vertices); + static const GLuint vao = generate_vao(); + static const GLuint ebo [[maybe_unused]] = generate_ebo(indices); + static const GLint u_colour = glGetUniformLocation(program, "_u_colour"); + static const GLint u_matrix = glGetUniformLocation(program, "_u_matrix"); + + glEnable(GL_BLEND); + glUseProgram(program); + glBindVertexArray(vao); + + glUniform4fv(u_colour, 1, glm::value_ptr(colour)); + glUniformMatrix4fv(u_matrix, 1, GL_FALSE, glm::value_ptr(make_matrix())); + + glDrawElements(GL_LINES, std::size(indices), GL_UNSIGNED_INT, nullptr); +} + +void render_rectangle(const glm::vec2& pos, const glm::vec2& size, + const glm::vec4& colour) noexcept { + const auto generate_vbo = [](const auto& vertices) -> GLuint { + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), std::data(vertices), + GL_STATIC_DRAW); + return vbo; + }; + const auto generate_vao = []() -> GLuint { + GLuint vao = 0; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // position + glVertexAttribPointer(0, sizeof(glm::vec2) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(glm::vec2), nullptr); + glEnableVertexAttribArray(0); + return vao; + }; + const auto generate_ebo = [](const auto& indices) -> GLuint { + GLuint ebo = 0; + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, + GL_STATIC_DRAW); + return ebo; + }; + const auto make_matrix = [&]() -> glm::mat4 { + constexpr auto identity = glm::mat4(1.0f); + const glm::vec2& window_size = get_window_size(); + const auto proj = glm::ortho(0.f, window_size.x, 0.f, window_size.y); + const auto scale = + glm::scale(identity, glm::vec3(size.x, size.y, 0.0f)); + const auto trans = + glm::translate(identity, glm::vec3(pos.x, pos.y, 0.0f)); + return proj * trans * scale; + }; + + static constexpr std::array vertices = { + glm::vec2{-0.5f, -0.5f}, glm::vec2{0.5f, -0.5f}, glm::vec2{0.5f, 0.5f}, + glm::vec2{-0.5f, 0.5f}}; + static constexpr std::array indices = {0, 1, 2, 2, 3, 0}; + static const program program{"res/shaders/rectangle.vs", + "res/shaders/rectangle.fs"}; + static const GLuint vbo [[maybe_unused]] = generate_vbo(vertices); + static const GLuint vao = generate_vao(); + static const GLuint ebo [[maybe_unused]] = generate_ebo(indices); + static const GLint u_colour = glGetUniformLocation(program, "_u_colour"); + static const GLint u_matrix = glGetUniformLocation(program, "_u_matrix"); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glUseProgram(program); + glBindVertexArray(vao); + + glUniform4fv(u_colour, 1, glm::value_ptr(colour)); + glUniformMatrix4fv(u_matrix, 1, GL_FALSE, glm::value_ptr(make_matrix())); + + glDrawElements(GL_TRIANGLES, std::size(indices), GL_UNSIGNED_INT, nullptr); +} + +// http://blog.wolfire.com/2013/03/High-quality-text-rendering +// When rendering our fonts, despite what usually occurs in graphics, +// downscaling will result in a decrease in visual quality (even if by a small +// margin). If we want nice looking fonts, we must NEVER scale it - meaning if +// we want a change in size, we will have to generate a new font atlas each time +// with a different size. In addition, we are limited only to rendering at +// integers. + +// This class solves this problem by lazily loading characters when necessary, +// so we can avoid the runtime penalty of generating a couple thousand chars +// in our atlas every time we request a new size. +class font_atlas { +public: + struct character_info { + float advance_x; + float advance_y; + float bitmap_width; + float bitmap_height; + float bitmap_left; + float bitmap_top; + float x_offset; // offset in texture atlas. + float y_offset; + }; + struct texture_info { + GLuint texture; + GLint width; // max width of a row in our atlas + GLint height; + unsigned cur_max_glyph_height; // max height of a row in our atlas + glm::ivec2 last_offset; // where to upload next + + operator GLuint() const noexcept { return this->texture; } + }; + +private: + static constexpr const /*CPP SUCKS*/ char* const font_dir = + "res/fonts/NotoSansMono-SemiBold.ttf"; + static constexpr auto flags = + 0u; // FT_LOAD_TARGET_LIGHT | FT_LOAD_FORCE_AUTOHINT; + + unsigned font_size; + texture_info texture; + std::unordered_map characters; + +private: + static FT_Library get_ft_library() noexcept { + static FT_Library library = []() -> FT_Library { + FT_Library library; + if (FT_Init_FreeType(&library)) { + throw std::runtime_error("failed to init freetype2"); + } + return library; + }(); + return library; + } + static GLint get_row_size() noexcept { + static const GLint row_size = []() -> GLint { + GLint row_size; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &row_size); + return row_size; + }(); + return row_size; + } + // This will set cur_max_glyph_height to size and our last_offset to {0, 0} + // so it may be necessary to set them manually. + static struct texture_info make_texture_info(const unsigned size) noexcept { + GLuint texture; + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + + // Allocate a big strip so that we do not frequently reallocate. + const GLint row_size = get_row_size(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, row_size, size, 0, GL_ALPHA, + GL_UNSIGNED_BYTE, nullptr); + + return {.texture = texture, + .width = row_size, + .height = static_cast(size), + .cur_max_glyph_height = size, + .last_offset = {0, 0}}; + } + +private: + // Occasionally we will fill the texture atlas too much. This may occur if + // we stuff too many characters in and we run out of x, or if a glyph just + // happens to be bigger on the y than any other glyph we have inserted. + // We must allocate a new texture with the appropriate dimensions that + // accomodates for this new glyph while copying over our atlas's previous + // contents. + void prepare_texture_info(const glm::ivec2 glyph) noexcept { + const bool over_x = + this->texture.last_offset.x + glyph.x > this->texture.width; + const bool over_y = + this->texture.last_offset.y + glyph.y > this->texture.height; + + this->texture.cur_max_glyph_height = std::max( + this->texture.cur_max_glyph_height, static_cast(glyph.y)); + + if (!over_x && !over_y) { + return; + } + + const struct texture_info old = this->texture; + if (over_x) { + this->texture = make_texture_info( + static_cast(old.height) + old.cur_max_glyph_height); + this->texture.last_offset = {0.0f, old.last_offset.y + old.height}; + } else if (over_y) { + this->texture = make_texture_info(old.cur_max_glyph_height); + this->texture.last_offset = old.last_offset; + } + this->texture.cur_max_glyph_height = old.cur_max_glyph_height; + glCopyImageSubData(old.texture, GL_TEXTURE_2D, 0, 0, 0, 0, + this->texture, GL_TEXTURE_2D, 0, 0, 0, 0, old.width, + old.height, 1); + + glDeleteTextures(1, &old.texture); + } + + struct character_info make_character_info(const char c) noexcept { + const FT_Library library = this->get_ft_library(); + + FT_Face face; + if (FT_New_Face(library, font_dir, 0, &face)) { + throw std::runtime_error("failed to load font"); + } + + FT_Set_Pixel_Sizes(face, 0, this->font_size); + if (FT_Load_Char(face, static_cast(c), + flags | FT_LOAD_RENDER)) { + return this->operator[]('?'); // placeholder + } + + const int width = static_cast(face->glyph->bitmap.width); + const int height = static_cast(face->glyph->bitmap.rows); + + this->prepare_texture_info(glm::ivec2{width, height}); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, this->texture.texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, this->texture.last_offset.x, + this->texture.last_offset.y, width, height, GL_RED, + GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer); + + character_info character_info = { + .advance_x = static_cast(face->glyph->advance.x >> 6), + .advance_y = static_cast(face->glyph->advance.y >> 6), + .bitmap_width = static_cast(face->glyph->bitmap.width), + .bitmap_height = static_cast(face->glyph->bitmap.rows), + .bitmap_left = static_cast(face->glyph->bitmap_left), + .bitmap_top = static_cast(face->glyph->bitmap_top), + .x_offset = static_cast(this->texture.last_offset.x), + .y_offset = static_cast(this->texture.last_offset.y)}; + + this->texture.last_offset.x += width; + + FT_Done_Face(face); + return character_info; + } + +public: + // Use this operator to get specific chars. + const struct character_info& operator[](const char c) noexcept { + if (const auto find_it = this->characters.find(c); + find_it != std::end(this->characters)) { + + return find_it->second; + } + + const auto emplace = + this->characters.emplace(c, make_character_info(c)); + + return emplace.first->second; + } + + font_atlas(const unsigned size) noexcept + : font_size(size), texture(make_texture_info(size)) {} + ~font_atlas() noexcept { glDeleteTextures(1, &this->texture.texture); } + + GLint get_height() const noexcept { return this->texture.height; } + GLint get_width() const noexcept { return this->texture.width; } + unsigned get_glyph_height() const noexcept { + return this->texture.cur_max_glyph_height; + } + GLuint get_texture() const noexcept { return this->texture; } +}; + +void render_text(const std::string_view text, const unsigned int size, + const bool is_centered, const bool is_vcentered, + const glm::vec4& colour, const glm::mat4& matrix) noexcept { + const auto generate_vao = []() -> GLuint { + GLuint vao = 0; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + return vao; + }; + struct vertex { + glm::vec2 pos; + glm::vec2 tex; + }; + const auto generate_vbo = []() -> GLuint { + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 5, nullptr, + GL_DYNAMIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, sizeof(glm::vec2) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(vertex), 0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, sizeof(glm::vec2) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(vertex), + reinterpret_cast(sizeof(glm::vec2))); + return vbo; + }; + static const program program("res/shaders/text.vs", "res/shaders/text.fs"); + static const GLuint vao = generate_vao(); + static const GLuint vbo = generate_vbo(); + static const GLint u_matrix = glGetUniformLocation(program, "_u_matrix"); + static const GLint u_colour = glGetUniformLocation(program, "_u_colour"); + static std::unordered_map font_atlases; + + // Find or generate a font atlas in our unordered_map. + font_atlas& atlas = [&]() -> font_atlas& { + if (const auto find_it = font_atlases.find(size); + find_it != std::end(font_atlases)) { + + return find_it->second; + } + + const auto emplace = + font_atlases.emplace(std::pair(size, size)); + return emplace.first->second; + }(); + + const std::vector vertices = [&]() { + std::vector vertices; + + const float atlas_width = static_cast(atlas.get_width()); + const float atlas_height = static_cast(atlas.get_height()); + float total_width = 0.0f; + glm::vec3 pos{0.0f}; + for (const auto& c : text) { + const auto& character = atlas[c]; + + const float w = character.bitmap_width; + const float h = character.bitmap_height; + const float x = pos.x + character.bitmap_left; + const float y = -pos.y - (character.bitmap_top); + + pos.x += character.advance_x; + pos.y += character.advance_y; + + total_width += character.advance_x; + + if (w == 0.0f || h == 0.0f) { + continue; + } + + // clang-format off + vertices.push_back(vertex{{x , -y }, {character.x_offset / atlas_width , character.y_offset / atlas_height}}); + vertices.push_back(vertex{{x , -y - h}, {character.x_offset / atlas_width , (character.y_offset + character.bitmap_height) / atlas_height}}); + vertices.push_back(vertex{{x + w, -y }, {(character.x_offset + character.bitmap_width) / atlas_width, character.y_offset / atlas_height}}); + vertices.push_back(vertex{{x + w, -y }, {(character.x_offset + character.bitmap_width) / atlas_width, character.y_offset / atlas_height}}); + vertices.push_back(vertex{{x , -y - h}, {character.x_offset / atlas_width , (character.y_offset + character.bitmap_height) / atlas_height}}); + vertices.push_back(vertex{{x + w, -y - h}, {(character.x_offset + character.bitmap_width) / atlas_width, (character.y_offset + character.bitmap_height) / atlas_height}}); + // clang-format on + } + + const float xoffset = + is_centered ? std::floor(total_width / 2.0f) : 0.0f; + const float yoffset = + is_vcentered + ? std::floor(static_cast(atlas.get_glyph_height()) / + 3.0f) + : 0.0f; + for (auto& v : vertices) { + v.pos.x -= xoffset; + v.pos.y -= yoffset; + } + + return vertices; + }(); + + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + glUseProgram(program); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, atlas.get_texture()); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + + glBufferData(GL_ARRAY_BUFFER, std::size(vertices) * sizeof(vertex), + std::data(vertices), GL_DYNAMIC_DRAW); + + glUniform4f(u_colour, colour.x, colour.y, colour.z, colour.w); + glUniformMatrix4fv(u_matrix, 1, GL_FALSE, glm::value_ptr(matrix)); + + glDrawArrays(GL_TRIANGLES, 0, std::size(vertices)); + + glEnable(GL_CULL_FACE); +} + +// Updates our ebos, we want to call this once per frame. +void update_uniforms() noexcept { + struct ubo_data { + glm::mat4 proj; + glm::mat4 view; + std::array frustum; + float znear; + float zfar; + float xfov; // IN RADIANS + float yfov; // IN RADIANS + unsigned time; // resolution of 1000/s + float xwindow; + float ywindow; + }; + const auto make_ubo = [&]() -> GLuint { + GLuint ubo; + glGenBuffers(1, &ubo); + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(ubo_data), nullptr, + GL_DYNAMIC_DRAW); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo); // binding @ 0 + return ubo; + }; + static const GLuint ubo = make_ubo(); + + ubo_data upload = {.proj = camera::get_proj(), + .view = camera::get_view(), + .frustum = camera::get_frustum(), + .znear = camera::get_znear(), + .zfar = camera::get_zfar(), + .xfov = glm::radians(camera::get_xfov()), + .yfov = glm::radians(camera::get_yfov()), + .time = []() -> unsigned { + static const auto start = + std::chrono::steady_clock::now(); + const auto now = std::chrono::steady_clock::now(); + return static_cast( + (now - start) / std::chrono::milliseconds(1)); + }(), + .xwindow = static_cast(get_window_size().x), + .ywindow = static_cast(get_window_size().y)}; + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(upload), &upload); +} + +} // namespace render +} // namespace client diff --git a/src/client/render/render.hh b/src/client/render/render.hh new file mode 100644 index 0000000..ca98e6f --- /dev/null +++ b/src/client/render/render.hh @@ -0,0 +1,62 @@ +#ifndef CLIENT_RENDER_RENDER_HH_ +#define CLIENT_RENDER_RENDER_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // this has to go before SDL2 +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H + +#include "client/render/camera.hh" +#include "client/render/program.hh" +#include "shared/shared.hh" +#include "shared/world.hh" + +namespace client { +namespace render { + +void init(); +void quit() noexcept; + +// Getters +int get_fps() noexcept; +SDL_Window* const& get_sdl_window() noexcept; +const glm::ivec2& get_window_size() noexcept; + +// Update +void update_uniforms() noexcept; +void swap_window() noexcept; + +// Render +void render_rectangle(const glm::vec2& pos, const glm::vec2& size, + const glm::vec4& colour) noexcept; +void render_text(const std::string_view text, const unsigned int size, + const bool is_centered, const bool is_vcentered, + const glm::vec4& colour, const glm::mat4& matrix) noexcept; +void render_cube_outline(const glm::vec3& pos, + const glm::vec4& colour) noexcept; + + + +} // namespace render +} // namespace client + +#endif diff --git a/src/client/render/texture.cc b/src/client/render/texture.cc new file mode 100644 index 0000000..2c003ff --- /dev/null +++ b/src/client/render/texture.cc @@ -0,0 +1 @@ +#include "client/render/texture.hh" diff --git a/src/client/render/texture.hh b/src/client/render/texture.hh new file mode 100644 index 0000000..bc3d008 --- /dev/null +++ b/src/client/render/texture.hh @@ -0,0 +1,37 @@ +#ifndef CLIENT_RENDER_TEXTURE_HH_ +#define CLIENT_RENDER_TEXTURE_HH_ + +#include +#include + +#include "client/render/lib/stb_image/stb_image.hh" + +namespace client { +namespace render { + +// Automatic freeing of a texture from stb image. +struct texture { + unsigned char* image; + int width; + int height; + int channels; + + texture(const std::string& dir, const bool flip = false) { + stbi_set_flip_vertically_on_load(flip); + this->image = stbi_load(dir.c_str(), &this->width, &this->height, + &this->channels, 0); + + if (this->image == nullptr) { + throw std::runtime_error("stbi failed to load texture \"" + dir + + '\"'); + } + } + texture(const texture&) = delete; + texture(texture&&) = delete; + ~texture() noexcept { stbi_image_free(image); } +}; + +} // namespace render +} // namespace client + +#endif diff --git a/src/client/settings.cc b/src/client/settings.cc new file mode 100644 index 0000000..8e2d0c9 --- /dev/null +++ b/src/client/settings.cc @@ -0,0 +1,139 @@ +#include "client/settings.hh" + +namespace { +const std::string home_dir = getenv("HOME"); +const char* const config_dir = "/.config/blockgame_linux/"; +const char* const config_name = "blockgame_linux.conf"; +} // namespace + +namespace client { +namespace settings { + +static std::string get_settings_file() noexcept { + std::filesystem::create_directories(home_dir + ::config_dir); + std::ifstream in{home_dir + ::config_dir + config_name, + std::fstream::in | std::fstream::app}; + + // this must end with a newline, IT IS NOT UP FOR NEGOTIATION + const std::string file{std::istreambuf_iterator(in), + std::istreambuf_iterator()}; + return file.ends_with('\n') ? file : file + '\n'; +} + +static void set_settings_file(const std::string_view contents) noexcept { + std::filesystem::create_directories(home_dir + ::config_dir); + std::ofstream out{home_dir + ::config_dir + ::config_name, + std::fstream::out | std::fstream::trunc}; + out << contents; +} + +// Settings maps subkeys to std::string values (ie, "fov" -> "100.0"f). +// Heading maps setting to headings (ie, "camera -> {map with fov, 100.0f}). +using value_map = std::unordered_map; +using setting_map = std::unordered_map; +static setting_map& get_settings() noexcept { + static setting_map ret = []() -> setting_map { + setting_map settings{}; + + std::stringstream ss{get_settings_file()}; + std::string heading = "default"; + for (std::string line; std::getline(ss, line);) { + if (line.empty()) { + continue; + } + + if (line.starts_with('[') && line.ends_with(']')) { + heading = std::string{std::begin(line) + 1, std::end(line) - 1}; + continue; + } + + const size_t split_pos = line.find_first_of(':'); + + if (split_pos == std::string::npos) { + shared::print::warn("client: failed to parse line in settings " + "file, consider manual intervention\n"); + continue; + } + + const std::string key{std::begin(line), + std::begin(line) + + static_cast(split_pos)}; + const std::string value{std::begin(line) + + static_cast(split_pos) + 1, + std::end(line)}; + + value_map& values = settings[heading]; + + values.emplace(key, value); + } + return settings; + }(); + + return ret; +} + +// TODO fix this bit of code duplication +std::string +get_setting_str(const std::pair loc, + const std::string default_value) noexcept { + const auto& [heading, name] = loc; + + setting_map& settings = get_settings(); + value_map& values = settings[heading]; + + const auto find_it = values.find(name); + if (find_it == std::end(values)) { + values.emplace(name, default_value); + return default_value; + } + return find_it->second; +} + +void set_setting_str( + const std::pair loc, + const std::string& value) noexcept { + const auto& [heading, name] = loc; + + setting_map& settings = get_settings(); + value_map& values = settings[heading]; + + const auto find_it = values.find(name); + if (find_it == std::end(values)) { + values.emplace(name, value); + return; + } + find_it->second = value; +} + +void save() noexcept { + std::string contents; + + const setting_map& settings = get_settings(); + + // We alphabetically order the headings, and the key:values between them. + std::vector headings; + std::ranges::transform(std::begin(settings), std::end(settings), + std::back_inserter(headings), + [](const auto& map) { return map.first; }); + std::ranges::sort(headings); + + for (const auto& heading : headings) { + contents.append('[' + heading + "]\n"); + + const value_map& values = settings.find(heading)->second; + std::vector keys; + std::ranges::transform( + std::begin(values), std::end(values), std::back_inserter(keys), + [](const auto& key_val) { return key_val.first; }); + std::ranges::sort(keys); + + for (const auto& key : keys) { + contents.append(key + ':' + values.find(key)->second + '\n'); + } + } + + set_settings_file(contents); +} + +} // namespace settings +} // namespace client diff --git a/src/client/settings.hh b/src/client/settings.hh new file mode 100644 index 0000000..d65022b --- /dev/null +++ b/src/client/settings.hh @@ -0,0 +1,52 @@ +#ifndef CLIENT_SETTINGS_HH_ +#define CLIENT_SETTINGS_HH_ + +#include +#include +#include +#include +#include + +#include + +#include "client/shared.hh" +#include "shared/shared.hh" + +// This settings file just provides functionality for persistent variables, +// it has nothing to do with rendering or our window manager. + +namespace client { +namespace settings { + +void set_setting_str( + const std::pair loc, + const std::string& value) noexcept; + +std::string +get_setting_str(const std::pair loc, + const std::string default_value) noexcept; + +// Attempts to read the setting in the file, returning it if it exists. +// If either name or category does not exist, writes the default value in +// the file under the expected headings. +template +T get(const std::pair& loc, + const T& default_value) noexcept { + const std::string value = + get_setting_str(loc, boost::lexical_cast(default_value)); + return boost::lexical_cast(value); +} + +// Attempts to set the setting in the file, overwriting the pre-existing +// value or writing a new entry. +template +void set(const std::pair& loc, + const T& value) noexcept { + set_setting_str(loc, boost::lexical_cast(value)); +} + +void save() noexcept; +} // namespace settings +} // namespace client + +#endif diff --git a/src/client/shared.cc b/src/client/shared.cc new file mode 100644 index 0000000..3c6a2ec --- /dev/null +++ b/src/client/shared.cc @@ -0,0 +1 @@ +#include "shared.hh" diff --git a/src/client/shared.hh b/src/client/shared.hh new file mode 100644 index 0000000..557d13a --- /dev/null +++ b/src/client/shared.hh @@ -0,0 +1,29 @@ +#ifndef CLIENT_SHARED_HH_ +#define CLIENT_SHARED_HH_ + +#include +#include + +#include "shared/net/connection.hh" + +namespace client { + +struct state { + std::string_view address; + std::string_view port; + std::uint64_t seed; + std::uint32_t localplayer; + std::size_t player_count; + std::size_t requested_chunk_count; + std::size_t networked_chunk_count; + std::int32_t draw_distance; + std::uint16_t latency; + + shared::net::connection* connection = nullptr; +}; + +inline state state; + +}; // namespace client + +#endif diff --git a/src/client/window.cc b/src/client/window.cc new file mode 100644 index 0000000..6a11252 --- /dev/null +++ b/src/client/window.cc @@ -0,0 +1,449 @@ +#include "window.hh" + +namespace client { +namespace window { + +// All window objects should derive from basic_window, and make use of multiple +// inheritance for specific behaviours. +class basic_window { +protected: + // Colours borrowed from arc-dark(er). + static constexpr glm::vec3 primary_clr{0.21f, 0.23f, 0.29f}; // dark + static constexpr glm::vec3 secondary_clr{0.29f, 0.32f, 0.38f}; // less dark + static constexpr glm::vec3 tertiary_clr{0.48, 0.50, 0.54}; // less dark ^2 + static constexpr glm::vec3 highlight_clr{0.32, 0.58, 0.88}; // light blue + static constexpr glm::vec3 font_colour{0.88, 0.88, 0.88}; // light grey + +protected: + glm::vec2 pos; + glm::vec2 size; + +public: + bool is_inside(const glm::vec2& v) const noexcept { + if (v.x < this->pos.x || v.x > this->pos.x + this->size.x) { + return false; + } + if (v.y < this->pos.y || v.y > this->pos.y + this->size.y) { + return false; + } + return true; + } + +public: + basic_window(const client::draw::relative_arg& p, + const client::draw::relative_arg& s) noexcept + : pos(p.to_vec2()), size(s.to_vec2()) {} + virtual ~basic_window() noexcept {} + + virtual bool maybe_handle_event(const SDL_Event&) noexcept { return false; } + virtual void draw() noexcept { + client::draw::draw_rectangle({.pos = {.offset = this->pos + 6.0f}, + .size = {.offset = this->size}, + .colour = {this->tertiary_clr, 0.9f}}); + client::draw::draw_rectangle({.pos = {.offset = this->pos}, + .size = {.offset = this->size}, + .colour = {this->primary_clr, 1.0f}}); + } +}; + +static void remove_top_layer() noexcept; +class text_input_window : public basic_window { +private: + // text restricted to a size of 32. + static const std::string& get_send_text() noexcept { + auto& text = client::input::state.text_input; + text = std::string{std::begin(text), + std::begin(text) + + static_cast(std::min( + std::size(text), shared::MAX_SAY_LENGTH))}; + return text; + } + static bool maybe_handle_keydown(const SDL_Event& event) noexcept { + if (event.key.keysym.sym == SDLK_BACKSPACE) { + if (!client::input::state.text_input.empty()) { + client::input::state.text_input.pop_back(); + } + return true; + } + + if (event.key.keysym.sym != SDLK_RETURN || event.key.repeat) { + return false; + } + + if (!client::input::state.text_input.empty()) { + client::send_say_packet(get_send_text()); + } + + remove_top_layer(); // DELETE ME + return true; + } + static const glm::vec3& get_draw_colour() noexcept { + if (client::input::state.text_input.length() >= + shared::MAX_SAY_LENGTH) { + return basic_window::highlight_clr; + } + return basic_window::primary_clr; + } + +public: + template + text_input_window(Args&&... args) noexcept + : basic_window(std::forward(args)...) { + client::input::set_text_input(true); + } + virtual ~text_input_window() noexcept { + client::input::set_text_input(false); + } + virtual bool maybe_handle_event(const SDL_Event& event) noexcept override { + switch (event.type) { + case SDL_KEYDOWN: + return this->maybe_handle_keydown(event); + } + + return basic_window::maybe_handle_event(event); + } + + virtual void draw() noexcept override { + basic_window::draw(); + + client::draw::draw_rectangle( + {.pos = {.offset = this->pos}, + .size = {.offset = this->size}, + .colour = {this->get_draw_colour(), 1.0f}}); + + client::draw::draw_text( + this->get_send_text(), + {.pos = {.extent = {0.0f, 0.0f}, + .offset = this->pos + (this->size / 2.0f)}, + .offset_height = this->size.y / 2.0f, + .colour = {this->font_colour, 1.0f}, + .has_backing = false, + .is_centered = true, + .is_vcentered = true}); + }; +}; + +class button_window : public basic_window { +protected: + std::string name; + std::function callback; + bool is_pressed; + +private: + void handle_mousebuttondown(const SDL_Event& event) noexcept { + if (event.button.button != SDL_BUTTON_LEFT) { + return; + } + this->is_pressed = true; + } + void handle_mousebuttonup(const SDL_Event& event) noexcept { + if (event.button.button != SDL_BUTTON_LEFT) { + return; + } + if (!this->is_pressed) { + return; + } + this->is_pressed = false; + std::invoke(this->callback); // edge + } + const glm::vec3& get_draw_colour() noexcept { + if (!this->is_inside(client::input::state.mouse_pos)) { + this->is_pressed = false; + return this->primary_clr; + } + + if (!this->is_pressed) { + return this->secondary_clr; + } + + return this->highlight_clr; + } + +public: + template + button_window(const std::string_view n, const decltype(callback)& c, + Args&&... args) noexcept + : basic_window(std::forward(args)...), name(n), callback(c) {} + + virtual bool maybe_handle_event(const SDL_Event& event) noexcept override { + if (this->is_inside(client::input::state.mouse_pos)) { + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + this->handle_mousebuttondown(event); + return true; + case SDL_MOUSEBUTTONUP: + this->handle_mousebuttonup(event); + return true; + } + } + + return basic_window::maybe_handle_event(event); + } + virtual void draw() noexcept override { + basic_window::draw(); + + client::draw::draw_rectangle( + {.pos = {.offset = this->pos}, + .size = {.offset = this->size}, + .colour = {this->get_draw_colour(), 1.0f}}); + client::draw::draw_text( + this->name, {.pos = {.extent = {0.0f, 0.0f}, + .offset = this->pos + (this->size / 2.0f)}, + .offset_height = this->size.y / 2.0f, + .colour = {this->font_colour, 1.0f}, + .has_backing = false, + .is_centered = true, + .is_vcentered = true}); + }; +}; + +// Sliders are for numerical values of some type T. +// TODO +/* +template +class slider_window : public basic_window { +protected: + std::string name; + T min; + T cur; + T max; + T& var; + +private: + void handle_mousebuttondown(const SDL_Event& event) noexcept {} + void handle_mousebuttonup(const SDL_Event& event) noexcept {} + +public: + template + slider_window(const std::string_view name, const T& min, const T& cur, + const T& max, T& var, Args&&... args) noexcept + : basic_window(std::forward(args)...), name(name), min(min), + cur(cur), max(max), var(var) {} + + // slider_window( + virtual bool maybe_handle_event(const SDL_Event& event) noexcept +override { switch (event.type) { case SDL_MOUSEBUTTONDOWN: + this->handle_mousebuttondown(event); + return true; + case SDL_MOUSEBUTTONUP: + this->handle_mousebuttonup(event); + return true; + } + return basic_window::maybe_handle_event(event); + } + virtual void draw() noexcept override { basic_window::draw(); } +}; +*/ + +static void handle_event(const SDL_Event& event) noexcept; // ignore + +// All windows go in this list! +using layer = std::forward_list>; +using layers = std::forward_list; +static layers& get_layers() noexcept { + // We callbacks for our window manager are initialised here too. + static layers ret = []() -> layers { + client::input::register_event_handler(&handle_event); + client::input::set_text_input(false); + client::input::set_mouse_relative(true); + return {}; + }(); + return ret; +} + +static void remove_top_layer() noexcept { + if (!get_layers().empty()) { + get_layers().pop_front(); + } + // Our windows might be empty here, so set our mouse mode accordingly. + if (!client::window::is_open()) { + client::input::set_mouse_relative(true); + } +} + +// Constants used for uniform ui sizes. +constexpr glm::vec2 lsize_extent{0.4, 0.075}; +constexpr glm::vec2 ssize_extent{0.15, 0.075}; + +static void center_mouse_position() noexcept { + const glm::vec2& window = client::render::get_window_size(); + client::input::set_mouse_position({window.x / 2.0f, window.y / 2.0f}); +} + +template +void push_window(Args&&... args) noexcept { + get_layers().front().push_front( + std::make_unique(std::forward(args)...)); +} + +constexpr glm::vec2 center_extent(const glm::vec2 pos, + const glm::vec2 size) noexcept { + return {pos.x, pos.y - size.y / 2.0f}; +} + +static void make_options_menu() noexcept { + get_layers().push_front({}); + + /* + push_window<::slider_window>( + "Field of Vision", 0.0f, + settings::get(std::make_pair("gameplay", "fov"), 100.0f), 145.0f, + remove_top_layer, + client::draw::relative_arg{.extent = + center_extent({0.3, 0.7}, + lsize_extent)}, client::draw::relative_arg{.extent = lsize_extent}); + */ + + push_window( + "Back", remove_top_layer, + client::draw::relative_arg{.extent = + center_extent({0.3, 0.3}, ssize_extent)}, + client::draw::relative_arg{.extent = ssize_extent}); +} + +static void make_main_menu() noexcept { + get_layers().push_front({}); + + push_window( + "Return to Game", remove_top_layer, + client::draw::relative_arg{.extent = + center_extent({0.3, 0.7}, lsize_extent)}, + client::draw::relative_arg{.extent = lsize_extent}); + + push_window( + "Options", make_options_menu, + client::draw::relative_arg{ + .extent = center_extent({0.55, 0.6}, ssize_extent)}, + client::draw::relative_arg{.extent = ssize_extent}); + + push_window( + "?", remove_top_layer, + client::draw::relative_arg{ + .extent = center_extent({0.55, 0.5}, ssize_extent)}, + client::draw::relative_arg{.extent = ssize_extent}); + + push_window( + "?", remove_top_layer, + client::draw::relative_arg{ + .extent = center_extent({0.55, 0.4}, ssize_extent)}, + client::draw::relative_arg{.extent = ssize_extent}); + + push_window( + "Exit Game", [] { shared::should_exit = true; }, + client::draw::relative_arg{.extent = + center_extent({0.3, 0.3}, lsize_extent)}, + client::draw::relative_arg{.extent = lsize_extent}); + + client::input::set_mouse_relative(false); + center_mouse_position(); +} + +static void make_chat_window() noexcept { + get_layers().push_front({}); + + push_window( + client::draw::relative_arg{.extent = + center_extent({0.3, 0.3}, lsize_extent)}, + client::draw::relative_arg{.extent = lsize_extent}); + + client::input::set_mouse_relative(false); + center_mouse_position(); +} + +static void handle_meta_return() noexcept { + if (!is_open()) { + make_chat_window(); + return; + } +} + +static void handle_meta_escape() noexcept { + if (!is_open()) { + make_main_menu(); + return; + } + + remove_top_layer(); +} + +static void handle_meta_keydown(const SDL_Event& event) noexcept { + if (event.key.repeat) { // only handle keypresses + return; + } + + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: + handle_meta_escape(); + break; + case SDLK_RETURN: + handle_meta_return(); + break; + } +} + +static void handle_meta_mousemotion(const SDL_Event& event) noexcept { + // We convert SDL's weird coordinates into useful ones (0,0 = bottom + // left). + client::input::state.mouse_pos = { + event.motion.x, + static_cast(client::render::get_window_size().y) - event.motion.y}; +} + +static void handle_meta_windowevent(const SDL_Event& event) noexcept { + if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { + if (!is_open()) { + make_main_menu(); + return; + } + } +} + +static void handle_meta_event(const SDL_Event& event) noexcept { + switch (event.type) { + case SDL_KEYDOWN: + handle_meta_keydown(event); + break; + case SDL_MOUSEMOTION: + handle_meta_mousemotion(event); + break; + case SDL_WINDOWEVENT: + handle_meta_windowevent(event); + break; + } +} + +static void handle_event(const SDL_Event& event) noexcept { + // We ALWAYS update our mouse position. + if (event.type == SDL_MOUSEMOTION) { + handle_meta_mousemotion(event); + } + + // Either a window consumes our event, or no window does - so we send + // the event to our "meta handler" which does things like closing + // windows etc. + if (is_open()) { + for (const auto& window : get_layers().front()) { + if (window->maybe_handle_event(event)) { + return; + } + } + } + + handle_meta_event(event); +} + +void draw() noexcept { + if (!is_open()) { + return; + } + + client::draw::draw_colour({0.0f, 0.0f, 0.0f, 0.10f}); // very light shade + for (const auto& window : get_layers().front()) { + window->draw(); + } +} + +bool is_open() noexcept { return !get_layers().empty(); } + +} // namespace window +} // namespace client diff --git a/src/client/window.hh b/src/client/window.hh new file mode 100644 index 0000000..094c4ca --- /dev/null +++ b/src/client/window.hh @@ -0,0 +1,30 @@ +#ifndef CLIENT_WINDOW_HH_ +#define CLIENT_WINDOW_HH_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "client/client.hh" +#include "client/draw.hh" +#include "client/input.hh" +#include "client/settings.hh" +#include "shared/shared.hh" + +namespace client { +namespace window { + +void draw() noexcept; +bool is_open() noexcept; + +} // namespace window +} // namespace client + +#endif diff --git a/src/client/world.cc b/src/client/world.cc new file mode 100644 index 0000000..1ceb9fb --- /dev/null +++ b/src/client/world.cc @@ -0,0 +1,429 @@ +#include "world.hh" + +namespace client { +namespace world { + +// Additional sanity checks for our atlas. +static void check_atlas(const client::render::texture& texture) { + if (texture.width % 6) { + throw std::runtime_error("invalid atlas; WIDTH is not divisible by 6"); + } + if (texture.height % (texture.width / 6)) { + throw std::runtime_error( + "invalid atlas, HEIGHT is not divisible by (WIDTH / 6)"); + } +} + +void chunk::render(const float world_x, const float world_z, + const pass& pass) noexcept { + const auto make_texture = []() -> GLuint { + GLuint texture = 0; + glActiveTexture(GL_TEXTURE1); + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D_ARRAY, texture); + + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY, 16.0f); + + const client::render::texture stbi{"res/textures/atlas.png"}; + check_atlas(stbi); + const int face_size = stbi.width / 6; + + // 2D texture array, where our depth is our block face. + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, face_size, face_size, + 6 * (stbi.height / face_size), 0, + stbi.channels == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + + // Fill the 2D texture array. + // Because our image has multiple images on the x-axis and opengl + // expects a single image per axis, we must fill it in row by row. + const auto get_pixel_xy = [&stbi](const int x, const int y) { + return stbi.image + 4 * (y * stbi.width + x); + }; + for (int x = 0; x < 6; ++x) { + const int x_pixel = x * face_size; + + for (int y = 0; y < stbi.height / face_size; ++y) { + const int y_pixel = y * face_size; + + for (auto row = 0; row < face_size; ++row) { + glTexSubImage3D( + GL_TEXTURE_2D_ARRAY, 0, 0, row, x + y * 6, face_size, 1, + 1, GL_RGBA, GL_UNSIGNED_BYTE, + get_pixel_xy(x_pixel, row + y_pixel)); // pixel + } + } + } + + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + + return texture; + }; + const auto make_matrix = [&]() -> glm::mat4 { + const auto& proj = client::render::camera::get_proj(); + const auto& view = client::render::camera::get_view(); + return glm::translate(proj * view, glm::vec3{world_x, 0, world_z}); + }; + static client::render::program program{"res/shaders/face.vs", + "res/shaders/face.fs"}; + static const GLuint texture [[maybe_unused]] = make_texture(); + static const GLint u_matrix = glGetUniformLocation(program, "_u_matrix"); + + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glUseProgram(program); + // Our choice of vao depends on which pass we're doing. + const auto [vao, elements] = [&pass, this]() -> std::pair { + if (pass == pass::solid) { + return {this->glo->solid_vao, this->glo->solid_elements}; + } + return {this->glo->water_vao, this->glo->water_elements}; + }(); + glBindVertexArray(vao); + + glUniformMatrix4fv(u_matrix, 1, GL_FALSE, glm::value_ptr(make_matrix())); + + glDrawArrays(GL_TRIANGLES, 0, elements); +} + +// This function translates and rotates a set of vertices that describes a +// neutral face and also adds a vector to the texture coords. +std::array +chunk::make_glfaces(const glface_args& args) noexcept { + + static constexpr std::array glfaces = { + glface{{-0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}}, + glface{{0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 0.0f}}, + glface{{0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + glface{{0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}}, + glface{{-0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 0.0f}}, + glface{{-0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}}}; + + // We have to be careful here not to rotate/translate a zero vector. + const glm::mat4 mtranslate = + args.translate == glm::vec3{} + ? glm::mat4{1.0f} + : glm::translate(glm::mat4{1.0f}, args.translate); + const glm::mat4 mrotate = + args.rotate_axis == glm::vec3{} + ? glm::mat4{1.0f} + : glm::rotate(glm::mat4{1.0f}, glm::radians(args.rotate_degrees), + args.rotate_axis); + + std::array ret; + + std::ranges::transform(glfaces, std::begin(ret), [&](const auto f) { + auto face = f; // unfortunate copy + face.vertice = + glm::vec3(mtranslate * mrotate * glm::vec4{face.vertice, 1.0f}); + face.texture += args.texture_offset; + return face; + }); + + return ret; +} + +const chunk* chunk::get_neighbour(const chunk::map& chunks, + shared::math::coords offset) const noexcept { + const auto find_it = chunks.find(this->pos + offset); + if (find_it == std::end(chunks) || !find_it->second.has_value()) { + return nullptr; + } + return &((*find_it).second.value()); +} + +bool chunk::maybe_regenerate_glo(const chunk::map& chunks) noexcept { + // We need all surrounding chunks to make our vbo, this is why it's called + // "maybe" regenerate vbo. + const auto chunk_forward = this->get_neighbour(chunks, {0, 1}); + const auto chunk_backward = this->get_neighbour(chunks, {0, -1}); + const auto chunk_right = this->get_neighbour(chunks, {1, 0}); + const auto chunk_left = this->get_neighbour(chunks, {-1, 0}); + if (!chunk_forward || !chunk_left || !chunk_backward || !chunk_right) { + return false; + } + + static const auto [atlas_width, + atlas_height] = []() -> std::pair { + const client::render::texture texture{"res/textures/atlas.png"}; + check_atlas(texture); + return {texture.width, texture.height}; + }(); + + // Single-axis-outside-chunk-bounds-allowed block access. + const auto get_outside_block = [&](const int x, const int y, + const int z) -> shared::world::block { + if (y < 0 || y >= shared::world::chunk::HEIGHT) { + return shared::world::block::type::air; + } else if (x >= shared::world::chunk::WIDTH) { + return chunk_right->get_block({x - WIDTH, y, z}); + } else if (x < 0) { + return chunk_left->get_block({x + WIDTH, y, z}); + } else if (z >= shared::world::chunk::WIDTH) { + return chunk_forward->get_block({x, y, z - WIDTH}); + } else if (z < 0) { + return chunk_backward->get_block({x, y, z + WIDTH}); + } + return this->get_block({x, y, z}); + }; + + // We fill up two vbos, one for each possible rendering pass. + std::vector solid_data; + std::vector water_data; + + // For all blocks in the chunk, check if its neighbours are air. If they + // are, it's possible that we can see the block, so add it to vertices. + // We need to read into the neighbours chunk occasionally. + for (auto x = 0; x < WIDTH; ++x) { + for (auto y = 0; y < HEIGHT; ++y) { + for (auto z = 0; z < WIDTH; ++z) { + const auto& block = this->get_block({x, y, z}); + const auto bv = shared::world::block::get_visibility(block); + + if (bv == shared::world::block::visibility::invisible) { + continue; + } + + const auto& front{get_outside_block(x, y, z + 1)}; + const auto& back{get_outside_block(x, y, z - 1)}; + const auto& right{get_outside_block(x + 1, y, z)}; + const auto& left{get_outside_block(x - 1, y, z)}; + const auto& up{get_outside_block(x, y + 1, z)}; + const auto& down{get_outside_block(x, y - 1, z)}; + + std::vector glfaces; + glfaces.reserve(6 * 6); + + const auto should_draw_face = [&bv](const auto& other) -> bool { + const auto ov = shared::world::block::get_visibility(other); + if (bv == shared::world::block::visibility::translucent && + ov == shared::world::block::visibility::translucent) { + return false; + } + return ov != shared::world::block::visibility::solid; + }; + // Special shrub block case, ugly I know. + if (block.type == shared::world::block::type::shrub || + block.type == shared::world::block::type::dead_shrub || + block.type == shared::world::block::type::snowy_shrub) { + static const auto front_shrub = + make_glfaces({.translate = {0.0f, 0.0f, 0.0f}, + .rotate_degrees = 45.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 0.0f}}); + static const auto right_shrub = + make_glfaces({.translate = {0.0f, 0.0f, 0.0f}, + .rotate_degrees = 135.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 0.0f}}); + static const auto back_shrub = + make_glfaces({.translate = {0.0f, 0.0f, 0.0f}, + .rotate_degrees = 225.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 0.0f}}); + static const auto left_shrub = + make_glfaces({.translate = {0.0f, 0.0f, 0.0f}, + .rotate_degrees = 315.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 0.0f}}); + + std::ranges::copy(front_shrub, std::back_inserter(glfaces)); + std::ranges::copy(right_shrub, std::back_inserter(glfaces)); + std::ranges::copy(back_shrub, std::back_inserter(glfaces)); + std::ranges::copy(left_shrub, std::back_inserter(glfaces)); + + } else { + if (should_draw_face(front)) { + static const auto front_faces = make_glfaces( + {.translate = {0.0f, 0.0f, 0.5f}, + .rotate_degrees = 0.0f, + .rotate_axis = {0.0f, 0.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 0.0f}}); + std::ranges::copy(front_faces, + std::back_inserter(glfaces)); + } + if (should_draw_face(right)) { + static const auto right_faces = make_glfaces( + {.translate = {0.5f, 0.0f, 0.0f}, + .rotate_degrees = 90.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 1.0f}}); + std::ranges::copy(right_faces, + std::back_inserter(glfaces)); + } + if (should_draw_face(back)) { + static const auto back_faces = make_glfaces( + {.translate = {0.0f, 0.0f, -0.5f}, + .rotate_degrees = 180.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 2.0f}}); + std::ranges::copy(back_faces, + std::back_inserter(glfaces)); + } + if (should_draw_face(left)) { + static const auto left_faces = make_glfaces( + {.translate = {-0.5f, 0.0f, 0.0f}, + .rotate_degrees = 270.0f, + .rotate_axis = {0.0f, 1.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 3.0f}}); + std::ranges::copy(left_faces, + std::back_inserter(glfaces)); + } + if (should_draw_face(up)) { + static const auto up_faces = make_glfaces( + {.translate = {0.0f, 0.5f, 0.0f}, + .rotate_degrees = -90.0f, + .rotate_axis = {1.0f, 0.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 4.0f}}); + std::ranges::copy(up_faces, + std::back_inserter(glfaces)); + } + if (should_draw_face(down)) { + static const auto down_faces = make_glfaces( + {.translate = {0.0f, -0.5f, 0.0f}, + .rotate_degrees = 90.0f, + .rotate_axis = {1.0f, 0.0f, 0.0f}, + .texture_offset = {0.0f, 0.0f, 5.0f}}); + std::ranges::copy(down_faces, + std::back_inserter(glfaces)); + } + } + + // Move the block pos verts to its intended position. + // Move the block texture verts to fit in the atlas. + const glm::vec3 offset_vec3{x, y, z}; + const float tex_yoff = static_cast(block.type) - 1.0f; + + const auto fix_face = [&, atlas_width = std::ref(atlas_width), + atlas_height = + std::ref(atlas_height)](auto& face) { + face.vertice += offset_vec3 + 0.5f; // move to origin too + face.texture.z += tex_yoff * 6.0f; + return face; + }; + + auto& vbo_dest = block.type == shared::world::block::type::water + ? water_data + : solid_data; + std::ranges::transform(glfaces, std::back_inserter(vbo_dest), + fix_face); + } + } + } + + const auto generate_vbo = [](const auto& data) -> GLuint { + GLuint vbo = 0; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, std::size(data) * sizeof(glface), + std::data(data), GL_STATIC_DRAW); + return vbo; + }; + const auto generate_vao = []() -> GLuint { + GLuint vao = 0; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // position + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, sizeof(glm::vec3) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(glface), nullptr); + // texture + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, sizeof(glm::vec3) / sizeof(float), GL_FLOAT, + GL_FALSE, sizeof(glface), + reinterpret_cast(sizeof(glm::vec3))); + return vao; + }; + // If we were to emplace glo with these there is no guarantee that each + // function will be called in order (at least, for g++ it isn't). Therefore + // we need to call them in order first. + const auto solid_vbo = generate_vbo(solid_data); + const auto solid_vao = generate_vao(); + const auto water_vbo = generate_vbo(water_data); + const auto water_vao = generate_vao(); + this->glo.emplace(std::size(solid_data), solid_vbo, solid_vao, + std::size(water_data), water_vbo, water_vao); + return true; +} + +// http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes/ +static bool box_in_frustum(const std::array& points) noexcept { + const auto& frustum = client::render::camera::get_frustum(); + + for (const auto& plane : frustum) { + bool inside = false; + bool outside = false; + + for (const auto& point : points) { + const float distance = plane.x * point.x + plane.y * point.y + + plane.z * point.z + plane.w; + if (distance < 0.0f) { + outside = true; + } else { + inside = true; + } + + if (inside && outside) { + break; + } + } + + if (!inside) { + return false; + } + } + + return true; +}; + +static bool is_chunk_visible(const float world_x, + const float world_z) noexcept { + const std::array box_vertices = + [&world_x, &world_z]() -> std::array { + const float max_world_x = world_x + shared::world::chunk::WIDTH; + const float max_world_z = world_z + shared::world::chunk::WIDTH; + + return {glm::vec3{world_x, 0.0f, world_z}, + {max_world_x, 0.0f, world_z}, + {world_x, 0.0f, max_world_z}, + {max_world_x, 0.0f, max_world_z}, + {world_x, shared::world::chunk::HEIGHT, world_z}, + {max_world_x, shared::world::chunk::HEIGHT, world_z}, + {world_x, shared::world::chunk::HEIGHT, max_world_z}, + {max_world_x, shared::world::chunk::HEIGHT, max_world_z}}; + }(); + + return box_in_frustum(box_vertices); +} + +void chunk::draw(const chunk::map& chunks, const shared::player& lp, + const pass& pass) noexcept { + if (!this->glo.has_value() || this->should_regenerate_vbo) { + if (!maybe_regenerate_glo(chunks)) { + return; + } + this->should_regenerate_vbo = false; + } + + const auto [world_x, world_z] = [&lp, this]() -> std::pair { + const float offset_x = static_cast(this->pos.x - lp.chunk_pos.x); + const float offset_z = static_cast(this->pos.z - lp.chunk_pos.z); + return {offset_x * chunk::WIDTH, offset_z * chunk::WIDTH}; + }(); + + if (!is_chunk_visible(world_x, world_z)) { + return; + } + + render(world_x, world_z, pass); +} + +} // namespace world +} // namespace client diff --git a/src/client/world.hh b/src/client/world.hh new file mode 100644 index 0000000..067f74c --- /dev/null +++ b/src/client/world.hh @@ -0,0 +1,90 @@ +#ifndef CLIENT_WORLD_HH_ +#define CLIENT_WORLD_HH_ + +#include +#include +#include +#include +#include + +#include "client/render/render.hh" +#include "client/render/texture.hh" +#include "shared/player.hh" +#include "shared/world.hh" + +namespace client { +namespace world { + +// client::world::chunk is a renderable shared::world::chunk. +class chunk : public shared::world::chunk { +public: + using map = std::unordered_map, + decltype(&shared::world::chunk::hash), + decltype(&shared::world::chunk::equal)>; + // Which part to draw when we call draw. + enum class pass { solid, water }; + +public: + bool should_regenerate_vbo; + +private: + struct gl_objects { + unsigned long solid_elements; + GLuint solid_vbo; + GLuint solid_vao; + unsigned long water_elements; + GLuint water_vbo; + GLuint water_vao; + + gl_objects(const unsigned long se, const GLuint svbo, const GLuint svao, + const unsigned long we, const GLuint wvbo, const GLuint wvao) + : solid_elements(se), solid_vbo(svbo), solid_vao(svao), + water_elements(we), water_vbo(wvbo), water_vao(wvao) {} + gl_objects(const gl_objects&) = delete; + gl_objects(gl_objects&&) = delete; + ~gl_objects() { + glDeleteBuffers(1, &solid_vbo); + glDeleteVertexArrays(1, &solid_vao); + glDeleteBuffers(1, &water_vbo); + glDeleteVertexArrays(1, &water_vao); + } + }; + std::optional glo; + +private: + const chunk* get_neighbour(const chunk::map& chunks, + shared::math::coords offset) const noexcept; + struct glface { + glm::vec3 vertice; + glm::vec3 texture; + }; + struct glface_args { + glm::vec3 translate; + float rotate_degrees; + glm::vec3 rotate_axis; + glm::vec3 texture_offset; + }; + static std::array make_glfaces(const glface_args& args) noexcept; + + void render(const float x_offset, const float z_offset, + const pass& pass) noexcept; + bool maybe_regenerate_glo(const chunk::map& chunks) noexcept; + +public: + template + chunk(Args&&... args) noexcept + : shared::world::chunk(std::forward(args)...) {} + + void draw(const map& chunks, const shared::player& lp, + const pass& pass) noexcept; + + bool can_draw() const noexcept { + return this->glo.has_value(); + } +}; + +} // namespace world +} // namespace client + +#endif diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..56efb55 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,193 @@ +#include "main.hh" + +static void set_signal(const decltype(SIGINT) signal, + void (*const callback)(int)) { + struct sigaction sa {}; + sa.sa_handler = callback; + sa.sa_flags = 0; + if (sigaction(signal, &sa, nullptr) == -1) { + throw std::runtime_error("failed to set signal handler for signal " + + std::to_string(signal)); + } +} + +// Parse arg, store result in dest after casting with boost::lexical_cast. +template +static bool maybe_parse_arg(std::vector& args, + const std::initializer_list& keys, + T& dest) noexcept { + const auto find_it = std::ranges::find_if(args, [&keys](const auto& arg) { + return std::ranges::find(keys, arg) != std::end(keys); + }); + + if (find_it == std::end(args)) { + return false; + } + + try { + const auto i = static_cast(find_it - std::begin(args)); + dest = boost::lexical_cast(args.at(i + 1u)); + } catch (const boost::bad_lexical_cast& e) { + shared::print::fault("bad type conversion for \"" + + std::string{*find_it} + "\" arg\n"); + std::exit(EXIT_FAILURE); + } catch (const std::out_of_range& e) { + shared::print::fault("missing \"" + std::string{*find_it} + "\" arg\n"); + std::exit(EXIT_FAILURE); + } + + args.erase(find_it, std::next(find_it, 2)); + + return true; +} + +// Parse arg, return true or false if arg exists. +static bool +maybe_parse_arg(std::vector& args, + const std::initializer_list& keys) noexcept { + + const auto find_it = std::ranges::find_if(args, [&keys](const auto& arg) { + return std::ranges::find(keys, arg) != std::end(keys); + }); + + if (find_it == std::end(args)) { + return false; + } + + args.erase(find_it); + return true; +} + +static void do_server(const std::string_view address, + const std::string_view port) noexcept { + try { + server::main(address, port); + } catch (const std::exception& e) { + shared::print::fault(std::string{"exception in server!\n"} + + " what: " + e.what() + '\n'); + std::exit(EXIT_FAILURE); + } +} + +static void do_client(const std::string_view address, + const std::string_view port) noexcept { + try { + client::main(address, port); + } catch (const std::exception& e) { + shared::print::fault(std::string{"exception in client!\n"} + + " what: " + e.what() + '\n'); + std::exit(EXIT_FAILURE); + } +} + +static void init() noexcept { + // Because we use noexcept liberally, exceptions are often not unwound. + std::set_terminate([]() { + try { + throw; + } catch (const std::exception& e) { + shared::print::fault(std::string{"unhandled exception!\n"} + + " what: " + e.what() + '\n'); + + constexpr std::size_t BACKTRACE_BUF_SIZE = 64; + std::array bt_buffer{}; + const int nptrs = + backtrace(std::data(bt_buffer), std::size(bt_buffer)); + char** strings = backtrace_symbols(std::data(bt_buffer), nptrs); + + shared::print::message("\n backtrace:\n", false); + for (int i = 0; i < nptrs; ++i) { + shared::print::message(" " + std::string{strings[i]} + '\n', + false); + } + free(strings); // controversial + + } catch (...) { + } + std::exit(EXIT_FAILURE); + }); + + set_signal(SIGPIPE, SIG_IGN); + set_signal(SIGINT, []([[maybe_unused]] const int signum) { + shared::print::warn(" interrupt signal received\n", false); + shared::should_exit = true; // graceful cleanup + }); + +#ifndef NDEBUG + shared::print::debug( + "This binary is a debug build and should not be used in production.\n", + false); +#endif +} + +int main(const int argc, const char* const argv[]) { + GOOGLE_PROTOBUF_VERIFY_VERSION; + + // Default argument values, which starts a multiplayer server with a client. + std::string address = "0.0.0.0"; + std::string port = "8191"; + bool has_address = false; + bool has_headless = false; + { + std::vector args; + for (auto i = 1; i < argc; ++i) { + args.emplace_back(argv[i]); + } + + if (maybe_parse_arg(args, {"--help", "-h"})) { + // clang-format off + std::cout << " --help -h : display this, quit\n" + " --address -a : connect elsewhere\n" + " --port -p : override the default port\n" + " --headless -H : run without a client\n" + " --singleplayer -s : avoid hosting a lan server\n" + " --seed -S : manually set the worldseed\n" + " --directory -d : manually set the directory\n" + " --tickrate -t : override the default tickrate\n" + " --distance -D : set the max chunk distance the server provides\n"; + // clang-format on + std::exit(EXIT_SUCCESS); + } + + has_address = maybe_parse_arg(args, {"--address", "-a"}, address); + has_headless = maybe_parse_arg(args, {"--headless", "-H"}); + + maybe_parse_arg(args, {"--port", "-p"}, port); + maybe_parse_arg(args, {"--seed", "-S"}, server::state.seed); + maybe_parse_arg(args, {"--directory", "-d"}, server::state.directory); + maybe_parse_arg(args, {"--tickrate", "-t"}, server::state.tickrate); + maybe_parse_arg(args, {"--distance", "-D"}, + server::state.draw_distance); + + if (maybe_parse_arg(args, {"--singleplayer", "-s"})) { + if (has_address) { + shared::print::warn("singleplayer argument ignored due " + "to conflicting address argument\n"); + } + address = "localhost"; + } + + std::ranges::for_each(args, [](const auto& arg) { + shared::print::warn("unused argument \"" + std::string{arg} + + "\"\n"); + }); + } + + init(); + + // Split server/client execution, while waiting for server to boot before + // running the client. + std::jthread server_thread; + if (!has_address) { + if (has_headless) { + do_server(address, port); + std::exit(EXIT_SUCCESS); + } + server_thread = std::jthread{do_server, address, port}; + while (!server::has_initialised) { + continue; + } + } + + do_client(address, port); +} diff --git a/src/main.hh b/src/main.hh new file mode 100644 index 0000000..28e7b0c --- /dev/null +++ b/src/main.hh @@ -0,0 +1,25 @@ +#ifndef MAIN_HH_ +#define MAIN_HH_ + +// -DCMAKE_BUILD_TYPE=Release disables the following (=Debug for enable): +// shared::world::chunk::get_block bounds checking +// collision debug information +// unknown packet printing + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "client/client.hh" +#include "server/server.hh" +#include "server/shared.hh" + +#endif diff --git a/src/server/chunk_data.cc b/src/server/chunk_data.cc new file mode 100644 index 0000000..722e9bb --- /dev/null +++ b/src/server/chunk_data.cc @@ -0,0 +1 @@ +#include "server/chunk_data.hh" diff --git a/src/server/chunk_data.hh b/src/server/chunk_data.hh new file mode 100644 index 0000000..eea5cef --- /dev/null +++ b/src/server/chunk_data.hh @@ -0,0 +1,30 @@ +#ifndef SERVER_CHUNK_DATA_HH_ +#define SERVER_CHUNK_DATA_HH_ + +#include +#include +#include + +#include "server/world.hh" +#include "shared/player.hh" + +namespace server { + +struct chunk_data { +public: + // nullopt = constructing/destructing via future operations in thread pool + // we use shared_ptr here to avoid complex moves in boost::asio::post. + // There is no good reason to use shared_ptr over unique_ptr, other than + // boost::asio::post requiring copy_constructable args in std::bind. + std::optional> chunk; + // players associated with the chunk + std::unordered_set players; + +public: + server::world::chunk& get_chunk() noexcept { return *(*this->chunk); } + bool has_initialised() const noexcept { return chunk.has_value(); } +}; + +} // namespace server + +#endif diff --git a/src/server/client.cc b/src/server/client.cc new file mode 100644 index 0000000..0197f90 --- /dev/null +++ b/src/server/client.cc @@ -0,0 +1 @@ +#include "server/client.hh" diff --git a/src/server/client.hh b/src/server/client.hh new file mode 100644 index 0000000..5866035 --- /dev/null +++ b/src/server/client.hh @@ -0,0 +1,67 @@ +#ifndef SERVER_CLIENT_HH_ +#define SERVER_CLIENT_HH_ + +#include +#include +#include +#include +#include +#include + +#include "server/chunk_data.hh" +#include "server/world.hh" +#include "shared/net/connection.hh" +#include "shared/player.hh" +#include "shared/world.hh" + +namespace server { + +// Client represents the entire state of a player. +class client { +public: + shared::net::connection connection; + shared::player::index_t index; + + // If this is set a disconnect packet should be set + std::optional disconnect_reason; + + struct player_info { + std::string username; + std::string password; + shared::player player; + }; + // If this is nullopt, we haven't got our init packet yet which contained + // their user + pass. + std::optional> player_info; + + // flag for disconnecting, the client must stay while the server is writing + // its contents to a db + bool disconnecting = false; + + // Chunks for which the player is associated with. + std::unordered_set + chunks{4096, shared::world::chunk::hash, shared::world::chunk::equal}; + +public: + client(shared::net::connection&& con, const shared::player::index_t& index) + : connection(std::move(con)), index(index) {} + + bool has_initialised() const noexcept { + return this->player_info.has_value(); + } + shared::player& get_player() noexcept { + return (*this->player_info)->player; + } + const std::string& get_username() const noexcept { + return (*this->player_info)->username; + } + const std::string& get_password() const noexcept { + return (*this->player_info)->password; + } +}; + +} // namespace server + +#endif diff --git a/src/server/database.cc b/src/server/database.cc new file mode 100644 index 0000000..077c86c --- /dev/null +++ b/src/server/database.cc @@ -0,0 +1,238 @@ +#include "server/database.hh" + +namespace server { +namespace database { + +sqlite3* get_database() noexcept { + + static sqlite3* const database = []() -> sqlite3* { + std::filesystem::create_directory(server::state.directory); + const std::string path = server::state.directory + "world.dat"; + if (!std::filesystem::exists(path)) { + shared::print::warn( + "server: regenerating non-existent world data\n"); + } + + sqlite3* database = nullptr; + if (const int status = sqlite3_open(path.c_str(), &database); + status != SQLITE_OK) { + + throw std::runtime_error("failed to open chunk database at " + + path); + } + + return database; + }(); + + return database; +} + +static void prepare(sqlite3_stmt*& statement, const std::string& sql) noexcept { + sqlite3* const db = get_database(); + + if (const int status = sqlite3_prepare_v2( + db, sql.c_str(), static_cast(std::size(sql) + 1), &statement, + nullptr); + status != SQLITE_OK) { + + throw std::runtime_error(std::string{"sqlite prepare error \""} + + sqlite3_errmsg(db) + '\"'); + } +} + +static auto step(sqlite3_stmt*& statement) noexcept { + const int status = sqlite3_step(statement); + if (status == SQLITE_ERROR) { + sqlite3* const db = get_database(); + throw std::runtime_error(std::string{"sqlite step error \""} + + sqlite3_errmsg(db) + '\"'); + } + return status; +} + +static void finalise(sqlite3_stmt*& statement) noexcept { + if (const int status = sqlite3_finalize(statement); status != SQLITE_OK) { + throw std::runtime_error(std::string{"sqlite bind blob error \""} + + sqlite3_errstr(status) + '\"'); + } +} + +static void bind_int64(sqlite3_stmt*& statement, const int index, + const std::uint64_t& key) noexcept { + if (const int status = sqlite3_bind_int64(statement, index, + std::bit_cast(key)); + status != SQLITE_OK) { + throw std::runtime_error(std::string{"sqlite bind int error \""} + + sqlite3_errstr(status) + '\"'); + } +} + +static void bind_text(sqlite3_stmt*& statement, const int index, + const std::string& text) noexcept { + if (const int status = + sqlite3_bind_text(statement, index, std::data(text), + static_cast(std::size(text)), SQLITE_STATIC); + status != SQLITE_OK) { + throw std::runtime_error(std::string{"sqlite bind text error \""} + + sqlite3_errstr(status) + '\"'); + } +} + +template +static void bind_blob(sqlite3_stmt*& statement, const int index, + const T& blob) noexcept { + if (const int status = + sqlite3_bind_blob(statement, index, std::data(blob), + static_cast(std::size(blob)), SQLITE_STATIC); + status != SQLITE_OK) { + throw std::runtime_error(std::string{"sqlite bind blob error \""} + + sqlite3_errstr(status) + '\"'); + } +} + +static void exec_void_stmt(const std::string& sql) noexcept { + sqlite3_stmt* statement = nullptr; + prepare(statement, sql); + step(statement); + finalise(statement); +} + +void init() noexcept { + exec_void_stmt("CREATE TABLE IF NOT EXISTS Chunks (" + " coords BIGINT PRIMARY KEY," + " blocks BLOB NOT NULL" + ");"); + + exec_void_stmt("CREATE TABLE IF NOT EXISTS Players (" + " username TEXT PRIMARY KEY," + " password TEXT NOT NULL," + " player BLOB NOT NULL" + ");"); +} + +void quit() noexcept { + sqlite3* database = get_database(); + if (const int status = sqlite3_close(database); status != SQLITE_OK) { + throw std::runtime_error(std::string{"failed to close chunk database"} + + sqlite3_errmsg(database)); + }; +} + +// We have to store our key in network byte order! +static std::uint64_t make_key(const shared::math::coords& coords) noexcept { + const auto to_64 = [](const std::int32_t& val, const int lshift) { + return static_cast( + htonl(std::bit_cast(val))) + << lshift; + }; + + return to_64(coords.x, 32) + to_64(coords.z, 0); +} + +std::optional +maybe_read_chunk(const shared::math::coords& pos) noexcept { + sqlite3_stmt* statement = nullptr; + prepare(statement, "SELECT blocks FROM Chunks WHERE Chunks.coords = ?;"); + bind_int64(statement, 1, make_key(pos)); + + if (step(statement) != SQLITE_ROW) { + finalise(statement); + return std::nullopt; + } + + const char* addr = + static_cast(sqlite3_column_blob(statement, 0)); + std::string blocks{addr, addr + sqlite3_column_bytes(statement, 0)}; + finalise(statement); + + shared::decompress_string(blocks); + proto::chunk chunk; + if (!chunk.ParseFromString(blocks)) { + + shared::print::fault("server: chunk [" + std::to_string(pos.x) + ", " + + std::to_string(pos.z) + + "] failed to parse and was evicted\n"); + + statement = nullptr; + prepare(statement, "DELETE FROM Chunks WHERE Chunks.coords = ?;"); + bind_int64(statement, 1, make_key(pos)); + step(statement); + finalise(statement); + return std::nullopt; + } + return chunk; +} + +void write_chunk(const shared::math::coords& pos, + const proto::chunk& chunk) noexcept { + std::string blocks; + chunk.SerializeToString(&blocks); + shared::compress_string(blocks); + + sqlite3_stmt* statement = nullptr; + + prepare(statement, "INSERT OR REPLACE INTO Chunks VALUES(?, ?);"); + bind_int64(statement, 1, make_key(pos)); + bind_blob(statement, 2, blocks); + + step(statement); + + finalise(statement); +} + +std::optional> +maybe_read_player(const std::string& username) noexcept { + sqlite3_stmt* statement = nullptr; + prepare(statement, "SELECT player, password " + "FROM Players " + "WHERE Players.username = ?"); + bind_text(statement, 1, username); + + if (step(statement) != SQLITE_ROW) { + finalise(statement); + return std::nullopt; + } + + const char* plr_adr = + static_cast(sqlite3_column_blob(statement, 0)); + std::string player_bytes{plr_adr, plr_adr + sqlite3_column_bytes(statement, 0)}; + + const unsigned char* pass_adr = sqlite3_column_text(statement, 1); + std::string pass_bytes{pass_adr, pass_adr + sqlite3_column_bytes(statement, 1)}; + finalise(statement); + + shared::decompress_string(player_bytes); + proto::player player; + if (!player.ParseFromString(player_bytes)) { + shared::print::fault("server: player \"" + username + + "\" failed to parse and was evicted\n"); + + statement = nullptr; + prepare(statement, "DELETE FROM Players WHERE Players.username = ?;"); + bind_text(statement, 1, username); + step(statement); + finalise(statement); + return std::nullopt; + } + return std::make_pair(player, pass_bytes); +} + +void write_player(const std::string& username, const std::string& password, + const proto::player& player) noexcept { + std::string player_bytes; + player.SerializeToString(&player_bytes); + shared::compress_string(player_bytes); + + sqlite3_stmt* statement = nullptr; + prepare(statement, "INSERT OR REPLACE INTO Players VALUES(?, ?, ?);"); + bind_text(statement, 1, username); + bind_text(statement, 2, password); + bind_blob(statement, 3, player_bytes); + + step(statement); + finalise(statement); +} + +} // namespace database +} // namespace server + diff --git a/src/server/database.hh b/src/server/database.hh new file mode 100644 index 0000000..154cdf2 --- /dev/null +++ b/src/server/database.hh @@ -0,0 +1,39 @@ +#ifndef SERVER_DATABASE_HH_ +#define SERVER_DATABASE_HH_ + +#include +#include +#include +#include +#include +#include + +#include + +#include "server/shared.hh" +#include "shared/net/net.hh" +#include "shared/shared.hh" +#include "shared/world.hh" + +namespace server { +namespace database { + +void init() noexcept; +void quit() noexcept; + +// chunks +std::optional +maybe_read_chunk(const shared::math::coords& c) noexcept; +void write_chunk(const shared::math::coords& pos, + const proto::chunk& chunk) noexcept; + +// players +std::optional> // player, password +maybe_read_player(const std::string& username) noexcept; +void write_player(const std::string& username, const std::string& password, + const proto::player& player) noexcept; + +} // namespace database +} // namespace server + +#endif diff --git a/src/server/movement.cc b/src/server/movement.cc new file mode 100644 index 0000000..42b17f1 --- /dev/null +++ b/src/server/movement.cc @@ -0,0 +1,87 @@ +#include "server/movement.hh" + +// Gets blocks from chunks, returning nullopt if it doesn't exist. +static std::optional +get_block(const shared::math::coords& pos, server::resources::chunk_map& chunks, + const glm::ivec3& block_pos) noexcept { + + const auto find_it = chunks.find(pos); + if (find_it == std::end(chunks)) { + return std::nullopt; + } + auto& chunk_data = find_it->second; + if (!chunk_data->has_initialised()) { + return std::nullopt; + } + + return chunk_data->get_chunk().get_block(block_pos); +} + +static std::optional> +make_blockinfos(server::client& client, + server::resources::chunk_map& chunks) noexcept { + + std::vector blockinfos; + + constexpr int width = shared::movement::move_width; + constexpr int height = shared::movement::move_height; + for (int x = -width; x <= width; ++x) { + for (int y = -height; y <= height; ++y) { + for (int z = -width; z <= width; ++z) { + + const glm::ivec3 rel_pos = + glm::ivec3{x, y, z} + + glm::ivec3{client.get_player().local_pos}; + + if (rel_pos.y < 0 || + rel_pos.y >= shared::world::chunk::HEIGHT) { + continue; + } + + const shared::math::coords norm_chunk_pos = + shared::world::chunk::get_normalised_chunk( + client.get_player().chunk_pos, rel_pos.x, rel_pos.z); + const glm::ivec3 norm_pos = + shared::world::chunk::get_normalised_coords(rel_pos); + + const auto block = get_block(norm_chunk_pos, chunks, norm_pos); + + if (!block.has_value()) { + return std::nullopt; + } + + const glm::vec3 pos = + glm::vec3{rel_pos} - client.get_player().local_pos; + + const shared::movement::aabb aabb = { + .min = glm::vec3{0.0f, 0.0f, 0.0f} + pos, + .max = glm::vec3{1.0f, 1.0f, 1.0f} + pos}; + blockinfos.push_back( + shared::movement::blockinfo{.block = *block, + .aabb = aabb, + .chunk_pos = norm_chunk_pos, + .pos = norm_pos}); + } + } + } + + return blockinfos; +} + +void server::movement::move(server::client& client, + server::resources::chunk_map& chunks) noexcept { + + if (!client.has_initialised()) { + return; + } + + const auto blockinfos = make_blockinfos(client, chunks); + + if (!blockinfos.has_value()) { + return; + } + + const float deltatime = 1.0f / static_cast(server::state.tickrate); + + shared::movement::move(client.get_player(), *blockinfos, deltatime); +} diff --git a/src/server/movement.hh b/src/server/movement.hh new file mode 100644 index 0000000..2c647b3 --- /dev/null +++ b/src/server/movement.hh @@ -0,0 +1,19 @@ +#ifndef SERVER_MOVEMENT_HH_ +#define SERVER_MOVEMENT_HH_ + +#include "server/client.hh" +#include "server/resources.hh" +#include "server/world.hh" +#include "shared/movement.hh" + +namespace server { + +namespace movement { + +void move(server::client& client, + server::resources::chunk_map& chunks) noexcept; + +} // namespace movement +} // namespace server + +#endif diff --git a/src/server/resources.cc b/src/server/resources.cc new file mode 100644 index 0000000..7eb3d8b --- /dev/null +++ b/src/server/resources.cc @@ -0,0 +1,59 @@ +#include "resources.hh" + +namespace server { +namespace resources { + +void init() noexcept { server::database::init(); } + +// NOT THREAD SAFE! Use get_resources_lock! +static client_map& get_client_map() noexcept { + static client_map ret{}; + return ret; +} + +static chunk_map& get_chunk_map() noexcept { + static chunk_map ret{314'159, shared::world::chunk::hash, + shared::world::chunk::equal}; + return ret; +} + +static pool_t& get_pool() noexcept { + static pool_t ret{}; + return ret; +} + +static resources& get_resources() noexcept { + static struct resources ret = {.clients = get_client_map(), + .chunks = get_chunk_map(), + .pool = get_pool()}; + return ret; +} + +low_priority_lock get_resources_lock() noexcept { + return low_priority_lock{get_resources()}; +} +high_priority_lock get_resources_lock_immediate() noexcept { + return high_priority_lock{get_resources()}; +} + +void quit() noexcept { + const auto sleep = []() { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + }; + + // we recursively post in some cases, so this check is necessary. + while (!get_resources_lock()->clients.empty()) { + sleep(); + continue; + } + while (!get_resources_lock()->chunks.empty()) { + sleep(); + continue; + } + + get_resources_lock()->pool.join(); + server::database::quit(); +} + +} // namespace resources +} // namespace server diff --git a/src/server/resources.hh b/src/server/resources.hh new file mode 100644 index 0000000..578a248 --- /dev/null +++ b/src/server/resources.hh @@ -0,0 +1,119 @@ +#ifndef SERVER_RESOURCES_HH_ +#define SERVER_RESOURCES_HH_ + +#include +#include +#include +#include + +#include +#include + +#include "server/chunk_data.hh" +#include "server/client.hh" +#include "server/database.hh" +#include "server/world.hh" +#include "shared/player.hh" +#include "shared/world.hh" + +namespace server { +namespace resources { + +// Occasionally we need access to certain objects quickly. +// These classes enable the server to take priority over the thread pool's work +// when necessary. Construct a low_priority_lock when it can happen whenever, +// and a high_priority_lock when it should happen ~ now. +template +class lock_base { +private: + T& obj; + +protected: + static inline std::mutex data_mutex; + static inline std::mutex next_mutex; + static inline std::mutex low_priority_mutex; + +protected: + lock_base(T& obj) noexcept : obj(obj) {} + +public: + lock_base(const lock_base&) = delete; + lock_base(lock_base&&) = default; + virtual ~lock_base(){}; + + T& get() noexcept { return this->obj; } + T& operator*() noexcept { return this->get(); } + T* const operator->() noexcept { return &this->get(); } +}; + +// https://stackoverflow.com/questions/11666610/how-to-give-priority-to-privileged-thread-in-mutex-locking +// ty ecatmur! +template +class low_priority_lock : public lock_base { +public: + low_priority_lock(T& t) noexcept : lock_base(t) { + lock_base::low_priority_mutex.lock(); + lock_base::next_mutex.lock(); + lock_base::data_mutex.lock(); + lock_base::next_mutex.unlock(); + } + virtual ~low_priority_lock() noexcept { + lock_base::data_mutex.unlock(); + lock_base::low_priority_mutex.unlock(); + } +}; + +template +class high_priority_lock : public lock_base { +public: + high_priority_lock(T& t) noexcept : lock_base(t) { + lock_base::next_mutex.lock(); + lock_base::data_mutex.lock(); + lock_base::next_mutex.unlock(); + } + virtual ~high_priority_lock() noexcept { + lock_base::data_mutex.unlock(); + } +}; + +using chunk_map_key = shared::math::coords; +using chunk_map_value = std::unique_ptr; +using chunk_map = std::unordered_map; + +using client_map_key = shared::player::index_t; +using client_map_value = std::unique_ptr; +using client_map = std::unordered_map; + +using pool_t = boost::asio::thread_pool; + +struct resources { + client_map& clients; + chunk_map& chunks; + pool_t& pool; +}; + +void init() noexcept; +void quit() noexcept; + +low_priority_lock get_resources_lock() noexcept; +high_priority_lock get_resources_lock_immediate() noexcept; + +inline void associate_client_chunk(const shared::math::coords& coords, + client_map_value& client, + chunk_map_value& chunk) noexcept { + client->chunks.emplace(coords); + chunk->players.emplace(client->index); +} +inline void disassociate_client_chunk(const shared::math::coords& coords, + client_map_value& client, + chunk_map_value& chunk) noexcept { + client->chunks.erase(coords); + chunk->players.erase(client->index); +} + +} // namespace resources +} // namespace server + +#endif diff --git a/src/server/server.cc b/src/server/server.cc new file mode 100644 index 0000000..72faa03 --- /dev/null +++ b/src/server/server.cc @@ -0,0 +1,640 @@ +#include "server.hh" + +namespace server { + +static proto::packet +make_init_packet(const resources::client_map_value& client) noexcept { + proto::packet packet; + + const auto init_packet = packet.mutable_init_packet(); + init_packet->set_seed(state.seed); + init_packet->set_draw_distance(state.draw_distance); + shared::net::set_player(*init_packet->mutable_localplayer(), + client->get_player()); + + return packet; +} + +static proto::packet make_player_packet(const shared::player& player) noexcept { + proto::packet packet; + + const auto player_packet = packet.mutable_player_packet(); + shared::net::set_player(*player_packet, player); + + return packet; +} + +static proto::packet make_server_message_packet(const std::string& msg, + const bool fatal) noexcept { + proto::packet packet; + + const auto server_message_packet = packet.mutable_server_message_packet(); + server_message_packet->set_message(msg); + server_message_packet->set_fatal(fatal); + + return packet; +} + +static proto::packet +make_remove_packet(const resources::client_map_value& client) noexcept { + proto::packet packet; + + const auto remove_packet = packet.mutable_remove_player_packet(); + remove_packet->set_index(client->index); + + return packet; +} + +static proto::packet make_hear_packet(const std::string& message, + const std::uint32_t index) noexcept { + proto::packet packet; + + const auto hear_player_packet = packet.mutable_hear_player_packet(); + hear_player_packet->set_index(index); + hear_player_packet->set_text(message); + + return packet; +} + +static proto::packet make_chunk_packet(const world::chunk& chunk) noexcept { + return chunk.packet; +} + +static void block_by_tickrate() noexcept { + const auto tickrate = server::state.tickrate; + static const auto ratetime = std::chrono::milliseconds( + static_cast((1.0 / static_cast(tickrate)) * 1000.0)); + static auto prev = std::chrono::steady_clock::now(); + const auto now = std::chrono::steady_clock::now(); + std::this_thread::sleep_for(ratetime - (now - prev)); + prev = std::chrono::steady_clock::now(); +} + +// Creates, binds, listens on new nonblocking socket. +static int create_listen_socket(const std::string_view address, + const std::string_view port) noexcept { + constexpr addrinfo hints = {.ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM}; + const auto info = shared::net::get_addr_info(address, port, &hints); + const auto sock = shared::net::make_socket(info.get()); + shared::net::bind_socket(sock, info.get()); + shared::net::listen_socket(sock); + return sock; +} + +// Gets new connections if possible based on non-blocking listener socket. +static std::optional make_connection(const int sock) { + const auto accept = shared::net::get_accept(sock); + if (!accept.has_value()) { + return std::nullopt; + } + return shared::net::connection(accept->socket); +} + +static void handle_move_packet(const proto::move& packet, + resources::client_map_value& client) noexcept { + client->get_player().viewangles = {.pitch = packet.viewangles().pitch(), + .yaw = packet.viewangles().yaw()}; + client->get_player().commands = packet.commands(); +} + +static void handle_say_packet(const proto::say& packet, + resources::client_map_value& client, + server::resources::client_map& clients) noexcept { + if (std::size(packet.text()) > shared::MAX_SAY_LENGTH) { +#ifndef NDEBUG + shared::print::warn( + "server: client tried to say a message that was too long, size: " + + std::to_string(std::size(packet.text())) + '\n'); + +#endif + return; + } + + shared::print::message("server: player " + std::to_string(client->index) + + " said \"" + packet.text() + "\"\n"); + const auto hear_packet = make_hear_packet(packet.text(), client->index); + for (auto& [index, client_ptr] : clients) { + client_ptr->connection.rsend_packet(hear_packet); + } +} + +static void send_chunk(const server::world::chunk& chunk, + resources::client_map_value& client) noexcept { + client->connection.rsend_packet(make_chunk_packet(chunk)); +} + +static void send_message(const std::string& message, + resources::client_map_value& client, + const bool fatal = false) { + client->connection.rsend_packet(make_server_message_packet(message, fatal)); +} + +static void send_chunk_associated(resources::chunk_map_value& chunk_data, + resources::client_map& clients) noexcept { + if (!chunk_data->has_initialised()) { + return; + } + + chunk_data->get_chunk().update(); + for (auto& client_index : chunk_data->players) { + const auto find_it = clients.find(client_index); + + // Should NEVER happen. If this occurs our clients are not cleaning up + // correctly. + if (find_it == std::end(clients)) { +#ifndef NDEBUG + shared::print::debug( + "client index " + std::to_string(client_index) + + " was associated with a chunk, but not found\n"); +#endif + continue; + } + + auto& client = find_it->second; + send_chunk(chunk_data->get_chunk(), client); + } +} + +// Checks if a chunk should be removed, posting it's async writing and +// possible removal if it should. +static void maybe_post_chunk_rm(const shared::math::coords& coords, + resources::chunk_map_value& chunk_data, + resources::pool_t& pool) noexcept { + // Chunk is in a state of contructing/destructing, do not touch. + if (!chunk_data->has_initialised()) { + return; + } + + // Players are still associated with the chunk, do not touch. + if (std::size(chunk_data->players) > 0) { + return; + } + + // Nobody is associated with the chunk and it should be removed. + boost::asio::post( + pool, std::bind( + [](const shared::math::coords coords, + std::shared_ptr chunk) { + chunk->write(); + + auto res_lock = resources::get_resources_lock(); + const auto find_it = res_lock->chunks.find(coords); + if (find_it == std::end(res_lock->chunks)) { + return; + } + auto& chunk_data = find_it->second; + + // Two possible states here! + // The chunk still has people associated, meaning someone + // has requested the chunk while we were writing it. + // Put the chunk back, and send out the old chunk to the + // new clients. + if (std::size(chunk_data->players) > 0) { + chunk_data->chunk.emplace(std::move(chunk)); + send_chunk_associated(chunk_data, res_lock->clients); + return; + } + + res_lock->chunks.erase(find_it); + }, + coords, std::move(*chunk_data->chunk))); + chunk_data->chunk.reset(); // std::move is not an implicit .reset() +} + +// We don't send off our chunk immediately here because generating chunks are +// expensive - we defer it later as it gets added to a threadpool. +static void handle_request_chunk_packet(const proto::request_chunk& packet, + resources::client_map_value& client, + resources::chunk_map& chunks, + resources::pool_t& pool) noexcept { + const shared::math::coords coords{packet.chunk_pos().x(), + packet.chunk_pos().z()}; + + if (const auto find_it = chunks.find(coords); find_it != std::end(chunks)) { + auto& chunk_data = find_it->second; + resources::associate_client_chunk(coords, client, chunk_data); + boost::asio::post( + pool, + std::bind( + [](const shared::math::coords coords, + const shared::player::index_t index) { + auto res_lock = resources::get_resources_lock(); + auto& chunk_data = res_lock->chunks.find(coords)->second; + + if (!chunk_data->has_initialised()) { + return; // will be sent on construction + } + + const auto& client_it = res_lock->clients.find(index); + if (client_it == std::end(res_lock->clients)) { + return; + } + auto& client = client_it->second; + send_chunk(chunk_data->get_chunk(), client); + maybe_post_chunk_rm(coords, chunk_data, res_lock->pool); + }, + coords, client->index)); + + return; + } + + auto& data = chunks + .emplace(coords, std::make_unique( + chunk_data{.chunk = std::nullopt})) + .first->second; + resources::associate_client_chunk(coords, client, data); + + boost::asio::post( + pool, + std::bind( + [](const shared::math::coords coords) { + server::world::chunk chunk{server::state.seed, coords}; + + auto res_lock = resources::get_resources_lock(); + auto& chunk_data = res_lock->chunks.find(coords)->second; + chunk_data->chunk.emplace( + std::make_unique(std::move(chunk))); + send_chunk_associated(chunk_data, res_lock->clients); + maybe_post_chunk_rm(coords, chunk_data, res_lock->pool); + }, + coords)); +} + +// Disassociates a client with a chunk, while performing necessary cleanups. +static void disassociate_client_coords(const shared::math::coords& coords, + resources::client_map_value& client, + resources::chunk_map& chunks, + resources::pool_t& pool) noexcept { + // Disassociate client with chunk. + client->chunks.erase(coords); + + // Disassociate chunk with client. + const auto find_it = chunks.find(coords); + if (find_it == std::end(chunks)) { + return; + } + auto& chunk_data = find_it->second; + chunk_data->players.erase(client->index); + + // Potentially remove the chunk from the chunks (if necessary). + maybe_post_chunk_rm(coords, chunk_data, pool); +} + +// Our client tells us if they removed a chunk. +// This system could be abused to blow up our memory, so we set a hard +// limit for the amount of chunks a player may have associated. +static void handle_remove_chunk_packet(const proto::remove_chunk& packet, + resources::client_map_value& client, + resources::chunk_map& chunks, + resources::pool_t& pool) noexcept { + const shared::math::coords coords{packet.chunk_pos().x(), + packet.chunk_pos().z()}; + disassociate_client_coords(coords, client, chunks, pool); +} + +static void post_chunk_update(const shared::math::coords& coords, + resources::pool_t& pool) noexcept { + boost::asio::post( + pool, std::bind( + [](const shared::math::coords coords) { + auto res_lock = resources::get_resources_lock(); + const auto find_it = res_lock->chunks.find(coords); + if (find_it == std::end(res_lock->chunks)) { + return; + } + auto& chunk_data = find_it->second; + send_chunk_associated(chunk_data, res_lock->clients); + }, + coords)); +} + +static void modify_block(const enum shared::world::block::type block_type, + const glm::ivec3& block_pos, + const shared::math::coords& coords, + resources::chunk_map& chunks) noexcept { + + const auto find_it = chunks.find(coords); + if (find_it == std::end(chunks)) { + return; + } + + if (shared::world::chunk::is_outside_chunk(block_pos)) { + return; + } + + auto& chunk_data = find_it->second; + if (!chunk_data->has_initialised()) { + return; + } + + chunk_data->get_chunk().get_block(block_pos) = block_type; + chunk_data->get_chunk().arm_should_update(); +} + +static void +handle_add_block_packet(const proto::add_block& packet, + [[maybe_unused]] resources::client_map_value& client, + server::resources::chunk_map& chunks, + resources::pool_t& pool) noexcept { + const shared::math::coords coords{packet.chunk_pos().x(), + packet.chunk_pos().z()}; + const glm::ivec3 block_pos{packet.block_pos().x(), packet.block_pos().y(), + packet.block_pos().z()}; + const auto block = + static_cast(packet.block()); + modify_block(block, block_pos, coords, chunks); + post_chunk_update(coords, pool); +} + +static void +handle_remove_block_packet(const proto::remove_block& packet, + [[maybe_unused]] resources::client_map_value& client, + resources::chunk_map& chunks, + resources::pool_t& pool) noexcept { + const shared::math::coords coords{packet.chunk_pos().x(), + packet.chunk_pos().z()}; + const glm::ivec3 block_pos{packet.block_pos().x(), packet.block_pos().y(), + packet.block_pos().z()}; + modify_block(shared::world::block::type::air, block_pos, coords, chunks); + post_chunk_update(coords, pool); +} + +static void handle_auth_packet(const proto::auth& packet, + resources::client_map_value& client, + resources::pool_t& pool) noexcept { + boost::asio::post( + pool, + std::bind( + [](const resources::client_map_key client_index, + const std::string user, const std::string pass) { + const auto db_plr = database::maybe_read_player(user); + + auto res_lock = resources::get_resources_lock(); + const auto find_it = res_lock->clients.find(client_index); + if (find_it == std::end(res_lock->clients)) { + return; + } + auto& client = find_it->second; + + // find if we're already associated, eventually kick our client + // it would be nice if this wasn't a find_if + if (std::find_if(std::begin(res_lock->clients), + std::end(res_lock->clients), + [&](const auto& it) { + auto& client = it.second; + if (!client->has_initialised()) { + return false; + } + return client->index != client_index && + client->get_username() == user; + }) != std::end(res_lock->clients)) { + + client->disconnect_reason.emplace("user already in server"); + return; + } + + struct client::player_info player_info { + .username = user, .password = pass + }; + if (db_plr.has_value()) { + auto& [player, db_password] = *db_plr; + + if (db_password != pass) { + client->disconnect_reason.emplace("bad password"); + return; + } + + player_info.player = shared::net::get_player(player); + player_info.player.index = client_index; + } else { + // TODO: Find a random spawn chunk and put the player + // on the highest block. Because we don't want to gen chunks + // while blocking, we can't do this here. For now, we'll + // just put the player at a high spot. + player_info.player = + shared::player{.index = client_index, + .local_pos = {0.0f, 140.0f, 0.0f}}; + } + client->player_info.emplace( + std::make_shared( + std::move(player_info))); + + client->connection.rsend_packet(make_init_packet(client)); + }, + client->index, std::move(packet.username()), + std::move(packet.password()))); +} + +// Get new packets from clients, this will change client data and worldata. +static void parse_client_packets(resources::client_map_value& client, + resources::resources& res) noexcept { + while (auto packet = client->connection.recv_packet()) { + if (packet->has_auth_packet()) { + handle_auth_packet(packet->auth_packet(), client, res.pool); + } else if (packet->has_move_packet()) { + handle_move_packet(packet->move_packet(), client); + } else if (packet->has_say_packet()) { + handle_say_packet(packet->say_packet(), client, res.clients); + } else if (packet->has_request_chunk_packet()) { + handle_request_chunk_packet(packet->request_chunk_packet(), client, + res.chunks, res.pool); + } else if (packet->has_remove_chunk_packet()) { + handle_remove_chunk_packet(packet->remove_chunk_packet(), client, + res.chunks, res.pool); + } else if (packet->has_add_block_packet()) { + handle_add_block_packet(packet->add_block_packet(), client, + res.chunks, res.pool); + } else if (packet->has_remove_block_packet()) { + handle_remove_block_packet(packet->remove_block_packet(), client, + res.chunks, res.pool); + } +#ifndef NDEBUG + else { + shared::print::warn("server: unhandled packet type\n"); + } +#endif + } +} + +[[maybe_unused]] // [[actually_used]] +static void +send_remove_packets(server::resources::client_map_value& remove_client, + server::resources::client_map& clients) noexcept { + const auto remove_packet = make_remove_packet(remove_client); + for (auto& [index, client_ptr] : clients) { + client_ptr->connection.rsend_packet(remove_packet); + } +} + +static void handle_new_connections(shared::net::connection& connection, + resources::resources& res) noexcept { + shared::print::message("server: got connection from " + + connection.get_address() + '\n'); + + // Add the client, waiting for an auth packet. + static uint32_t index = 0; + res.clients.insert_or_assign(index, server::resources::client_map_value{ + std::make_unique( + std::move(connection), index)}); + ++index; +} + +static void move_client(resources::client_map_value& client, + resources::chunk_map& chunks) noexcept { + // shared::movement::fly(client.player, client.commands); + movement::move(*client, chunks); +} + +static void send_client_packets(resources::client_map_value& client, + resources::resources& res) noexcept { + // TODO PVS, as simple as checking if a client has our chunk pos in their + // associated chunks list + for (auto& [index, c] : res.clients) { + if (!c->has_initialised()) { + continue; + } + if (!client->chunks.contains(c->get_player().chunk_pos)) { + continue; + } + + client->connection.usend_packet(make_player_packet(c->get_player())); + } +} + +// returns a dc reason that will be printed and sent to the client +[[maybe_unused]] std::optional +get_sent_disconnect_reason(const resources::client_map_value& client) noexcept { + if (!client->connection.good()) { + return client->connection.get_bad_reason(); + } + + if (client->chunks.size() > + unsigned(state.draw_distance * state.draw_distance * 4)) { + return "too many chunks associated with client"; + } + + return client->disconnect_reason; +} + +static void remove_bad_clients(resources::resources& res) noexcept { + for (auto& [index, client] : res.clients) { + const auto reason = get_sent_disconnect_reason(client); + if (reason == std::nullopt) { + continue; + } + + if (client->disconnecting) { + continue; + } + client->disconnecting = true; + + shared::print::message("server: dropped " + + client->connection.get_address() + " for \"" + + *reason + "\"\n"); + send_message("disconnected for " + *reason, client, true); + send_remove_packets(client, res.clients); + + boost::asio::post( + res.pool, + std::bind( + [](const auto rm_coords, + const resources::client_map_key client_index, + const decltype(client::player_info) plr_info) { + // Write the player to the db before we do any locks. + if (plr_info.has_value()) { + database::write_player( + (*plr_info)->username, (*plr_info)->password, + make_player_packet((*plr_info)->player) + .player_packet()); + } + + // cleanup associated chunks + for (const auto& coords : rm_coords) { + auto res_lock = resources::get_resources_lock(); + + const auto find_it = res_lock->chunks.find(coords); + if (find_it == std::end(res_lock->chunks)) { + return; + } + auto& chunk_data = find_it->second; + chunk_data->players.erase(client_index); + + maybe_post_chunk_rm(coords, chunk_data, res_lock->pool); + } + + // final cleanup, now we may reconnect + resources::get_resources_lock()->clients.erase( + client_index); + }, + std::move(client->chunks), client->index, + std::move(client->player_info))); + client->chunks.clear(); // just being explicit + client->player_info.reset(); + } +} + +static void process_resources(resources::resources& res) noexcept { + // Get new packets from clients. The contents of these packets will + // determine how the world + client data changes. + for (auto& [index, client] : res.clients) { + parse_client_packets(client, res); + } + + // Move clients via their (hopefully updated) command. + for (auto& [index, client] : res.clients) { + move_client(client, res.chunks); + } + + // Send packets which are sent once per tick, as of now the player + // struct of other clients. + for (auto& [index, client] : res.clients) { + send_client_packets(client, res); + } + + // Delete bad connections, print if it happens. Also sends a remove + // to all clients per client removed. + remove_bad_clients(res); +} + +void main(const std::string_view address, const std::string_view port) { + const auto rsock = create_listen_socket(address, port); // reliable socket + + server::resources::init(); + has_initialised = true; + shared::print::notify("server: started at " + std::string{address} + ':' + + std::string{port} + '\n'); + + // Server has a tickrate, we will use non-blocking polling at this + // tickrate. + for (; !shared::should_exit; block_by_tickrate()) { + // Lock resources with a higher priority than work on the pool + auto resources_lock = server::resources::get_resources_lock_immediate(); + + // Get new connections and add them to our clients map. + while (auto connection = make_connection(rsock)) { + handle_new_connections(connection.value(), *resources_lock); + } + + // Process data from resources including client packets, chunk + // updates, etc. + process_resources(*resources_lock); + } + + // Cleanup of clients. + { + auto res_lock = resources::get_resources_lock(); + std::ranges::for_each(res_lock->clients, [](const auto& it) { + const auto& client = it.second; + client->disconnect_reason.emplace("server shutting down"); + }); + remove_bad_clients(*res_lock); + } + + shared::print::notify("server: writing world data\n"); + server::resources::quit(); + shared::print::notify("server: gracefully exited\n"); +} + +} // namespace server diff --git a/src/server/server.hh b/src/server/server.hh new file mode 100644 index 0000000..bd2d5fd --- /dev/null +++ b/src/server/server.hh @@ -0,0 +1,37 @@ +#ifndef SERVER_SERVER_HH_ +#define SERVER_SERVER_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "server/client.hh" +#include "server/database.hh" +#include "server/movement.hh" +#include "server/resources.hh" +#include "server/world.hh" +#include "shared/net/net.hh" +#include "shared/net/proto.hh" +#include "shared/player.hh" +#include "shared/shared.hh" + +namespace server { +inline std::atomic has_initialised; + +void main(const std::string_view address, const std::string_view port); +} // namespace server + +#endif diff --git a/src/server/shared.cc b/src/server/shared.cc new file mode 100644 index 0000000..fbdbcaa --- /dev/null +++ b/src/server/shared.cc @@ -0,0 +1 @@ +#include "server/shared.hh" diff --git a/src/server/shared.hh b/src/server/shared.hh new file mode 100644 index 0000000..ffbf0f9 --- /dev/null +++ b/src/server/shared.hh @@ -0,0 +1,19 @@ +#ifndef SERVER_SHARED_HH_ +#define SERVER_SHARED_HH_ + +#include +#include + +namespace server { + +struct state { + int draw_distance = 32; + std::uint64_t seed = 123456789; + std::string directory = "world/"; + std::uint32_t tickrate = 144; +}; +inline state state; + +} // namespace server + +#endif diff --git a/src/server/world.cc b/src/server/world.cc new file mode 100644 index 0000000..6527d6c --- /dev/null +++ b/src/server/world.cc @@ -0,0 +1,53 @@ +#include "server/world.hh" + +namespace server { +namespace world { + +proto::packet chunk::make_chunk_packet() const noexcept { + + proto::packet ret_packet; + + auto chunk_packet = ret_packet.mutable_chunk_packet(); + + auto chunk_pos = chunk_packet->mutable_chunk_pos(); + const shared::math::coords this_chunk_pos = this->get_pos(); + chunk_pos->set_x(this_chunk_pos.x); + chunk_pos->set_z(this_chunk_pos.z); + + // Since protobuf can store at minimum uint32, we mash four of our + // uint_8 chunk blocks into a single uint32. + static_assert(shared::world::chunk::VOLUME % 4 == 0); + for (unsigned i = 0u; i < shared::world::chunk::VOLUME / 4u; ++i) { + std::uint32_t packed_blocks = 0u; + + for (unsigned j = 0; j < 4; ++j) { + const auto block = + static_cast(this->blocks[i * 4 + j].type); + packed_blocks |= static_cast(block << j * 8); + } + + chunk_packet->add_blocks(packed_blocks); + } + + return ret_packet; +} + +static std::optional +maybe_get_blocks(const shared::math::coords& coords) { + const auto chunk = database::maybe_read_chunk(coords); + if (!chunk.has_value()) { + return std::nullopt; + } + return shared::world::chunk::make_blocks_from_chunk(chunk.value()); +} + +chunk::chunk(const std::uint64_t& seed, + const shared::math::coords& coords) noexcept + : shared::world::chunk(seed, coords, maybe_get_blocks(coords)) { + this->update(); +} + +chunk::~chunk() noexcept { this->write(); } + +} // namespace world +} // namespace server diff --git a/src/server/world.hh b/src/server/world.hh new file mode 100644 index 0000000..134f63b --- /dev/null +++ b/src/server/world.hh @@ -0,0 +1,59 @@ +#ifndef SERVER_WORLD_HH_ +#define SERVER_WORLD_HH_ + +#include + +#include "server/database.hh" +#include "server/shared.hh" +#include "shared/math.hh" +#include "shared/net/net.hh" +#include "shared/net/proto.hh" +#include "shared/player.hh" +#include "shared/world.hh" + +namespace server { +namespace world { + +class chunk : public shared::world::chunk { +private: + bool should_write = false; + bool should_update = true; + +public: + proto::packet packet; // Packet ready for sending, updated in update(). + void arm_should_update() noexcept { + this->should_update = this->should_write = true; + } + bool get_should_update() noexcept { return this->should_update; } + +private: + proto::packet make_chunk_packet() const noexcept; + +public: + // Attempt to read the file using protobuf, otherwise create a new chunk. + // chunk(const chunk&) = delete; + chunk(const uint64_t& seed, const shared::math::coords& coords) noexcept; + ~chunk() noexcept; + + // Update the chunk_packet associated with the chunk if necessary. + void update() noexcept { + if (!this->should_update) { + return; + } + this->packet = make_chunk_packet(); + this->should_update = false; + } + // calling .write before the destrutor will not result in a double write + void write() noexcept { + if (!this->should_write) { + return; + } + server::database::write_chunk(this->pos, this->packet.chunk_packet()); + this->should_write = false; + } +}; + +} // namespace world +} // namespace server + +#endif diff --git a/src/shared/math.cc b/src/shared/math.cc new file mode 100644 index 0000000..80eba81 --- /dev/null +++ b/src/shared/math.cc @@ -0,0 +1,23 @@ +#include "shared/math.hh" + +namespace shared { +namespace math { + +glm::vec3 angle_to_dir(const angles& ang) noexcept { + const float x = std::cos(ang.pitch) * std::cos(ang.yaw); + const float y = std::sin(ang.pitch); + const float z = std::cos(ang.pitch) * std::sin(ang.yaw); + return {x, y, z}; +} + +bool is_inside_draw(const coords& a, const coords& b, + const std::int32_t draw_distance) noexcept { + const auto x2 = (a.x - b.x) * (a.x - b.x); + const auto z2 = (a.z - b.z) * (a.z - b.z); + const auto dd2 = draw_distance * draw_distance; + + return (x2 < dd2 - z2) && (z2 < dd2 - x2); +} + +} // namespace math +} // namespace shared diff --git a/src/shared/math.hh b/src/shared/math.hh new file mode 100644 index 0000000..5f03ab4 --- /dev/null +++ b/src/shared/math.hh @@ -0,0 +1,53 @@ +#ifndef SHARED_MATH_HH_ +#define SHARED_MATH_HH_ + +#include + +#include +#include +#include + +namespace shared { +namespace math { + +// 2D coordinates. +struct coords { + std::int32_t x; + std::int32_t z; + coords operator+(const coords& c) const noexcept { + auto ret = *this; + ret.x += c.x; + ret.z += c.z; + return ret; + } + coords operator-(const coords& c) const noexcept { + auto ret = *this; + ret.x -= c.x; + ret.z -= c.z; + return ret; + } + auto operator<=>(const coords& c) const noexcept = default; +}; + +struct angles { + float pitch; + float yaw; + angles operator+(const angles& a) const noexcept { + auto ret = *this; + ret.pitch += a.pitch; + ret.yaw += a.yaw; + return ret; + } +}; + +// Returns a vector pointing in the direction of pitch + yaw. +glm::vec3 angle_to_dir(const angles& ang) noexcept; + +bool is_inside_draw(const shared::math::coords& a, + const shared::math::coords& b, + const std::int32_t draw_distance) noexcept; + +} // namespace math +} // namespace shared + +#endif diff --git a/src/shared/movement.cc b/src/shared/movement.cc new file mode 100644 index 0000000..985062c --- /dev/null +++ b/src/shared/movement.cc @@ -0,0 +1,490 @@ +#include "shared/movement.hh" + +namespace shared { +namespace movement { + +// Move a player into the correct neighbour chunk if they go over a border. +static void shift_chunk(shared::player& player) noexcept { + const bool g_x = (player.local_pos.x >= shared::world::chunk::WIDTH); + const bool l_x = (player.local_pos.x < 0.0f); + const bool g_z = (player.local_pos.z >= shared::world::chunk::WIDTH); + const bool l_z = (player.local_pos.z < 0.0f); + + player.chunk_pos.x += g_x - l_x; + player.local_pos.x += shared::world::chunk::WIDTH * (l_x - g_x); + player.chunk_pos.z += g_z - l_z; + player.local_pos.z += shared::world::chunk::WIDTH * (l_z - g_z); +} + +constexpr float epsilon = 0.001f; // counteract arithmetic errors +constexpr float epsilon2 = epsilon + 2 * epsilon * epsilon; + +bool intersect_aabbs(const aabb& a, const aabb& b) noexcept { + if (a.max.x < b.min.x || a.min.x > b.max.x) { + return false; + } + if (a.max.y < b.min.y || a.min.y > b.max.y) { + return false; + } + if (a.max.z < b.min.z || a.min.z > b.max.z) { + return false; + } + return true; +} + +static glm::vec3 plane_to_normal(const int plane) { + glm::vec3 normal{0.0f, 0.0f, 0.0f}; + normal[std::abs(plane) - 1] = std::signbit(plane) ? -1.0f : 1.0f; + return normal; +} + +std::optional intersect_ray_aabb(const line& line, + const aabb& aabb) noexcept { + float tmin = -std::numeric_limits::max(); + float tmax = std::numeric_limits::max(); + + int p = 0; + for (int i = 0; i < 3; ++i) { + if (std::abs(line.dir[i]) < epsilon) { + + // Ray is parallel to slab, no hit if origin not within slab. + if (line.origin[i] < aabb.min[i] || line.origin[i] > aabb.max[i]) { + return std::nullopt; + } + + } else { + // Intersection t value of ray with near and far plane of slab. + const float ood = 1.0f / line.dir[i]; + float t1 = (aabb.min[i] - line.origin[i]) * ood; + float t2 = (aabb.max[i] - line.origin[i]) * ood; + + if (t1 > t2) { + std::swap(t1, t2); + } + auto old = tmin; + tmin = std::max(tmin, t1); + if (tmin != old) { + p = (i + 1); + } + tmax = std::min(tmax, t2); + if (tmin > tmax) { + return std::nullopt; + } + } + } + + if (tmin <= 0.0f) { + return std::nullopt; + } + + return ray_aabb_ret{.position = line.origin + line.dir * tmin, + .time = tmin, + .normal = plane_to_normal(p)}; +} + +std::optional +intersect_moving_aabbs(const moving_aabb& a, const moving_aabb& b) noexcept { + + if (intersect_aabbs(a.aabb, b.aabb)) { + return std::nullopt; + } + + const glm::vec3 velocity = b.velocity - a.velocity; + float tfirst = 0.0f; + float tlast = 10.0f; + int p = 0; + + for (int i = 0; i < 3; ++i) { + if (velocity[i] < 0.0f) { + if (b.aabb.max[i] < a.aabb.min[i]) { + return std::nullopt; + } + if (a.aabb.max[i] < b.aabb.min[i]) { + const auto old = tfirst; + tfirst = std::max((a.aabb.max[i] - b.aabb.min[i]) / velocity[i], + tfirst); + if (tfirst != old) { + p = (i + 1); + } + } + if (b.aabb.max[i] > a.aabb.min[i]) { + tlast = std::min((a.aabb.min[i] - b.aabb.max[i]) / velocity[i], + tlast); + } + } else if (velocity[i] > 0.0f) { + if (b.aabb.min[i] > a.aabb.max[i]) { + return std::nullopt; + } + if (b.aabb.max[i] < a.aabb.min[i]) { + const auto old = tfirst; + tfirst = std::max((a.aabb.min[i] - b.aabb.max[i]) / velocity[i], + tfirst); + if (tfirst != old) { + p = -(i + 1); + } + } + if (a.aabb.max[i] > b.aabb.min[i]) { + tlast = std::min((a.aabb.max[i] - b.aabb.min[i]) / velocity[i], + tlast); + } + } else { + if (b.aabb.max[i] < a.aabb.min[i] || + b.aabb.min[i] > a.aabb.max[i]) { + return std::nullopt; + } + } + if (tfirst > tlast) { + return std::nullopt; + } + } + /* + if (tfirst < 0.0f || tfirst > 1.0f) { + return std::nullopt; + } + */ + + return moving_aabb_ret{.time = tfirst, .normal = plane_to_normal(p)}; +} + +static std::optional +get_ground(const aabb& player_aabb, const std::vector blockinfos, + bool (*delimit)(const enum shared::world::block::type) = + shared::world::block::is_tangible) noexcept { + + const moving_aabb player_moving_aabb{.aabb = player_aabb, + .velocity = {0.0f, -1.0f, 0.0f}}; + for (const auto& block_aabb : blockinfos) { + + if (!delimit(block_aabb.block)) { + continue; + } + + const struct moving_aabb block_moving_aabb { + .aabb = block_aabb.aabb, .velocity = { 0.0f, 0.0f, 0.0f } + }; + + if (const auto intersect = + intersect_moving_aabbs(player_moving_aabb, block_moving_aabb); + intersect.has_value()) { + + if (intersect->time >= 1.0f) { + continue; + } + + if (intersect->time <= epsilon2) { + return block_aabb.block; + } + } + } + return std::nullopt; +} + +// Only returns ground if we can collide with it. +static std::optional +get_collidable_ground(const aabb& player_aabb, + const std::vector blockinfo) noexcept { + + return get_ground(player_aabb, blockinfo, + shared::world::block::is_collidable); +} + +// Recursively resolve collisions against blocks, up to n times. +static void resolve_collisions(shared::player& player, aabb player_aabb, + const std::vector& blockinfos, + const float deltatime, + const int n = 3) noexcept { + + const moving_aabb player_moving_aabb{ + .aabb = player_aabb, .velocity = player.velocity * deltatime}; + + std::optional> collision; + for (const auto& block_aabb : blockinfos) { + if (!shared::world::block::is_collidable(block_aabb.block)) { + continue; + } + + const struct moving_aabb block_moving_aabb { + .aabb = block_aabb.aabb, .velocity = { 0.0f, 0.0f, 0.0f } + }; + const auto intersect = + intersect_moving_aabbs(player_moving_aabb, block_moving_aabb); + + if (!intersect.has_value() || intersect->time > 1.0f) { + continue; + } + + // Update collision if it doesn't exist or if this one is closer. + if (!collision.has_value() || intersect->time < collision->first.time) { + + collision = std::make_pair(intersect.value(), block_aabb.block); + } + } + + // No more collisions :) + if (!collision.has_value()) { + player.local_pos += player.velocity * deltatime; + return; + } + + const glm::vec3 collision_pos = + collision->first.time * player.velocity * deltatime; + const glm::vec3 offset = collision->first.normal * epsilon; + const float backoff = glm::dot(player.velocity, collision->first.normal); + +#ifndef NDEBUG + // clang-format off + shared::print::debug("Collision with n = " + std::to_string(n) + "\n"); + shared::print::message(" Unresolved player position: {" + std::to_string(player.local_pos.x) + ", " + std::to_string(player.local_pos.y) + ", " + std::to_string(player.local_pos.z) + "}\n", false); + shared::print::message(" Unresolved player velocity: {" + std::to_string(player.velocity.x) + ", " + std::to_string(player.velocity.y) + ", " + std::to_string(player.velocity.z) + "}\n", false); + shared::print::message(" Collision delta vector: {" + std::to_string(collision_pos.x) + ", " + std::to_string(collision_pos.y) + ", " + std::to_string(collision_pos.z) + "}\n", false); + shared::print::message(" Backoff: " + std::to_string(backoff) + "\n", false); + shared::print::message(" On ground before collision: " + std::to_string(get_collidable_ground(player_aabb, blockinfos).has_value()) + "\n", false); + shared::print::message(" Collision normal: {" + std::to_string(collision->first.normal.x) + ", " + std::to_string(collision->first.normal.y) + ", " + std::to_string(collision->first.normal.z) + "}\n", false); + // clang-format on +#endif + + // Quake engine's reflect velocity. + for (int i = 0; i < 3; ++i) { + player.velocity[i] -= collision->first.normal[i] * backoff; + if (std::abs(player.velocity[i]) <= epsilon) { + player.velocity[i] = 0.0f; + } + if (std::abs(collision_pos[i]) <= epsilon2) { + +#ifndef NDEBUG + shared::print::message( + " Ignored axis: " + std::to_string(i) + "\n", false); +#endif + + continue; + } + player.local_pos[i] += collision_pos[i] - offset[i]; + player_aabb.min[i] += collision_pos[i] - offset[i]; + player_aabb.max[i] += collision_pos[i] - offset[i]; + } + +#ifndef NDEBUG + // clang-format off + shared::print::message(" Resolved player position: {" + std::to_string(player.local_pos.x) + ", " + std::to_string(player.local_pos.y) + ", " + std::to_string(player.local_pos.z) + "}\n", false); + shared::print::message(" Resolved player velocity: {" + std::to_string(player.velocity.x) + ", " + std::to_string(player.velocity.y) + ", " + std::to_string(player.velocity.z) + "}\n", false); + shared::print::message(" On ground after collision: " + std::to_string(get_collidable_ground(player_aabb, blockinfos).has_value()) + "\n", false); + // clang-format on +#endif + + if (n <= 0) { + return; + } + resolve_collisions(player, player_aabb, blockinfos, + deltatime - collision->first.time * deltatime, n - 1); +} + +// Returns the highest friction value of a block that intersects an aabb. +static std::optional +get_intersect_friction(const aabb& aabb, + const std::vector& blockinfos) noexcept { + std::optional greatest_friction; + for (const auto& block_aabb : blockinfos) { + if (!intersect_aabbs(aabb, block_aabb.aabb)) { + continue; + } + const float friction = + shared::world::block::get_friction(block_aabb.block); + + if (!greatest_friction.has_value() || + friction > greatest_friction.value()) { + + greatest_friction = friction; + } + } + + return greatest_friction; +} + +// In air is slightly more complicated becase of edge cases involving water. +static bool is_in_air( + const aabb& aabb, const std::vector& blockinfos, + const std::optional& collidable_ground) noexcept { + if (!std::all_of(std::begin(blockinfos), std::end(blockinfos), + [&aabb](const auto& ba) { + if (!intersect_aabbs(aabb, ba.aabb)) { + return true; + } + return !shared::world::block::is_tangible(ba.block); + })) { + return false; + } + if (collidable_ground.has_value()) { + return false; + } + return true; +} + +static bool is_in_liquid(const aabb& aabb, + const std::vector& blockinfos) noexcept { + return std::any_of(std::begin(blockinfos), std::end(blockinfos), + [&aabb](const auto& ba) { + if (!intersect_aabbs(aabb, ba.aabb)) { + return false; + } + return shared::world::block::is_liquid(ba.block); + }); +} + +static bool +can_jump(const std::optional& collidable_ground, + const bool in_liquid) noexcept { + if (collidable_ground.has_value()) { + return true; + } + if (in_liquid) { + return true; + } + return false; +} + +// Move state is a cache of expensive operations that we use more than once. +struct move_state { + std::optional ground; + std::optional collidable_ground; + bool is_in_air; + bool is_in_liquid; + bool can_jump; +}; +static move_state +make_move_state(const aabb& player_aabb, + const std::vector& blockinfos) noexcept { + + const auto get_ground_ret = get_ground(player_aabb, blockinfos); + const auto get_collidable_ground_ret = + get_collidable_ground(player_aabb, blockinfos); + const bool is_in_air_ret = + is_in_air(player_aabb, blockinfos, get_collidable_ground_ret); + const bool is_in_liquid_ret = is_in_liquid(player_aabb, blockinfos); + const bool can_jump_ret = + can_jump(get_collidable_ground_ret, is_in_liquid_ret); + + return {.ground = get_ground_ret, + .collidable_ground = get_collidable_ground_ret, + .is_in_air = is_in_air_ret, + .is_in_liquid = is_in_liquid_ret, + .can_jump = can_jump_ret}; +} + +static float get_jump_magnitude(const shared::player& player, const aabb& aabb, + const std::vector& blockinfos, + const struct move_state& move_state) noexcept { + if (!move_state.can_jump) { + return 0.0f; + } + if (move_state.is_in_liquid) { + const struct aabb jump_aabb = { + .min = glm::vec3{0.0f, aabb.min.y + aabb.max.y / 5.0f, 0.0f}, + .max = aabb.max}; + if (player.velocity.y > 0.0f && + is_in_air(jump_aabb, blockinfos, + get_collidable_ground(jump_aabb, blockinfos))) { + return 1.0f; + } + return 0.5f; + } + if (player.velocity.y < 0.0f) { + return 0.0f; + } + return 8.0f; +} + +void move(shared::player& player, const std::vector& blockinfos, + const float deltatime) noexcept { + + constexpr glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); + const glm::vec3 front = shared::math::angle_to_dir(player.viewangles); + const glm::vec3 right = glm::normalize(glm::cross(front, up)); + + constexpr aabb player_aabb = {.min = {-shared::player::HALFWIDTH + epsilon, + 0.0f + epsilon, + -shared::player::HALFWIDTH + epsilon}, + .max = {shared::player::HALFWIDTH - epsilon, + shared::player::HEIGHT - epsilon, + shared::player::HALFWIDTH - epsilon}}; + + const auto move_state = make_move_state(player_aabb, blockinfos); + + // Some of velocity we want to add or remove should be scaled by our + // tickrate (eg, walking), while others such as jumping should not. + + const glm::vec3 scaled_acceleration = [&]() -> glm::vec3 { + glm::vec3 acceleration = {0.0f, 0.0f, 0.0f}; + if (player.commands & shared::player::mask::forward) { + acceleration += front; + } + if (player.commands & shared::player::mask::left) { + acceleration -= right; + } + if (player.commands & shared::player::mask::backward) { + acceleration -= front; + } + if (player.commands & shared::player::mask::right) { + acceleration += right; + } + acceleration.y = 0.0f; + if (acceleration != glm::vec3{}) { + acceleration = glm::normalize(acceleration); + } + acceleration *= 1.75f; + if (player.commands & shared::player::mask::sprint) { + acceleration *= 1.25f; + } + + // Increase movement when on the ground - heavily reduced with friction. + if (!move_state.is_in_air) { + acceleration *= 30.0f; + } + + // Gravity. + if (!move_state.collidable_ground.has_value()) { + acceleration -= 25.0f * up; + } + + return acceleration; + }(); + + const glm::vec3 constant_acceleration = [&]() -> glm::vec3 { + glm::vec3 acceleration = {0.0f, 0.0f, 0.0f}; + // Jumping - we have to adjust our magnitude based on our environment. + // Technically swimming is just lots of small jumps. + if (player.commands & shared::player::mask::jump) { + acceleration += get_jump_magnitude(player, player_aabb, blockinfos, + move_state) * + up; + } + return acceleration; + }(); + + // Our deceleration is the max friction of what we're in and what we're on. + const glm::vec3 scaled_deceleration = [&]() -> glm::vec3 { + const auto drag = get_intersect_friction(player_aabb, blockinfos); + + float max_friction = 0.0f; + if (move_state.collidable_ground.has_value()) { + const float friction = shared::world::block::get_friction( + move_state.collidable_ground.value()); + if (drag.has_value()) { + max_friction = std::max(friction, drag.value()); + } + } else if (drag.has_value()) { + max_friction = drag.value(); + } + + return player.velocity * max_friction; + }(); + + player.velocity += (scaled_acceleration - scaled_deceleration) * deltatime; + player.velocity += constant_acceleration; + + resolve_collisions(player, player_aabb, blockinfos, deltatime); + + shift_chunk(player); +} + +} // namespace movement +} // namespace shared diff --git a/src/shared/movement.hh b/src/shared/movement.hh new file mode 100644 index 0000000..375c030 --- /dev/null +++ b/src/shared/movement.hh @@ -0,0 +1,67 @@ +#ifndef SHARED_MOVEMENT_HH_ +#define SHARED_MOVEMENT_HH_ + +#include "shared/math.hh" +#include "shared/player.hh" +#include "shared/shared.hh" +#include "shared/world.hh" + +#include +#include + +#include +#include + +namespace shared { +namespace movement { + +struct aabb { + glm::vec3 min; + glm::vec3 max; +}; +bool intersect_aabbs(const aabb& a, const aabb& b) noexcept; + +struct line { + glm::vec3 origin; + glm::vec3 dir; +}; +struct ray_aabb_ret { + glm::vec3 position; + float time; + glm::vec3 normal; +}; +std::optional intersect_ray_aabb(const line& line, + const aabb& aabb) noexcept; +struct moving_aabb { + struct aabb aabb; + glm::vec3 velocity; +}; +struct moving_aabb_ret { + float time; + glm::vec3 normal; +}; +std::optional +intersect_moving_aabbs(const moving_aabb& a, const moving_aabb& b) noexcept; + +// A block with a bit more info. +struct blockinfo { + shared::world::block block; + struct aabb aabb; + shared::math::coords chunk_pos; + glm::ivec3 pos; +}; +// /WE/ should use this function to generate our blockdatas. +constexpr int move_width = + static_cast(1.0f + 2 * shared::player::HALFWIDTH + 1.0f); +constexpr int move_height = static_cast(1.0f + shared::player::HEIGHT); + +// Walking a player is fairly complicated, and requires a std::vector of +// blockdata that represents all the blocks near a player. +// TODO provide an additional deltatime arugment to enable prediction. +void move(shared::player& player, const std::vector& blockinfos, + const float deltatime) noexcept; + +} // namespace movement +} // namespace shared + +#endif diff --git a/src/shared/net/connection.cc b/src/shared/net/connection.cc new file mode 100644 index 0000000..79a83f5 --- /dev/null +++ b/src/shared/net/connection.cc @@ -0,0 +1 @@ +#include "shared/net/connection.hh" diff --git a/src/shared/net/connection.hh b/src/shared/net/connection.hh new file mode 100644 index 0000000..79146af --- /dev/null +++ b/src/shared/net/connection.hh @@ -0,0 +1,212 @@ +#ifndef SHARED_NET_CONNECTION_HH_ +#define SHARED_NET_CONNECTION_HH_ + +#include +#include +#include + +#include "shared/net/net.hh" +#include "shared/net/proto.hh" + +namespace shared { +namespace net { + +class connection { +private: + struct sockets { + int rsock; + int usock; // connected in constructor, no need to use sendto or revfrom + std::string address; + std::string port; + + sockets(const int r, const int u, const std::string& a, + const std::string& p) + : rsock(r), usock(u), address(a), port(p) {} + }; + std::optional socks; + std::optional bad_reason; + +private: + struct packet_header { + std::uint32_t size; + }; + + // Data has a non-serialised header, and variable length serialised + // protobuf content. + static std::string packet_to_data(const proto::packet& packet) { + + std::string data; + packet.SerializeToString(&data); + shared::compress_string(data); + + packet_header header{.size = htonl(static_cast( + std::size(data) + sizeof(packet_header)))}; + + return std::string{reinterpret_cast(&header), + reinterpret_cast(&header) + sizeof(header)} + + std::move(data); + } + + void send_sock_packet(const int sock, const proto::packet& packet) { + if (!this->good()) { + return; + } + + const std::string data = packet_to_data(packet); + + if (send(sock, std::data(data), std::size(data), 0) == -1) { + this->bad_reason = shared::net::get_errno_error(); + } + } + +public: + connection(const int rsock) { + using namespace shared::net; + + const std::string peer_address = get_socket_peer_address(rsock); + const std::string peer_port = get_socket_peer_port(rsock); + + // Open up a connected usock based on the state of the connected rsock. + const int usock = [&peer_address, &peer_port, &rsock]() -> int { + constexpr addrinfo hints = {.ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_DGRAM}; + const std::string host_address = get_socket_host_address(rsock); + const std::string host_port = get_socket_host_port(rsock); + const auto host_info = + get_addr_info(host_address, host_port, &hints); + const int usock = make_socket(host_info.get()); + bind_socket(usock, host_info.get()); + + const auto peer_info = + get_addr_info(peer_address, peer_port, &hints); + connect_socket(usock, peer_info.get()); + + return usock; + }(); + + nonblock_socket(usock); + nonblock_socket(rsock); + + this->socks.emplace(rsock, usock, peer_address, peer_port); + } + + // We do not want to copy this object! + // We use std::nullopt to determine if this object has been moved and if we + // should close its sockets. + connection(const connection&) = delete; + connection(connection&& other) noexcept { + std::swap(this->socks, other.socks); + std::swap(this->bad_reason, other.bad_reason); + other.socks.reset(); + } + connection& operator=(connection&& other) noexcept { + std::swap(this->socks, other.socks); + std::swap(this->bad_reason, other.bad_reason); + other.socks.reset(); + return *this; + } + ~connection() noexcept { + if (this->socks.has_value()) { + shared::net::close_socket(socks->rsock); + shared::net::close_socket(socks->usock); + } + } + + // Getters. + bool good() const noexcept { return !bad_reason.has_value(); } + std::string get_bad_reason() const noexcept { + return this->bad_reason.value(); + } + std::string get_address() const noexcept { return this->socks->address; } + +public: + // Send does nothing if good() returns false! + // Returns whether or not we were able to send our packet. + void rsend_packet(const proto::packet& packet) noexcept { + return send_sock_packet(this->socks->rsock, packet); + } + void usend_packet(const proto::packet& packet) noexcept { + return send_sock_packet(this->socks->usock, packet); + } + std::optional rrecv_packet() noexcept { + const int sock = this->socks->rsock; + + // Get the size of the backlog, early out of there's nothing there yet. + const auto backlog_size = shared::net::get_backlog_size(sock); + if (backlog_size < sizeof(packet_header)) { + return std::nullopt; + } + + // Read for the packet headers and get the claimed size. Early out if + // our stream isn't big enough for that yet. + packet_header header = {}; + recv(sock, &header, sizeof(header), MSG_PEEK); + const std::uint32_t read_packet_size = ntohl(header.size); + if (backlog_size < read_packet_size) { + return std::nullopt; + } + + // Read the actual packet now, based on our claimed size. + std::string data; + data.reserve(read_packet_size); + if (read(sock, std::data(data), read_packet_size) == -1) { + this->bad_reason = shared::net::get_errno_error(); + return std::nullopt; + } + + data = std::string{ + reinterpret_cast(std::data(data)) + sizeof(packet_header), + reinterpret_cast(std::data(data)) + read_packet_size}; + shared::decompress_string(data); + + // Parse the packet, ignoring the header. + proto::packet packet; + if (!packet.ParseFromString(data)) { + return std::nullopt; + } + + return packet; + } + std::optional urecv_packet() noexcept { + const int sock = this->socks->usock; + + restart: + const auto packet_size = shared::net::get_backlog_size(sock); + + if (packet_size == 0) { + return std::nullopt; + } + + std::string data; + data.reserve(packet_size); + if (recv(sock, std::data(data), packet_size, 0) == -1) { + this->bad_reason = shared::net::get_errno_error(); + return std::nullopt; + } + + data = std::string{ + reinterpret_cast(std::data(data)) + sizeof(packet_header), + reinterpret_cast(std::data(data)) + packet_size}; + shared::decompress_string(data); + + proto::packet packet; + if (!packet.ParseFromString(data)) { + goto restart; + } + + return packet; + } + // Gets packets from r/u streams, doesn't care which. + std::optional recv_packet() noexcept { + if (const auto ret = urecv_packet(); ret.has_value()) { + return ret; + } + return rrecv_packet(); + } +}; + +} // namespace net +} // namespace shared + +#endif diff --git a/src/shared/net/lib/protobuf/net.pb.cc b/src/shared/net/lib/protobuf/net.pb.cc new file mode 100644 index 0000000..a938799 --- /dev/null +++ b/src/shared/net/lib/protobuf/net.pb.cc @@ -0,0 +1,5548 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: net.proto + +#include "net.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) +#include + +PROTOBUF_PRAGMA_INIT_SEG +namespace proto { +constexpr angles::angles( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : pitch_(0) + , yaw_(0){} +struct anglesDefaultTypeInternal { + constexpr anglesDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~anglesDefaultTypeInternal() {} + union { + angles _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT anglesDefaultTypeInternal _angles_default_instance_; +constexpr coords::coords( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : x_(0) + , z_(0){} +struct coordsDefaultTypeInternal { + constexpr coordsDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~coordsDefaultTypeInternal() {} + union { + coords _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT coordsDefaultTypeInternal _coords_default_instance_; +constexpr vec3::vec3( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : x_(0) + , y_(0) + , z_(0){} +struct vec3DefaultTypeInternal { + constexpr vec3DefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~vec3DefaultTypeInternal() {} + union { + vec3 _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT vec3DefaultTypeInternal _vec3_default_instance_; +constexpr ivec3::ivec3( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : x_(0) + , y_(0) + , z_(0){} +struct ivec3DefaultTypeInternal { + constexpr ivec3DefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~ivec3DefaultTypeInternal() {} + union { + ivec3 _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ivec3DefaultTypeInternal _ivec3_default_instance_; +constexpr player::player( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : chunk_pos_(nullptr) + , local_pos_(nullptr) + , viewangles_(nullptr) + , velocity_(nullptr) + , index_(0u) + , commands_(0u){} +struct playerDefaultTypeInternal { + constexpr playerDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~playerDefaultTypeInternal() {} + union { + player _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT playerDefaultTypeInternal _player_default_instance_; +constexpr auth::auth( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : username_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , password_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){} +struct authDefaultTypeInternal { + constexpr authDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~authDefaultTypeInternal() {} + union { + auth _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT authDefaultTypeInternal _auth_default_instance_; +constexpr init::init( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : localplayer_(nullptr) + , seed_(uint64_t{0u}) + , draw_distance_(0){} +struct initDefaultTypeInternal { + constexpr initDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~initDefaultTypeInternal() {} + union { + init _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT initDefaultTypeInternal _init_default_instance_; +constexpr move::move( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : viewangles_(nullptr) + , commands_(0u){} +struct moveDefaultTypeInternal { + constexpr moveDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~moveDefaultTypeInternal() {} + union { + move _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT moveDefaultTypeInternal _move_default_instance_; +constexpr remove_player::remove_player( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : index_(0u){} +struct remove_playerDefaultTypeInternal { + constexpr remove_playerDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~remove_playerDefaultTypeInternal() {} + union { + remove_player _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT remove_playerDefaultTypeInternal _remove_player_default_instance_; +constexpr say::say( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : text_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string){} +struct sayDefaultTypeInternal { + constexpr sayDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~sayDefaultTypeInternal() {} + union { + say _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT sayDefaultTypeInternal _say_default_instance_; +constexpr hear_player::hear_player( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : text_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , index_(0u){} +struct hear_playerDefaultTypeInternal { + constexpr hear_playerDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~hear_playerDefaultTypeInternal() {} + union { + hear_player _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT hear_playerDefaultTypeInternal _hear_player_default_instance_; +constexpr request_chunk::request_chunk( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : chunk_pos_(nullptr){} +struct request_chunkDefaultTypeInternal { + constexpr request_chunkDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~request_chunkDefaultTypeInternal() {} + union { + request_chunk _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT request_chunkDefaultTypeInternal _request_chunk_default_instance_; +constexpr remove_chunk::remove_chunk( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : chunk_pos_(nullptr){} +struct remove_chunkDefaultTypeInternal { + constexpr remove_chunkDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~remove_chunkDefaultTypeInternal() {} + union { + remove_chunk _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT remove_chunkDefaultTypeInternal _remove_chunk_default_instance_; +constexpr chunk::chunk( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : blocks_() + , _blocks_cached_byte_size_(0) + , chunk_pos_(nullptr){} +struct chunkDefaultTypeInternal { + constexpr chunkDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~chunkDefaultTypeInternal() {} + union { + chunk _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT chunkDefaultTypeInternal _chunk_default_instance_; +constexpr add_block::add_block( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : chunk_pos_(nullptr) + , block_pos_(nullptr) + , block_(0u){} +struct add_blockDefaultTypeInternal { + constexpr add_blockDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~add_blockDefaultTypeInternal() {} + union { + add_block _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT add_blockDefaultTypeInternal _add_block_default_instance_; +constexpr remove_block::remove_block( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : chunk_pos_(nullptr) + , block_pos_(nullptr){} +struct remove_blockDefaultTypeInternal { + constexpr remove_blockDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~remove_blockDefaultTypeInternal() {} + union { + remove_block _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT remove_blockDefaultTypeInternal _remove_block_default_instance_; +constexpr server_message::server_message( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : message_(&::PROTOBUF_NAMESPACE_ID::internal::fixed_address_empty_string) + , fatal_(false){} +struct server_messageDefaultTypeInternal { + constexpr server_messageDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~server_messageDefaultTypeInternal() {} + union { + server_message _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT server_messageDefaultTypeInternal _server_message_default_instance_; +constexpr packet::packet( + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized) + : _oneof_case_{}{} +struct packetDefaultTypeInternal { + constexpr packetDefaultTypeInternal() + : _instance(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized{}) {} + ~packetDefaultTypeInternal() {} + union { + packet _instance; + }; +}; +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT packetDefaultTypeInternal _packet_default_instance_; +} // namespace proto +static ::PROTOBUF_NAMESPACE_ID::Metadata file_level_metadata_net_2eproto[18]; +static constexpr ::PROTOBUF_NAMESPACE_ID::EnumDescriptor const** file_level_enum_descriptors_net_2eproto = nullptr; +static constexpr ::PROTOBUF_NAMESPACE_ID::ServiceDescriptor const** file_level_service_descriptors_net_2eproto = nullptr; + +const uint32_t TableStruct_net_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::angles, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::angles, pitch_), + PROTOBUF_FIELD_OFFSET(::proto::angles, yaw_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::coords, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::coords, x_), + PROTOBUF_FIELD_OFFSET(::proto::coords, z_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::vec3, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::vec3, x_), + PROTOBUF_FIELD_OFFSET(::proto::vec3, y_), + PROTOBUF_FIELD_OFFSET(::proto::vec3, z_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::ivec3, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::ivec3, x_), + PROTOBUF_FIELD_OFFSET(::proto::ivec3, y_), + PROTOBUF_FIELD_OFFSET(::proto::ivec3, z_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::player, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::player, index_), + PROTOBUF_FIELD_OFFSET(::proto::player, commands_), + PROTOBUF_FIELD_OFFSET(::proto::player, chunk_pos_), + PROTOBUF_FIELD_OFFSET(::proto::player, local_pos_), + PROTOBUF_FIELD_OFFSET(::proto::player, viewangles_), + PROTOBUF_FIELD_OFFSET(::proto::player, velocity_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::auth, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::auth, username_), + PROTOBUF_FIELD_OFFSET(::proto::auth, password_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::init, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::init, seed_), + PROTOBUF_FIELD_OFFSET(::proto::init, draw_distance_), + PROTOBUF_FIELD_OFFSET(::proto::init, localplayer_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::move, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::move, commands_), + PROTOBUF_FIELD_OFFSET(::proto::move, viewangles_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::remove_player, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::remove_player, index_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::say, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::say, text_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::hear_player, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::hear_player, index_), + PROTOBUF_FIELD_OFFSET(::proto::hear_player, text_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::request_chunk, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::request_chunk, chunk_pos_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::remove_chunk, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::remove_chunk, chunk_pos_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::chunk, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::chunk, chunk_pos_), + PROTOBUF_FIELD_OFFSET(::proto::chunk, blocks_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::add_block, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::add_block, chunk_pos_), + PROTOBUF_FIELD_OFFSET(::proto::add_block, block_pos_), + PROTOBUF_FIELD_OFFSET(::proto::add_block, block_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::remove_block, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::remove_block, chunk_pos_), + PROTOBUF_FIELD_OFFSET(::proto::remove_block, block_pos_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::server_message, _internal_metadata_), + ~0u, // no _extensions_ + ~0u, // no _oneof_case_ + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + PROTOBUF_FIELD_OFFSET(::proto::server_message, message_), + PROTOBUF_FIELD_OFFSET(::proto::server_message, fatal_), + ~0u, // no _has_bits_ + PROTOBUF_FIELD_OFFSET(::proto::packet, _internal_metadata_), + ~0u, // no _extensions_ + PROTOBUF_FIELD_OFFSET(::proto::packet, _oneof_case_[0]), + ~0u, // no _weak_field_map_ + ~0u, // no _inlined_string_donated_ + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + ::PROTOBUF_NAMESPACE_ID::internal::kInvalidFieldOffsetTag, + PROTOBUF_FIELD_OFFSET(::proto::packet, contents_), +}; +static const ::PROTOBUF_NAMESPACE_ID::internal::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + { 0, -1, -1, sizeof(::proto::angles)}, + { 8, -1, -1, sizeof(::proto::coords)}, + { 16, -1, -1, sizeof(::proto::vec3)}, + { 25, -1, -1, sizeof(::proto::ivec3)}, + { 34, -1, -1, sizeof(::proto::player)}, + { 46, -1, -1, sizeof(::proto::auth)}, + { 54, -1, -1, sizeof(::proto::init)}, + { 63, -1, -1, sizeof(::proto::move)}, + { 71, -1, -1, sizeof(::proto::remove_player)}, + { 78, -1, -1, sizeof(::proto::say)}, + { 85, -1, -1, sizeof(::proto::hear_player)}, + { 93, -1, -1, sizeof(::proto::request_chunk)}, + { 100, -1, -1, sizeof(::proto::remove_chunk)}, + { 107, -1, -1, sizeof(::proto::chunk)}, + { 115, -1, -1, sizeof(::proto::add_block)}, + { 124, -1, -1, sizeof(::proto::remove_block)}, + { 132, -1, -1, sizeof(::proto::server_message)}, + { 140, -1, -1, sizeof(::proto::packet)}, +}; + +static ::PROTOBUF_NAMESPACE_ID::Message const * const file_default_instances[] = { + reinterpret_cast(&::proto::_angles_default_instance_), + reinterpret_cast(&::proto::_coords_default_instance_), + reinterpret_cast(&::proto::_vec3_default_instance_), + reinterpret_cast(&::proto::_ivec3_default_instance_), + reinterpret_cast(&::proto::_player_default_instance_), + reinterpret_cast(&::proto::_auth_default_instance_), + reinterpret_cast(&::proto::_init_default_instance_), + reinterpret_cast(&::proto::_move_default_instance_), + reinterpret_cast(&::proto::_remove_player_default_instance_), + reinterpret_cast(&::proto::_say_default_instance_), + reinterpret_cast(&::proto::_hear_player_default_instance_), + reinterpret_cast(&::proto::_request_chunk_default_instance_), + reinterpret_cast(&::proto::_remove_chunk_default_instance_), + reinterpret_cast(&::proto::_chunk_default_instance_), + reinterpret_cast(&::proto::_add_block_default_instance_), + reinterpret_cast(&::proto::_remove_block_default_instance_), + reinterpret_cast(&::proto::_server_message_default_instance_), + reinterpret_cast(&::proto::_packet_default_instance_), +}; + +const char descriptor_table_protodef_net_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = + "\n\tnet.proto\022\005proto\"$\n\006angles\022\r\n\005pitch\030\001 " + "\001(\002\022\013\n\003yaw\030\002 \001(\002\"\036\n\006coords\022\t\n\001x\030\001 \001(\005\022\t\n" + "\001z\030\002 \001(\005\"\'\n\004vec3\022\t\n\001x\030\001 \001(\002\022\t\n\001y\030\002 \001(\002\022\t" + "\n\001z\030\003 \001(\002\"(\n\005ivec3\022\t\n\001x\030\001 \001(\005\022\t\n\001y\030\002 \001(\005" + "\022\t\n\001z\030\003 \001(\005\"\255\001\n\006player\022\r\n\005index\030\001 \001(\r\022\020\n" + "\010commands\030\002 \001(\r\022 \n\tchunk_pos\030\003 \001(\0132\r.pro" + "to.coords\022\036\n\tlocal_pos\030\004 \001(\0132\013.proto.vec" + "3\022!\n\nviewangles\030\005 \001(\0132\r.proto.angles\022\035\n\010" + "velocity\030\006 \001(\0132\013.proto.vec3\"*\n\004auth\022\020\n\010u" + "sername\030\001 \001(\t\022\020\n\010password\030\002 \001(\t\"O\n\004init\022" + "\014\n\004seed\030\001 \001(\004\022\025\n\rdraw_distance\030\002 \001(\005\022\"\n\013" + "localplayer\030\003 \001(\0132\r.proto.player\";\n\004move" + "\022\020\n\010commands\030\001 \001(\r\022!\n\nviewangles\030\002 \001(\0132\r" + ".proto.angles\"\036\n\rremove_player\022\r\n\005index\030" + "\001 \001(\r\"\023\n\003say\022\014\n\004text\030\001 \001(\t\"*\n\013hear_playe" + "r\022\r\n\005index\030\001 \001(\r\022\014\n\004text\030\002 \001(\t\"1\n\rreques" + "t_chunk\022 \n\tchunk_pos\030\001 \001(\0132\r.proto.coord" + "s\"0\n\014remove_chunk\022 \n\tchunk_pos\030\001 \001(\0132\r.p" + "roto.coords\"=\n\005chunk\022 \n\tchunk_pos\030\001 \001(\0132" + "\r.proto.coords\022\022\n\006blocks\030\002 \003(\rB\002\020\001\"]\n\tad" + "d_block\022 \n\tchunk_pos\030\001 \001(\0132\r.proto.coord" + "s\022\037\n\tblock_pos\030\002 \001(\0132\014.proto.ivec3\022\r\n\005bl" + "ock\030\003 \001(\r\"Q\n\014remove_block\022 \n\tchunk_pos\030\001" + " \001(\0132\r.proto.coords\022\037\n\tblock_pos\030\002 \001(\0132\014" + ".proto.ivec3\"0\n\016server_message\022\017\n\007messag" + "e\030\001 \001(\t\022\r\n\005fatal\030\002 \001(\010\"\334\004\n\006packet\022\"\n\013aut" + "h_packet\030\001 \001(\0132\013.proto.authH\000\022\"\n\013init_pa" + "cket\030\002 \001(\0132\013.proto.initH\000\022\"\n\013move_packet" + "\030\003 \001(\0132\013.proto.moveH\000\022&\n\rplayer_packet\030\004" + " \001(\0132\r.proto.playerH\000\0224\n\024remove_player_p" + "acket\030\005 \001(\0132\024.proto.remove_playerH\000\022 \n\ns" + "ay_packet\030\006 \001(\0132\n.proto.sayH\000\0220\n\022hear_pl" + "ayer_packet\030\007 \001(\0132\022.proto.hear_playerH\000\022" + "4\n\024request_chunk_packet\030\010 \001(\0132\024.proto.re" + "quest_chunkH\000\022$\n\014chunk_packet\030\t \001(\0132\014.pr" + "oto.chunkH\000\0222\n\023remove_chunk_packet\030\n \001(\013" + "2\023.proto.remove_chunkH\000\022,\n\020add_block_pac" + "ket\030\013 \001(\0132\020.proto.add_blockH\000\0222\n\023remove_" + "block_packet\030\014 \001(\0132\023.proto.remove_blockH" + "\000\0226\n\025server_message_packet\030\r \001(\0132\025.proto" + ".server_messageH\000B\n\n\010contentsb\006proto3" + ; +static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_net_2eproto_once; +const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_net_2eproto = { + false, false, 1637, descriptor_table_protodef_net_2eproto, "net.proto", + &descriptor_table_net_2eproto_once, nullptr, 0, 18, + schemas, file_default_instances, TableStruct_net_2eproto::offsets, + file_level_metadata_net_2eproto, file_level_enum_descriptors_net_2eproto, file_level_service_descriptors_net_2eproto, +}; +PROTOBUF_ATTRIBUTE_WEAK const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable* descriptor_table_net_2eproto_getter() { + return &descriptor_table_net_2eproto; +} + +// Force running AddDescriptors() at dynamic initialization time. +PROTOBUF_ATTRIBUTE_INIT_PRIORITY static ::PROTOBUF_NAMESPACE_ID::internal::AddDescriptorsRunner dynamic_init_dummy_net_2eproto(&descriptor_table_net_2eproto); +namespace proto { + +// =================================================================== + +class angles::_Internal { + public: +}; + +angles::angles(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.angles) +} +angles::angles(const angles& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::memcpy(&pitch_, &from.pitch_, + static_cast(reinterpret_cast(&yaw_) - + reinterpret_cast(&pitch_)) + sizeof(yaw_)); + // @@protoc_insertion_point(copy_constructor:proto.angles) +} + +inline void angles::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&pitch_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&yaw_) - + reinterpret_cast(&pitch_)) + sizeof(yaw_)); +} + +angles::~angles() { + // @@protoc_insertion_point(destructor:proto.angles) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void angles::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void angles::ArenaDtor(void* object) { + angles* _this = reinterpret_cast< angles* >(object); + (void)_this; +} +void angles::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void angles::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void angles::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.angles) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + ::memset(&pitch_, 0, static_cast( + reinterpret_cast(&yaw_) - + reinterpret_cast(&pitch_)) + sizeof(yaw_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* angles::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // float pitch = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 13)) { + pitch_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else + goto handle_unusual; + continue; + // float yaw = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 21)) { + yaw_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* angles::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.angles) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // float pitch = 1; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_pitch = this->_internal_pitch(); + uint32_t raw_pitch; + memcpy(&raw_pitch, &tmp_pitch, sizeof(tmp_pitch)); + if (raw_pitch != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(1, this->_internal_pitch(), target); + } + + // float yaw = 2; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_yaw = this->_internal_yaw(); + uint32_t raw_yaw; + memcpy(&raw_yaw, &tmp_yaw, sizeof(tmp_yaw)); + if (raw_yaw != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(2, this->_internal_yaw(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.angles) + return target; +} + +size_t angles::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.angles) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // float pitch = 1; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_pitch = this->_internal_pitch(); + uint32_t raw_pitch; + memcpy(&raw_pitch, &tmp_pitch, sizeof(tmp_pitch)); + if (raw_pitch != 0) { + total_size += 1 + 4; + } + + // float yaw = 2; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_yaw = this->_internal_yaw(); + uint32_t raw_yaw; + memcpy(&raw_yaw, &tmp_yaw, sizeof(tmp_yaw)); + if (raw_yaw != 0) { + total_size += 1 + 4; + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData angles::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + angles::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*angles::GetClassData() const { return &_class_data_; } + +void angles::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void angles::MergeFrom(const angles& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.angles) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_pitch = from._internal_pitch(); + uint32_t raw_pitch; + memcpy(&raw_pitch, &tmp_pitch, sizeof(tmp_pitch)); + if (raw_pitch != 0) { + _internal_set_pitch(from._internal_pitch()); + } + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_yaw = from._internal_yaw(); + uint32_t raw_yaw; + memcpy(&raw_yaw, &tmp_yaw, sizeof(tmp_yaw)); + if (raw_yaw != 0) { + _internal_set_yaw(from._internal_yaw()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void angles::CopyFrom(const angles& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.angles) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool angles::IsInitialized() const { + return true; +} + +void angles::InternalSwap(angles* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(angles, yaw_) + + sizeof(angles::yaw_) + - PROTOBUF_FIELD_OFFSET(angles, pitch_)>( + reinterpret_cast(&pitch_), + reinterpret_cast(&other->pitch_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata angles::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[0]); +} + +// =================================================================== + +class coords::_Internal { + public: +}; + +coords::coords(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.coords) +} +coords::coords(const coords& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::memcpy(&x_, &from.x_, + static_cast(reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); + // @@protoc_insertion_point(copy_constructor:proto.coords) +} + +inline void coords::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&x_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); +} + +coords::~coords() { + // @@protoc_insertion_point(destructor:proto.coords) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void coords::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void coords::ArenaDtor(void* object) { + coords* _this = reinterpret_cast< coords* >(object); + (void)_this; +} +void coords::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void coords::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void coords::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.coords) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + ::memset(&x_, 0, static_cast( + reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* coords::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // int32 x = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + x_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // int32 z = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + z_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* coords::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.coords) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // int32 x = 1; + if (this->_internal_x() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_x(), target); + } + + // int32 z = 2; + if (this->_internal_z() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_z(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.coords) + return target; +} + +size_t coords::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.coords) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // int32 x = 1; + if (this->_internal_x() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_x()); + } + + // int32 z = 2; + if (this->_internal_z() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_z()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData coords::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + coords::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*coords::GetClassData() const { return &_class_data_; } + +void coords::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void coords::MergeFrom(const coords& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.coords) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_x() != 0) { + _internal_set_x(from._internal_x()); + } + if (from._internal_z() != 0) { + _internal_set_z(from._internal_z()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void coords::CopyFrom(const coords& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.coords) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool coords::IsInitialized() const { + return true; +} + +void coords::InternalSwap(coords* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(coords, z_) + + sizeof(coords::z_) + - PROTOBUF_FIELD_OFFSET(coords, x_)>( + reinterpret_cast(&x_), + reinterpret_cast(&other->x_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata coords::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[1]); +} + +// =================================================================== + +class vec3::_Internal { + public: +}; + +vec3::vec3(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.vec3) +} +vec3::vec3(const vec3& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::memcpy(&x_, &from.x_, + static_cast(reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); + // @@protoc_insertion_point(copy_constructor:proto.vec3) +} + +inline void vec3::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&x_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); +} + +vec3::~vec3() { + // @@protoc_insertion_point(destructor:proto.vec3) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void vec3::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void vec3::ArenaDtor(void* object) { + vec3* _this = reinterpret_cast< vec3* >(object); + (void)_this; +} +void vec3::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void vec3::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void vec3::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.vec3) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + ::memset(&x_, 0, static_cast( + reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* vec3::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // float x = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 13)) { + x_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else + goto handle_unusual; + continue; + // float y = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 21)) { + y_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else + goto handle_unusual; + continue; + // float z = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 29)) { + z_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad(ptr); + ptr += sizeof(float); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* vec3::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.vec3) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // float x = 1; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_x = this->_internal_x(); + uint32_t raw_x; + memcpy(&raw_x, &tmp_x, sizeof(tmp_x)); + if (raw_x != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(1, this->_internal_x(), target); + } + + // float y = 2; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_y = this->_internal_y(); + uint32_t raw_y; + memcpy(&raw_y, &tmp_y, sizeof(tmp_y)); + if (raw_y != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(2, this->_internal_y(), target); + } + + // float z = 3; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_z = this->_internal_z(); + uint32_t raw_z; + memcpy(&raw_z, &tmp_z, sizeof(tmp_z)); + if (raw_z != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(3, this->_internal_z(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.vec3) + return target; +} + +size_t vec3::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.vec3) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // float x = 1; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_x = this->_internal_x(); + uint32_t raw_x; + memcpy(&raw_x, &tmp_x, sizeof(tmp_x)); + if (raw_x != 0) { + total_size += 1 + 4; + } + + // float y = 2; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_y = this->_internal_y(); + uint32_t raw_y; + memcpy(&raw_y, &tmp_y, sizeof(tmp_y)); + if (raw_y != 0) { + total_size += 1 + 4; + } + + // float z = 3; + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_z = this->_internal_z(); + uint32_t raw_z; + memcpy(&raw_z, &tmp_z, sizeof(tmp_z)); + if (raw_z != 0) { + total_size += 1 + 4; + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData vec3::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + vec3::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*vec3::GetClassData() const { return &_class_data_; } + +void vec3::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void vec3::MergeFrom(const vec3& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.vec3) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_x = from._internal_x(); + uint32_t raw_x; + memcpy(&raw_x, &tmp_x, sizeof(tmp_x)); + if (raw_x != 0) { + _internal_set_x(from._internal_x()); + } + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_y = from._internal_y(); + uint32_t raw_y; + memcpy(&raw_y, &tmp_y, sizeof(tmp_y)); + if (raw_y != 0) { + _internal_set_y(from._internal_y()); + } + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_z = from._internal_z(); + uint32_t raw_z; + memcpy(&raw_z, &tmp_z, sizeof(tmp_z)); + if (raw_z != 0) { + _internal_set_z(from._internal_z()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void vec3::CopyFrom(const vec3& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.vec3) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool vec3::IsInitialized() const { + return true; +} + +void vec3::InternalSwap(vec3* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(vec3, z_) + + sizeof(vec3::z_) + - PROTOBUF_FIELD_OFFSET(vec3, x_)>( + reinterpret_cast(&x_), + reinterpret_cast(&other->x_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata vec3::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[2]); +} + +// =================================================================== + +class ivec3::_Internal { + public: +}; + +ivec3::ivec3(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.ivec3) +} +ivec3::ivec3(const ivec3& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + ::memcpy(&x_, &from.x_, + static_cast(reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); + // @@protoc_insertion_point(copy_constructor:proto.ivec3) +} + +inline void ivec3::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&x_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); +} + +ivec3::~ivec3() { + // @@protoc_insertion_point(destructor:proto.ivec3) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void ivec3::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void ivec3::ArenaDtor(void* object) { + ivec3* _this = reinterpret_cast< ivec3* >(object); + (void)_this; +} +void ivec3::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void ivec3::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void ivec3::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.ivec3) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + ::memset(&x_, 0, static_cast( + reinterpret_cast(&z_) - + reinterpret_cast(&x_)) + sizeof(z_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* ivec3::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // int32 x = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + x_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // int32 y = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + y_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // int32 z = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 24)) { + z_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* ivec3::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.ivec3) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // int32 x = 1; + if (this->_internal_x() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->_internal_x(), target); + } + + // int32 y = 2; + if (this->_internal_y() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_y(), target); + } + + // int32 z = 3; + if (this->_internal_z() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->_internal_z(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.ivec3) + return target; +} + +size_t ivec3::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.ivec3) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // int32 x = 1; + if (this->_internal_x() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_x()); + } + + // int32 y = 2; + if (this->_internal_y() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_y()); + } + + // int32 z = 3; + if (this->_internal_z() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_z()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData ivec3::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + ivec3::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*ivec3::GetClassData() const { return &_class_data_; } + +void ivec3::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void ivec3::MergeFrom(const ivec3& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.ivec3) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_x() != 0) { + _internal_set_x(from._internal_x()); + } + if (from._internal_y() != 0) { + _internal_set_y(from._internal_y()); + } + if (from._internal_z() != 0) { + _internal_set_z(from._internal_z()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void ivec3::CopyFrom(const ivec3& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.ivec3) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool ivec3::IsInitialized() const { + return true; +} + +void ivec3::InternalSwap(ivec3* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(ivec3, z_) + + sizeof(ivec3::z_) + - PROTOBUF_FIELD_OFFSET(ivec3, x_)>( + reinterpret_cast(&x_), + reinterpret_cast(&other->x_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata ivec3::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[3]); +} + +// =================================================================== + +class player::_Internal { + public: + static const ::proto::coords& chunk_pos(const player* msg); + static const ::proto::vec3& local_pos(const player* msg); + static const ::proto::angles& viewangles(const player* msg); + static const ::proto::vec3& velocity(const player* msg); +}; + +const ::proto::coords& +player::_Internal::chunk_pos(const player* msg) { + return *msg->chunk_pos_; +} +const ::proto::vec3& +player::_Internal::local_pos(const player* msg) { + return *msg->local_pos_; +} +const ::proto::angles& +player::_Internal::viewangles(const player* msg) { + return *msg->viewangles_; +} +const ::proto::vec3& +player::_Internal::velocity(const player* msg) { + return *msg->velocity_; +} +player::player(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.player) +} +player::player(const player& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_chunk_pos()) { + chunk_pos_ = new ::proto::coords(*from.chunk_pos_); + } else { + chunk_pos_ = nullptr; + } + if (from._internal_has_local_pos()) { + local_pos_ = new ::proto::vec3(*from.local_pos_); + } else { + local_pos_ = nullptr; + } + if (from._internal_has_viewangles()) { + viewangles_ = new ::proto::angles(*from.viewangles_); + } else { + viewangles_ = nullptr; + } + if (from._internal_has_velocity()) { + velocity_ = new ::proto::vec3(*from.velocity_); + } else { + velocity_ = nullptr; + } + ::memcpy(&index_, &from.index_, + static_cast(reinterpret_cast(&commands_) - + reinterpret_cast(&index_)) + sizeof(commands_)); + // @@protoc_insertion_point(copy_constructor:proto.player) +} + +inline void player::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&chunk_pos_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&commands_) - + reinterpret_cast(&chunk_pos_)) + sizeof(commands_)); +} + +player::~player() { + // @@protoc_insertion_point(destructor:proto.player) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void player::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete chunk_pos_; + if (this != internal_default_instance()) delete local_pos_; + if (this != internal_default_instance()) delete viewangles_; + if (this != internal_default_instance()) delete velocity_; +} + +void player::ArenaDtor(void* object) { + player* _this = reinterpret_cast< player* >(object); + (void)_this; +} +void player::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void player::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void player::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.player) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; + if (GetArenaForAllocation() == nullptr && local_pos_ != nullptr) { + delete local_pos_; + } + local_pos_ = nullptr; + if (GetArenaForAllocation() == nullptr && viewangles_ != nullptr) { + delete viewangles_; + } + viewangles_ = nullptr; + if (GetArenaForAllocation() == nullptr && velocity_ != nullptr) { + delete velocity_; + } + velocity_ = nullptr; + ::memset(&index_, 0, static_cast( + reinterpret_cast(&commands_) - + reinterpret_cast(&index_)) + sizeof(commands_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* player::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // uint32 index = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // uint32 commands = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + commands_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.coords chunk_pos = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.vec3 local_pos = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 34)) { + ptr = ctx->ParseMessage(_internal_mutable_local_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.angles viewangles = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 42)) { + ptr = ctx->ParseMessage(_internal_mutable_viewangles(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.vec3 velocity = 6; + case 6: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 50)) { + ptr = ctx->ParseMessage(_internal_mutable_velocity(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* player::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.player) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // uint32 index = 1; + if (this->_internal_index() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->_internal_index(), target); + } + + // uint32 commands = 2; + if (this->_internal_commands() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(2, this->_internal_commands(), target); + } + + // .proto.coords chunk_pos = 3; + if (this->_internal_has_chunk_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::chunk_pos(this), target, stream); + } + + // .proto.vec3 local_pos = 4; + if (this->_internal_has_local_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 4, _Internal::local_pos(this), target, stream); + } + + // .proto.angles viewangles = 5; + if (this->_internal_has_viewangles()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 5, _Internal::viewangles(this), target, stream); + } + + // .proto.vec3 velocity = 6; + if (this->_internal_has_velocity()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 6, _Internal::velocity(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.player) + return target; +} + +size_t player::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.player) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.coords chunk_pos = 3; + if (this->_internal_has_chunk_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *chunk_pos_); + } + + // .proto.vec3 local_pos = 4; + if (this->_internal_has_local_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *local_pos_); + } + + // .proto.angles viewangles = 5; + if (this->_internal_has_viewangles()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *viewangles_); + } + + // .proto.vec3 velocity = 6; + if (this->_internal_has_velocity()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *velocity_); + } + + // uint32 index = 1; + if (this->_internal_index() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_index()); + } + + // uint32 commands = 2; + if (this->_internal_commands() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_commands()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData player::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + player::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*player::GetClassData() const { return &_class_data_; } + +void player::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void player::MergeFrom(const player& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.player) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_chunk_pos()) { + _internal_mutable_chunk_pos()->::proto::coords::MergeFrom(from._internal_chunk_pos()); + } + if (from._internal_has_local_pos()) { + _internal_mutable_local_pos()->::proto::vec3::MergeFrom(from._internal_local_pos()); + } + if (from._internal_has_viewangles()) { + _internal_mutable_viewangles()->::proto::angles::MergeFrom(from._internal_viewangles()); + } + if (from._internal_has_velocity()) { + _internal_mutable_velocity()->::proto::vec3::MergeFrom(from._internal_velocity()); + } + if (from._internal_index() != 0) { + _internal_set_index(from._internal_index()); + } + if (from._internal_commands() != 0) { + _internal_set_commands(from._internal_commands()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void player::CopyFrom(const player& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.player) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool player::IsInitialized() const { + return true; +} + +void player::InternalSwap(player* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(player, commands_) + + sizeof(player::commands_) + - PROTOBUF_FIELD_OFFSET(player, chunk_pos_)>( + reinterpret_cast(&chunk_pos_), + reinterpret_cast(&other->chunk_pos_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata player::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[4]); +} + +// =================================================================== + +class auth::_Internal { + public: +}; + +auth::auth(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.auth) +} +auth::auth(const auth& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + username_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (!from._internal_username().empty()) { + username_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_username(), + GetArenaForAllocation()); + } + password_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (!from._internal_password().empty()) { + password_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_password(), + GetArenaForAllocation()); + } + // @@protoc_insertion_point(copy_constructor:proto.auth) +} + +inline void auth::SharedCtor() { +username_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +password_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +} + +auth::~auth() { + // @@protoc_insertion_point(destructor:proto.auth) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void auth::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + username_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + password_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void auth::ArenaDtor(void* object) { + auth* _this = reinterpret_cast< auth* >(object); + (void)_this; +} +void auth::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void auth::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void auth::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.auth) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + username_.ClearToEmpty(); + password_.ClearToEmpty(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* auth::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // string username = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_username(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "proto.auth.username")); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // string password = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + auto str = _internal_mutable_password(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "proto.auth.password")); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* auth::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.auth) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // string username = 1; + if (!this->_internal_username().empty()) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_username().data(), static_cast(this->_internal_username().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "proto.auth.username"); + target = stream->WriteStringMaybeAliased( + 1, this->_internal_username(), target); + } + + // string password = 2; + if (!this->_internal_password().empty()) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_password().data(), static_cast(this->_internal_password().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "proto.auth.password"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_password(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.auth) + return target; +} + +size_t auth::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.auth) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string username = 1; + if (!this->_internal_username().empty()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_username()); + } + + // string password = 2; + if (!this->_internal_password().empty()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_password()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData auth::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + auth::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*auth::GetClassData() const { return &_class_data_; } + +void auth::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void auth::MergeFrom(const auth& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.auth) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (!from._internal_username().empty()) { + _internal_set_username(from._internal_username()); + } + if (!from._internal_password().empty()) { + _internal_set_password(from._internal_password()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void auth::CopyFrom(const auth& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.auth) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool auth::IsInitialized() const { + return true; +} + +void auth::InternalSwap(auth* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &username_, lhs_arena, + &other->username_, rhs_arena + ); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &password_, lhs_arena, + &other->password_, rhs_arena + ); +} + +::PROTOBUF_NAMESPACE_ID::Metadata auth::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[5]); +} + +// =================================================================== + +class init::_Internal { + public: + static const ::proto::player& localplayer(const init* msg); +}; + +const ::proto::player& +init::_Internal::localplayer(const init* msg) { + return *msg->localplayer_; +} +init::init(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.init) +} +init::init(const init& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_localplayer()) { + localplayer_ = new ::proto::player(*from.localplayer_); + } else { + localplayer_ = nullptr; + } + ::memcpy(&seed_, &from.seed_, + static_cast(reinterpret_cast(&draw_distance_) - + reinterpret_cast(&seed_)) + sizeof(draw_distance_)); + // @@protoc_insertion_point(copy_constructor:proto.init) +} + +inline void init::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&localplayer_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&draw_distance_) - + reinterpret_cast(&localplayer_)) + sizeof(draw_distance_)); +} + +init::~init() { + // @@protoc_insertion_point(destructor:proto.init) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void init::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete localplayer_; +} + +void init::ArenaDtor(void* object) { + init* _this = reinterpret_cast< init* >(object); + (void)_this; +} +void init::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void init::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void init::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.init) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && localplayer_ != nullptr) { + delete localplayer_; + } + localplayer_ = nullptr; + ::memset(&seed_, 0, static_cast( + reinterpret_cast(&draw_distance_) - + reinterpret_cast(&seed_)) + sizeof(draw_distance_)); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* init::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // uint64 seed = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + seed_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // int32 draw_distance = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + draw_distance_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.player localplayer = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_localplayer(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* init::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.init) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // uint64 seed = 1; + if (this->_internal_seed() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(1, this->_internal_seed(), target); + } + + // int32 draw_distance = 2; + if (this->_internal_draw_distance() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->_internal_draw_distance(), target); + } + + // .proto.player localplayer = 3; + if (this->_internal_has_localplayer()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::localplayer(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.init) + return target; +} + +size_t init::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.init) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.player localplayer = 3; + if (this->_internal_has_localplayer()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *localplayer_); + } + + // uint64 seed = 1; + if (this->_internal_seed() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt64SizePlusOne(this->_internal_seed()); + } + + // int32 draw_distance = 2; + if (this->_internal_draw_distance() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32SizePlusOne(this->_internal_draw_distance()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData init::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + init::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*init::GetClassData() const { return &_class_data_; } + +void init::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void init::MergeFrom(const init& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.init) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_localplayer()) { + _internal_mutable_localplayer()->::proto::player::MergeFrom(from._internal_localplayer()); + } + if (from._internal_seed() != 0) { + _internal_set_seed(from._internal_seed()); + } + if (from._internal_draw_distance() != 0) { + _internal_set_draw_distance(from._internal_draw_distance()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void init::CopyFrom(const init& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.init) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool init::IsInitialized() const { + return true; +} + +void init::InternalSwap(init* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(init, draw_distance_) + + sizeof(init::draw_distance_) + - PROTOBUF_FIELD_OFFSET(init, localplayer_)>( + reinterpret_cast(&localplayer_), + reinterpret_cast(&other->localplayer_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata init::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[6]); +} + +// =================================================================== + +class move::_Internal { + public: + static const ::proto::angles& viewangles(const move* msg); +}; + +const ::proto::angles& +move::_Internal::viewangles(const move* msg) { + return *msg->viewangles_; +} +move::move(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.move) +} +move::move(const move& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_viewangles()) { + viewangles_ = new ::proto::angles(*from.viewangles_); + } else { + viewangles_ = nullptr; + } + commands_ = from.commands_; + // @@protoc_insertion_point(copy_constructor:proto.move) +} + +inline void move::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&viewangles_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&commands_) - + reinterpret_cast(&viewangles_)) + sizeof(commands_)); +} + +move::~move() { + // @@protoc_insertion_point(destructor:proto.move) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void move::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete viewangles_; +} + +void move::ArenaDtor(void* object) { + move* _this = reinterpret_cast< move* >(object); + (void)_this; +} +void move::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void move::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void move::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.move) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && viewangles_ != nullptr) { + delete viewangles_; + } + viewangles_ = nullptr; + commands_ = 0u; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* move::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // uint32 commands = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + commands_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.angles viewangles = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ctx->ParseMessage(_internal_mutable_viewangles(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* move::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.move) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // uint32 commands = 1; + if (this->_internal_commands() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->_internal_commands(), target); + } + + // .proto.angles viewangles = 2; + if (this->_internal_has_viewangles()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 2, _Internal::viewangles(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.move) + return target; +} + +size_t move::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.move) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.angles viewangles = 2; + if (this->_internal_has_viewangles()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *viewangles_); + } + + // uint32 commands = 1; + if (this->_internal_commands() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_commands()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData move::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + move::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*move::GetClassData() const { return &_class_data_; } + +void move::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void move::MergeFrom(const move& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.move) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_viewangles()) { + _internal_mutable_viewangles()->::proto::angles::MergeFrom(from._internal_viewangles()); + } + if (from._internal_commands() != 0) { + _internal_set_commands(from._internal_commands()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void move::CopyFrom(const move& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.move) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool move::IsInitialized() const { + return true; +} + +void move::InternalSwap(move* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(move, commands_) + + sizeof(move::commands_) + - PROTOBUF_FIELD_OFFSET(move, viewangles_)>( + reinterpret_cast(&viewangles_), + reinterpret_cast(&other->viewangles_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata move::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[7]); +} + +// =================================================================== + +class remove_player::_Internal { + public: +}; + +remove_player::remove_player(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.remove_player) +} +remove_player::remove_player(const remove_player& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + index_ = from.index_; + // @@protoc_insertion_point(copy_constructor:proto.remove_player) +} + +inline void remove_player::SharedCtor() { +index_ = 0u; +} + +remove_player::~remove_player() { + // @@protoc_insertion_point(destructor:proto.remove_player) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void remove_player::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); +} + +void remove_player::ArenaDtor(void* object) { + remove_player* _this = reinterpret_cast< remove_player* >(object); + (void)_this; +} +void remove_player::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void remove_player::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void remove_player::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.remove_player) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + index_ = 0u; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* remove_player::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // uint32 index = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* remove_player::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.remove_player) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // uint32 index = 1; + if (this->_internal_index() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->_internal_index(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.remove_player) + return target; +} + +size_t remove_player::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.remove_player) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // uint32 index = 1; + if (this->_internal_index() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_index()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData remove_player::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + remove_player::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*remove_player::GetClassData() const { return &_class_data_; } + +void remove_player::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void remove_player::MergeFrom(const remove_player& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.remove_player) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_index() != 0) { + _internal_set_index(from._internal_index()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void remove_player::CopyFrom(const remove_player& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.remove_player) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool remove_player::IsInitialized() const { + return true; +} + +void remove_player::InternalSwap(remove_player* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(index_, other->index_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata remove_player::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[8]); +} + +// =================================================================== + +class say::_Internal { + public: +}; + +say::say(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.say) +} +say::say(const say& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + text_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + text_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (!from._internal_text().empty()) { + text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_text(), + GetArenaForAllocation()); + } + // @@protoc_insertion_point(copy_constructor:proto.say) +} + +inline void say::SharedCtor() { +text_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + text_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +} + +say::~say() { + // @@protoc_insertion_point(destructor:proto.say) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void say::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + text_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void say::ArenaDtor(void* object) { + say* _this = reinterpret_cast< say* >(object); + (void)_this; +} +void say::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void say::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void say::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.say) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + text_.ClearToEmpty(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* say::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // string text = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_text(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "proto.say.text")); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* say::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.say) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // string text = 1; + if (!this->_internal_text().empty()) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_text().data(), static_cast(this->_internal_text().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "proto.say.text"); + target = stream->WriteStringMaybeAliased( + 1, this->_internal_text(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.say) + return target; +} + +size_t say::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.say) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string text = 1; + if (!this->_internal_text().empty()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_text()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData say::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + say::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*say::GetClassData() const { return &_class_data_; } + +void say::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void say::MergeFrom(const say& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.say) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (!from._internal_text().empty()) { + _internal_set_text(from._internal_text()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void say::CopyFrom(const say& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.say) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool say::IsInitialized() const { + return true; +} + +void say::InternalSwap(say* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &text_, lhs_arena, + &other->text_, rhs_arena + ); +} + +::PROTOBUF_NAMESPACE_ID::Metadata say::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[9]); +} + +// =================================================================== + +class hear_player::_Internal { + public: +}; + +hear_player::hear_player(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.hear_player) +} +hear_player::hear_player(const hear_player& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + text_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + text_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (!from._internal_text().empty()) { + text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_text(), + GetArenaForAllocation()); + } + index_ = from.index_; + // @@protoc_insertion_point(copy_constructor:proto.hear_player) +} + +inline void hear_player::SharedCtor() { +text_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + text_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +index_ = 0u; +} + +hear_player::~hear_player() { + // @@protoc_insertion_point(destructor:proto.hear_player) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void hear_player::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + text_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void hear_player::ArenaDtor(void* object) { + hear_player* _this = reinterpret_cast< hear_player* >(object); + (void)_this; +} +void hear_player::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void hear_player::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void hear_player::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.hear_player) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + text_.ClearToEmpty(); + index_ = 0u; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* hear_player::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // uint32 index = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 8)) { + index_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // string text = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + auto str = _internal_mutable_text(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "proto.hear_player.text")); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* hear_player::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.hear_player) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // uint32 index = 1; + if (this->_internal_index() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->_internal_index(), target); + } + + // string text = 2; + if (!this->_internal_text().empty()) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_text().data(), static_cast(this->_internal_text().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "proto.hear_player.text"); + target = stream->WriteStringMaybeAliased( + 2, this->_internal_text(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.hear_player) + return target; +} + +size_t hear_player::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.hear_player) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string text = 2; + if (!this->_internal_text().empty()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_text()); + } + + // uint32 index = 1; + if (this->_internal_index() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_index()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData hear_player::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + hear_player::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*hear_player::GetClassData() const { return &_class_data_; } + +void hear_player::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void hear_player::MergeFrom(const hear_player& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.hear_player) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (!from._internal_text().empty()) { + _internal_set_text(from._internal_text()); + } + if (from._internal_index() != 0) { + _internal_set_index(from._internal_index()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void hear_player::CopyFrom(const hear_player& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.hear_player) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool hear_player::IsInitialized() const { + return true; +} + +void hear_player::InternalSwap(hear_player* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &text_, lhs_arena, + &other->text_, rhs_arena + ); + swap(index_, other->index_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata hear_player::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[10]); +} + +// =================================================================== + +class request_chunk::_Internal { + public: + static const ::proto::coords& chunk_pos(const request_chunk* msg); +}; + +const ::proto::coords& +request_chunk::_Internal::chunk_pos(const request_chunk* msg) { + return *msg->chunk_pos_; +} +request_chunk::request_chunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.request_chunk) +} +request_chunk::request_chunk(const request_chunk& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_chunk_pos()) { + chunk_pos_ = new ::proto::coords(*from.chunk_pos_); + } else { + chunk_pos_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:proto.request_chunk) +} + +inline void request_chunk::SharedCtor() { +chunk_pos_ = nullptr; +} + +request_chunk::~request_chunk() { + // @@protoc_insertion_point(destructor:proto.request_chunk) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void request_chunk::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete chunk_pos_; +} + +void request_chunk::ArenaDtor(void* object) { + request_chunk* _this = reinterpret_cast< request_chunk* >(object); + (void)_this; +} +void request_chunk::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void request_chunk::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void request_chunk::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.request_chunk) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* request_chunk::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .proto.coords chunk_pos = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* request_chunk::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.request_chunk) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::chunk_pos(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.request_chunk) + return target; +} + +size_t request_chunk::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.request_chunk) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *chunk_pos_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData request_chunk::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + request_chunk::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*request_chunk::GetClassData() const { return &_class_data_; } + +void request_chunk::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void request_chunk::MergeFrom(const request_chunk& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.request_chunk) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_chunk_pos()) { + _internal_mutable_chunk_pos()->::proto::coords::MergeFrom(from._internal_chunk_pos()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void request_chunk::CopyFrom(const request_chunk& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.request_chunk) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool request_chunk::IsInitialized() const { + return true; +} + +void request_chunk::InternalSwap(request_chunk* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(chunk_pos_, other->chunk_pos_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata request_chunk::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[11]); +} + +// =================================================================== + +class remove_chunk::_Internal { + public: + static const ::proto::coords& chunk_pos(const remove_chunk* msg); +}; + +const ::proto::coords& +remove_chunk::_Internal::chunk_pos(const remove_chunk* msg) { + return *msg->chunk_pos_; +} +remove_chunk::remove_chunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.remove_chunk) +} +remove_chunk::remove_chunk(const remove_chunk& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_chunk_pos()) { + chunk_pos_ = new ::proto::coords(*from.chunk_pos_); + } else { + chunk_pos_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:proto.remove_chunk) +} + +inline void remove_chunk::SharedCtor() { +chunk_pos_ = nullptr; +} + +remove_chunk::~remove_chunk() { + // @@protoc_insertion_point(destructor:proto.remove_chunk) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void remove_chunk::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete chunk_pos_; +} + +void remove_chunk::ArenaDtor(void* object) { + remove_chunk* _this = reinterpret_cast< remove_chunk* >(object); + (void)_this; +} +void remove_chunk::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void remove_chunk::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void remove_chunk::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.remove_chunk) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* remove_chunk::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .proto.coords chunk_pos = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* remove_chunk::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.remove_chunk) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::chunk_pos(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.remove_chunk) + return target; +} + +size_t remove_chunk::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.remove_chunk) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *chunk_pos_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData remove_chunk::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + remove_chunk::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*remove_chunk::GetClassData() const { return &_class_data_; } + +void remove_chunk::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void remove_chunk::MergeFrom(const remove_chunk& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.remove_chunk) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_chunk_pos()) { + _internal_mutable_chunk_pos()->::proto::coords::MergeFrom(from._internal_chunk_pos()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void remove_chunk::CopyFrom(const remove_chunk& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.remove_chunk) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool remove_chunk::IsInitialized() const { + return true; +} + +void remove_chunk::InternalSwap(remove_chunk* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(chunk_pos_, other->chunk_pos_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata remove_chunk::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[12]); +} + +// =================================================================== + +class chunk::_Internal { + public: + static const ::proto::coords& chunk_pos(const chunk* msg); +}; + +const ::proto::coords& +chunk::_Internal::chunk_pos(const chunk* msg) { + return *msg->chunk_pos_; +} +chunk::chunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned), + blocks_(arena) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.chunk) +} +chunk::chunk(const chunk& from) + : ::PROTOBUF_NAMESPACE_ID::Message(), + blocks_(from.blocks_) { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_chunk_pos()) { + chunk_pos_ = new ::proto::coords(*from.chunk_pos_); + } else { + chunk_pos_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:proto.chunk) +} + +inline void chunk::SharedCtor() { +chunk_pos_ = nullptr; +} + +chunk::~chunk() { + // @@protoc_insertion_point(destructor:proto.chunk) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void chunk::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete chunk_pos_; +} + +void chunk::ArenaDtor(void* object) { + chunk* _this = reinterpret_cast< chunk* >(object); + (void)_this; +} +void chunk::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void chunk::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void chunk::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.chunk) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + blocks_.Clear(); + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* chunk::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .proto.coords chunk_pos = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // repeated uint32 blocks = 2 [packed = true]; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedUInt32Parser(_internal_mutable_blocks(), ptr, ctx); + CHK_(ptr); + } else if (static_cast(tag) == 16) { + _internal_add_blocks(::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr)); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* chunk::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.chunk) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::chunk_pos(this), target, stream); + } + + // repeated uint32 blocks = 2 [packed = true]; + { + int byte_size = _blocks_cached_byte_size_.load(std::memory_order_relaxed); + if (byte_size > 0) { + target = stream->WriteUInt32Packed( + 2, _internal_blocks(), byte_size, target); + } + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.chunk) + return target; +} + +size_t chunk::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.chunk) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // repeated uint32 blocks = 2 [packed = true]; + { + size_t data_size = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + UInt32Size(this->blocks_); + if (data_size > 0) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::Int32Size( + static_cast(data_size)); + } + int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(data_size); + _blocks_cached_byte_size_.store(cached_size, + std::memory_order_relaxed); + total_size += data_size; + } + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *chunk_pos_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData chunk::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + chunk::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*chunk::GetClassData() const { return &_class_data_; } + +void chunk::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void chunk::MergeFrom(const chunk& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.chunk) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + blocks_.MergeFrom(from.blocks_); + if (from._internal_has_chunk_pos()) { + _internal_mutable_chunk_pos()->::proto::coords::MergeFrom(from._internal_chunk_pos()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void chunk::CopyFrom(const chunk& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.chunk) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool chunk::IsInitialized() const { + return true; +} + +void chunk::InternalSwap(chunk* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + blocks_.InternalSwap(&other->blocks_); + swap(chunk_pos_, other->chunk_pos_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata chunk::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[13]); +} + +// =================================================================== + +class add_block::_Internal { + public: + static const ::proto::coords& chunk_pos(const add_block* msg); + static const ::proto::ivec3& block_pos(const add_block* msg); +}; + +const ::proto::coords& +add_block::_Internal::chunk_pos(const add_block* msg) { + return *msg->chunk_pos_; +} +const ::proto::ivec3& +add_block::_Internal::block_pos(const add_block* msg) { + return *msg->block_pos_; +} +add_block::add_block(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.add_block) +} +add_block::add_block(const add_block& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_chunk_pos()) { + chunk_pos_ = new ::proto::coords(*from.chunk_pos_); + } else { + chunk_pos_ = nullptr; + } + if (from._internal_has_block_pos()) { + block_pos_ = new ::proto::ivec3(*from.block_pos_); + } else { + block_pos_ = nullptr; + } + block_ = from.block_; + // @@protoc_insertion_point(copy_constructor:proto.add_block) +} + +inline void add_block::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&chunk_pos_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&block_) - + reinterpret_cast(&chunk_pos_)) + sizeof(block_)); +} + +add_block::~add_block() { + // @@protoc_insertion_point(destructor:proto.add_block) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void add_block::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete chunk_pos_; + if (this != internal_default_instance()) delete block_pos_; +} + +void add_block::ArenaDtor(void* object) { + add_block* _this = reinterpret_cast< add_block* >(object); + (void)_this; +} +void add_block::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void add_block::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void add_block::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.add_block) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; + if (GetArenaForAllocation() == nullptr && block_pos_ != nullptr) { + delete block_pos_; + } + block_pos_ = nullptr; + block_ = 0u; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* add_block::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .proto.coords chunk_pos = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.ivec3 block_pos = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ctx->ParseMessage(_internal_mutable_block_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // uint32 block = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 24)) { + block_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* add_block::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.add_block) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::chunk_pos(this), target, stream); + } + + // .proto.ivec3 block_pos = 2; + if (this->_internal_has_block_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 2, _Internal::block_pos(this), target, stream); + } + + // uint32 block = 3; + if (this->_internal_block() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(3, this->_internal_block(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.add_block) + return target; +} + +size_t add_block::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.add_block) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *chunk_pos_); + } + + // .proto.ivec3 block_pos = 2; + if (this->_internal_has_block_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *block_pos_); + } + + // uint32 block = 3; + if (this->_internal_block() != 0) { + total_size += ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::UInt32SizePlusOne(this->_internal_block()); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData add_block::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + add_block::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*add_block::GetClassData() const { return &_class_data_; } + +void add_block::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void add_block::MergeFrom(const add_block& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.add_block) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_chunk_pos()) { + _internal_mutable_chunk_pos()->::proto::coords::MergeFrom(from._internal_chunk_pos()); + } + if (from._internal_has_block_pos()) { + _internal_mutable_block_pos()->::proto::ivec3::MergeFrom(from._internal_block_pos()); + } + if (from._internal_block() != 0) { + _internal_set_block(from._internal_block()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void add_block::CopyFrom(const add_block& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.add_block) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool add_block::IsInitialized() const { + return true; +} + +void add_block::InternalSwap(add_block* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(add_block, block_) + + sizeof(add_block::block_) + - PROTOBUF_FIELD_OFFSET(add_block, chunk_pos_)>( + reinterpret_cast(&chunk_pos_), + reinterpret_cast(&other->chunk_pos_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata add_block::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[14]); +} + +// =================================================================== + +class remove_block::_Internal { + public: + static const ::proto::coords& chunk_pos(const remove_block* msg); + static const ::proto::ivec3& block_pos(const remove_block* msg); +}; + +const ::proto::coords& +remove_block::_Internal::chunk_pos(const remove_block* msg) { + return *msg->chunk_pos_; +} +const ::proto::ivec3& +remove_block::_Internal::block_pos(const remove_block* msg) { + return *msg->block_pos_; +} +remove_block::remove_block(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.remove_block) +} +remove_block::remove_block(const remove_block& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + if (from._internal_has_chunk_pos()) { + chunk_pos_ = new ::proto::coords(*from.chunk_pos_); + } else { + chunk_pos_ = nullptr; + } + if (from._internal_has_block_pos()) { + block_pos_ = new ::proto::ivec3(*from.block_pos_); + } else { + block_pos_ = nullptr; + } + // @@protoc_insertion_point(copy_constructor:proto.remove_block) +} + +inline void remove_block::SharedCtor() { +::memset(reinterpret_cast(this) + static_cast( + reinterpret_cast(&chunk_pos_) - reinterpret_cast(this)), + 0, static_cast(reinterpret_cast(&block_pos_) - + reinterpret_cast(&chunk_pos_)) + sizeof(block_pos_)); +} + +remove_block::~remove_block() { + // @@protoc_insertion_point(destructor:proto.remove_block) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void remove_block::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (this != internal_default_instance()) delete chunk_pos_; + if (this != internal_default_instance()) delete block_pos_; +} + +void remove_block::ArenaDtor(void* object) { + remove_block* _this = reinterpret_cast< remove_block* >(object); + (void)_this; +} +void remove_block::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void remove_block::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void remove_block::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.remove_block) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; + if (GetArenaForAllocation() == nullptr && block_pos_ != nullptr) { + delete block_pos_; + } + block_pos_ = nullptr; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* remove_block::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .proto.coords chunk_pos = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.ivec3 block_pos = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ctx->ParseMessage(_internal_mutable_block_pos(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* remove_block::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.remove_block) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::chunk_pos(this), target, stream); + } + + // .proto.ivec3 block_pos = 2; + if (this->_internal_has_block_pos()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 2, _Internal::block_pos(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.remove_block) + return target; +} + +size_t remove_block::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.remove_block) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // .proto.coords chunk_pos = 1; + if (this->_internal_has_chunk_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *chunk_pos_); + } + + // .proto.ivec3 block_pos = 2; + if (this->_internal_has_block_pos()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *block_pos_); + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData remove_block::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + remove_block::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*remove_block::GetClassData() const { return &_class_data_; } + +void remove_block::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void remove_block::MergeFrom(const remove_block& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.remove_block) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (from._internal_has_chunk_pos()) { + _internal_mutable_chunk_pos()->::proto::coords::MergeFrom(from._internal_chunk_pos()); + } + if (from._internal_has_block_pos()) { + _internal_mutable_block_pos()->::proto::ivec3::MergeFrom(from._internal_block_pos()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void remove_block::CopyFrom(const remove_block& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.remove_block) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool remove_block::IsInitialized() const { + return true; +} + +void remove_block::InternalSwap(remove_block* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::memswap< + PROTOBUF_FIELD_OFFSET(remove_block, block_pos_) + + sizeof(remove_block::block_pos_) + - PROTOBUF_FIELD_OFFSET(remove_block, chunk_pos_)>( + reinterpret_cast(&chunk_pos_), + reinterpret_cast(&other->chunk_pos_)); +} + +::PROTOBUF_NAMESPACE_ID::Metadata remove_block::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[15]); +} + +// =================================================================== + +class server_message::_Internal { + public: +}; + +server_message::server_message(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.server_message) +} +server_message::server_message(const server_message& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + message_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); + #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + message_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (!from._internal_message().empty()) { + message_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_message(), + GetArenaForAllocation()); + } + fatal_ = from.fatal_; + // @@protoc_insertion_point(copy_constructor:proto.server_message) +} + +inline void server_message::SharedCtor() { +message_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + message_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING +fatal_ = false; +} + +server_message::~server_message() { + // @@protoc_insertion_point(destructor:proto.server_message) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void server_message::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + message_.DestroyNoArena(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited()); +} + +void server_message::ArenaDtor(void* object) { + server_message* _this = reinterpret_cast< server_message* >(object); + (void)_this; +} +void server_message::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void server_message::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void server_message::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.server_message) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + message_.ClearToEmpty(); + fatal_ = false; + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* server_message::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // string message = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + auto str = _internal_mutable_message(); + ptr = ::PROTOBUF_NAMESPACE_ID::internal::InlineGreedyStringParser(str, ptr, ctx); + CHK_(::PROTOBUF_NAMESPACE_ID::internal::VerifyUTF8(str, "proto.server_message.message")); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // bool fatal = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 16)) { + fatal_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* server_message::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.server_message) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // string message = 1; + if (!this->_internal_message().empty()) { + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String( + this->_internal_message().data(), static_cast(this->_internal_message().length()), + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, + "proto.server_message.message"); + target = stream->WriteStringMaybeAliased( + 1, this->_internal_message(), target); + } + + // bool fatal = 2; + if (this->_internal_fatal() != 0) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->_internal_fatal(), target); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.server_message) + return target; +} + +size_t server_message::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.server_message) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + // string message = 1; + if (!this->_internal_message().empty()) { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize( + this->_internal_message()); + } + + // bool fatal = 2; + if (this->_internal_fatal() != 0) { + total_size += 1 + 1; + } + + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData server_message::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + server_message::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*server_message::GetClassData() const { return &_class_data_; } + +void server_message::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void server_message::MergeFrom(const server_message& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.server_message) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + if (!from._internal_message().empty()) { + _internal_set_message(from._internal_message()); + } + if (from._internal_fatal() != 0) { + _internal_set_fatal(from._internal_fatal()); + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void server_message::CopyFrom(const server_message& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.server_message) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool server_message::IsInitialized() const { + return true; +} + +void server_message::InternalSwap(server_message* other) { + using std::swap; + auto* lhs_arena = GetArenaForAllocation(); + auto* rhs_arena = other->GetArenaForAllocation(); + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap( + &::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), + &message_, lhs_arena, + &other->message_, rhs_arena + ); + swap(fatal_, other->fatal_); +} + +::PROTOBUF_NAMESPACE_ID::Metadata server_message::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[16]); +} + +// =================================================================== + +class packet::_Internal { + public: + static const ::proto::auth& auth_packet(const packet* msg); + static const ::proto::init& init_packet(const packet* msg); + static const ::proto::move& move_packet(const packet* msg); + static const ::proto::player& player_packet(const packet* msg); + static const ::proto::remove_player& remove_player_packet(const packet* msg); + static const ::proto::say& say_packet(const packet* msg); + static const ::proto::hear_player& hear_player_packet(const packet* msg); + static const ::proto::request_chunk& request_chunk_packet(const packet* msg); + static const ::proto::chunk& chunk_packet(const packet* msg); + static const ::proto::remove_chunk& remove_chunk_packet(const packet* msg); + static const ::proto::add_block& add_block_packet(const packet* msg); + static const ::proto::remove_block& remove_block_packet(const packet* msg); + static const ::proto::server_message& server_message_packet(const packet* msg); +}; + +const ::proto::auth& +packet::_Internal::auth_packet(const packet* msg) { + return *msg->contents_.auth_packet_; +} +const ::proto::init& +packet::_Internal::init_packet(const packet* msg) { + return *msg->contents_.init_packet_; +} +const ::proto::move& +packet::_Internal::move_packet(const packet* msg) { + return *msg->contents_.move_packet_; +} +const ::proto::player& +packet::_Internal::player_packet(const packet* msg) { + return *msg->contents_.player_packet_; +} +const ::proto::remove_player& +packet::_Internal::remove_player_packet(const packet* msg) { + return *msg->contents_.remove_player_packet_; +} +const ::proto::say& +packet::_Internal::say_packet(const packet* msg) { + return *msg->contents_.say_packet_; +} +const ::proto::hear_player& +packet::_Internal::hear_player_packet(const packet* msg) { + return *msg->contents_.hear_player_packet_; +} +const ::proto::request_chunk& +packet::_Internal::request_chunk_packet(const packet* msg) { + return *msg->contents_.request_chunk_packet_; +} +const ::proto::chunk& +packet::_Internal::chunk_packet(const packet* msg) { + return *msg->contents_.chunk_packet_; +} +const ::proto::remove_chunk& +packet::_Internal::remove_chunk_packet(const packet* msg) { + return *msg->contents_.remove_chunk_packet_; +} +const ::proto::add_block& +packet::_Internal::add_block_packet(const packet* msg) { + return *msg->contents_.add_block_packet_; +} +const ::proto::remove_block& +packet::_Internal::remove_block_packet(const packet* msg) { + return *msg->contents_.remove_block_packet_; +} +const ::proto::server_message& +packet::_Internal::server_message_packet(const packet* msg) { + return *msg->contents_.server_message_packet_; +} +void packet::set_allocated_auth_packet(::proto::auth* auth_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (auth_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::auth>::GetOwningArena(auth_packet); + if (message_arena != submessage_arena) { + auth_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, auth_packet, submessage_arena); + } + set_has_auth_packet(); + contents_.auth_packet_ = auth_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.auth_packet) +} +void packet::set_allocated_init_packet(::proto::init* init_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (init_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::init>::GetOwningArena(init_packet); + if (message_arena != submessage_arena) { + init_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, init_packet, submessage_arena); + } + set_has_init_packet(); + contents_.init_packet_ = init_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.init_packet) +} +void packet::set_allocated_move_packet(::proto::move* move_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (move_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::move>::GetOwningArena(move_packet); + if (message_arena != submessage_arena) { + move_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, move_packet, submessage_arena); + } + set_has_move_packet(); + contents_.move_packet_ = move_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.move_packet) +} +void packet::set_allocated_player_packet(::proto::player* player_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (player_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::player>::GetOwningArena(player_packet); + if (message_arena != submessage_arena) { + player_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, player_packet, submessage_arena); + } + set_has_player_packet(); + contents_.player_packet_ = player_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.player_packet) +} +void packet::set_allocated_remove_player_packet(::proto::remove_player* remove_player_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (remove_player_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::remove_player>::GetOwningArena(remove_player_packet); + if (message_arena != submessage_arena) { + remove_player_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, remove_player_packet, submessage_arena); + } + set_has_remove_player_packet(); + contents_.remove_player_packet_ = remove_player_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.remove_player_packet) +} +void packet::set_allocated_say_packet(::proto::say* say_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (say_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::say>::GetOwningArena(say_packet); + if (message_arena != submessage_arena) { + say_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, say_packet, submessage_arena); + } + set_has_say_packet(); + contents_.say_packet_ = say_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.say_packet) +} +void packet::set_allocated_hear_player_packet(::proto::hear_player* hear_player_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (hear_player_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::hear_player>::GetOwningArena(hear_player_packet); + if (message_arena != submessage_arena) { + hear_player_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, hear_player_packet, submessage_arena); + } + set_has_hear_player_packet(); + contents_.hear_player_packet_ = hear_player_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.hear_player_packet) +} +void packet::set_allocated_request_chunk_packet(::proto::request_chunk* request_chunk_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (request_chunk_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::request_chunk>::GetOwningArena(request_chunk_packet); + if (message_arena != submessage_arena) { + request_chunk_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, request_chunk_packet, submessage_arena); + } + set_has_request_chunk_packet(); + contents_.request_chunk_packet_ = request_chunk_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.request_chunk_packet) +} +void packet::set_allocated_chunk_packet(::proto::chunk* chunk_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (chunk_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::chunk>::GetOwningArena(chunk_packet); + if (message_arena != submessage_arena) { + chunk_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_packet, submessage_arena); + } + set_has_chunk_packet(); + contents_.chunk_packet_ = chunk_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.chunk_packet) +} +void packet::set_allocated_remove_chunk_packet(::proto::remove_chunk* remove_chunk_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (remove_chunk_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::remove_chunk>::GetOwningArena(remove_chunk_packet); + if (message_arena != submessage_arena) { + remove_chunk_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, remove_chunk_packet, submessage_arena); + } + set_has_remove_chunk_packet(); + contents_.remove_chunk_packet_ = remove_chunk_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.remove_chunk_packet) +} +void packet::set_allocated_add_block_packet(::proto::add_block* add_block_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (add_block_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::add_block>::GetOwningArena(add_block_packet); + if (message_arena != submessage_arena) { + add_block_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, add_block_packet, submessage_arena); + } + set_has_add_block_packet(); + contents_.add_block_packet_ = add_block_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.add_block_packet) +} +void packet::set_allocated_remove_block_packet(::proto::remove_block* remove_block_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (remove_block_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::remove_block>::GetOwningArena(remove_block_packet); + if (message_arena != submessage_arena) { + remove_block_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, remove_block_packet, submessage_arena); + } + set_has_remove_block_packet(); + contents_.remove_block_packet_ = remove_block_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.remove_block_packet) +} +void packet::set_allocated_server_message_packet(::proto::server_message* server_message_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + clear_contents(); + if (server_message_packet) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::server_message>::GetOwningArena(server_message_packet); + if (message_arena != submessage_arena) { + server_message_packet = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, server_message_packet, submessage_arena); + } + set_has_server_message_packet(); + contents_.server_message_packet_ = server_message_packet; + } + // @@protoc_insertion_point(field_set_allocated:proto.packet.server_message_packet) +} +packet::packet(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned) + : ::PROTOBUF_NAMESPACE_ID::Message(arena, is_message_owned) { + SharedCtor(); + if (!is_message_owned) { + RegisterArenaDtor(arena); + } + // @@protoc_insertion_point(arena_constructor:proto.packet) +} +packet::packet(const packet& from) + : ::PROTOBUF_NAMESPACE_ID::Message() { + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); + clear_has_contents(); + switch (from.contents_case()) { + case kAuthPacket: { + _internal_mutable_auth_packet()->::proto::auth::MergeFrom(from._internal_auth_packet()); + break; + } + case kInitPacket: { + _internal_mutable_init_packet()->::proto::init::MergeFrom(from._internal_init_packet()); + break; + } + case kMovePacket: { + _internal_mutable_move_packet()->::proto::move::MergeFrom(from._internal_move_packet()); + break; + } + case kPlayerPacket: { + _internal_mutable_player_packet()->::proto::player::MergeFrom(from._internal_player_packet()); + break; + } + case kRemovePlayerPacket: { + _internal_mutable_remove_player_packet()->::proto::remove_player::MergeFrom(from._internal_remove_player_packet()); + break; + } + case kSayPacket: { + _internal_mutable_say_packet()->::proto::say::MergeFrom(from._internal_say_packet()); + break; + } + case kHearPlayerPacket: { + _internal_mutable_hear_player_packet()->::proto::hear_player::MergeFrom(from._internal_hear_player_packet()); + break; + } + case kRequestChunkPacket: { + _internal_mutable_request_chunk_packet()->::proto::request_chunk::MergeFrom(from._internal_request_chunk_packet()); + break; + } + case kChunkPacket: { + _internal_mutable_chunk_packet()->::proto::chunk::MergeFrom(from._internal_chunk_packet()); + break; + } + case kRemoveChunkPacket: { + _internal_mutable_remove_chunk_packet()->::proto::remove_chunk::MergeFrom(from._internal_remove_chunk_packet()); + break; + } + case kAddBlockPacket: { + _internal_mutable_add_block_packet()->::proto::add_block::MergeFrom(from._internal_add_block_packet()); + break; + } + case kRemoveBlockPacket: { + _internal_mutable_remove_block_packet()->::proto::remove_block::MergeFrom(from._internal_remove_block_packet()); + break; + } + case kServerMessagePacket: { + _internal_mutable_server_message_packet()->::proto::server_message::MergeFrom(from._internal_server_message_packet()); + break; + } + case CONTENTS_NOT_SET: { + break; + } + } + // @@protoc_insertion_point(copy_constructor:proto.packet) +} + +inline void packet::SharedCtor() { +clear_has_contents(); +} + +packet::~packet() { + // @@protoc_insertion_point(destructor:proto.packet) + if (GetArenaForAllocation() != nullptr) return; + SharedDtor(); + _internal_metadata_.Delete<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +inline void packet::SharedDtor() { + GOOGLE_DCHECK(GetArenaForAllocation() == nullptr); + if (has_contents()) { + clear_contents(); + } +} + +void packet::ArenaDtor(void* object) { + packet* _this = reinterpret_cast< packet* >(object); + (void)_this; +} +void packet::RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena*) { +} +void packet::SetCachedSize(int size) const { + _cached_size_.Set(size); +} + +void packet::clear_contents() { +// @@protoc_insertion_point(one_of_clear_start:proto.packet) + switch (contents_case()) { + case kAuthPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.auth_packet_; + } + break; + } + case kInitPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.init_packet_; + } + break; + } + case kMovePacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.move_packet_; + } + break; + } + case kPlayerPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.player_packet_; + } + break; + } + case kRemovePlayerPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.remove_player_packet_; + } + break; + } + case kSayPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.say_packet_; + } + break; + } + case kHearPlayerPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.hear_player_packet_; + } + break; + } + case kRequestChunkPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.request_chunk_packet_; + } + break; + } + case kChunkPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.chunk_packet_; + } + break; + } + case kRemoveChunkPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.remove_chunk_packet_; + } + break; + } + case kAddBlockPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.add_block_packet_; + } + break; + } + case kRemoveBlockPacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.remove_block_packet_; + } + break; + } + case kServerMessagePacket: { + if (GetArenaForAllocation() == nullptr) { + delete contents_.server_message_packet_; + } + break; + } + case CONTENTS_NOT_SET: { + break; + } + } + _oneof_case_[0] = CONTENTS_NOT_SET; +} + + +void packet::Clear() { +// @@protoc_insertion_point(message_clear_start:proto.packet) + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + clear_contents(); + _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); +} + +const char* packet::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) { +#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure + while (!ctx->Done(&ptr)) { + uint32_t tag; + ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag); + switch (tag >> 3) { + // .proto.auth auth_packet = 1; + case 1: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 10)) { + ptr = ctx->ParseMessage(_internal_mutable_auth_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.init init_packet = 2; + case 2: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 18)) { + ptr = ctx->ParseMessage(_internal_mutable_init_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.move move_packet = 3; + case 3: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 26)) { + ptr = ctx->ParseMessage(_internal_mutable_move_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.player player_packet = 4; + case 4: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 34)) { + ptr = ctx->ParseMessage(_internal_mutable_player_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.remove_player remove_player_packet = 5; + case 5: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 42)) { + ptr = ctx->ParseMessage(_internal_mutable_remove_player_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.say say_packet = 6; + case 6: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 50)) { + ptr = ctx->ParseMessage(_internal_mutable_say_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.hear_player hear_player_packet = 7; + case 7: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 58)) { + ptr = ctx->ParseMessage(_internal_mutable_hear_player_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.request_chunk request_chunk_packet = 8; + case 8: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 66)) { + ptr = ctx->ParseMessage(_internal_mutable_request_chunk_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.chunk chunk_packet = 9; + case 9: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 74)) { + ptr = ctx->ParseMessage(_internal_mutable_chunk_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.remove_chunk remove_chunk_packet = 10; + case 10: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 82)) { + ptr = ctx->ParseMessage(_internal_mutable_remove_chunk_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.add_block add_block_packet = 11; + case 11: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 90)) { + ptr = ctx->ParseMessage(_internal_mutable_add_block_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.remove_block remove_block_packet = 12; + case 12: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 98)) { + ptr = ctx->ParseMessage(_internal_mutable_remove_block_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + // .proto.server_message server_message_packet = 13; + case 13: + if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 106)) { + ptr = ctx->ParseMessage(_internal_mutable_server_message_packet(), ptr); + CHK_(ptr); + } else + goto handle_unusual; + continue; + default: + goto handle_unusual; + } // switch + handle_unusual: + if ((tag == 0) || ((tag & 7) == 4)) { + CHK_(ptr); + ctx->SetLastTag(tag); + goto message_done; + } + ptr = UnknownFieldParse( + tag, + _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(), + ptr, ctx); + CHK_(ptr != nullptr); + } // while +message_done: + return ptr; +failure: + ptr = nullptr; + goto message_done; +#undef CHK_ +} + +uint8_t* packet::_InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const { + // @@protoc_insertion_point(serialize_to_array_start:proto.packet) + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + // .proto.auth auth_packet = 1; + if (_internal_has_auth_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 1, _Internal::auth_packet(this), target, stream); + } + + // .proto.init init_packet = 2; + if (_internal_has_init_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 2, _Internal::init_packet(this), target, stream); + } + + // .proto.move move_packet = 3; + if (_internal_has_move_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 3, _Internal::move_packet(this), target, stream); + } + + // .proto.player player_packet = 4; + if (_internal_has_player_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 4, _Internal::player_packet(this), target, stream); + } + + // .proto.remove_player remove_player_packet = 5; + if (_internal_has_remove_player_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 5, _Internal::remove_player_packet(this), target, stream); + } + + // .proto.say say_packet = 6; + if (_internal_has_say_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 6, _Internal::say_packet(this), target, stream); + } + + // .proto.hear_player hear_player_packet = 7; + if (_internal_has_hear_player_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 7, _Internal::hear_player_packet(this), target, stream); + } + + // .proto.request_chunk request_chunk_packet = 8; + if (_internal_has_request_chunk_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 8, _Internal::request_chunk_packet(this), target, stream); + } + + // .proto.chunk chunk_packet = 9; + if (_internal_has_chunk_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 9, _Internal::chunk_packet(this), target, stream); + } + + // .proto.remove_chunk remove_chunk_packet = 10; + if (_internal_has_remove_chunk_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 10, _Internal::remove_chunk_packet(this), target, stream); + } + + // .proto.add_block add_block_packet = 11; + if (_internal_has_add_block_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 11, _Internal::add_block_packet(this), target, stream); + } + + // .proto.remove_block remove_block_packet = 12; + if (_internal_has_remove_block_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 12, _Internal::remove_block_packet(this), target, stream); + } + + // .proto.server_message server_message_packet = 13; + if (_internal_has_server_message_packet()) { + target = stream->EnsureSpace(target); + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite:: + InternalWriteMessage( + 13, _Internal::server_message_packet(this), target, stream); + } + + if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { + target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray( + _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream); + } + // @@protoc_insertion_point(serialize_to_array_end:proto.packet) + return target; +} + +size_t packet::ByteSizeLong() const { +// @@protoc_insertion_point(message_byte_size_start:proto.packet) + size_t total_size = 0; + + uint32_t cached_has_bits = 0; + // Prevent compiler warnings about cached_has_bits being unused + (void) cached_has_bits; + + switch (contents_case()) { + // .proto.auth auth_packet = 1; + case kAuthPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.auth_packet_); + break; + } + // .proto.init init_packet = 2; + case kInitPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.init_packet_); + break; + } + // .proto.move move_packet = 3; + case kMovePacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.move_packet_); + break; + } + // .proto.player player_packet = 4; + case kPlayerPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.player_packet_); + break; + } + // .proto.remove_player remove_player_packet = 5; + case kRemovePlayerPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.remove_player_packet_); + break; + } + // .proto.say say_packet = 6; + case kSayPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.say_packet_); + break; + } + // .proto.hear_player hear_player_packet = 7; + case kHearPlayerPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.hear_player_packet_); + break; + } + // .proto.request_chunk request_chunk_packet = 8; + case kRequestChunkPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.request_chunk_packet_); + break; + } + // .proto.chunk chunk_packet = 9; + case kChunkPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.chunk_packet_); + break; + } + // .proto.remove_chunk remove_chunk_packet = 10; + case kRemoveChunkPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.remove_chunk_packet_); + break; + } + // .proto.add_block add_block_packet = 11; + case kAddBlockPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.add_block_packet_); + break; + } + // .proto.remove_block remove_block_packet = 12; + case kRemoveBlockPacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.remove_block_packet_); + break; + } + // .proto.server_message server_message_packet = 13; + case kServerMessagePacket: { + total_size += 1 + + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize( + *contents_.server_message_packet_); + break; + } + case CONTENTS_NOT_SET: { + break; + } + } + return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_); +} + +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData packet::_class_data_ = { + ::PROTOBUF_NAMESPACE_ID::Message::CopyWithSizeCheck, + packet::MergeImpl +}; +const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*packet::GetClassData() const { return &_class_data_; } + +void packet::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, + const ::PROTOBUF_NAMESPACE_ID::Message& from) { + static_cast(to)->MergeFrom( + static_cast(from)); +} + + +void packet::MergeFrom(const packet& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:proto.packet) + GOOGLE_DCHECK_NE(&from, this); + uint32_t cached_has_bits = 0; + (void) cached_has_bits; + + switch (from.contents_case()) { + case kAuthPacket: { + _internal_mutable_auth_packet()->::proto::auth::MergeFrom(from._internal_auth_packet()); + break; + } + case kInitPacket: { + _internal_mutable_init_packet()->::proto::init::MergeFrom(from._internal_init_packet()); + break; + } + case kMovePacket: { + _internal_mutable_move_packet()->::proto::move::MergeFrom(from._internal_move_packet()); + break; + } + case kPlayerPacket: { + _internal_mutable_player_packet()->::proto::player::MergeFrom(from._internal_player_packet()); + break; + } + case kRemovePlayerPacket: { + _internal_mutable_remove_player_packet()->::proto::remove_player::MergeFrom(from._internal_remove_player_packet()); + break; + } + case kSayPacket: { + _internal_mutable_say_packet()->::proto::say::MergeFrom(from._internal_say_packet()); + break; + } + case kHearPlayerPacket: { + _internal_mutable_hear_player_packet()->::proto::hear_player::MergeFrom(from._internal_hear_player_packet()); + break; + } + case kRequestChunkPacket: { + _internal_mutable_request_chunk_packet()->::proto::request_chunk::MergeFrom(from._internal_request_chunk_packet()); + break; + } + case kChunkPacket: { + _internal_mutable_chunk_packet()->::proto::chunk::MergeFrom(from._internal_chunk_packet()); + break; + } + case kRemoveChunkPacket: { + _internal_mutable_remove_chunk_packet()->::proto::remove_chunk::MergeFrom(from._internal_remove_chunk_packet()); + break; + } + case kAddBlockPacket: { + _internal_mutable_add_block_packet()->::proto::add_block::MergeFrom(from._internal_add_block_packet()); + break; + } + case kRemoveBlockPacket: { + _internal_mutable_remove_block_packet()->::proto::remove_block::MergeFrom(from._internal_remove_block_packet()); + break; + } + case kServerMessagePacket: { + _internal_mutable_server_message_packet()->::proto::server_message::MergeFrom(from._internal_server_message_packet()); + break; + } + case CONTENTS_NOT_SET: { + break; + } + } + _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); +} + +void packet::CopyFrom(const packet& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:proto.packet) + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool packet::IsInitialized() const { + return true; +} + +void packet::InternalSwap(packet* other) { + using std::swap; + _internal_metadata_.InternalSwap(&other->_internal_metadata_); + swap(contents_, other->contents_); + swap(_oneof_case_[0], other->_oneof_case_[0]); +} + +::PROTOBUF_NAMESPACE_ID::Metadata packet::GetMetadata() const { + return ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors( + &descriptor_table_net_2eproto_getter, &descriptor_table_net_2eproto_once, + file_level_metadata_net_2eproto[17]); +} + +// @@protoc_insertion_point(namespace_scope) +} // namespace proto +PROTOBUF_NAMESPACE_OPEN +template<> PROTOBUF_NOINLINE ::proto::angles* Arena::CreateMaybeMessage< ::proto::angles >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::angles >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::coords* Arena::CreateMaybeMessage< ::proto::coords >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::coords >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::vec3* Arena::CreateMaybeMessage< ::proto::vec3 >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::vec3 >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::ivec3* Arena::CreateMaybeMessage< ::proto::ivec3 >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::ivec3 >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::player* Arena::CreateMaybeMessage< ::proto::player >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::player >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::auth* Arena::CreateMaybeMessage< ::proto::auth >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::auth >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::init* Arena::CreateMaybeMessage< ::proto::init >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::init >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::move* Arena::CreateMaybeMessage< ::proto::move >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::move >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::remove_player* Arena::CreateMaybeMessage< ::proto::remove_player >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::remove_player >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::say* Arena::CreateMaybeMessage< ::proto::say >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::say >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::hear_player* Arena::CreateMaybeMessage< ::proto::hear_player >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::hear_player >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::request_chunk* Arena::CreateMaybeMessage< ::proto::request_chunk >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::request_chunk >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::remove_chunk* Arena::CreateMaybeMessage< ::proto::remove_chunk >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::remove_chunk >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::chunk* Arena::CreateMaybeMessage< ::proto::chunk >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::chunk >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::add_block* Arena::CreateMaybeMessage< ::proto::add_block >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::add_block >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::remove_block* Arena::CreateMaybeMessage< ::proto::remove_block >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::remove_block >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::server_message* Arena::CreateMaybeMessage< ::proto::server_message >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::server_message >(arena); +} +template<> PROTOBUF_NOINLINE ::proto::packet* Arena::CreateMaybeMessage< ::proto::packet >(Arena* arena) { + return Arena::CreateMessageInternal< ::proto::packet >(arena); +} +PROTOBUF_NAMESPACE_CLOSE + +// @@protoc_insertion_point(global_scope) +#include diff --git a/src/shared/net/lib/protobuf/net.pb.h b/src/shared/net/lib/protobuf/net.pb.h new file mode 100644 index 0000000..9160072 --- /dev/null +++ b/src/shared/net/lib/protobuf/net.pb.h @@ -0,0 +1,6386 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: net.proto + +#ifndef GOOGLE_PROTOBUF_INCLUDED_net_2eproto +#define GOOGLE_PROTOBUF_INCLUDED_net_2eproto + +#include +#include + +#include +#if PROTOBUF_VERSION < 3019000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 3019002 < PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: export +#include // IWYU pragma: export +#include +// @@protoc_insertion_point(includes) +#include +#define PROTOBUF_INTERNAL_EXPORT_net_2eproto +PROTOBUF_NAMESPACE_OPEN +namespace internal { +class AnyMetadata; +} // namespace internal +PROTOBUF_NAMESPACE_CLOSE + +// Internal implementation detail -- do not use these members. +struct TableStruct_net_2eproto { + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTableField entries[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::AuxiliaryParseTableField aux[] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::ParseTable schema[18] + PROTOBUF_SECTION_VARIABLE(protodesc_cold); + static const ::PROTOBUF_NAMESPACE_ID::internal::FieldMetadata field_metadata[]; + static const ::PROTOBUF_NAMESPACE_ID::internal::SerializationTable serialization_table[]; + static const uint32_t offsets[]; +}; +extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_net_2eproto; +namespace proto { +class add_block; +struct add_blockDefaultTypeInternal; +extern add_blockDefaultTypeInternal _add_block_default_instance_; +class angles; +struct anglesDefaultTypeInternal; +extern anglesDefaultTypeInternal _angles_default_instance_; +class auth; +struct authDefaultTypeInternal; +extern authDefaultTypeInternal _auth_default_instance_; +class chunk; +struct chunkDefaultTypeInternal; +extern chunkDefaultTypeInternal _chunk_default_instance_; +class coords; +struct coordsDefaultTypeInternal; +extern coordsDefaultTypeInternal _coords_default_instance_; +class hear_player; +struct hear_playerDefaultTypeInternal; +extern hear_playerDefaultTypeInternal _hear_player_default_instance_; +class init; +struct initDefaultTypeInternal; +extern initDefaultTypeInternal _init_default_instance_; +class ivec3; +struct ivec3DefaultTypeInternal; +extern ivec3DefaultTypeInternal _ivec3_default_instance_; +class move; +struct moveDefaultTypeInternal; +extern moveDefaultTypeInternal _move_default_instance_; +class packet; +struct packetDefaultTypeInternal; +extern packetDefaultTypeInternal _packet_default_instance_; +class player; +struct playerDefaultTypeInternal; +extern playerDefaultTypeInternal _player_default_instance_; +class remove_block; +struct remove_blockDefaultTypeInternal; +extern remove_blockDefaultTypeInternal _remove_block_default_instance_; +class remove_chunk; +struct remove_chunkDefaultTypeInternal; +extern remove_chunkDefaultTypeInternal _remove_chunk_default_instance_; +class remove_player; +struct remove_playerDefaultTypeInternal; +extern remove_playerDefaultTypeInternal _remove_player_default_instance_; +class request_chunk; +struct request_chunkDefaultTypeInternal; +extern request_chunkDefaultTypeInternal _request_chunk_default_instance_; +class say; +struct sayDefaultTypeInternal; +extern sayDefaultTypeInternal _say_default_instance_; +class server_message; +struct server_messageDefaultTypeInternal; +extern server_messageDefaultTypeInternal _server_message_default_instance_; +class vec3; +struct vec3DefaultTypeInternal; +extern vec3DefaultTypeInternal _vec3_default_instance_; +} // namespace proto +PROTOBUF_NAMESPACE_OPEN +template<> ::proto::add_block* Arena::CreateMaybeMessage<::proto::add_block>(Arena*); +template<> ::proto::angles* Arena::CreateMaybeMessage<::proto::angles>(Arena*); +template<> ::proto::auth* Arena::CreateMaybeMessage<::proto::auth>(Arena*); +template<> ::proto::chunk* Arena::CreateMaybeMessage<::proto::chunk>(Arena*); +template<> ::proto::coords* Arena::CreateMaybeMessage<::proto::coords>(Arena*); +template<> ::proto::hear_player* Arena::CreateMaybeMessage<::proto::hear_player>(Arena*); +template<> ::proto::init* Arena::CreateMaybeMessage<::proto::init>(Arena*); +template<> ::proto::ivec3* Arena::CreateMaybeMessage<::proto::ivec3>(Arena*); +template<> ::proto::move* Arena::CreateMaybeMessage<::proto::move>(Arena*); +template<> ::proto::packet* Arena::CreateMaybeMessage<::proto::packet>(Arena*); +template<> ::proto::player* Arena::CreateMaybeMessage<::proto::player>(Arena*); +template<> ::proto::remove_block* Arena::CreateMaybeMessage<::proto::remove_block>(Arena*); +template<> ::proto::remove_chunk* Arena::CreateMaybeMessage<::proto::remove_chunk>(Arena*); +template<> ::proto::remove_player* Arena::CreateMaybeMessage<::proto::remove_player>(Arena*); +template<> ::proto::request_chunk* Arena::CreateMaybeMessage<::proto::request_chunk>(Arena*); +template<> ::proto::say* Arena::CreateMaybeMessage<::proto::say>(Arena*); +template<> ::proto::server_message* Arena::CreateMaybeMessage<::proto::server_message>(Arena*); +template<> ::proto::vec3* Arena::CreateMaybeMessage<::proto::vec3>(Arena*); +PROTOBUF_NAMESPACE_CLOSE +namespace proto { + +// =================================================================== + +class angles final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.angles) */ { + public: + inline angles() : angles(nullptr) {} + ~angles() override; + explicit constexpr angles(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + angles(const angles& from); + angles(angles&& from) noexcept + : angles() { + *this = ::std::move(from); + } + + inline angles& operator=(const angles& from) { + CopyFrom(from); + return *this; + } + inline angles& operator=(angles&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const angles& default_instance() { + return *internal_default_instance(); + } + static inline const angles* internal_default_instance() { + return reinterpret_cast( + &_angles_default_instance_); + } + static constexpr int kIndexInFileMessages = + 0; + + friend void swap(angles& a, angles& b) { + a.Swap(&b); + } + inline void Swap(angles* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(angles* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + angles* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const angles& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const angles& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(angles* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.angles"; + } + protected: + explicit angles(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kPitchFieldNumber = 1, + kYawFieldNumber = 2, + }; + // float pitch = 1; + void clear_pitch(); + float pitch() const; + void set_pitch(float value); + private: + float _internal_pitch() const; + void _internal_set_pitch(float value); + public: + + // float yaw = 2; + void clear_yaw(); + float yaw() const; + void set_yaw(float value); + private: + float _internal_yaw() const; + void _internal_set_yaw(float value); + public: + + // @@protoc_insertion_point(class_scope:proto.angles) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + float pitch_; + float yaw_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class coords final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.coords) */ { + public: + inline coords() : coords(nullptr) {} + ~coords() override; + explicit constexpr coords(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + coords(const coords& from); + coords(coords&& from) noexcept + : coords() { + *this = ::std::move(from); + } + + inline coords& operator=(const coords& from) { + CopyFrom(from); + return *this; + } + inline coords& operator=(coords&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const coords& default_instance() { + return *internal_default_instance(); + } + static inline const coords* internal_default_instance() { + return reinterpret_cast( + &_coords_default_instance_); + } + static constexpr int kIndexInFileMessages = + 1; + + friend void swap(coords& a, coords& b) { + a.Swap(&b); + } + inline void Swap(coords* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(coords* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + coords* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const coords& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const coords& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(coords* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.coords"; + } + protected: + explicit coords(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kXFieldNumber = 1, + kZFieldNumber = 2, + }; + // int32 x = 1; + void clear_x(); + int32_t x() const; + void set_x(int32_t value); + private: + int32_t _internal_x() const; + void _internal_set_x(int32_t value); + public: + + // int32 z = 2; + void clear_z(); + int32_t z() const; + void set_z(int32_t value); + private: + int32_t _internal_z() const; + void _internal_set_z(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.coords) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + int32_t x_; + int32_t z_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class vec3 final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.vec3) */ { + public: + inline vec3() : vec3(nullptr) {} + ~vec3() override; + explicit constexpr vec3(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + vec3(const vec3& from); + vec3(vec3&& from) noexcept + : vec3() { + *this = ::std::move(from); + } + + inline vec3& operator=(const vec3& from) { + CopyFrom(from); + return *this; + } + inline vec3& operator=(vec3&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const vec3& default_instance() { + return *internal_default_instance(); + } + static inline const vec3* internal_default_instance() { + return reinterpret_cast( + &_vec3_default_instance_); + } + static constexpr int kIndexInFileMessages = + 2; + + friend void swap(vec3& a, vec3& b) { + a.Swap(&b); + } + inline void Swap(vec3* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(vec3* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + vec3* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const vec3& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const vec3& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(vec3* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.vec3"; + } + protected: + explicit vec3(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kXFieldNumber = 1, + kYFieldNumber = 2, + kZFieldNumber = 3, + }; + // float x = 1; + void clear_x(); + float x() const; + void set_x(float value); + private: + float _internal_x() const; + void _internal_set_x(float value); + public: + + // float y = 2; + void clear_y(); + float y() const; + void set_y(float value); + private: + float _internal_y() const; + void _internal_set_y(float value); + public: + + // float z = 3; + void clear_z(); + float z() const; + void set_z(float value); + private: + float _internal_z() const; + void _internal_set_z(float value); + public: + + // @@protoc_insertion_point(class_scope:proto.vec3) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + float x_; + float y_; + float z_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class ivec3 final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.ivec3) */ { + public: + inline ivec3() : ivec3(nullptr) {} + ~ivec3() override; + explicit constexpr ivec3(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + ivec3(const ivec3& from); + ivec3(ivec3&& from) noexcept + : ivec3() { + *this = ::std::move(from); + } + + inline ivec3& operator=(const ivec3& from) { + CopyFrom(from); + return *this; + } + inline ivec3& operator=(ivec3&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const ivec3& default_instance() { + return *internal_default_instance(); + } + static inline const ivec3* internal_default_instance() { + return reinterpret_cast( + &_ivec3_default_instance_); + } + static constexpr int kIndexInFileMessages = + 3; + + friend void swap(ivec3& a, ivec3& b) { + a.Swap(&b); + } + inline void Swap(ivec3* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(ivec3* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + ivec3* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const ivec3& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const ivec3& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(ivec3* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.ivec3"; + } + protected: + explicit ivec3(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kXFieldNumber = 1, + kYFieldNumber = 2, + kZFieldNumber = 3, + }; + // int32 x = 1; + void clear_x(); + int32_t x() const; + void set_x(int32_t value); + private: + int32_t _internal_x() const; + void _internal_set_x(int32_t value); + public: + + // int32 y = 2; + void clear_y(); + int32_t y() const; + void set_y(int32_t value); + private: + int32_t _internal_y() const; + void _internal_set_y(int32_t value); + public: + + // int32 z = 3; + void clear_z(); + int32_t z() const; + void set_z(int32_t value); + private: + int32_t _internal_z() const; + void _internal_set_z(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.ivec3) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + int32_t x_; + int32_t y_; + int32_t z_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class player final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.player) */ { + public: + inline player() : player(nullptr) {} + ~player() override; + explicit constexpr player(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + player(const player& from); + player(player&& from) noexcept + : player() { + *this = ::std::move(from); + } + + inline player& operator=(const player& from) { + CopyFrom(from); + return *this; + } + inline player& operator=(player&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const player& default_instance() { + return *internal_default_instance(); + } + static inline const player* internal_default_instance() { + return reinterpret_cast( + &_player_default_instance_); + } + static constexpr int kIndexInFileMessages = + 4; + + friend void swap(player& a, player& b) { + a.Swap(&b); + } + inline void Swap(player* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(player* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + player* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const player& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const player& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(player* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.player"; + } + protected: + explicit player(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kChunkPosFieldNumber = 3, + kLocalPosFieldNumber = 4, + kViewanglesFieldNumber = 5, + kVelocityFieldNumber = 6, + kIndexFieldNumber = 1, + kCommandsFieldNumber = 2, + }; + // .proto.coords chunk_pos = 3; + bool has_chunk_pos() const; + private: + bool _internal_has_chunk_pos() const; + public: + void clear_chunk_pos(); + const ::proto::coords& chunk_pos() const; + PROTOBUF_NODISCARD ::proto::coords* release_chunk_pos(); + ::proto::coords* mutable_chunk_pos(); + void set_allocated_chunk_pos(::proto::coords* chunk_pos); + private: + const ::proto::coords& _internal_chunk_pos() const; + ::proto::coords* _internal_mutable_chunk_pos(); + public: + void unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos); + ::proto::coords* unsafe_arena_release_chunk_pos(); + + // .proto.vec3 local_pos = 4; + bool has_local_pos() const; + private: + bool _internal_has_local_pos() const; + public: + void clear_local_pos(); + const ::proto::vec3& local_pos() const; + PROTOBUF_NODISCARD ::proto::vec3* release_local_pos(); + ::proto::vec3* mutable_local_pos(); + void set_allocated_local_pos(::proto::vec3* local_pos); + private: + const ::proto::vec3& _internal_local_pos() const; + ::proto::vec3* _internal_mutable_local_pos(); + public: + void unsafe_arena_set_allocated_local_pos( + ::proto::vec3* local_pos); + ::proto::vec3* unsafe_arena_release_local_pos(); + + // .proto.angles viewangles = 5; + bool has_viewangles() const; + private: + bool _internal_has_viewangles() const; + public: + void clear_viewangles(); + const ::proto::angles& viewangles() const; + PROTOBUF_NODISCARD ::proto::angles* release_viewangles(); + ::proto::angles* mutable_viewangles(); + void set_allocated_viewangles(::proto::angles* viewangles); + private: + const ::proto::angles& _internal_viewangles() const; + ::proto::angles* _internal_mutable_viewangles(); + public: + void unsafe_arena_set_allocated_viewangles( + ::proto::angles* viewangles); + ::proto::angles* unsafe_arena_release_viewangles(); + + // .proto.vec3 velocity = 6; + bool has_velocity() const; + private: + bool _internal_has_velocity() const; + public: + void clear_velocity(); + const ::proto::vec3& velocity() const; + PROTOBUF_NODISCARD ::proto::vec3* release_velocity(); + ::proto::vec3* mutable_velocity(); + void set_allocated_velocity(::proto::vec3* velocity); + private: + const ::proto::vec3& _internal_velocity() const; + ::proto::vec3* _internal_mutable_velocity(); + public: + void unsafe_arena_set_allocated_velocity( + ::proto::vec3* velocity); + ::proto::vec3* unsafe_arena_release_velocity(); + + // uint32 index = 1; + void clear_index(); + uint32_t index() const; + void set_index(uint32_t value); + private: + uint32_t _internal_index() const; + void _internal_set_index(uint32_t value); + public: + + // uint32 commands = 2; + void clear_commands(); + uint32_t commands() const; + void set_commands(uint32_t value); + private: + uint32_t _internal_commands() const; + void _internal_set_commands(uint32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.player) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::coords* chunk_pos_; + ::proto::vec3* local_pos_; + ::proto::angles* viewangles_; + ::proto::vec3* velocity_; + uint32_t index_; + uint32_t commands_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class auth final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.auth) */ { + public: + inline auth() : auth(nullptr) {} + ~auth() override; + explicit constexpr auth(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + auth(const auth& from); + auth(auth&& from) noexcept + : auth() { + *this = ::std::move(from); + } + + inline auth& operator=(const auth& from) { + CopyFrom(from); + return *this; + } + inline auth& operator=(auth&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const auth& default_instance() { + return *internal_default_instance(); + } + static inline const auth* internal_default_instance() { + return reinterpret_cast( + &_auth_default_instance_); + } + static constexpr int kIndexInFileMessages = + 5; + + friend void swap(auth& a, auth& b) { + a.Swap(&b); + } + inline void Swap(auth* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(auth* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + auth* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const auth& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const auth& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(auth* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.auth"; + } + protected: + explicit auth(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kUsernameFieldNumber = 1, + kPasswordFieldNumber = 2, + }; + // string username = 1; + void clear_username(); + const std::string& username() const; + template + void set_username(ArgT0&& arg0, ArgT... args); + std::string* mutable_username(); + PROTOBUF_NODISCARD std::string* release_username(); + void set_allocated_username(std::string* username); + private: + const std::string& _internal_username() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_username(const std::string& value); + std::string* _internal_mutable_username(); + public: + + // string password = 2; + void clear_password(); + const std::string& password() const; + template + void set_password(ArgT0&& arg0, ArgT... args); + std::string* mutable_password(); + PROTOBUF_NODISCARD std::string* release_password(); + void set_allocated_password(std::string* password); + private: + const std::string& _internal_password() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_password(const std::string& value); + std::string* _internal_mutable_password(); + public: + + // @@protoc_insertion_point(class_scope:proto.auth) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr username_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr password_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class init final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.init) */ { + public: + inline init() : init(nullptr) {} + ~init() override; + explicit constexpr init(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + init(const init& from); + init(init&& from) noexcept + : init() { + *this = ::std::move(from); + } + + inline init& operator=(const init& from) { + CopyFrom(from); + return *this; + } + inline init& operator=(init&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const init& default_instance() { + return *internal_default_instance(); + } + static inline const init* internal_default_instance() { + return reinterpret_cast( + &_init_default_instance_); + } + static constexpr int kIndexInFileMessages = + 6; + + friend void swap(init& a, init& b) { + a.Swap(&b); + } + inline void Swap(init* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(init* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + init* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const init& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const init& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(init* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.init"; + } + protected: + explicit init(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kLocalplayerFieldNumber = 3, + kSeedFieldNumber = 1, + kDrawDistanceFieldNumber = 2, + }; + // .proto.player localplayer = 3; + bool has_localplayer() const; + private: + bool _internal_has_localplayer() const; + public: + void clear_localplayer(); + const ::proto::player& localplayer() const; + PROTOBUF_NODISCARD ::proto::player* release_localplayer(); + ::proto::player* mutable_localplayer(); + void set_allocated_localplayer(::proto::player* localplayer); + private: + const ::proto::player& _internal_localplayer() const; + ::proto::player* _internal_mutable_localplayer(); + public: + void unsafe_arena_set_allocated_localplayer( + ::proto::player* localplayer); + ::proto::player* unsafe_arena_release_localplayer(); + + // uint64 seed = 1; + void clear_seed(); + uint64_t seed() const; + void set_seed(uint64_t value); + private: + uint64_t _internal_seed() const; + void _internal_set_seed(uint64_t value); + public: + + // int32 draw_distance = 2; + void clear_draw_distance(); + int32_t draw_distance() const; + void set_draw_distance(int32_t value); + private: + int32_t _internal_draw_distance() const; + void _internal_set_draw_distance(int32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.init) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::player* localplayer_; + uint64_t seed_; + int32_t draw_distance_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class move final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.move) */ { + public: + inline move() : move(nullptr) {} + ~move() override; + explicit constexpr move(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + move(const move& from); + move(move&& from) noexcept + : move() { + *this = ::std::move(from); + } + + inline move& operator=(const move& from) { + CopyFrom(from); + return *this; + } + inline move& operator=(move&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const move& default_instance() { + return *internal_default_instance(); + } + static inline const move* internal_default_instance() { + return reinterpret_cast( + &_move_default_instance_); + } + static constexpr int kIndexInFileMessages = + 7; + + friend void swap(move& a, move& b) { + a.Swap(&b); + } + inline void Swap(move* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(move* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + move* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const move& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const move& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(move* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.move"; + } + protected: + explicit move(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kViewanglesFieldNumber = 2, + kCommandsFieldNumber = 1, + }; + // .proto.angles viewangles = 2; + bool has_viewangles() const; + private: + bool _internal_has_viewangles() const; + public: + void clear_viewangles(); + const ::proto::angles& viewangles() const; + PROTOBUF_NODISCARD ::proto::angles* release_viewangles(); + ::proto::angles* mutable_viewangles(); + void set_allocated_viewangles(::proto::angles* viewangles); + private: + const ::proto::angles& _internal_viewangles() const; + ::proto::angles* _internal_mutable_viewangles(); + public: + void unsafe_arena_set_allocated_viewangles( + ::proto::angles* viewangles); + ::proto::angles* unsafe_arena_release_viewangles(); + + // uint32 commands = 1; + void clear_commands(); + uint32_t commands() const; + void set_commands(uint32_t value); + private: + uint32_t _internal_commands() const; + void _internal_set_commands(uint32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.move) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::angles* viewangles_; + uint32_t commands_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class remove_player final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.remove_player) */ { + public: + inline remove_player() : remove_player(nullptr) {} + ~remove_player() override; + explicit constexpr remove_player(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + remove_player(const remove_player& from); + remove_player(remove_player&& from) noexcept + : remove_player() { + *this = ::std::move(from); + } + + inline remove_player& operator=(const remove_player& from) { + CopyFrom(from); + return *this; + } + inline remove_player& operator=(remove_player&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const remove_player& default_instance() { + return *internal_default_instance(); + } + static inline const remove_player* internal_default_instance() { + return reinterpret_cast( + &_remove_player_default_instance_); + } + static constexpr int kIndexInFileMessages = + 8; + + friend void swap(remove_player& a, remove_player& b) { + a.Swap(&b); + } + inline void Swap(remove_player* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(remove_player* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + remove_player* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const remove_player& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const remove_player& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(remove_player* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.remove_player"; + } + protected: + explicit remove_player(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kIndexFieldNumber = 1, + }; + // uint32 index = 1; + void clear_index(); + uint32_t index() const; + void set_index(uint32_t value); + private: + uint32_t _internal_index() const; + void _internal_set_index(uint32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.remove_player) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + uint32_t index_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class say final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.say) */ { + public: + inline say() : say(nullptr) {} + ~say() override; + explicit constexpr say(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + say(const say& from); + say(say&& from) noexcept + : say() { + *this = ::std::move(from); + } + + inline say& operator=(const say& from) { + CopyFrom(from); + return *this; + } + inline say& operator=(say&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const say& default_instance() { + return *internal_default_instance(); + } + static inline const say* internal_default_instance() { + return reinterpret_cast( + &_say_default_instance_); + } + static constexpr int kIndexInFileMessages = + 9; + + friend void swap(say& a, say& b) { + a.Swap(&b); + } + inline void Swap(say* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(say* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + say* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const say& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const say& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(say* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.say"; + } + protected: + explicit say(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kTextFieldNumber = 1, + }; + // string text = 1; + void clear_text(); + const std::string& text() const; + template + void set_text(ArgT0&& arg0, ArgT... args); + std::string* mutable_text(); + PROTOBUF_NODISCARD std::string* release_text(); + void set_allocated_text(std::string* text); + private: + const std::string& _internal_text() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_text(const std::string& value); + std::string* _internal_mutable_text(); + public: + + // @@protoc_insertion_point(class_scope:proto.say) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr text_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class hear_player final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.hear_player) */ { + public: + inline hear_player() : hear_player(nullptr) {} + ~hear_player() override; + explicit constexpr hear_player(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + hear_player(const hear_player& from); + hear_player(hear_player&& from) noexcept + : hear_player() { + *this = ::std::move(from); + } + + inline hear_player& operator=(const hear_player& from) { + CopyFrom(from); + return *this; + } + inline hear_player& operator=(hear_player&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const hear_player& default_instance() { + return *internal_default_instance(); + } + static inline const hear_player* internal_default_instance() { + return reinterpret_cast( + &_hear_player_default_instance_); + } + static constexpr int kIndexInFileMessages = + 10; + + friend void swap(hear_player& a, hear_player& b) { + a.Swap(&b); + } + inline void Swap(hear_player* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(hear_player* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + hear_player* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const hear_player& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const hear_player& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(hear_player* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.hear_player"; + } + protected: + explicit hear_player(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kTextFieldNumber = 2, + kIndexFieldNumber = 1, + }; + // string text = 2; + void clear_text(); + const std::string& text() const; + template + void set_text(ArgT0&& arg0, ArgT... args); + std::string* mutable_text(); + PROTOBUF_NODISCARD std::string* release_text(); + void set_allocated_text(std::string* text); + private: + const std::string& _internal_text() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_text(const std::string& value); + std::string* _internal_mutable_text(); + public: + + // uint32 index = 1; + void clear_index(); + uint32_t index() const; + void set_index(uint32_t value); + private: + uint32_t _internal_index() const; + void _internal_set_index(uint32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.hear_player) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr text_; + uint32_t index_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class request_chunk final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.request_chunk) */ { + public: + inline request_chunk() : request_chunk(nullptr) {} + ~request_chunk() override; + explicit constexpr request_chunk(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + request_chunk(const request_chunk& from); + request_chunk(request_chunk&& from) noexcept + : request_chunk() { + *this = ::std::move(from); + } + + inline request_chunk& operator=(const request_chunk& from) { + CopyFrom(from); + return *this; + } + inline request_chunk& operator=(request_chunk&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const request_chunk& default_instance() { + return *internal_default_instance(); + } + static inline const request_chunk* internal_default_instance() { + return reinterpret_cast( + &_request_chunk_default_instance_); + } + static constexpr int kIndexInFileMessages = + 11; + + friend void swap(request_chunk& a, request_chunk& b) { + a.Swap(&b); + } + inline void Swap(request_chunk* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(request_chunk* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + request_chunk* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const request_chunk& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const request_chunk& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(request_chunk* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.request_chunk"; + } + protected: + explicit request_chunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kChunkPosFieldNumber = 1, + }; + // .proto.coords chunk_pos = 1; + bool has_chunk_pos() const; + private: + bool _internal_has_chunk_pos() const; + public: + void clear_chunk_pos(); + const ::proto::coords& chunk_pos() const; + PROTOBUF_NODISCARD ::proto::coords* release_chunk_pos(); + ::proto::coords* mutable_chunk_pos(); + void set_allocated_chunk_pos(::proto::coords* chunk_pos); + private: + const ::proto::coords& _internal_chunk_pos() const; + ::proto::coords* _internal_mutable_chunk_pos(); + public: + void unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos); + ::proto::coords* unsafe_arena_release_chunk_pos(); + + // @@protoc_insertion_point(class_scope:proto.request_chunk) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::coords* chunk_pos_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class remove_chunk final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.remove_chunk) */ { + public: + inline remove_chunk() : remove_chunk(nullptr) {} + ~remove_chunk() override; + explicit constexpr remove_chunk(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + remove_chunk(const remove_chunk& from); + remove_chunk(remove_chunk&& from) noexcept + : remove_chunk() { + *this = ::std::move(from); + } + + inline remove_chunk& operator=(const remove_chunk& from) { + CopyFrom(from); + return *this; + } + inline remove_chunk& operator=(remove_chunk&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const remove_chunk& default_instance() { + return *internal_default_instance(); + } + static inline const remove_chunk* internal_default_instance() { + return reinterpret_cast( + &_remove_chunk_default_instance_); + } + static constexpr int kIndexInFileMessages = + 12; + + friend void swap(remove_chunk& a, remove_chunk& b) { + a.Swap(&b); + } + inline void Swap(remove_chunk* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(remove_chunk* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + remove_chunk* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const remove_chunk& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const remove_chunk& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(remove_chunk* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.remove_chunk"; + } + protected: + explicit remove_chunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kChunkPosFieldNumber = 1, + }; + // .proto.coords chunk_pos = 1; + bool has_chunk_pos() const; + private: + bool _internal_has_chunk_pos() const; + public: + void clear_chunk_pos(); + const ::proto::coords& chunk_pos() const; + PROTOBUF_NODISCARD ::proto::coords* release_chunk_pos(); + ::proto::coords* mutable_chunk_pos(); + void set_allocated_chunk_pos(::proto::coords* chunk_pos); + private: + const ::proto::coords& _internal_chunk_pos() const; + ::proto::coords* _internal_mutable_chunk_pos(); + public: + void unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos); + ::proto::coords* unsafe_arena_release_chunk_pos(); + + // @@protoc_insertion_point(class_scope:proto.remove_chunk) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::coords* chunk_pos_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class chunk final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.chunk) */ { + public: + inline chunk() : chunk(nullptr) {} + ~chunk() override; + explicit constexpr chunk(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + chunk(const chunk& from); + chunk(chunk&& from) noexcept + : chunk() { + *this = ::std::move(from); + } + + inline chunk& operator=(const chunk& from) { + CopyFrom(from); + return *this; + } + inline chunk& operator=(chunk&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const chunk& default_instance() { + return *internal_default_instance(); + } + static inline const chunk* internal_default_instance() { + return reinterpret_cast( + &_chunk_default_instance_); + } + static constexpr int kIndexInFileMessages = + 13; + + friend void swap(chunk& a, chunk& b) { + a.Swap(&b); + } + inline void Swap(chunk* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(chunk* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + chunk* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const chunk& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const chunk& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(chunk* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.chunk"; + } + protected: + explicit chunk(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kBlocksFieldNumber = 2, + kChunkPosFieldNumber = 1, + }; + // repeated uint32 blocks = 2 [packed = true]; + int blocks_size() const; + private: + int _internal_blocks_size() const; + public: + void clear_blocks(); + private: + uint32_t _internal_blocks(int index) const; + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >& + _internal_blocks() const; + void _internal_add_blocks(uint32_t value); + ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >* + _internal_mutable_blocks(); + public: + uint32_t blocks(int index) const; + void set_blocks(int index, uint32_t value); + void add_blocks(uint32_t value); + const ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >& + blocks() const; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >* + mutable_blocks(); + + // .proto.coords chunk_pos = 1; + bool has_chunk_pos() const; + private: + bool _internal_has_chunk_pos() const; + public: + void clear_chunk_pos(); + const ::proto::coords& chunk_pos() const; + PROTOBUF_NODISCARD ::proto::coords* release_chunk_pos(); + ::proto::coords* mutable_chunk_pos(); + void set_allocated_chunk_pos(::proto::coords* chunk_pos); + private: + const ::proto::coords& _internal_chunk_pos() const; + ::proto::coords* _internal_mutable_chunk_pos(); + public: + void unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos); + ::proto::coords* unsafe_arena_release_chunk_pos(); + + // @@protoc_insertion_point(class_scope:proto.chunk) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t > blocks_; + mutable std::atomic _blocks_cached_byte_size_; + ::proto::coords* chunk_pos_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class add_block final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.add_block) */ { + public: + inline add_block() : add_block(nullptr) {} + ~add_block() override; + explicit constexpr add_block(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + add_block(const add_block& from); + add_block(add_block&& from) noexcept + : add_block() { + *this = ::std::move(from); + } + + inline add_block& operator=(const add_block& from) { + CopyFrom(from); + return *this; + } + inline add_block& operator=(add_block&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const add_block& default_instance() { + return *internal_default_instance(); + } + static inline const add_block* internal_default_instance() { + return reinterpret_cast( + &_add_block_default_instance_); + } + static constexpr int kIndexInFileMessages = + 14; + + friend void swap(add_block& a, add_block& b) { + a.Swap(&b); + } + inline void Swap(add_block* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(add_block* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + add_block* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const add_block& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const add_block& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(add_block* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.add_block"; + } + protected: + explicit add_block(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kChunkPosFieldNumber = 1, + kBlockPosFieldNumber = 2, + kBlockFieldNumber = 3, + }; + // .proto.coords chunk_pos = 1; + bool has_chunk_pos() const; + private: + bool _internal_has_chunk_pos() const; + public: + void clear_chunk_pos(); + const ::proto::coords& chunk_pos() const; + PROTOBUF_NODISCARD ::proto::coords* release_chunk_pos(); + ::proto::coords* mutable_chunk_pos(); + void set_allocated_chunk_pos(::proto::coords* chunk_pos); + private: + const ::proto::coords& _internal_chunk_pos() const; + ::proto::coords* _internal_mutable_chunk_pos(); + public: + void unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos); + ::proto::coords* unsafe_arena_release_chunk_pos(); + + // .proto.ivec3 block_pos = 2; + bool has_block_pos() const; + private: + bool _internal_has_block_pos() const; + public: + void clear_block_pos(); + const ::proto::ivec3& block_pos() const; + PROTOBUF_NODISCARD ::proto::ivec3* release_block_pos(); + ::proto::ivec3* mutable_block_pos(); + void set_allocated_block_pos(::proto::ivec3* block_pos); + private: + const ::proto::ivec3& _internal_block_pos() const; + ::proto::ivec3* _internal_mutable_block_pos(); + public: + void unsafe_arena_set_allocated_block_pos( + ::proto::ivec3* block_pos); + ::proto::ivec3* unsafe_arena_release_block_pos(); + + // uint32 block = 3; + void clear_block(); + uint32_t block() const; + void set_block(uint32_t value); + private: + uint32_t _internal_block() const; + void _internal_set_block(uint32_t value); + public: + + // @@protoc_insertion_point(class_scope:proto.add_block) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::coords* chunk_pos_; + ::proto::ivec3* block_pos_; + uint32_t block_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class remove_block final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.remove_block) */ { + public: + inline remove_block() : remove_block(nullptr) {} + ~remove_block() override; + explicit constexpr remove_block(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + remove_block(const remove_block& from); + remove_block(remove_block&& from) noexcept + : remove_block() { + *this = ::std::move(from); + } + + inline remove_block& operator=(const remove_block& from) { + CopyFrom(from); + return *this; + } + inline remove_block& operator=(remove_block&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const remove_block& default_instance() { + return *internal_default_instance(); + } + static inline const remove_block* internal_default_instance() { + return reinterpret_cast( + &_remove_block_default_instance_); + } + static constexpr int kIndexInFileMessages = + 15; + + friend void swap(remove_block& a, remove_block& b) { + a.Swap(&b); + } + inline void Swap(remove_block* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(remove_block* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + remove_block* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const remove_block& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const remove_block& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(remove_block* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.remove_block"; + } + protected: + explicit remove_block(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kChunkPosFieldNumber = 1, + kBlockPosFieldNumber = 2, + }; + // .proto.coords chunk_pos = 1; + bool has_chunk_pos() const; + private: + bool _internal_has_chunk_pos() const; + public: + void clear_chunk_pos(); + const ::proto::coords& chunk_pos() const; + PROTOBUF_NODISCARD ::proto::coords* release_chunk_pos(); + ::proto::coords* mutable_chunk_pos(); + void set_allocated_chunk_pos(::proto::coords* chunk_pos); + private: + const ::proto::coords& _internal_chunk_pos() const; + ::proto::coords* _internal_mutable_chunk_pos(); + public: + void unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos); + ::proto::coords* unsafe_arena_release_chunk_pos(); + + // .proto.ivec3 block_pos = 2; + bool has_block_pos() const; + private: + bool _internal_has_block_pos() const; + public: + void clear_block_pos(); + const ::proto::ivec3& block_pos() const; + PROTOBUF_NODISCARD ::proto::ivec3* release_block_pos(); + ::proto::ivec3* mutable_block_pos(); + void set_allocated_block_pos(::proto::ivec3* block_pos); + private: + const ::proto::ivec3& _internal_block_pos() const; + ::proto::ivec3* _internal_mutable_block_pos(); + public: + void unsafe_arena_set_allocated_block_pos( + ::proto::ivec3* block_pos); + ::proto::ivec3* unsafe_arena_release_block_pos(); + + // @@protoc_insertion_point(class_scope:proto.remove_block) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::proto::coords* chunk_pos_; + ::proto::ivec3* block_pos_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class server_message final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.server_message) */ { + public: + inline server_message() : server_message(nullptr) {} + ~server_message() override; + explicit constexpr server_message(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + server_message(const server_message& from); + server_message(server_message&& from) noexcept + : server_message() { + *this = ::std::move(from); + } + + inline server_message& operator=(const server_message& from) { + CopyFrom(from); + return *this; + } + inline server_message& operator=(server_message&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const server_message& default_instance() { + return *internal_default_instance(); + } + static inline const server_message* internal_default_instance() { + return reinterpret_cast( + &_server_message_default_instance_); + } + static constexpr int kIndexInFileMessages = + 16; + + friend void swap(server_message& a, server_message& b) { + a.Swap(&b); + } + inline void Swap(server_message* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(server_message* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + server_message* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const server_message& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const server_message& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(server_message* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.server_message"; + } + protected: + explicit server_message(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kMessageFieldNumber = 1, + kFatalFieldNumber = 2, + }; + // string message = 1; + void clear_message(); + const std::string& message() const; + template + void set_message(ArgT0&& arg0, ArgT... args); + std::string* mutable_message(); + PROTOBUF_NODISCARD std::string* release_message(); + void set_allocated_message(std::string* message); + private: + const std::string& _internal_message() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_message(const std::string& value); + std::string* _internal_mutable_message(); + public: + + // bool fatal = 2; + void clear_fatal(); + bool fatal() const; + void set_fatal(bool value); + private: + bool _internal_fatal() const; + void _internal_set_fatal(bool value); + public: + + // @@protoc_insertion_point(class_scope:proto.server_message) + private: + class _Internal; + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr message_; + bool fatal_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + friend struct ::TableStruct_net_2eproto; +}; +// ------------------------------------------------------------------- + +class packet final : + public ::PROTOBUF_NAMESPACE_ID::Message /* @@protoc_insertion_point(class_definition:proto.packet) */ { + public: + inline packet() : packet(nullptr) {} + ~packet() override; + explicit constexpr packet(::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized); + + packet(const packet& from); + packet(packet&& from) noexcept + : packet() { + *this = ::std::move(from); + } + + inline packet& operator=(const packet& from) { + CopyFrom(from); + return *this; + } + inline packet& operator=(packet&& from) noexcept { + if (this == &from) return *this; + if (GetOwningArena() == from.GetOwningArena() + #ifdef PROTOBUF_FORCE_COPY_IN_MOVE + && GetOwningArena() != nullptr + #endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + InternalSwap(&from); + } else { + CopyFrom(from); + } + return *this; + } + + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() { + return GetDescriptor(); + } + static const ::PROTOBUF_NAMESPACE_ID::Descriptor* GetDescriptor() { + return default_instance().GetMetadata().descriptor; + } + static const ::PROTOBUF_NAMESPACE_ID::Reflection* GetReflection() { + return default_instance().GetMetadata().reflection; + } + static const packet& default_instance() { + return *internal_default_instance(); + } + enum ContentsCase { + kAuthPacket = 1, + kInitPacket = 2, + kMovePacket = 3, + kPlayerPacket = 4, + kRemovePlayerPacket = 5, + kSayPacket = 6, + kHearPlayerPacket = 7, + kRequestChunkPacket = 8, + kChunkPacket = 9, + kRemoveChunkPacket = 10, + kAddBlockPacket = 11, + kRemoveBlockPacket = 12, + kServerMessagePacket = 13, + CONTENTS_NOT_SET = 0, + }; + + static inline const packet* internal_default_instance() { + return reinterpret_cast( + &_packet_default_instance_); + } + static constexpr int kIndexInFileMessages = + 17; + + friend void swap(packet& a, packet& b) { + a.Swap(&b); + } + inline void Swap(packet* other) { + if (other == this) return; + #ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() != nullptr && + GetOwningArena() == other->GetOwningArena()) { + #else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetOwningArena() == other->GetOwningArena()) { + #endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other); + } + } + void UnsafeArenaSwap(packet* other) { + if (other == this) return; + GOOGLE_DCHECK(GetOwningArena() == other->GetOwningArena()); + InternalSwap(other); + } + + // implements Message ---------------------------------------------- + + packet* New(::PROTOBUF_NAMESPACE_ID::Arena* arena = nullptr) const final { + return CreateMaybeMessage(arena); + } + using ::PROTOBUF_NAMESPACE_ID::Message::CopyFrom; + void CopyFrom(const packet& from); + using ::PROTOBUF_NAMESPACE_ID::Message::MergeFrom; + void MergeFrom(const packet& from); + private: + static void MergeImpl(::PROTOBUF_NAMESPACE_ID::Message* to, const ::PROTOBUF_NAMESPACE_ID::Message& from); + public: + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final; + bool IsInitialized() const final; + + size_t ByteSizeLong() const final; + const char* _InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) final; + uint8_t* _InternalSerialize( + uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final; + int GetCachedSize() const final { return _cached_size_.Get(); } + + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const final; + void InternalSwap(packet* other); + + private: + friend class ::PROTOBUF_NAMESPACE_ID::internal::AnyMetadata; + static ::PROTOBUF_NAMESPACE_ID::StringPiece FullMessageName() { + return "proto.packet"; + } + protected: + explicit packet(::PROTOBUF_NAMESPACE_ID::Arena* arena, + bool is_message_owned = false); + private: + static void ArenaDtor(void* object); + inline void RegisterArenaDtor(::PROTOBUF_NAMESPACE_ID::Arena* arena); + public: + + static const ClassData _class_data_; + const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*GetClassData() const final; + + ::PROTOBUF_NAMESPACE_ID::Metadata GetMetadata() const final; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + enum : int { + kAuthPacketFieldNumber = 1, + kInitPacketFieldNumber = 2, + kMovePacketFieldNumber = 3, + kPlayerPacketFieldNumber = 4, + kRemovePlayerPacketFieldNumber = 5, + kSayPacketFieldNumber = 6, + kHearPlayerPacketFieldNumber = 7, + kRequestChunkPacketFieldNumber = 8, + kChunkPacketFieldNumber = 9, + kRemoveChunkPacketFieldNumber = 10, + kAddBlockPacketFieldNumber = 11, + kRemoveBlockPacketFieldNumber = 12, + kServerMessagePacketFieldNumber = 13, + }; + // .proto.auth auth_packet = 1; + bool has_auth_packet() const; + private: + bool _internal_has_auth_packet() const; + public: + void clear_auth_packet(); + const ::proto::auth& auth_packet() const; + PROTOBUF_NODISCARD ::proto::auth* release_auth_packet(); + ::proto::auth* mutable_auth_packet(); + void set_allocated_auth_packet(::proto::auth* auth_packet); + private: + const ::proto::auth& _internal_auth_packet() const; + ::proto::auth* _internal_mutable_auth_packet(); + public: + void unsafe_arena_set_allocated_auth_packet( + ::proto::auth* auth_packet); + ::proto::auth* unsafe_arena_release_auth_packet(); + + // .proto.init init_packet = 2; + bool has_init_packet() const; + private: + bool _internal_has_init_packet() const; + public: + void clear_init_packet(); + const ::proto::init& init_packet() const; + PROTOBUF_NODISCARD ::proto::init* release_init_packet(); + ::proto::init* mutable_init_packet(); + void set_allocated_init_packet(::proto::init* init_packet); + private: + const ::proto::init& _internal_init_packet() const; + ::proto::init* _internal_mutable_init_packet(); + public: + void unsafe_arena_set_allocated_init_packet( + ::proto::init* init_packet); + ::proto::init* unsafe_arena_release_init_packet(); + + // .proto.move move_packet = 3; + bool has_move_packet() const; + private: + bool _internal_has_move_packet() const; + public: + void clear_move_packet(); + const ::proto::move& move_packet() const; + PROTOBUF_NODISCARD ::proto::move* release_move_packet(); + ::proto::move* mutable_move_packet(); + void set_allocated_move_packet(::proto::move* move_packet); + private: + const ::proto::move& _internal_move_packet() const; + ::proto::move* _internal_mutable_move_packet(); + public: + void unsafe_arena_set_allocated_move_packet( + ::proto::move* move_packet); + ::proto::move* unsafe_arena_release_move_packet(); + + // .proto.player player_packet = 4; + bool has_player_packet() const; + private: + bool _internal_has_player_packet() const; + public: + void clear_player_packet(); + const ::proto::player& player_packet() const; + PROTOBUF_NODISCARD ::proto::player* release_player_packet(); + ::proto::player* mutable_player_packet(); + void set_allocated_player_packet(::proto::player* player_packet); + private: + const ::proto::player& _internal_player_packet() const; + ::proto::player* _internal_mutable_player_packet(); + public: + void unsafe_arena_set_allocated_player_packet( + ::proto::player* player_packet); + ::proto::player* unsafe_arena_release_player_packet(); + + // .proto.remove_player remove_player_packet = 5; + bool has_remove_player_packet() const; + private: + bool _internal_has_remove_player_packet() const; + public: + void clear_remove_player_packet(); + const ::proto::remove_player& remove_player_packet() const; + PROTOBUF_NODISCARD ::proto::remove_player* release_remove_player_packet(); + ::proto::remove_player* mutable_remove_player_packet(); + void set_allocated_remove_player_packet(::proto::remove_player* remove_player_packet); + private: + const ::proto::remove_player& _internal_remove_player_packet() const; + ::proto::remove_player* _internal_mutable_remove_player_packet(); + public: + void unsafe_arena_set_allocated_remove_player_packet( + ::proto::remove_player* remove_player_packet); + ::proto::remove_player* unsafe_arena_release_remove_player_packet(); + + // .proto.say say_packet = 6; + bool has_say_packet() const; + private: + bool _internal_has_say_packet() const; + public: + void clear_say_packet(); + const ::proto::say& say_packet() const; + PROTOBUF_NODISCARD ::proto::say* release_say_packet(); + ::proto::say* mutable_say_packet(); + void set_allocated_say_packet(::proto::say* say_packet); + private: + const ::proto::say& _internal_say_packet() const; + ::proto::say* _internal_mutable_say_packet(); + public: + void unsafe_arena_set_allocated_say_packet( + ::proto::say* say_packet); + ::proto::say* unsafe_arena_release_say_packet(); + + // .proto.hear_player hear_player_packet = 7; + bool has_hear_player_packet() const; + private: + bool _internal_has_hear_player_packet() const; + public: + void clear_hear_player_packet(); + const ::proto::hear_player& hear_player_packet() const; + PROTOBUF_NODISCARD ::proto::hear_player* release_hear_player_packet(); + ::proto::hear_player* mutable_hear_player_packet(); + void set_allocated_hear_player_packet(::proto::hear_player* hear_player_packet); + private: + const ::proto::hear_player& _internal_hear_player_packet() const; + ::proto::hear_player* _internal_mutable_hear_player_packet(); + public: + void unsafe_arena_set_allocated_hear_player_packet( + ::proto::hear_player* hear_player_packet); + ::proto::hear_player* unsafe_arena_release_hear_player_packet(); + + // .proto.request_chunk request_chunk_packet = 8; + bool has_request_chunk_packet() const; + private: + bool _internal_has_request_chunk_packet() const; + public: + void clear_request_chunk_packet(); + const ::proto::request_chunk& request_chunk_packet() const; + PROTOBUF_NODISCARD ::proto::request_chunk* release_request_chunk_packet(); + ::proto::request_chunk* mutable_request_chunk_packet(); + void set_allocated_request_chunk_packet(::proto::request_chunk* request_chunk_packet); + private: + const ::proto::request_chunk& _internal_request_chunk_packet() const; + ::proto::request_chunk* _internal_mutable_request_chunk_packet(); + public: + void unsafe_arena_set_allocated_request_chunk_packet( + ::proto::request_chunk* request_chunk_packet); + ::proto::request_chunk* unsafe_arena_release_request_chunk_packet(); + + // .proto.chunk chunk_packet = 9; + bool has_chunk_packet() const; + private: + bool _internal_has_chunk_packet() const; + public: + void clear_chunk_packet(); + const ::proto::chunk& chunk_packet() const; + PROTOBUF_NODISCARD ::proto::chunk* release_chunk_packet(); + ::proto::chunk* mutable_chunk_packet(); + void set_allocated_chunk_packet(::proto::chunk* chunk_packet); + private: + const ::proto::chunk& _internal_chunk_packet() const; + ::proto::chunk* _internal_mutable_chunk_packet(); + public: + void unsafe_arena_set_allocated_chunk_packet( + ::proto::chunk* chunk_packet); + ::proto::chunk* unsafe_arena_release_chunk_packet(); + + // .proto.remove_chunk remove_chunk_packet = 10; + bool has_remove_chunk_packet() const; + private: + bool _internal_has_remove_chunk_packet() const; + public: + void clear_remove_chunk_packet(); + const ::proto::remove_chunk& remove_chunk_packet() const; + PROTOBUF_NODISCARD ::proto::remove_chunk* release_remove_chunk_packet(); + ::proto::remove_chunk* mutable_remove_chunk_packet(); + void set_allocated_remove_chunk_packet(::proto::remove_chunk* remove_chunk_packet); + private: + const ::proto::remove_chunk& _internal_remove_chunk_packet() const; + ::proto::remove_chunk* _internal_mutable_remove_chunk_packet(); + public: + void unsafe_arena_set_allocated_remove_chunk_packet( + ::proto::remove_chunk* remove_chunk_packet); + ::proto::remove_chunk* unsafe_arena_release_remove_chunk_packet(); + + // .proto.add_block add_block_packet = 11; + bool has_add_block_packet() const; + private: + bool _internal_has_add_block_packet() const; + public: + void clear_add_block_packet(); + const ::proto::add_block& add_block_packet() const; + PROTOBUF_NODISCARD ::proto::add_block* release_add_block_packet(); + ::proto::add_block* mutable_add_block_packet(); + void set_allocated_add_block_packet(::proto::add_block* add_block_packet); + private: + const ::proto::add_block& _internal_add_block_packet() const; + ::proto::add_block* _internal_mutable_add_block_packet(); + public: + void unsafe_arena_set_allocated_add_block_packet( + ::proto::add_block* add_block_packet); + ::proto::add_block* unsafe_arena_release_add_block_packet(); + + // .proto.remove_block remove_block_packet = 12; + bool has_remove_block_packet() const; + private: + bool _internal_has_remove_block_packet() const; + public: + void clear_remove_block_packet(); + const ::proto::remove_block& remove_block_packet() const; + PROTOBUF_NODISCARD ::proto::remove_block* release_remove_block_packet(); + ::proto::remove_block* mutable_remove_block_packet(); + void set_allocated_remove_block_packet(::proto::remove_block* remove_block_packet); + private: + const ::proto::remove_block& _internal_remove_block_packet() const; + ::proto::remove_block* _internal_mutable_remove_block_packet(); + public: + void unsafe_arena_set_allocated_remove_block_packet( + ::proto::remove_block* remove_block_packet); + ::proto::remove_block* unsafe_arena_release_remove_block_packet(); + + // .proto.server_message server_message_packet = 13; + bool has_server_message_packet() const; + private: + bool _internal_has_server_message_packet() const; + public: + void clear_server_message_packet(); + const ::proto::server_message& server_message_packet() const; + PROTOBUF_NODISCARD ::proto::server_message* release_server_message_packet(); + ::proto::server_message* mutable_server_message_packet(); + void set_allocated_server_message_packet(::proto::server_message* server_message_packet); + private: + const ::proto::server_message& _internal_server_message_packet() const; + ::proto::server_message* _internal_mutable_server_message_packet(); + public: + void unsafe_arena_set_allocated_server_message_packet( + ::proto::server_message* server_message_packet); + ::proto::server_message* unsafe_arena_release_server_message_packet(); + + void clear_contents(); + ContentsCase contents_case() const; + // @@protoc_insertion_point(class_scope:proto.packet) + private: + class _Internal; + void set_has_auth_packet(); + void set_has_init_packet(); + void set_has_move_packet(); + void set_has_player_packet(); + void set_has_remove_player_packet(); + void set_has_say_packet(); + void set_has_hear_player_packet(); + void set_has_request_chunk_packet(); + void set_has_chunk_packet(); + void set_has_remove_chunk_packet(); + void set_has_add_block_packet(); + void set_has_remove_block_packet(); + void set_has_server_message_packet(); + + inline bool has_contents() const; + inline void clear_has_contents(); + + template friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper; + typedef void InternalArenaConstructable_; + typedef void DestructorSkippable_; + union ContentsUnion { + constexpr ContentsUnion() : _constinit_{} {} + ::PROTOBUF_NAMESPACE_ID::internal::ConstantInitialized _constinit_; + ::proto::auth* auth_packet_; + ::proto::init* init_packet_; + ::proto::move* move_packet_; + ::proto::player* player_packet_; + ::proto::remove_player* remove_player_packet_; + ::proto::say* say_packet_; + ::proto::hear_player* hear_player_packet_; + ::proto::request_chunk* request_chunk_packet_; + ::proto::chunk* chunk_packet_; + ::proto::remove_chunk* remove_chunk_packet_; + ::proto::add_block* add_block_packet_; + ::proto::remove_block* remove_block_packet_; + ::proto::server_message* server_message_packet_; + } contents_; + mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; + uint32_t _oneof_case_[1]; + + friend struct ::TableStruct_net_2eproto; +}; +// =================================================================== + + +// =================================================================== + +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif // __GNUC__ +// angles + +// float pitch = 1; +inline void angles::clear_pitch() { + pitch_ = 0; +} +inline float angles::_internal_pitch() const { + return pitch_; +} +inline float angles::pitch() const { + // @@protoc_insertion_point(field_get:proto.angles.pitch) + return _internal_pitch(); +} +inline void angles::_internal_set_pitch(float value) { + + pitch_ = value; +} +inline void angles::set_pitch(float value) { + _internal_set_pitch(value); + // @@protoc_insertion_point(field_set:proto.angles.pitch) +} + +// float yaw = 2; +inline void angles::clear_yaw() { + yaw_ = 0; +} +inline float angles::_internal_yaw() const { + return yaw_; +} +inline float angles::yaw() const { + // @@protoc_insertion_point(field_get:proto.angles.yaw) + return _internal_yaw(); +} +inline void angles::_internal_set_yaw(float value) { + + yaw_ = value; +} +inline void angles::set_yaw(float value) { + _internal_set_yaw(value); + // @@protoc_insertion_point(field_set:proto.angles.yaw) +} + +// ------------------------------------------------------------------- + +// coords + +// int32 x = 1; +inline void coords::clear_x() { + x_ = 0; +} +inline int32_t coords::_internal_x() const { + return x_; +} +inline int32_t coords::x() const { + // @@protoc_insertion_point(field_get:proto.coords.x) + return _internal_x(); +} +inline void coords::_internal_set_x(int32_t value) { + + x_ = value; +} +inline void coords::set_x(int32_t value) { + _internal_set_x(value); + // @@protoc_insertion_point(field_set:proto.coords.x) +} + +// int32 z = 2; +inline void coords::clear_z() { + z_ = 0; +} +inline int32_t coords::_internal_z() const { + return z_; +} +inline int32_t coords::z() const { + // @@protoc_insertion_point(field_get:proto.coords.z) + return _internal_z(); +} +inline void coords::_internal_set_z(int32_t value) { + + z_ = value; +} +inline void coords::set_z(int32_t value) { + _internal_set_z(value); + // @@protoc_insertion_point(field_set:proto.coords.z) +} + +// ------------------------------------------------------------------- + +// vec3 + +// float x = 1; +inline void vec3::clear_x() { + x_ = 0; +} +inline float vec3::_internal_x() const { + return x_; +} +inline float vec3::x() const { + // @@protoc_insertion_point(field_get:proto.vec3.x) + return _internal_x(); +} +inline void vec3::_internal_set_x(float value) { + + x_ = value; +} +inline void vec3::set_x(float value) { + _internal_set_x(value); + // @@protoc_insertion_point(field_set:proto.vec3.x) +} + +// float y = 2; +inline void vec3::clear_y() { + y_ = 0; +} +inline float vec3::_internal_y() const { + return y_; +} +inline float vec3::y() const { + // @@protoc_insertion_point(field_get:proto.vec3.y) + return _internal_y(); +} +inline void vec3::_internal_set_y(float value) { + + y_ = value; +} +inline void vec3::set_y(float value) { + _internal_set_y(value); + // @@protoc_insertion_point(field_set:proto.vec3.y) +} + +// float z = 3; +inline void vec3::clear_z() { + z_ = 0; +} +inline float vec3::_internal_z() const { + return z_; +} +inline float vec3::z() const { + // @@protoc_insertion_point(field_get:proto.vec3.z) + return _internal_z(); +} +inline void vec3::_internal_set_z(float value) { + + z_ = value; +} +inline void vec3::set_z(float value) { + _internal_set_z(value); + // @@protoc_insertion_point(field_set:proto.vec3.z) +} + +// ------------------------------------------------------------------- + +// ivec3 + +// int32 x = 1; +inline void ivec3::clear_x() { + x_ = 0; +} +inline int32_t ivec3::_internal_x() const { + return x_; +} +inline int32_t ivec3::x() const { + // @@protoc_insertion_point(field_get:proto.ivec3.x) + return _internal_x(); +} +inline void ivec3::_internal_set_x(int32_t value) { + + x_ = value; +} +inline void ivec3::set_x(int32_t value) { + _internal_set_x(value); + // @@protoc_insertion_point(field_set:proto.ivec3.x) +} + +// int32 y = 2; +inline void ivec3::clear_y() { + y_ = 0; +} +inline int32_t ivec3::_internal_y() const { + return y_; +} +inline int32_t ivec3::y() const { + // @@protoc_insertion_point(field_get:proto.ivec3.y) + return _internal_y(); +} +inline void ivec3::_internal_set_y(int32_t value) { + + y_ = value; +} +inline void ivec3::set_y(int32_t value) { + _internal_set_y(value); + // @@protoc_insertion_point(field_set:proto.ivec3.y) +} + +// int32 z = 3; +inline void ivec3::clear_z() { + z_ = 0; +} +inline int32_t ivec3::_internal_z() const { + return z_; +} +inline int32_t ivec3::z() const { + // @@protoc_insertion_point(field_get:proto.ivec3.z) + return _internal_z(); +} +inline void ivec3::_internal_set_z(int32_t value) { + + z_ = value; +} +inline void ivec3::set_z(int32_t value) { + _internal_set_z(value); + // @@protoc_insertion_point(field_set:proto.ivec3.z) +} + +// ------------------------------------------------------------------- + +// player + +// uint32 index = 1; +inline void player::clear_index() { + index_ = 0u; +} +inline uint32_t player::_internal_index() const { + return index_; +} +inline uint32_t player::index() const { + // @@protoc_insertion_point(field_get:proto.player.index) + return _internal_index(); +} +inline void player::_internal_set_index(uint32_t value) { + + index_ = value; +} +inline void player::set_index(uint32_t value) { + _internal_set_index(value); + // @@protoc_insertion_point(field_set:proto.player.index) +} + +// uint32 commands = 2; +inline void player::clear_commands() { + commands_ = 0u; +} +inline uint32_t player::_internal_commands() const { + return commands_; +} +inline uint32_t player::commands() const { + // @@protoc_insertion_point(field_get:proto.player.commands) + return _internal_commands(); +} +inline void player::_internal_set_commands(uint32_t value) { + + commands_ = value; +} +inline void player::set_commands(uint32_t value) { + _internal_set_commands(value); + // @@protoc_insertion_point(field_set:proto.player.commands) +} + +// .proto.coords chunk_pos = 3; +inline bool player::_internal_has_chunk_pos() const { + return this != internal_default_instance() && chunk_pos_ != nullptr; +} +inline bool player::has_chunk_pos() const { + return _internal_has_chunk_pos(); +} +inline void player::clear_chunk_pos() { + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; +} +inline const ::proto::coords& player::_internal_chunk_pos() const { + const ::proto::coords* p = chunk_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_coords_default_instance_); +} +inline const ::proto::coords& player::chunk_pos() const { + // @@protoc_insertion_point(field_get:proto.player.chunk_pos) + return _internal_chunk_pos(); +} +inline void player::unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(chunk_pos_); + } + chunk_pos_ = chunk_pos; + if (chunk_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.player.chunk_pos) +} +inline ::proto::coords* player::release_chunk_pos() { + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::coords* player::unsafe_arena_release_chunk_pos() { + // @@protoc_insertion_point(field_release:proto.player.chunk_pos) + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; + return temp; +} +inline ::proto::coords* player::_internal_mutable_chunk_pos() { + + if (chunk_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::coords>(GetArenaForAllocation()); + chunk_pos_ = p; + } + return chunk_pos_; +} +inline ::proto::coords* player::mutable_chunk_pos() { + ::proto::coords* _msg = _internal_mutable_chunk_pos(); + // @@protoc_insertion_point(field_mutable:proto.player.chunk_pos) + return _msg; +} +inline void player::set_allocated_chunk_pos(::proto::coords* chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete chunk_pos_; + } + if (chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::coords>::GetOwningArena(chunk_pos); + if (message_arena != submessage_arena) { + chunk_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_pos, submessage_arena); + } + + } else { + + } + chunk_pos_ = chunk_pos; + // @@protoc_insertion_point(field_set_allocated:proto.player.chunk_pos) +} + +// .proto.vec3 local_pos = 4; +inline bool player::_internal_has_local_pos() const { + return this != internal_default_instance() && local_pos_ != nullptr; +} +inline bool player::has_local_pos() const { + return _internal_has_local_pos(); +} +inline void player::clear_local_pos() { + if (GetArenaForAllocation() == nullptr && local_pos_ != nullptr) { + delete local_pos_; + } + local_pos_ = nullptr; +} +inline const ::proto::vec3& player::_internal_local_pos() const { + const ::proto::vec3* p = local_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_vec3_default_instance_); +} +inline const ::proto::vec3& player::local_pos() const { + // @@protoc_insertion_point(field_get:proto.player.local_pos) + return _internal_local_pos(); +} +inline void player::unsafe_arena_set_allocated_local_pos( + ::proto::vec3* local_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(local_pos_); + } + local_pos_ = local_pos; + if (local_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.player.local_pos) +} +inline ::proto::vec3* player::release_local_pos() { + + ::proto::vec3* temp = local_pos_; + local_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::vec3* player::unsafe_arena_release_local_pos() { + // @@protoc_insertion_point(field_release:proto.player.local_pos) + + ::proto::vec3* temp = local_pos_; + local_pos_ = nullptr; + return temp; +} +inline ::proto::vec3* player::_internal_mutable_local_pos() { + + if (local_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::vec3>(GetArenaForAllocation()); + local_pos_ = p; + } + return local_pos_; +} +inline ::proto::vec3* player::mutable_local_pos() { + ::proto::vec3* _msg = _internal_mutable_local_pos(); + // @@protoc_insertion_point(field_mutable:proto.player.local_pos) + return _msg; +} +inline void player::set_allocated_local_pos(::proto::vec3* local_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete local_pos_; + } + if (local_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::vec3>::GetOwningArena(local_pos); + if (message_arena != submessage_arena) { + local_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, local_pos, submessage_arena); + } + + } else { + + } + local_pos_ = local_pos; + // @@protoc_insertion_point(field_set_allocated:proto.player.local_pos) +} + +// .proto.angles viewangles = 5; +inline bool player::_internal_has_viewangles() const { + return this != internal_default_instance() && viewangles_ != nullptr; +} +inline bool player::has_viewangles() const { + return _internal_has_viewangles(); +} +inline void player::clear_viewangles() { + if (GetArenaForAllocation() == nullptr && viewangles_ != nullptr) { + delete viewangles_; + } + viewangles_ = nullptr; +} +inline const ::proto::angles& player::_internal_viewangles() const { + const ::proto::angles* p = viewangles_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_angles_default_instance_); +} +inline const ::proto::angles& player::viewangles() const { + // @@protoc_insertion_point(field_get:proto.player.viewangles) + return _internal_viewangles(); +} +inline void player::unsafe_arena_set_allocated_viewangles( + ::proto::angles* viewangles) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(viewangles_); + } + viewangles_ = viewangles; + if (viewangles) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.player.viewangles) +} +inline ::proto::angles* player::release_viewangles() { + + ::proto::angles* temp = viewangles_; + viewangles_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::angles* player::unsafe_arena_release_viewangles() { + // @@protoc_insertion_point(field_release:proto.player.viewangles) + + ::proto::angles* temp = viewangles_; + viewangles_ = nullptr; + return temp; +} +inline ::proto::angles* player::_internal_mutable_viewangles() { + + if (viewangles_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::angles>(GetArenaForAllocation()); + viewangles_ = p; + } + return viewangles_; +} +inline ::proto::angles* player::mutable_viewangles() { + ::proto::angles* _msg = _internal_mutable_viewangles(); + // @@protoc_insertion_point(field_mutable:proto.player.viewangles) + return _msg; +} +inline void player::set_allocated_viewangles(::proto::angles* viewangles) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete viewangles_; + } + if (viewangles) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::angles>::GetOwningArena(viewangles); + if (message_arena != submessage_arena) { + viewangles = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, viewangles, submessage_arena); + } + + } else { + + } + viewangles_ = viewangles; + // @@protoc_insertion_point(field_set_allocated:proto.player.viewangles) +} + +// .proto.vec3 velocity = 6; +inline bool player::_internal_has_velocity() const { + return this != internal_default_instance() && velocity_ != nullptr; +} +inline bool player::has_velocity() const { + return _internal_has_velocity(); +} +inline void player::clear_velocity() { + if (GetArenaForAllocation() == nullptr && velocity_ != nullptr) { + delete velocity_; + } + velocity_ = nullptr; +} +inline const ::proto::vec3& player::_internal_velocity() const { + const ::proto::vec3* p = velocity_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_vec3_default_instance_); +} +inline const ::proto::vec3& player::velocity() const { + // @@protoc_insertion_point(field_get:proto.player.velocity) + return _internal_velocity(); +} +inline void player::unsafe_arena_set_allocated_velocity( + ::proto::vec3* velocity) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(velocity_); + } + velocity_ = velocity; + if (velocity) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.player.velocity) +} +inline ::proto::vec3* player::release_velocity() { + + ::proto::vec3* temp = velocity_; + velocity_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::vec3* player::unsafe_arena_release_velocity() { + // @@protoc_insertion_point(field_release:proto.player.velocity) + + ::proto::vec3* temp = velocity_; + velocity_ = nullptr; + return temp; +} +inline ::proto::vec3* player::_internal_mutable_velocity() { + + if (velocity_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::vec3>(GetArenaForAllocation()); + velocity_ = p; + } + return velocity_; +} +inline ::proto::vec3* player::mutable_velocity() { + ::proto::vec3* _msg = _internal_mutable_velocity(); + // @@protoc_insertion_point(field_mutable:proto.player.velocity) + return _msg; +} +inline void player::set_allocated_velocity(::proto::vec3* velocity) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete velocity_; + } + if (velocity) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::vec3>::GetOwningArena(velocity); + if (message_arena != submessage_arena) { + velocity = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, velocity, submessage_arena); + } + + } else { + + } + velocity_ = velocity; + // @@protoc_insertion_point(field_set_allocated:proto.player.velocity) +} + +// ------------------------------------------------------------------- + +// auth + +// string username = 1; +inline void auth::clear_username() { + username_.ClearToEmpty(); +} +inline const std::string& auth::username() const { + // @@protoc_insertion_point(field_get:proto.auth.username) + return _internal_username(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void auth::set_username(ArgT0&& arg0, ArgT... args) { + + username_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:proto.auth.username) +} +inline std::string* auth::mutable_username() { + std::string* _s = _internal_mutable_username(); + // @@protoc_insertion_point(field_mutable:proto.auth.username) + return _s; +} +inline const std::string& auth::_internal_username() const { + return username_.Get(); +} +inline void auth::_internal_set_username(const std::string& value) { + + username_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* auth::_internal_mutable_username() { + + return username_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* auth::release_username() { + // @@protoc_insertion_point(field_release:proto.auth.username) + return username_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +} +inline void auth::set_allocated_username(std::string* username) { + if (username != nullptr) { + + } else { + + } + username_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), username, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (username_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + username_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:proto.auth.username) +} + +// string password = 2; +inline void auth::clear_password() { + password_.ClearToEmpty(); +} +inline const std::string& auth::password() const { + // @@protoc_insertion_point(field_get:proto.auth.password) + return _internal_password(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void auth::set_password(ArgT0&& arg0, ArgT... args) { + + password_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:proto.auth.password) +} +inline std::string* auth::mutable_password() { + std::string* _s = _internal_mutable_password(); + // @@protoc_insertion_point(field_mutable:proto.auth.password) + return _s; +} +inline const std::string& auth::_internal_password() const { + return password_.Get(); +} +inline void auth::_internal_set_password(const std::string& value) { + + password_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* auth::_internal_mutable_password() { + + return password_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* auth::release_password() { + // @@protoc_insertion_point(field_release:proto.auth.password) + return password_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +} +inline void auth::set_allocated_password(std::string* password) { + if (password != nullptr) { + + } else { + + } + password_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), password, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (password_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + password_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:proto.auth.password) +} + +// ------------------------------------------------------------------- + +// init + +// uint64 seed = 1; +inline void init::clear_seed() { + seed_ = uint64_t{0u}; +} +inline uint64_t init::_internal_seed() const { + return seed_; +} +inline uint64_t init::seed() const { + // @@protoc_insertion_point(field_get:proto.init.seed) + return _internal_seed(); +} +inline void init::_internal_set_seed(uint64_t value) { + + seed_ = value; +} +inline void init::set_seed(uint64_t value) { + _internal_set_seed(value); + // @@protoc_insertion_point(field_set:proto.init.seed) +} + +// int32 draw_distance = 2; +inline void init::clear_draw_distance() { + draw_distance_ = 0; +} +inline int32_t init::_internal_draw_distance() const { + return draw_distance_; +} +inline int32_t init::draw_distance() const { + // @@protoc_insertion_point(field_get:proto.init.draw_distance) + return _internal_draw_distance(); +} +inline void init::_internal_set_draw_distance(int32_t value) { + + draw_distance_ = value; +} +inline void init::set_draw_distance(int32_t value) { + _internal_set_draw_distance(value); + // @@protoc_insertion_point(field_set:proto.init.draw_distance) +} + +// .proto.player localplayer = 3; +inline bool init::_internal_has_localplayer() const { + return this != internal_default_instance() && localplayer_ != nullptr; +} +inline bool init::has_localplayer() const { + return _internal_has_localplayer(); +} +inline void init::clear_localplayer() { + if (GetArenaForAllocation() == nullptr && localplayer_ != nullptr) { + delete localplayer_; + } + localplayer_ = nullptr; +} +inline const ::proto::player& init::_internal_localplayer() const { + const ::proto::player* p = localplayer_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_player_default_instance_); +} +inline const ::proto::player& init::localplayer() const { + // @@protoc_insertion_point(field_get:proto.init.localplayer) + return _internal_localplayer(); +} +inline void init::unsafe_arena_set_allocated_localplayer( + ::proto::player* localplayer) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(localplayer_); + } + localplayer_ = localplayer; + if (localplayer) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.init.localplayer) +} +inline ::proto::player* init::release_localplayer() { + + ::proto::player* temp = localplayer_; + localplayer_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::player* init::unsafe_arena_release_localplayer() { + // @@protoc_insertion_point(field_release:proto.init.localplayer) + + ::proto::player* temp = localplayer_; + localplayer_ = nullptr; + return temp; +} +inline ::proto::player* init::_internal_mutable_localplayer() { + + if (localplayer_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::player>(GetArenaForAllocation()); + localplayer_ = p; + } + return localplayer_; +} +inline ::proto::player* init::mutable_localplayer() { + ::proto::player* _msg = _internal_mutable_localplayer(); + // @@protoc_insertion_point(field_mutable:proto.init.localplayer) + return _msg; +} +inline void init::set_allocated_localplayer(::proto::player* localplayer) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete localplayer_; + } + if (localplayer) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::player>::GetOwningArena(localplayer); + if (message_arena != submessage_arena) { + localplayer = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, localplayer, submessage_arena); + } + + } else { + + } + localplayer_ = localplayer; + // @@protoc_insertion_point(field_set_allocated:proto.init.localplayer) +} + +// ------------------------------------------------------------------- + +// move + +// uint32 commands = 1; +inline void move::clear_commands() { + commands_ = 0u; +} +inline uint32_t move::_internal_commands() const { + return commands_; +} +inline uint32_t move::commands() const { + // @@protoc_insertion_point(field_get:proto.move.commands) + return _internal_commands(); +} +inline void move::_internal_set_commands(uint32_t value) { + + commands_ = value; +} +inline void move::set_commands(uint32_t value) { + _internal_set_commands(value); + // @@protoc_insertion_point(field_set:proto.move.commands) +} + +// .proto.angles viewangles = 2; +inline bool move::_internal_has_viewangles() const { + return this != internal_default_instance() && viewangles_ != nullptr; +} +inline bool move::has_viewangles() const { + return _internal_has_viewangles(); +} +inline void move::clear_viewangles() { + if (GetArenaForAllocation() == nullptr && viewangles_ != nullptr) { + delete viewangles_; + } + viewangles_ = nullptr; +} +inline const ::proto::angles& move::_internal_viewangles() const { + const ::proto::angles* p = viewangles_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_angles_default_instance_); +} +inline const ::proto::angles& move::viewangles() const { + // @@protoc_insertion_point(field_get:proto.move.viewangles) + return _internal_viewangles(); +} +inline void move::unsafe_arena_set_allocated_viewangles( + ::proto::angles* viewangles) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(viewangles_); + } + viewangles_ = viewangles; + if (viewangles) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.move.viewangles) +} +inline ::proto::angles* move::release_viewangles() { + + ::proto::angles* temp = viewangles_; + viewangles_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::angles* move::unsafe_arena_release_viewangles() { + // @@protoc_insertion_point(field_release:proto.move.viewangles) + + ::proto::angles* temp = viewangles_; + viewangles_ = nullptr; + return temp; +} +inline ::proto::angles* move::_internal_mutable_viewangles() { + + if (viewangles_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::angles>(GetArenaForAllocation()); + viewangles_ = p; + } + return viewangles_; +} +inline ::proto::angles* move::mutable_viewangles() { + ::proto::angles* _msg = _internal_mutable_viewangles(); + // @@protoc_insertion_point(field_mutable:proto.move.viewangles) + return _msg; +} +inline void move::set_allocated_viewangles(::proto::angles* viewangles) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete viewangles_; + } + if (viewangles) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::angles>::GetOwningArena(viewangles); + if (message_arena != submessage_arena) { + viewangles = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, viewangles, submessage_arena); + } + + } else { + + } + viewangles_ = viewangles; + // @@protoc_insertion_point(field_set_allocated:proto.move.viewangles) +} + +// ------------------------------------------------------------------- + +// remove_player + +// uint32 index = 1; +inline void remove_player::clear_index() { + index_ = 0u; +} +inline uint32_t remove_player::_internal_index() const { + return index_; +} +inline uint32_t remove_player::index() const { + // @@protoc_insertion_point(field_get:proto.remove_player.index) + return _internal_index(); +} +inline void remove_player::_internal_set_index(uint32_t value) { + + index_ = value; +} +inline void remove_player::set_index(uint32_t value) { + _internal_set_index(value); + // @@protoc_insertion_point(field_set:proto.remove_player.index) +} + +// ------------------------------------------------------------------- + +// say + +// string text = 1; +inline void say::clear_text() { + text_.ClearToEmpty(); +} +inline const std::string& say::text() const { + // @@protoc_insertion_point(field_get:proto.say.text) + return _internal_text(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void say::set_text(ArgT0&& arg0, ArgT... args) { + + text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:proto.say.text) +} +inline std::string* say::mutable_text() { + std::string* _s = _internal_mutable_text(); + // @@protoc_insertion_point(field_mutable:proto.say.text) + return _s; +} +inline const std::string& say::_internal_text() const { + return text_.Get(); +} +inline void say::_internal_set_text(const std::string& value) { + + text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* say::_internal_mutable_text() { + + return text_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* say::release_text() { + // @@protoc_insertion_point(field_release:proto.say.text) + return text_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +} +inline void say::set_allocated_text(std::string* text) { + if (text != nullptr) { + + } else { + + } + text_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), text, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (text_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + text_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:proto.say.text) +} + +// ------------------------------------------------------------------- + +// hear_player + +// uint32 index = 1; +inline void hear_player::clear_index() { + index_ = 0u; +} +inline uint32_t hear_player::_internal_index() const { + return index_; +} +inline uint32_t hear_player::index() const { + // @@protoc_insertion_point(field_get:proto.hear_player.index) + return _internal_index(); +} +inline void hear_player::_internal_set_index(uint32_t value) { + + index_ = value; +} +inline void hear_player::set_index(uint32_t value) { + _internal_set_index(value); + // @@protoc_insertion_point(field_set:proto.hear_player.index) +} + +// string text = 2; +inline void hear_player::clear_text() { + text_.ClearToEmpty(); +} +inline const std::string& hear_player::text() const { + // @@protoc_insertion_point(field_get:proto.hear_player.text) + return _internal_text(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void hear_player::set_text(ArgT0&& arg0, ArgT... args) { + + text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:proto.hear_player.text) +} +inline std::string* hear_player::mutable_text() { + std::string* _s = _internal_mutable_text(); + // @@protoc_insertion_point(field_mutable:proto.hear_player.text) + return _s; +} +inline const std::string& hear_player::_internal_text() const { + return text_.Get(); +} +inline void hear_player::_internal_set_text(const std::string& value) { + + text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* hear_player::_internal_mutable_text() { + + return text_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* hear_player::release_text() { + // @@protoc_insertion_point(field_release:proto.hear_player.text) + return text_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +} +inline void hear_player::set_allocated_text(std::string* text) { + if (text != nullptr) { + + } else { + + } + text_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), text, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (text_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + text_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:proto.hear_player.text) +} + +// ------------------------------------------------------------------- + +// request_chunk + +// .proto.coords chunk_pos = 1; +inline bool request_chunk::_internal_has_chunk_pos() const { + return this != internal_default_instance() && chunk_pos_ != nullptr; +} +inline bool request_chunk::has_chunk_pos() const { + return _internal_has_chunk_pos(); +} +inline void request_chunk::clear_chunk_pos() { + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; +} +inline const ::proto::coords& request_chunk::_internal_chunk_pos() const { + const ::proto::coords* p = chunk_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_coords_default_instance_); +} +inline const ::proto::coords& request_chunk::chunk_pos() const { + // @@protoc_insertion_point(field_get:proto.request_chunk.chunk_pos) + return _internal_chunk_pos(); +} +inline void request_chunk::unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(chunk_pos_); + } + chunk_pos_ = chunk_pos; + if (chunk_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.request_chunk.chunk_pos) +} +inline ::proto::coords* request_chunk::release_chunk_pos() { + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::coords* request_chunk::unsafe_arena_release_chunk_pos() { + // @@protoc_insertion_point(field_release:proto.request_chunk.chunk_pos) + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; + return temp; +} +inline ::proto::coords* request_chunk::_internal_mutable_chunk_pos() { + + if (chunk_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::coords>(GetArenaForAllocation()); + chunk_pos_ = p; + } + return chunk_pos_; +} +inline ::proto::coords* request_chunk::mutable_chunk_pos() { + ::proto::coords* _msg = _internal_mutable_chunk_pos(); + // @@protoc_insertion_point(field_mutable:proto.request_chunk.chunk_pos) + return _msg; +} +inline void request_chunk::set_allocated_chunk_pos(::proto::coords* chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete chunk_pos_; + } + if (chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::coords>::GetOwningArena(chunk_pos); + if (message_arena != submessage_arena) { + chunk_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_pos, submessage_arena); + } + + } else { + + } + chunk_pos_ = chunk_pos; + // @@protoc_insertion_point(field_set_allocated:proto.request_chunk.chunk_pos) +} + +// ------------------------------------------------------------------- + +// remove_chunk + +// .proto.coords chunk_pos = 1; +inline bool remove_chunk::_internal_has_chunk_pos() const { + return this != internal_default_instance() && chunk_pos_ != nullptr; +} +inline bool remove_chunk::has_chunk_pos() const { + return _internal_has_chunk_pos(); +} +inline void remove_chunk::clear_chunk_pos() { + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; +} +inline const ::proto::coords& remove_chunk::_internal_chunk_pos() const { + const ::proto::coords* p = chunk_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_coords_default_instance_); +} +inline const ::proto::coords& remove_chunk::chunk_pos() const { + // @@protoc_insertion_point(field_get:proto.remove_chunk.chunk_pos) + return _internal_chunk_pos(); +} +inline void remove_chunk::unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(chunk_pos_); + } + chunk_pos_ = chunk_pos; + if (chunk_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.remove_chunk.chunk_pos) +} +inline ::proto::coords* remove_chunk::release_chunk_pos() { + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::coords* remove_chunk::unsafe_arena_release_chunk_pos() { + // @@protoc_insertion_point(field_release:proto.remove_chunk.chunk_pos) + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; + return temp; +} +inline ::proto::coords* remove_chunk::_internal_mutable_chunk_pos() { + + if (chunk_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::coords>(GetArenaForAllocation()); + chunk_pos_ = p; + } + return chunk_pos_; +} +inline ::proto::coords* remove_chunk::mutable_chunk_pos() { + ::proto::coords* _msg = _internal_mutable_chunk_pos(); + // @@protoc_insertion_point(field_mutable:proto.remove_chunk.chunk_pos) + return _msg; +} +inline void remove_chunk::set_allocated_chunk_pos(::proto::coords* chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete chunk_pos_; + } + if (chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::coords>::GetOwningArena(chunk_pos); + if (message_arena != submessage_arena) { + chunk_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_pos, submessage_arena); + } + + } else { + + } + chunk_pos_ = chunk_pos; + // @@protoc_insertion_point(field_set_allocated:proto.remove_chunk.chunk_pos) +} + +// ------------------------------------------------------------------- + +// chunk + +// .proto.coords chunk_pos = 1; +inline bool chunk::_internal_has_chunk_pos() const { + return this != internal_default_instance() && chunk_pos_ != nullptr; +} +inline bool chunk::has_chunk_pos() const { + return _internal_has_chunk_pos(); +} +inline void chunk::clear_chunk_pos() { + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; +} +inline const ::proto::coords& chunk::_internal_chunk_pos() const { + const ::proto::coords* p = chunk_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_coords_default_instance_); +} +inline const ::proto::coords& chunk::chunk_pos() const { + // @@protoc_insertion_point(field_get:proto.chunk.chunk_pos) + return _internal_chunk_pos(); +} +inline void chunk::unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(chunk_pos_); + } + chunk_pos_ = chunk_pos; + if (chunk_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.chunk.chunk_pos) +} +inline ::proto::coords* chunk::release_chunk_pos() { + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::coords* chunk::unsafe_arena_release_chunk_pos() { + // @@protoc_insertion_point(field_release:proto.chunk.chunk_pos) + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; + return temp; +} +inline ::proto::coords* chunk::_internal_mutable_chunk_pos() { + + if (chunk_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::coords>(GetArenaForAllocation()); + chunk_pos_ = p; + } + return chunk_pos_; +} +inline ::proto::coords* chunk::mutable_chunk_pos() { + ::proto::coords* _msg = _internal_mutable_chunk_pos(); + // @@protoc_insertion_point(field_mutable:proto.chunk.chunk_pos) + return _msg; +} +inline void chunk::set_allocated_chunk_pos(::proto::coords* chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete chunk_pos_; + } + if (chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::coords>::GetOwningArena(chunk_pos); + if (message_arena != submessage_arena) { + chunk_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_pos, submessage_arena); + } + + } else { + + } + chunk_pos_ = chunk_pos; + // @@protoc_insertion_point(field_set_allocated:proto.chunk.chunk_pos) +} + +// repeated uint32 blocks = 2 [packed = true]; +inline int chunk::_internal_blocks_size() const { + return blocks_.size(); +} +inline int chunk::blocks_size() const { + return _internal_blocks_size(); +} +inline void chunk::clear_blocks() { + blocks_.Clear(); +} +inline uint32_t chunk::_internal_blocks(int index) const { + return blocks_.Get(index); +} +inline uint32_t chunk::blocks(int index) const { + // @@protoc_insertion_point(field_get:proto.chunk.blocks) + return _internal_blocks(index); +} +inline void chunk::set_blocks(int index, uint32_t value) { + blocks_.Set(index, value); + // @@protoc_insertion_point(field_set:proto.chunk.blocks) +} +inline void chunk::_internal_add_blocks(uint32_t value) { + blocks_.Add(value); +} +inline void chunk::add_blocks(uint32_t value) { + _internal_add_blocks(value); + // @@protoc_insertion_point(field_add:proto.chunk.blocks) +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >& +chunk::_internal_blocks() const { + return blocks_; +} +inline const ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >& +chunk::blocks() const { + // @@protoc_insertion_point(field_list:proto.chunk.blocks) + return _internal_blocks(); +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >* +chunk::_internal_mutable_blocks() { + return &blocks_; +} +inline ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t >* +chunk::mutable_blocks() { + // @@protoc_insertion_point(field_mutable_list:proto.chunk.blocks) + return _internal_mutable_blocks(); +} + +// ------------------------------------------------------------------- + +// add_block + +// .proto.coords chunk_pos = 1; +inline bool add_block::_internal_has_chunk_pos() const { + return this != internal_default_instance() && chunk_pos_ != nullptr; +} +inline bool add_block::has_chunk_pos() const { + return _internal_has_chunk_pos(); +} +inline void add_block::clear_chunk_pos() { + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; +} +inline const ::proto::coords& add_block::_internal_chunk_pos() const { + const ::proto::coords* p = chunk_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_coords_default_instance_); +} +inline const ::proto::coords& add_block::chunk_pos() const { + // @@protoc_insertion_point(field_get:proto.add_block.chunk_pos) + return _internal_chunk_pos(); +} +inline void add_block::unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(chunk_pos_); + } + chunk_pos_ = chunk_pos; + if (chunk_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.add_block.chunk_pos) +} +inline ::proto::coords* add_block::release_chunk_pos() { + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::coords* add_block::unsafe_arena_release_chunk_pos() { + // @@protoc_insertion_point(field_release:proto.add_block.chunk_pos) + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; + return temp; +} +inline ::proto::coords* add_block::_internal_mutable_chunk_pos() { + + if (chunk_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::coords>(GetArenaForAllocation()); + chunk_pos_ = p; + } + return chunk_pos_; +} +inline ::proto::coords* add_block::mutable_chunk_pos() { + ::proto::coords* _msg = _internal_mutable_chunk_pos(); + // @@protoc_insertion_point(field_mutable:proto.add_block.chunk_pos) + return _msg; +} +inline void add_block::set_allocated_chunk_pos(::proto::coords* chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete chunk_pos_; + } + if (chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::coords>::GetOwningArena(chunk_pos); + if (message_arena != submessage_arena) { + chunk_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_pos, submessage_arena); + } + + } else { + + } + chunk_pos_ = chunk_pos; + // @@protoc_insertion_point(field_set_allocated:proto.add_block.chunk_pos) +} + +// .proto.ivec3 block_pos = 2; +inline bool add_block::_internal_has_block_pos() const { + return this != internal_default_instance() && block_pos_ != nullptr; +} +inline bool add_block::has_block_pos() const { + return _internal_has_block_pos(); +} +inline void add_block::clear_block_pos() { + if (GetArenaForAllocation() == nullptr && block_pos_ != nullptr) { + delete block_pos_; + } + block_pos_ = nullptr; +} +inline const ::proto::ivec3& add_block::_internal_block_pos() const { + const ::proto::ivec3* p = block_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_ivec3_default_instance_); +} +inline const ::proto::ivec3& add_block::block_pos() const { + // @@protoc_insertion_point(field_get:proto.add_block.block_pos) + return _internal_block_pos(); +} +inline void add_block::unsafe_arena_set_allocated_block_pos( + ::proto::ivec3* block_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(block_pos_); + } + block_pos_ = block_pos; + if (block_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.add_block.block_pos) +} +inline ::proto::ivec3* add_block::release_block_pos() { + + ::proto::ivec3* temp = block_pos_; + block_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::ivec3* add_block::unsafe_arena_release_block_pos() { + // @@protoc_insertion_point(field_release:proto.add_block.block_pos) + + ::proto::ivec3* temp = block_pos_; + block_pos_ = nullptr; + return temp; +} +inline ::proto::ivec3* add_block::_internal_mutable_block_pos() { + + if (block_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::ivec3>(GetArenaForAllocation()); + block_pos_ = p; + } + return block_pos_; +} +inline ::proto::ivec3* add_block::mutable_block_pos() { + ::proto::ivec3* _msg = _internal_mutable_block_pos(); + // @@protoc_insertion_point(field_mutable:proto.add_block.block_pos) + return _msg; +} +inline void add_block::set_allocated_block_pos(::proto::ivec3* block_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete block_pos_; + } + if (block_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::ivec3>::GetOwningArena(block_pos); + if (message_arena != submessage_arena) { + block_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, block_pos, submessage_arena); + } + + } else { + + } + block_pos_ = block_pos; + // @@protoc_insertion_point(field_set_allocated:proto.add_block.block_pos) +} + +// uint32 block = 3; +inline void add_block::clear_block() { + block_ = 0u; +} +inline uint32_t add_block::_internal_block() const { + return block_; +} +inline uint32_t add_block::block() const { + // @@protoc_insertion_point(field_get:proto.add_block.block) + return _internal_block(); +} +inline void add_block::_internal_set_block(uint32_t value) { + + block_ = value; +} +inline void add_block::set_block(uint32_t value) { + _internal_set_block(value); + // @@protoc_insertion_point(field_set:proto.add_block.block) +} + +// ------------------------------------------------------------------- + +// remove_block + +// .proto.coords chunk_pos = 1; +inline bool remove_block::_internal_has_chunk_pos() const { + return this != internal_default_instance() && chunk_pos_ != nullptr; +} +inline bool remove_block::has_chunk_pos() const { + return _internal_has_chunk_pos(); +} +inline void remove_block::clear_chunk_pos() { + if (GetArenaForAllocation() == nullptr && chunk_pos_ != nullptr) { + delete chunk_pos_; + } + chunk_pos_ = nullptr; +} +inline const ::proto::coords& remove_block::_internal_chunk_pos() const { + const ::proto::coords* p = chunk_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_coords_default_instance_); +} +inline const ::proto::coords& remove_block::chunk_pos() const { + // @@protoc_insertion_point(field_get:proto.remove_block.chunk_pos) + return _internal_chunk_pos(); +} +inline void remove_block::unsafe_arena_set_allocated_chunk_pos( + ::proto::coords* chunk_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(chunk_pos_); + } + chunk_pos_ = chunk_pos; + if (chunk_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.remove_block.chunk_pos) +} +inline ::proto::coords* remove_block::release_chunk_pos() { + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::coords* remove_block::unsafe_arena_release_chunk_pos() { + // @@protoc_insertion_point(field_release:proto.remove_block.chunk_pos) + + ::proto::coords* temp = chunk_pos_; + chunk_pos_ = nullptr; + return temp; +} +inline ::proto::coords* remove_block::_internal_mutable_chunk_pos() { + + if (chunk_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::coords>(GetArenaForAllocation()); + chunk_pos_ = p; + } + return chunk_pos_; +} +inline ::proto::coords* remove_block::mutable_chunk_pos() { + ::proto::coords* _msg = _internal_mutable_chunk_pos(); + // @@protoc_insertion_point(field_mutable:proto.remove_block.chunk_pos) + return _msg; +} +inline void remove_block::set_allocated_chunk_pos(::proto::coords* chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete chunk_pos_; + } + if (chunk_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::coords>::GetOwningArena(chunk_pos); + if (message_arena != submessage_arena) { + chunk_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, chunk_pos, submessage_arena); + } + + } else { + + } + chunk_pos_ = chunk_pos; + // @@protoc_insertion_point(field_set_allocated:proto.remove_block.chunk_pos) +} + +// .proto.ivec3 block_pos = 2; +inline bool remove_block::_internal_has_block_pos() const { + return this != internal_default_instance() && block_pos_ != nullptr; +} +inline bool remove_block::has_block_pos() const { + return _internal_has_block_pos(); +} +inline void remove_block::clear_block_pos() { + if (GetArenaForAllocation() == nullptr && block_pos_ != nullptr) { + delete block_pos_; + } + block_pos_ = nullptr; +} +inline const ::proto::ivec3& remove_block::_internal_block_pos() const { + const ::proto::ivec3* p = block_pos_; + return p != nullptr ? *p : reinterpret_cast( + ::proto::_ivec3_default_instance_); +} +inline const ::proto::ivec3& remove_block::block_pos() const { + // @@protoc_insertion_point(field_get:proto.remove_block.block_pos) + return _internal_block_pos(); +} +inline void remove_block::unsafe_arena_set_allocated_block_pos( + ::proto::ivec3* block_pos) { + if (GetArenaForAllocation() == nullptr) { + delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(block_pos_); + } + block_pos_ = block_pos; + if (block_pos) { + + } else { + + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.remove_block.block_pos) +} +inline ::proto::ivec3* remove_block::release_block_pos() { + + ::proto::ivec3* temp = block_pos_; + block_pos_ = nullptr; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp); + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + if (GetArenaForAllocation() == nullptr) { delete old; } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return temp; +} +inline ::proto::ivec3* remove_block::unsafe_arena_release_block_pos() { + // @@protoc_insertion_point(field_release:proto.remove_block.block_pos) + + ::proto::ivec3* temp = block_pos_; + block_pos_ = nullptr; + return temp; +} +inline ::proto::ivec3* remove_block::_internal_mutable_block_pos() { + + if (block_pos_ == nullptr) { + auto* p = CreateMaybeMessage<::proto::ivec3>(GetArenaForAllocation()); + block_pos_ = p; + } + return block_pos_; +} +inline ::proto::ivec3* remove_block::mutable_block_pos() { + ::proto::ivec3* _msg = _internal_mutable_block_pos(); + // @@protoc_insertion_point(field_mutable:proto.remove_block.block_pos) + return _msg; +} +inline void remove_block::set_allocated_block_pos(::proto::ivec3* block_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation(); + if (message_arena == nullptr) { + delete block_pos_; + } + if (block_pos) { + ::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena = + ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper<::proto::ivec3>::GetOwningArena(block_pos); + if (message_arena != submessage_arena) { + block_pos = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage( + message_arena, block_pos, submessage_arena); + } + + } else { + + } + block_pos_ = block_pos; + // @@protoc_insertion_point(field_set_allocated:proto.remove_block.block_pos) +} + +// ------------------------------------------------------------------- + +// server_message + +// string message = 1; +inline void server_message::clear_message() { + message_.ClearToEmpty(); +} +inline const std::string& server_message::message() const { + // @@protoc_insertion_point(field_get:proto.server_message.message) + return _internal_message(); +} +template +inline PROTOBUF_ALWAYS_INLINE +void server_message::set_message(ArgT0&& arg0, ArgT... args) { + + message_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast(arg0), args..., GetArenaForAllocation()); + // @@protoc_insertion_point(field_set:proto.server_message.message) +} +inline std::string* server_message::mutable_message() { + std::string* _s = _internal_mutable_message(); + // @@protoc_insertion_point(field_mutable:proto.server_message.message) + return _s; +} +inline const std::string& server_message::_internal_message() const { + return message_.Get(); +} +inline void server_message::_internal_set_message(const std::string& value) { + + message_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArenaForAllocation()); +} +inline std::string* server_message::_internal_mutable_message() { + + return message_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArenaForAllocation()); +} +inline std::string* server_message::release_message() { + // @@protoc_insertion_point(field_release:proto.server_message.message) + return message_.Release(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArenaForAllocation()); +} +inline void server_message::set_allocated_message(std::string* message) { + if (message != nullptr) { + + } else { + + } + message_.SetAllocated(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), message, + GetArenaForAllocation()); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if (message_.IsDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited())) { + message_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), "", GetArenaForAllocation()); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + // @@protoc_insertion_point(field_set_allocated:proto.server_message.message) +} + +// bool fatal = 2; +inline void server_message::clear_fatal() { + fatal_ = false; +} +inline bool server_message::_internal_fatal() const { + return fatal_; +} +inline bool server_message::fatal() const { + // @@protoc_insertion_point(field_get:proto.server_message.fatal) + return _internal_fatal(); +} +inline void server_message::_internal_set_fatal(bool value) { + + fatal_ = value; +} +inline void server_message::set_fatal(bool value) { + _internal_set_fatal(value); + // @@protoc_insertion_point(field_set:proto.server_message.fatal) +} + +// ------------------------------------------------------------------- + +// packet + +// .proto.auth auth_packet = 1; +inline bool packet::_internal_has_auth_packet() const { + return contents_case() == kAuthPacket; +} +inline bool packet::has_auth_packet() const { + return _internal_has_auth_packet(); +} +inline void packet::set_has_auth_packet() { + _oneof_case_[0] = kAuthPacket; +} +inline void packet::clear_auth_packet() { + if (_internal_has_auth_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.auth_packet_; + } + clear_has_contents(); + } +} +inline ::proto::auth* packet::release_auth_packet() { + // @@protoc_insertion_point(field_release:proto.packet.auth_packet) + if (_internal_has_auth_packet()) { + clear_has_contents(); + ::proto::auth* temp = contents_.auth_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.auth_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::auth& packet::_internal_auth_packet() const { + return _internal_has_auth_packet() + ? *contents_.auth_packet_ + : reinterpret_cast< ::proto::auth&>(::proto::_auth_default_instance_); +} +inline const ::proto::auth& packet::auth_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.auth_packet) + return _internal_auth_packet(); +} +inline ::proto::auth* packet::unsafe_arena_release_auth_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.auth_packet) + if (_internal_has_auth_packet()) { + clear_has_contents(); + ::proto::auth* temp = contents_.auth_packet_; + contents_.auth_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_auth_packet(::proto::auth* auth_packet) { + clear_contents(); + if (auth_packet) { + set_has_auth_packet(); + contents_.auth_packet_ = auth_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.auth_packet) +} +inline ::proto::auth* packet::_internal_mutable_auth_packet() { + if (!_internal_has_auth_packet()) { + clear_contents(); + set_has_auth_packet(); + contents_.auth_packet_ = CreateMaybeMessage< ::proto::auth >(GetArenaForAllocation()); + } + return contents_.auth_packet_; +} +inline ::proto::auth* packet::mutable_auth_packet() { + ::proto::auth* _msg = _internal_mutable_auth_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.auth_packet) + return _msg; +} + +// .proto.init init_packet = 2; +inline bool packet::_internal_has_init_packet() const { + return contents_case() == kInitPacket; +} +inline bool packet::has_init_packet() const { + return _internal_has_init_packet(); +} +inline void packet::set_has_init_packet() { + _oneof_case_[0] = kInitPacket; +} +inline void packet::clear_init_packet() { + if (_internal_has_init_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.init_packet_; + } + clear_has_contents(); + } +} +inline ::proto::init* packet::release_init_packet() { + // @@protoc_insertion_point(field_release:proto.packet.init_packet) + if (_internal_has_init_packet()) { + clear_has_contents(); + ::proto::init* temp = contents_.init_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.init_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::init& packet::_internal_init_packet() const { + return _internal_has_init_packet() + ? *contents_.init_packet_ + : reinterpret_cast< ::proto::init&>(::proto::_init_default_instance_); +} +inline const ::proto::init& packet::init_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.init_packet) + return _internal_init_packet(); +} +inline ::proto::init* packet::unsafe_arena_release_init_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.init_packet) + if (_internal_has_init_packet()) { + clear_has_contents(); + ::proto::init* temp = contents_.init_packet_; + contents_.init_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_init_packet(::proto::init* init_packet) { + clear_contents(); + if (init_packet) { + set_has_init_packet(); + contents_.init_packet_ = init_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.init_packet) +} +inline ::proto::init* packet::_internal_mutable_init_packet() { + if (!_internal_has_init_packet()) { + clear_contents(); + set_has_init_packet(); + contents_.init_packet_ = CreateMaybeMessage< ::proto::init >(GetArenaForAllocation()); + } + return contents_.init_packet_; +} +inline ::proto::init* packet::mutable_init_packet() { + ::proto::init* _msg = _internal_mutable_init_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.init_packet) + return _msg; +} + +// .proto.move move_packet = 3; +inline bool packet::_internal_has_move_packet() const { + return contents_case() == kMovePacket; +} +inline bool packet::has_move_packet() const { + return _internal_has_move_packet(); +} +inline void packet::set_has_move_packet() { + _oneof_case_[0] = kMovePacket; +} +inline void packet::clear_move_packet() { + if (_internal_has_move_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.move_packet_; + } + clear_has_contents(); + } +} +inline ::proto::move* packet::release_move_packet() { + // @@protoc_insertion_point(field_release:proto.packet.move_packet) + if (_internal_has_move_packet()) { + clear_has_contents(); + ::proto::move* temp = contents_.move_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.move_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::move& packet::_internal_move_packet() const { + return _internal_has_move_packet() + ? *contents_.move_packet_ + : reinterpret_cast< ::proto::move&>(::proto::_move_default_instance_); +} +inline const ::proto::move& packet::move_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.move_packet) + return _internal_move_packet(); +} +inline ::proto::move* packet::unsafe_arena_release_move_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.move_packet) + if (_internal_has_move_packet()) { + clear_has_contents(); + ::proto::move* temp = contents_.move_packet_; + contents_.move_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_move_packet(::proto::move* move_packet) { + clear_contents(); + if (move_packet) { + set_has_move_packet(); + contents_.move_packet_ = move_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.move_packet) +} +inline ::proto::move* packet::_internal_mutable_move_packet() { + if (!_internal_has_move_packet()) { + clear_contents(); + set_has_move_packet(); + contents_.move_packet_ = CreateMaybeMessage< ::proto::move >(GetArenaForAllocation()); + } + return contents_.move_packet_; +} +inline ::proto::move* packet::mutable_move_packet() { + ::proto::move* _msg = _internal_mutable_move_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.move_packet) + return _msg; +} + +// .proto.player player_packet = 4; +inline bool packet::_internal_has_player_packet() const { + return contents_case() == kPlayerPacket; +} +inline bool packet::has_player_packet() const { + return _internal_has_player_packet(); +} +inline void packet::set_has_player_packet() { + _oneof_case_[0] = kPlayerPacket; +} +inline void packet::clear_player_packet() { + if (_internal_has_player_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.player_packet_; + } + clear_has_contents(); + } +} +inline ::proto::player* packet::release_player_packet() { + // @@protoc_insertion_point(field_release:proto.packet.player_packet) + if (_internal_has_player_packet()) { + clear_has_contents(); + ::proto::player* temp = contents_.player_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.player_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::player& packet::_internal_player_packet() const { + return _internal_has_player_packet() + ? *contents_.player_packet_ + : reinterpret_cast< ::proto::player&>(::proto::_player_default_instance_); +} +inline const ::proto::player& packet::player_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.player_packet) + return _internal_player_packet(); +} +inline ::proto::player* packet::unsafe_arena_release_player_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.player_packet) + if (_internal_has_player_packet()) { + clear_has_contents(); + ::proto::player* temp = contents_.player_packet_; + contents_.player_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_player_packet(::proto::player* player_packet) { + clear_contents(); + if (player_packet) { + set_has_player_packet(); + contents_.player_packet_ = player_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.player_packet) +} +inline ::proto::player* packet::_internal_mutable_player_packet() { + if (!_internal_has_player_packet()) { + clear_contents(); + set_has_player_packet(); + contents_.player_packet_ = CreateMaybeMessage< ::proto::player >(GetArenaForAllocation()); + } + return contents_.player_packet_; +} +inline ::proto::player* packet::mutable_player_packet() { + ::proto::player* _msg = _internal_mutable_player_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.player_packet) + return _msg; +} + +// .proto.remove_player remove_player_packet = 5; +inline bool packet::_internal_has_remove_player_packet() const { + return contents_case() == kRemovePlayerPacket; +} +inline bool packet::has_remove_player_packet() const { + return _internal_has_remove_player_packet(); +} +inline void packet::set_has_remove_player_packet() { + _oneof_case_[0] = kRemovePlayerPacket; +} +inline void packet::clear_remove_player_packet() { + if (_internal_has_remove_player_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.remove_player_packet_; + } + clear_has_contents(); + } +} +inline ::proto::remove_player* packet::release_remove_player_packet() { + // @@protoc_insertion_point(field_release:proto.packet.remove_player_packet) + if (_internal_has_remove_player_packet()) { + clear_has_contents(); + ::proto::remove_player* temp = contents_.remove_player_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.remove_player_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::remove_player& packet::_internal_remove_player_packet() const { + return _internal_has_remove_player_packet() + ? *contents_.remove_player_packet_ + : reinterpret_cast< ::proto::remove_player&>(::proto::_remove_player_default_instance_); +} +inline const ::proto::remove_player& packet::remove_player_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.remove_player_packet) + return _internal_remove_player_packet(); +} +inline ::proto::remove_player* packet::unsafe_arena_release_remove_player_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.remove_player_packet) + if (_internal_has_remove_player_packet()) { + clear_has_contents(); + ::proto::remove_player* temp = contents_.remove_player_packet_; + contents_.remove_player_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_remove_player_packet(::proto::remove_player* remove_player_packet) { + clear_contents(); + if (remove_player_packet) { + set_has_remove_player_packet(); + contents_.remove_player_packet_ = remove_player_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.remove_player_packet) +} +inline ::proto::remove_player* packet::_internal_mutable_remove_player_packet() { + if (!_internal_has_remove_player_packet()) { + clear_contents(); + set_has_remove_player_packet(); + contents_.remove_player_packet_ = CreateMaybeMessage< ::proto::remove_player >(GetArenaForAllocation()); + } + return contents_.remove_player_packet_; +} +inline ::proto::remove_player* packet::mutable_remove_player_packet() { + ::proto::remove_player* _msg = _internal_mutable_remove_player_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.remove_player_packet) + return _msg; +} + +// .proto.say say_packet = 6; +inline bool packet::_internal_has_say_packet() const { + return contents_case() == kSayPacket; +} +inline bool packet::has_say_packet() const { + return _internal_has_say_packet(); +} +inline void packet::set_has_say_packet() { + _oneof_case_[0] = kSayPacket; +} +inline void packet::clear_say_packet() { + if (_internal_has_say_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.say_packet_; + } + clear_has_contents(); + } +} +inline ::proto::say* packet::release_say_packet() { + // @@protoc_insertion_point(field_release:proto.packet.say_packet) + if (_internal_has_say_packet()) { + clear_has_contents(); + ::proto::say* temp = contents_.say_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.say_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::say& packet::_internal_say_packet() const { + return _internal_has_say_packet() + ? *contents_.say_packet_ + : reinterpret_cast< ::proto::say&>(::proto::_say_default_instance_); +} +inline const ::proto::say& packet::say_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.say_packet) + return _internal_say_packet(); +} +inline ::proto::say* packet::unsafe_arena_release_say_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.say_packet) + if (_internal_has_say_packet()) { + clear_has_contents(); + ::proto::say* temp = contents_.say_packet_; + contents_.say_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_say_packet(::proto::say* say_packet) { + clear_contents(); + if (say_packet) { + set_has_say_packet(); + contents_.say_packet_ = say_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.say_packet) +} +inline ::proto::say* packet::_internal_mutable_say_packet() { + if (!_internal_has_say_packet()) { + clear_contents(); + set_has_say_packet(); + contents_.say_packet_ = CreateMaybeMessage< ::proto::say >(GetArenaForAllocation()); + } + return contents_.say_packet_; +} +inline ::proto::say* packet::mutable_say_packet() { + ::proto::say* _msg = _internal_mutable_say_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.say_packet) + return _msg; +} + +// .proto.hear_player hear_player_packet = 7; +inline bool packet::_internal_has_hear_player_packet() const { + return contents_case() == kHearPlayerPacket; +} +inline bool packet::has_hear_player_packet() const { + return _internal_has_hear_player_packet(); +} +inline void packet::set_has_hear_player_packet() { + _oneof_case_[0] = kHearPlayerPacket; +} +inline void packet::clear_hear_player_packet() { + if (_internal_has_hear_player_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.hear_player_packet_; + } + clear_has_contents(); + } +} +inline ::proto::hear_player* packet::release_hear_player_packet() { + // @@protoc_insertion_point(field_release:proto.packet.hear_player_packet) + if (_internal_has_hear_player_packet()) { + clear_has_contents(); + ::proto::hear_player* temp = contents_.hear_player_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.hear_player_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::hear_player& packet::_internal_hear_player_packet() const { + return _internal_has_hear_player_packet() + ? *contents_.hear_player_packet_ + : reinterpret_cast< ::proto::hear_player&>(::proto::_hear_player_default_instance_); +} +inline const ::proto::hear_player& packet::hear_player_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.hear_player_packet) + return _internal_hear_player_packet(); +} +inline ::proto::hear_player* packet::unsafe_arena_release_hear_player_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.hear_player_packet) + if (_internal_has_hear_player_packet()) { + clear_has_contents(); + ::proto::hear_player* temp = contents_.hear_player_packet_; + contents_.hear_player_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_hear_player_packet(::proto::hear_player* hear_player_packet) { + clear_contents(); + if (hear_player_packet) { + set_has_hear_player_packet(); + contents_.hear_player_packet_ = hear_player_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.hear_player_packet) +} +inline ::proto::hear_player* packet::_internal_mutable_hear_player_packet() { + if (!_internal_has_hear_player_packet()) { + clear_contents(); + set_has_hear_player_packet(); + contents_.hear_player_packet_ = CreateMaybeMessage< ::proto::hear_player >(GetArenaForAllocation()); + } + return contents_.hear_player_packet_; +} +inline ::proto::hear_player* packet::mutable_hear_player_packet() { + ::proto::hear_player* _msg = _internal_mutable_hear_player_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.hear_player_packet) + return _msg; +} + +// .proto.request_chunk request_chunk_packet = 8; +inline bool packet::_internal_has_request_chunk_packet() const { + return contents_case() == kRequestChunkPacket; +} +inline bool packet::has_request_chunk_packet() const { + return _internal_has_request_chunk_packet(); +} +inline void packet::set_has_request_chunk_packet() { + _oneof_case_[0] = kRequestChunkPacket; +} +inline void packet::clear_request_chunk_packet() { + if (_internal_has_request_chunk_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.request_chunk_packet_; + } + clear_has_contents(); + } +} +inline ::proto::request_chunk* packet::release_request_chunk_packet() { + // @@protoc_insertion_point(field_release:proto.packet.request_chunk_packet) + if (_internal_has_request_chunk_packet()) { + clear_has_contents(); + ::proto::request_chunk* temp = contents_.request_chunk_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.request_chunk_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::request_chunk& packet::_internal_request_chunk_packet() const { + return _internal_has_request_chunk_packet() + ? *contents_.request_chunk_packet_ + : reinterpret_cast< ::proto::request_chunk&>(::proto::_request_chunk_default_instance_); +} +inline const ::proto::request_chunk& packet::request_chunk_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.request_chunk_packet) + return _internal_request_chunk_packet(); +} +inline ::proto::request_chunk* packet::unsafe_arena_release_request_chunk_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.request_chunk_packet) + if (_internal_has_request_chunk_packet()) { + clear_has_contents(); + ::proto::request_chunk* temp = contents_.request_chunk_packet_; + contents_.request_chunk_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_request_chunk_packet(::proto::request_chunk* request_chunk_packet) { + clear_contents(); + if (request_chunk_packet) { + set_has_request_chunk_packet(); + contents_.request_chunk_packet_ = request_chunk_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.request_chunk_packet) +} +inline ::proto::request_chunk* packet::_internal_mutable_request_chunk_packet() { + if (!_internal_has_request_chunk_packet()) { + clear_contents(); + set_has_request_chunk_packet(); + contents_.request_chunk_packet_ = CreateMaybeMessage< ::proto::request_chunk >(GetArenaForAllocation()); + } + return contents_.request_chunk_packet_; +} +inline ::proto::request_chunk* packet::mutable_request_chunk_packet() { + ::proto::request_chunk* _msg = _internal_mutable_request_chunk_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.request_chunk_packet) + return _msg; +} + +// .proto.chunk chunk_packet = 9; +inline bool packet::_internal_has_chunk_packet() const { + return contents_case() == kChunkPacket; +} +inline bool packet::has_chunk_packet() const { + return _internal_has_chunk_packet(); +} +inline void packet::set_has_chunk_packet() { + _oneof_case_[0] = kChunkPacket; +} +inline void packet::clear_chunk_packet() { + if (_internal_has_chunk_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.chunk_packet_; + } + clear_has_contents(); + } +} +inline ::proto::chunk* packet::release_chunk_packet() { + // @@protoc_insertion_point(field_release:proto.packet.chunk_packet) + if (_internal_has_chunk_packet()) { + clear_has_contents(); + ::proto::chunk* temp = contents_.chunk_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.chunk_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::chunk& packet::_internal_chunk_packet() const { + return _internal_has_chunk_packet() + ? *contents_.chunk_packet_ + : reinterpret_cast< ::proto::chunk&>(::proto::_chunk_default_instance_); +} +inline const ::proto::chunk& packet::chunk_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.chunk_packet) + return _internal_chunk_packet(); +} +inline ::proto::chunk* packet::unsafe_arena_release_chunk_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.chunk_packet) + if (_internal_has_chunk_packet()) { + clear_has_contents(); + ::proto::chunk* temp = contents_.chunk_packet_; + contents_.chunk_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_chunk_packet(::proto::chunk* chunk_packet) { + clear_contents(); + if (chunk_packet) { + set_has_chunk_packet(); + contents_.chunk_packet_ = chunk_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.chunk_packet) +} +inline ::proto::chunk* packet::_internal_mutable_chunk_packet() { + if (!_internal_has_chunk_packet()) { + clear_contents(); + set_has_chunk_packet(); + contents_.chunk_packet_ = CreateMaybeMessage< ::proto::chunk >(GetArenaForAllocation()); + } + return contents_.chunk_packet_; +} +inline ::proto::chunk* packet::mutable_chunk_packet() { + ::proto::chunk* _msg = _internal_mutable_chunk_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.chunk_packet) + return _msg; +} + +// .proto.remove_chunk remove_chunk_packet = 10; +inline bool packet::_internal_has_remove_chunk_packet() const { + return contents_case() == kRemoveChunkPacket; +} +inline bool packet::has_remove_chunk_packet() const { + return _internal_has_remove_chunk_packet(); +} +inline void packet::set_has_remove_chunk_packet() { + _oneof_case_[0] = kRemoveChunkPacket; +} +inline void packet::clear_remove_chunk_packet() { + if (_internal_has_remove_chunk_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.remove_chunk_packet_; + } + clear_has_contents(); + } +} +inline ::proto::remove_chunk* packet::release_remove_chunk_packet() { + // @@protoc_insertion_point(field_release:proto.packet.remove_chunk_packet) + if (_internal_has_remove_chunk_packet()) { + clear_has_contents(); + ::proto::remove_chunk* temp = contents_.remove_chunk_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.remove_chunk_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::remove_chunk& packet::_internal_remove_chunk_packet() const { + return _internal_has_remove_chunk_packet() + ? *contents_.remove_chunk_packet_ + : reinterpret_cast< ::proto::remove_chunk&>(::proto::_remove_chunk_default_instance_); +} +inline const ::proto::remove_chunk& packet::remove_chunk_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.remove_chunk_packet) + return _internal_remove_chunk_packet(); +} +inline ::proto::remove_chunk* packet::unsafe_arena_release_remove_chunk_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.remove_chunk_packet) + if (_internal_has_remove_chunk_packet()) { + clear_has_contents(); + ::proto::remove_chunk* temp = contents_.remove_chunk_packet_; + contents_.remove_chunk_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_remove_chunk_packet(::proto::remove_chunk* remove_chunk_packet) { + clear_contents(); + if (remove_chunk_packet) { + set_has_remove_chunk_packet(); + contents_.remove_chunk_packet_ = remove_chunk_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.remove_chunk_packet) +} +inline ::proto::remove_chunk* packet::_internal_mutable_remove_chunk_packet() { + if (!_internal_has_remove_chunk_packet()) { + clear_contents(); + set_has_remove_chunk_packet(); + contents_.remove_chunk_packet_ = CreateMaybeMessage< ::proto::remove_chunk >(GetArenaForAllocation()); + } + return contents_.remove_chunk_packet_; +} +inline ::proto::remove_chunk* packet::mutable_remove_chunk_packet() { + ::proto::remove_chunk* _msg = _internal_mutable_remove_chunk_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.remove_chunk_packet) + return _msg; +} + +// .proto.add_block add_block_packet = 11; +inline bool packet::_internal_has_add_block_packet() const { + return contents_case() == kAddBlockPacket; +} +inline bool packet::has_add_block_packet() const { + return _internal_has_add_block_packet(); +} +inline void packet::set_has_add_block_packet() { + _oneof_case_[0] = kAddBlockPacket; +} +inline void packet::clear_add_block_packet() { + if (_internal_has_add_block_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.add_block_packet_; + } + clear_has_contents(); + } +} +inline ::proto::add_block* packet::release_add_block_packet() { + // @@protoc_insertion_point(field_release:proto.packet.add_block_packet) + if (_internal_has_add_block_packet()) { + clear_has_contents(); + ::proto::add_block* temp = contents_.add_block_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.add_block_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::add_block& packet::_internal_add_block_packet() const { + return _internal_has_add_block_packet() + ? *contents_.add_block_packet_ + : reinterpret_cast< ::proto::add_block&>(::proto::_add_block_default_instance_); +} +inline const ::proto::add_block& packet::add_block_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.add_block_packet) + return _internal_add_block_packet(); +} +inline ::proto::add_block* packet::unsafe_arena_release_add_block_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.add_block_packet) + if (_internal_has_add_block_packet()) { + clear_has_contents(); + ::proto::add_block* temp = contents_.add_block_packet_; + contents_.add_block_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_add_block_packet(::proto::add_block* add_block_packet) { + clear_contents(); + if (add_block_packet) { + set_has_add_block_packet(); + contents_.add_block_packet_ = add_block_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.add_block_packet) +} +inline ::proto::add_block* packet::_internal_mutable_add_block_packet() { + if (!_internal_has_add_block_packet()) { + clear_contents(); + set_has_add_block_packet(); + contents_.add_block_packet_ = CreateMaybeMessage< ::proto::add_block >(GetArenaForAllocation()); + } + return contents_.add_block_packet_; +} +inline ::proto::add_block* packet::mutable_add_block_packet() { + ::proto::add_block* _msg = _internal_mutable_add_block_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.add_block_packet) + return _msg; +} + +// .proto.remove_block remove_block_packet = 12; +inline bool packet::_internal_has_remove_block_packet() const { + return contents_case() == kRemoveBlockPacket; +} +inline bool packet::has_remove_block_packet() const { + return _internal_has_remove_block_packet(); +} +inline void packet::set_has_remove_block_packet() { + _oneof_case_[0] = kRemoveBlockPacket; +} +inline void packet::clear_remove_block_packet() { + if (_internal_has_remove_block_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.remove_block_packet_; + } + clear_has_contents(); + } +} +inline ::proto::remove_block* packet::release_remove_block_packet() { + // @@protoc_insertion_point(field_release:proto.packet.remove_block_packet) + if (_internal_has_remove_block_packet()) { + clear_has_contents(); + ::proto::remove_block* temp = contents_.remove_block_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.remove_block_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::remove_block& packet::_internal_remove_block_packet() const { + return _internal_has_remove_block_packet() + ? *contents_.remove_block_packet_ + : reinterpret_cast< ::proto::remove_block&>(::proto::_remove_block_default_instance_); +} +inline const ::proto::remove_block& packet::remove_block_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.remove_block_packet) + return _internal_remove_block_packet(); +} +inline ::proto::remove_block* packet::unsafe_arena_release_remove_block_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.remove_block_packet) + if (_internal_has_remove_block_packet()) { + clear_has_contents(); + ::proto::remove_block* temp = contents_.remove_block_packet_; + contents_.remove_block_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_remove_block_packet(::proto::remove_block* remove_block_packet) { + clear_contents(); + if (remove_block_packet) { + set_has_remove_block_packet(); + contents_.remove_block_packet_ = remove_block_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.remove_block_packet) +} +inline ::proto::remove_block* packet::_internal_mutable_remove_block_packet() { + if (!_internal_has_remove_block_packet()) { + clear_contents(); + set_has_remove_block_packet(); + contents_.remove_block_packet_ = CreateMaybeMessage< ::proto::remove_block >(GetArenaForAllocation()); + } + return contents_.remove_block_packet_; +} +inline ::proto::remove_block* packet::mutable_remove_block_packet() { + ::proto::remove_block* _msg = _internal_mutable_remove_block_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.remove_block_packet) + return _msg; +} + +// .proto.server_message server_message_packet = 13; +inline bool packet::_internal_has_server_message_packet() const { + return contents_case() == kServerMessagePacket; +} +inline bool packet::has_server_message_packet() const { + return _internal_has_server_message_packet(); +} +inline void packet::set_has_server_message_packet() { + _oneof_case_[0] = kServerMessagePacket; +} +inline void packet::clear_server_message_packet() { + if (_internal_has_server_message_packet()) { + if (GetArenaForAllocation() == nullptr) { + delete contents_.server_message_packet_; + } + clear_has_contents(); + } +} +inline ::proto::server_message* packet::release_server_message_packet() { + // @@protoc_insertion_point(field_release:proto.packet.server_message_packet) + if (_internal_has_server_message_packet()) { + clear_has_contents(); + ::proto::server_message* temp = contents_.server_message_packet_; + if (GetArenaForAllocation() != nullptr) { + temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp); + } + contents_.server_message_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline const ::proto::server_message& packet::_internal_server_message_packet() const { + return _internal_has_server_message_packet() + ? *contents_.server_message_packet_ + : reinterpret_cast< ::proto::server_message&>(::proto::_server_message_default_instance_); +} +inline const ::proto::server_message& packet::server_message_packet() const { + // @@protoc_insertion_point(field_get:proto.packet.server_message_packet) + return _internal_server_message_packet(); +} +inline ::proto::server_message* packet::unsafe_arena_release_server_message_packet() { + // @@protoc_insertion_point(field_unsafe_arena_release:proto.packet.server_message_packet) + if (_internal_has_server_message_packet()) { + clear_has_contents(); + ::proto::server_message* temp = contents_.server_message_packet_; + contents_.server_message_packet_ = nullptr; + return temp; + } else { + return nullptr; + } +} +inline void packet::unsafe_arena_set_allocated_server_message_packet(::proto::server_message* server_message_packet) { + clear_contents(); + if (server_message_packet) { + set_has_server_message_packet(); + contents_.server_message_packet_ = server_message_packet; + } + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:proto.packet.server_message_packet) +} +inline ::proto::server_message* packet::_internal_mutable_server_message_packet() { + if (!_internal_has_server_message_packet()) { + clear_contents(); + set_has_server_message_packet(); + contents_.server_message_packet_ = CreateMaybeMessage< ::proto::server_message >(GetArenaForAllocation()); + } + return contents_.server_message_packet_; +} +inline ::proto::server_message* packet::mutable_server_message_packet() { + ::proto::server_message* _msg = _internal_mutable_server_message_packet(); + // @@protoc_insertion_point(field_mutable:proto.packet.server_message_packet) + return _msg; +} + +inline bool packet::has_contents() const { + return contents_case() != CONTENTS_NOT_SET; +} +inline void packet::clear_has_contents() { + _oneof_case_[0] = CONTENTS_NOT_SET; +} +inline packet::ContentsCase packet::contents_case() const { + return packet::ContentsCase(_oneof_case_[0]); +} +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif // __GNUC__ +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace proto + +// @@protoc_insertion_point(global_scope) + +#include +#endif // GOOGLE_PROTOBUF_INCLUDED_GOOGLE_PROTOBUF_INCLUDED_net_2eproto diff --git a/src/shared/net/lib/protobuf/net.proto b/src/shared/net/lib/protobuf/net.proto new file mode 100644 index 0000000..79d58e7 --- /dev/null +++ b/src/shared/net/lib/protobuf/net.proto @@ -0,0 +1,123 @@ +syntax = "proto3"; + +package proto; + +// STRUCTS +message angles { + float pitch = 1; + float yaw = 2; +} + +message coords { + int32 x = 1; + int32 z = 2; +} + +message vec3 { + float x = 1; + float y = 2; + float z = 3; +} + +message ivec3 { + int32 x = 1; + int32 y = 2; + int32 z = 3; +} + +message player { + uint32 index = 1; + uint32 commands = 2; + + coords chunk_pos = 3; + vec3 local_pos = 4; + + angles viewangles = 5; + vec3 velocity = 6; +} +// END OF STRUCTS + +// PACKETS +message auth { + string username = 1; + string password = 2; +} + +message init { + uint64 seed = 1; + int32 draw_distance = 2; + player localplayer = 3; +} + +message move { + uint32 commands = 1; + angles viewangles = 2; +} + +message remove_player { + uint32 index = 1; +} + +message say { + string text = 1; +} + +message hear_player { + uint32 index = 1; + string text = 2; +} + +message request_chunk { + coords chunk_pos = 1; +} + +message remove_chunk { + coords chunk_pos = 1; +} + +message chunk { + coords chunk_pos = 1; + // There is no uint8, so we have to pack four blocks into each uint32. + repeated uint32 blocks = 2 [packed = true]; +} + +message add_block { + coords chunk_pos = 1; + ivec3 block_pos = 2; + // A bit inefficient as we only need 8 bits. We could use the rest for other + // stuff down the road. + uint32 block = 3; +} + +message remove_block { + coords chunk_pos = 1; + ivec3 block_pos = 2; +} + +message server_message { + string message = 1; + bool fatal = 2; +} +// END OF PACKETS + +// Actual thing we read. +message packet { + +oneof contents { + auth auth_packet = 1; + init init_packet = 2; + move move_packet = 3; + player player_packet = 4; + remove_player remove_player_packet = 5; + say say_packet = 6; + hear_player hear_player_packet = 7; + request_chunk request_chunk_packet = 8; + chunk chunk_packet = 9; + remove_chunk remove_chunk_packet = 10; + add_block add_block_packet = 11; + remove_block remove_block_packet = 12; + server_message server_message_packet = 13; +} + +} + diff --git a/src/shared/net/net.cc b/src/shared/net/net.cc new file mode 100644 index 0000000..dc78261 --- /dev/null +++ b/src/shared/net/net.cc @@ -0,0 +1,138 @@ +#include "net.hh" + +namespace shared { +namespace net { + +// Some calls use errno, some use strerr. +std::string get_net_error(const int code) noexcept { + return make_string_lower(std::string(gai_strerror(code))); +} + +std::string get_errno_error() noexcept { + return make_string_lower(std::string(strerror(errno))); +} + +std::shared_ptr get_addr_info(const std::string_view address, + const std::string_view port, + const addrinfo* const hints) { + addrinfo* info; + if (int status = getaddrinfo(address.data(), port.data(), hints, &info)) { + throw std::runtime_error(get_net_error(status)); + } + return std::shared_ptr{info, [](auto p) { freeaddrinfo(p); }}; +} + +int make_socket(const addrinfo* const info) { + int sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + if (sock == -1) { + throw std::runtime_error(get_errno_error()); + } + int enable = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); + return sock; +} + +void bind_socket(const int sock, const addrinfo* const info) { + // Bind to the first we can, otherwise throw. + for (const addrinfo* i = info; i; i = i->ai_next) { + if (bind(sock, info->ai_addr, info->ai_addrlen) != -1) { + return; + } + } + throw std::runtime_error(get_errno_error()); +} + +void connect_socket(const int sock, const addrinfo* const info) { + if (connect(sock, info->ai_addr, info->ai_addrlen) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +void nonblock_socket(const int sock) { + if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +void* get_info_address(sockaddr& info) noexcept { + if (info.sa_family == AF_INET) { + return &(reinterpret_cast(&info)->sin_addr); + } + return &(reinterpret_cast(&info)->sin6_addr); +} + +void listen_socket(const int sock) { + fcntl(sock, F_SETFL, O_NONBLOCK); + if (listen(sock, SOMAXCONN) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +// Returns std::nullopt on failure! We lose the ability to throw here. +std::optional get_accept(const int sock) { + accept_ret info; + socklen_t size = sizeof(info.storage); + info.socket = + accept(sock, reinterpret_cast(&info.storage), &size); + if (info.socket == -1) { + return std::nullopt; + } + return info; +} + +void close_socket(const int sock) { + if (close(sock) == -1) { + throw std::runtime_error(get_errno_error()); + } +} + +// Returns the size of the receive buffer. +// For reliable, returns size of the stream (thanks [][][]). +// For unreliable, returns size of the next datagram available for reading. +std::size_t get_backlog_size(const int sock) { + size_t result = 0; + if (ioctl(sock, FIONREAD, &result) == -1) { + throw std::runtime_error(get_errno_error()); + } + return result; +} + +std::string get_socket_host_address(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getsockname(sock, reinterpret_cast(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::string(inet_ntoa(sin.sin_addr)); +} + +std::string get_socket_host_port(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getsockname(sock, reinterpret_cast(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::to_string(ntohs(sin.sin_port)); +} + +std::string get_socket_peer_address(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getpeername(sock, reinterpret_cast(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::string(inet_ntoa(sin.sin_addr)); +} + +std::string get_socket_peer_port(const int sock) { + sockaddr_in sin; + socklen_t size = sizeof(sin); + if (getpeername(sock, reinterpret_cast(&sin), &size) == -1) { + throw std::runtime_error(get_errno_error()); + } + return std::to_string(ntohs(sin.sin_port)); +} + +} // namespace net +} // namespace shared diff --git a/src/shared/net/net.hh b/src/shared/net/net.hh new file mode 100644 index 0000000..2603398 --- /dev/null +++ b/src/shared/net/net.hh @@ -0,0 +1,56 @@ +#ifndef SHARED_NET_NET_HH_ +#define SHARED_NET_NET_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "shared/shared.hh" + +namespace shared { +namespace net { + +std::string get_net_error(const int code) noexcept; +std::string get_errno_error() noexcept; +std::shared_ptr get_addr_info(const std::string_view address, + const std::string_view port, + const addrinfo* const hints); +int make_socket(const addrinfo* const info); +void bind_socket(const int socket, const addrinfo* const info); +void connect_socket(const int socket, const addrinfo* const info); +void nonblock_socket(const int sock); +void listen_socket(const int socket); +void* get_info_address(sockaddr& info) noexcept; +void close_socket(const int sock); +// Return socket and the sockaddr_storage we get from an accept call. +struct accept_ret { + sockaddr_storage storage; + int socket; +}; +std::optional get_accept(const int socket); +std::size_t get_backlog_size(const int sock); +std::string get_socket_host_address(const int sock); +std::string get_socket_host_port(const int sock); +std::string get_socket_peer_address(const int sock); +std::string get_socket_peer_port(const int sock); + +} // namespace net +} // namespace shared + +#endif diff --git a/src/shared/net/proto.cc b/src/shared/net/proto.cc new file mode 100644 index 0000000..1c954b1 --- /dev/null +++ b/src/shared/net/proto.cc @@ -0,0 +1,55 @@ +#include "shared/net/proto.hh" + +namespace shared { +namespace net { + +shared::player get_player(const proto::player& packet) noexcept { + return shared::player{ + .index = packet.index(), + .commands = packet.commands(), + .chunk_pos = {packet.chunk_pos().x(), packet.chunk_pos().z()}, + .local_pos = {packet.local_pos().x(), packet.local_pos().y(), + packet.local_pos().z()}, + .viewangles = {packet.viewangles().pitch(), packet.viewangles().yaw()}, + .velocity = {packet.velocity().x(), packet.velocity().y(), + packet.velocity().z()}, + }; +} + +void set_angles(proto::angles& proto_angles, + const shared::math::angles& angles) noexcept { + proto_angles.set_pitch(angles.pitch); + proto_angles.set_yaw(angles.yaw); +} + +void set_coords(proto::coords& proto_coords, + const shared::math::coords& coords) noexcept { + proto_coords.set_x(coords.x); + proto_coords.set_z(coords.z); +} + +void set_vec3(proto::vec3& proto_vec3, const glm::vec3& vec3) noexcept { + proto_vec3.set_x(vec3.x); + proto_vec3.set_y(vec3.y); + proto_vec3.set_z(vec3.z); +} + +void set_ivec3(proto::ivec3& proto_ivec3, const glm::ivec3& ivec3) noexcept { + proto_ivec3.set_x(ivec3.x); + proto_ivec3.set_y(ivec3.y); + proto_ivec3.set_z(ivec3.z); +} + +void set_player(proto::player& proto_player, + const shared::player& player) noexcept { + proto_player.set_index(player.index); + proto_player.set_commands(player.commands); + set_coords(*proto_player.mutable_chunk_pos(), player.chunk_pos); + set_vec3(*proto_player.mutable_local_pos(), player.local_pos); + set_angles(*proto_player.mutable_viewangles(), player.viewangles); + set_vec3(*proto_player.mutable_velocity(), player.velocity); +} + +} // namespace net + +} // namespace shared diff --git a/src/shared/net/proto.hh b/src/shared/net/proto.hh new file mode 100644 index 0000000..93bb005 --- /dev/null +++ b/src/shared/net/proto.hh @@ -0,0 +1,28 @@ +#ifndef SHARED_NET_PROTO_HH_ +#define SHARED_NET_PROTO_HH_ + +#include "shared/math.hh" +#include "shared/player.hh" + +#undef Status // Protobuf doesn't like xlib apparently. +#include "shared/net/lib/protobuf/net.pb.h" + +// TODO packet struct parsing packet helper functions +namespace shared { +namespace net { + +shared::player get_player(const proto::player& packet) noexcept; + +void set_angles(proto::angles& proto_angles, + const shared::math::angles& angles) noexcept; +void set_coords(proto::coords& proto_coords, + const shared::math::coords& coords) noexcept; +void set_vec3(proto::vec3& proto_vec3, const glm::vec3& vec3) noexcept; +void set_ivec3(proto::ivec3& proto_ivec3, const glm::ivec3& ivec3) noexcept; +void set_player(proto::player& proto_player, + const shared::player& player) noexcept; + +} // namespace net +} // namespace shared + +#endif diff --git a/src/shared/player.cc b/src/shared/player.cc new file mode 100644 index 0000000..55542ca --- /dev/null +++ b/src/shared/player.cc @@ -0,0 +1 @@ +#include "player.hh" diff --git a/src/shared/player.hh b/src/shared/player.hh new file mode 100644 index 0000000..5929c5b --- /dev/null +++ b/src/shared/player.hh @@ -0,0 +1,46 @@ +#ifndef SHARED_PLAYER_HH_ +#define SHARED_PLAYER_HH_ + +#include + +#include + +#include "shared/math.hh" + +namespace shared { + +// Anything here goes over the wire. +struct player { +public: + using index_t = std::uint32_t; + + static constexpr float HEIGHT = 1.9f; + static constexpr float EYE_HEIGHT = HEIGHT * 0.8f; + static constexpr float HALFWIDTH = 0.25f; + +public: + std::uint32_t index = 0; + std::uint32_t commands = 0; + + shared::math::coords chunk_pos = {}; + glm::vec3 local_pos = {}; + + shared::math::angles viewangles = {}; + glm::vec3 velocity = {}; + +public: + enum mask : decltype(commands) { + forward = 1 << 0, + left = 1 << 1, + backward = 1 << 2, + right = 1 << 3, + jump = 1 << 4, + crouch = 1 << 5, + sprint = 1 << 6, + attack = 1 << 7 + }; +}; + +} // namespace shared + +#endif diff --git a/src/shared/shared.cc b/src/shared/shared.cc new file mode 100644 index 0000000..55ccf1f --- /dev/null +++ b/src/shared/shared.cc @@ -0,0 +1,57 @@ +#include "shared.hh" + +namespace shared { + +std::string make_string_lower(std::string str) noexcept { + std::ranges::transform(str.begin(), str.end(), str.begin(), + [](const auto c) { return std::tolower(c); }); + return str; +} + +std::string read_file(const std::string& path) { + std::ifstream input(path); + if (!input.is_open()) { + throw std::runtime_error("failed to read file: " + path); + } + return std::string{std::istreambuf_iterator(input), + std::istreambuf_iterator()}; +} + +std::ofstream open_file(const std::string& dir, + const std::ios_base::openmode mode) { + std::ofstream ret(dir, mode); + if (!ret.is_open()) { + throw std::runtime_error("failed to write file: " + dir); + } + return ret; +} + +void compress_string(std::string& str) noexcept { + std::stringstream input(str); + + boost::iostreams::filtering_streambuf out; + out.push(boost::iostreams::gzip_compressor(boost::iostreams::gzip_params( + boost::iostreams::gzip::best_compression))); + out.push(input); + + std::stringstream result; + boost::iostreams::copy(out, result); + + str = result.str(); +} + +void decompress_string(std::string& str) noexcept { + std::stringstream input; + input << str; + + boost::iostreams::filtering_streambuf in; + in.push(boost::iostreams::gzip_decompressor()); + in.push(input); + + std::stringstream result; + boost::iostreams::copy(in, result); + + str = result.str(); +} + +} // namespace shared diff --git a/src/shared/shared.hh b/src/shared/shared.hh new file mode 100644 index 0000000..2d64814 --- /dev/null +++ b/src/shared/shared.hh @@ -0,0 +1,120 @@ +#ifndef SHARED_SHARED_HH_ +#define SHARED_SHARED_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "shared/math.hh" + +// Tiny thread safe printing. +namespace shared { + +std::string make_string_lower(std::string str) noexcept; +std::string read_file(const std::string& path); +void compress_string(std::string& str) noexcept; +void decompress_string(std::string& str) noexcept; +std::ofstream open_file(const std::string& dir, + const std::ios_base::openmode mode = std::ios::trunc); + +constexpr unsigned long MAX_SAY_LENGTH = 32ul; +constexpr unsigned long MAX_USER_PASS_LENGTH = 64; + +class print { +private: + static inline std::mutex lock; + +public: + enum class colour { + black = 30, + red = 31, + green = 32, + yellow = 33, + blue = 34, + magenta = 35, + cyan = 36, + white = 37, + none = 39, + grey = 90, + bright_red = 91, + bright_green = 92, + bright_yellow = 93, + bright_blue = 94, + bright_magenta = 95, + bright_cyan = 96, + bright_white = 97 + }; + +private: + static void print_message(const std::string_view message, + const bool print_time, + const std::string_view colour, + const bool cerr = false) noexcept { + const std::lock_guard guard(lock); + + if (print_time) { + const auto epoch = std::time(nullptr); + struct tm* local = localtime(&epoch); + std::cout << std::put_time(local, "[%F %T] "); + } + static std::string none = make_colour(colour::none); + + if (cerr) { + std::cerr << colour << message << none; + return; + } + + std::cout << colour << message << none; + } + static std::string make_colour(const colour clr) noexcept { + return {"\033[" + std::to_string(static_cast(clr)) + "m"}; + } + +public: + print() noexcept = delete; + static void message(const std::string_view msg, + const bool print_time = true) noexcept { + static const std::string grey = make_colour(colour::white); + print_message(msg, print_time, grey); + } + static void notify(const std::string_view msg, + const bool print_time = true) noexcept { + static const std::string cyan = make_colour(colour::cyan); + print_message(msg, print_time, cyan); + } + static void warn(const std::string_view msg, + const bool print_time = true) noexcept { + static const std::string b_yellow = make_colour(colour::bright_yellow); + print_message(msg, print_time, b_yellow); + } + static void fault(const std::string_view msg, + const bool print_time = true) noexcept { + static const std::string bright_red = make_colour(colour::bright_red); + print_message(msg, print_time, bright_red, true); + } + static void debug(const std::string_view msg, + const bool print_time = true) noexcept { + static const std::string magenta = make_colour(colour::magenta); + print_message(msg, print_time, magenta, true); + } + static void custom(const std::string_view msg, const enum colour colour, + const bool print_time = true) noexcept { + print_message(msg, print_time, make_colour(colour)); + } +}; + +inline std::atomic should_exit = false; + +}; // namespace shared + +#endif diff --git a/src/shared/world.cc b/src/shared/world.cc new file mode 100644 index 0000000..d56b7a8 --- /dev/null +++ b/src/shared/world.cc @@ -0,0 +1,932 @@ +#include "shared/world.hh" + +namespace shared { +namespace world { + +// Because C++ doesn't allow us to iterate over an enum, +// (or get the size of an enum, or get the name of an enum, etc) biomes defined +// in the chunk::biome enum class have to be readded here. Alternatively we +// could use some compiler hack library. +constexpr std::array biome_enums{ + shared::world::chunk::biome::alpine, shared::world::chunk::biome::tundra, + shared::world::chunk::biome::forest, shared::world::chunk::biome::plains, + shared::world::chunk::biome::ocean, shared::world::chunk::biome::islands, + shared::world::chunk::biome::desert}; + +constexpr long get_biome_index(const enum shared::world::chunk::biome biome) noexcept { + return std::distance(std::begin(biome_enums), + std::ranges::find(biome_enums, biome)); +} + +chunk::block_array +chunk::make_blocks_from_chunk(const proto::chunk& chunk) noexcept { + chunk::block_array blocks; + + for (int i = 0; i < chunk.blocks_size(); ++i) { + const std::uint32_t packed_blocks = chunk.blocks(i); + for (int j = 0; j < 4; ++j) { + blocks[static_cast(i * 4 + j)] = + static_cast( + static_cast(packed_blocks >> j * 8)); + } + } + + return blocks; +} + +// Returns a deterministic random number based on the args. +static unsigned long make_prandom(const uint64_t seed, + const shared::math::coords& coords) noexcept { + const auto ulx = static_cast(coords.x); + const auto ulz = static_cast(coords.z); + return std::ranlux48{std::ranlux48{std::ranlux48{seed}() + ulx}() + ulz}(); +} + +// Returns a pseduorandom gradient vector. +static glm::vec2 make_gvect(const std::uint64_t& seed, + const shared::math::coords& coords) noexcept { + const unsigned long pseudo = make_prandom(seed, coords); + // Return a vector based on the first four bits of this random number. + // This vector can point in dirs (x with a + on it) with range [-1, 1]. + const float v1 = ((pseudo & 0b00001111) / 7.5f) - 1.0f; + const float v2 = (((pseudo & 0b11110000) >> 4) / 7.5f) - 1.0f; + return {v1, v2}; +} + +// Returns a distance vector between a vector and a grid position in a chunk. +static glm::vec2 make_dvect(const glm::vec2 v, const unsigned int x, + const unsigned int z, const int width) noexcept { + const auto div = static_cast(width - 1); + const float v1 = v.x - (static_cast(x) / div); + const float v2 = v.y - (static_cast(z) / div); + return {v1, v2}; +} + +static float fade(const float v) noexcept { + return v * v * v * (v * (v * 6 - 15) + 10); +} + +static std::int32_t reflect_outer(const std::int32_t& n, + const int WIDTH = chunk::WIDTH) noexcept { + return n < 0 ? ((n - (WIDTH - 1)) / WIDTH) : n / WIDTH; +} + +static std::int32_t reflect_inner(const std::int32_t& n, + const int WIDTH = chunk::WIDTH) noexcept { + return ((n % WIDTH) + WIDTH) % WIDTH; +} + +// Moves perlin noise values from the range of [-1.0f, 1.0f] to [0.0f, 1.0f]. +// It's more useful to have a perlin layer add nothing at its absolute lowest, +// then it is for a perlin layer to potentially remove 1.0f at its lowest. +static float normalise_perlin(const float perlin) noexcept { + return 0.5f * (perlin + 1.0f); +} + +using chunk_array = std::array, chunk::WIDTH>; +using chunk_array_map = + std::unordered_map; + +// 2D Perlin noise, in which we: +// 1. Define corners of a square as vectors, in this case using 0 or 1. +// 2. Assign pseudorandom normalised gradient vectors to each corner vector. +// 3. Create and iterate through a 2d array, where we: +// 3.1: Generate distance vectors from each corner vector to the cell. +// 3.2: Dot our gradient vectors and distance vectors respectively. +// 3.3: Lerp our bottom and top dot product values by a fade function and x. +// 3.4: Lerp (3.3) via fade function and z. This is the cell result. +// There is an additional step where we make use of "scale" (any s* var). This +// involves moving the requested chunk into a potentially different chunk, and +// accessing a greater level of detail. It's just zoom and enhance. +static chunk_array make_2d_perlin_array(const std::uint64_t& seed, + const shared::math::coords& pos, + const int scale) noexcept { + constexpr glm::vec2 tr = {1.0f, 1.0f}; // (1) + constexpr glm::vec2 tl = {0.0f, 1.0f}; + constexpr glm::vec2 bl = {0.0f, 0.0f}; + constexpr glm::vec2 br = {1.0f, 0.0f}; + + const int scx = reflect_outer(pos.x, scale); + const int scz = reflect_outer(pos.z, scale); + const int swidth = chunk::WIDTH * scale; + + // clang-format off + const glm::vec2 tr_g = glm::normalize(make_gvect(seed, shared::math::coords{scx, scz})); // (2) + const glm::vec2 tl_g = glm::normalize(make_gvect(seed, shared::math::coords{scx - 1, scz})); + const glm::vec2 bl_g = glm::normalize(make_gvect(seed, shared::math::coords{scx - 1, scz - 1})); + const glm::vec2 br_g = glm::normalize(make_gvect(seed, shared::math::coords{scx, scz - 1})); + // clang-format on + + chunk_array perlin; // (3) + + const int x_offset = reflect_inner(pos.x, scale) * chunk::WIDTH; + const int z_offset = reflect_inner(pos.z, scale) * chunk::WIDTH; + for (auto x = 0u; x < chunk::WIDTH; ++x) { + const unsigned sx = x + static_cast(x_offset); + + for (auto z = 0u; z < chunk::WIDTH; ++z) { + const unsigned sz = z + static_cast(z_offset); + + const glm::vec2 tr_d = make_dvect(tr, sx, sz, swidth); // (3.1) + const glm::vec2 tl_d = make_dvect(tl, sx, sz, swidth); + const glm::vec2 bl_d = make_dvect(bl, sx, sz, swidth); + const glm::vec2 br_d = make_dvect(br, sx, sz, swidth); + + const float tr_dp = glm::dot(tr_g, tr_d); // (3.2) + const float tl_dp = glm::dot(tl_g, tl_d); + const float bl_dp = glm::dot(bl_g, bl_d); + const float br_dp = glm::dot(br_g, br_d); + + const float fswidth = static_cast(swidth - 1); + const float fracx = (static_cast(sx) + 0.5f) / fswidth; + const float fracz = (static_cast(sz) + 0.5f) / fswidth; + const float tl_tr = std::lerp(tl_dp, tr_dp, fade(fracx)); // (3.3) + const float bl_br = std::lerp(bl_dp, br_dp, fade(fracx)); + + const float result = std::lerp(tl_tr, bl_br, fade(1.0f - fracz)); + + perlin[x][z] = normalise_perlin(result); // (3.4) + } + } + + return perlin; +} + +using biome_array = std::array< + std::array, chunk::WIDTH>, + chunk::WIDTH>; +using biome_array_map = + std::unordered_map; +// A 2d_biome_array is a 2d array containing a [0.0f-1.0f] value, tied to a +// biome, representing the weight the biomes have on each column in the world. +// Naturally each column should take that % of each biome's ruleset during +// worldgen, resuling in an amount of rules that adds up to 100%. + +// Unfortunately this is a bit of a hell function because it is full of very +// specific operations that can't be reasonably separated without decreasing +// random number generation complexity or exposing a ton of random static +// functions that will never be used outside of this. +// Basically I am trying to minimise this bad code. +static biome_array make_2d_biome_array(const std::uint64_t& seed, + const shared::math::coords& coords, + const int scale) noexcept { + + // Decreasing NUM_POINTS to the smallest meaningful value of 1 while + // simultaneously decreasing our scale results in FAR lower computational + // cost while achieving approximately the same result. This is because we + // only have to generate 9 random numbers, as opposed to n * 9, which is a + // performance KILLER. + constexpr int NUM_POINTS = 1; + + struct point { + glm::vec2 pos; + enum chunk::biome biome; + }; + using point_array = std::array; + const auto make_points = + [&seed](const shared::math::coords& c) -> point_array { + constexpr int BITS_PER_FLOAT = 48 / 2; // ranlux 48 / 2 + constexpr int MASK = ((2 << BITS_PER_FLOAT) - 1); + static_assert(BITS_PER_FLOAT * 2 * NUM_POINTS <= 48); + + const unsigned long prand = make_prandom(seed, c); + std::uniform_int_distribution<> uniform{0, std::size(biome_enums) - 1}; + std::ranlux48 generator{prand}; + + point_array points; + std::ranges::generate(points, [&, n = 0]() mutable -> point { + const int x = (prand >> ((n + 1) * BITS_PER_FLOAT)) & MASK; + const int y = (prand >> ((n)*BITS_PER_FLOAT)) & MASK; + const glm::vec2 pos = glm::vec2{x, y} / static_cast(MASK); + const auto biome = static_cast(uniform(generator)); + ++n; + return {pos, biome}; + }); + return points; + }; + + const shared::math::coords scaled_coords{reflect_outer(coords.x, scale), + reflect_outer(coords.z, scale)}; + + using point_2d_array = std::array, 3>; + const point_2d_array point_arrays = [&]() -> point_2d_array { + point_2d_array point_arrays; + for (int x = -1; x <= 1; ++x) { + for (int z = -1; z <= 1; ++z) { + const auto offset_coords = + scaled_coords + shared::math::coords{x, z}; + const auto index_x = static_cast(x + 1); + const auto index_z = static_cast(z + 1); + point_arrays[index_x][index_z] = make_points(offset_coords); + } + } + return point_arrays; + }(); + + struct point_info { + struct point point; + glm::vec2 pos; + shared::math::coords coords; + float distance; + }; + using point_info_vector = std::vector; + const auto get_closest_point_infos = + [&](const glm::vec2 pos) -> point_info_vector { + std::vector point_infos; + for (int x = -1; x <= 1; ++x) { + for (int z = -1; z <= 1; ++z) { + const glm::vec2 offset = {x, z}; + const point_array& point_array = + point_arrays[static_cast(x + 1)] + [static_cast(z + 1)]; + + for (const auto& point : point_array) { + + const float distance = + glm::distance(point.pos + offset, pos); + if (distance > 1.0f) { + continue; + } + + point_infos.push_back(point_info{ + .point = point, + .pos = point.pos, + .coords = shared::math::coords{x, z} + scaled_coords, + .distance = distance}); + } + } + } + return point_infos; + }; + + const int x_offset = reflect_inner(coords.x, scale) * chunk::WIDTH; + const int z_offset = reflect_inner(coords.z, scale) * chunk::WIDTH; + const int scaled_width = chunk::WIDTH * scale; + + // We generate a bit of perlin noise here so we can add some (jitter?) + // along our distances - the end result is less of an obvious line and more + // variance along our chunk borders. + constexpr int BIOME_JITTER_SCALE = 3; + const chunk_array jitter = + make_2d_perlin_array(seed, coords, BIOME_JITTER_SCALE); + + // For our 2d array (ultimately columns of blocks in the world), we get the + // point that we're closest to in our world's voronoi noise points. For + // the points that are relevant (relatively close), we get the biome the + // point represents and add it to the column's array of biome influences. + // We ensure that these values add up to 1.0f. In the end, we have a struct + // that describes how much each biome affects each column as a %. + biome_array array = {}; + for (auto x = 0u; x < chunk::WIDTH; ++x) { + const unsigned sx = x + static_cast(x_offset); + + for (auto z = 0u; z < chunk::WIDTH; ++z) { + const unsigned sz = z + static_cast(z_offset); + + const glm::vec2 inner_pos = + glm::vec2{static_cast(sx) + 0.5f, + static_cast(sz) + 0.5f} / + static_cast(scaled_width) + + glm::vec2{std::sin(jitter[x][z]), std::cos(jitter[x][z])} * + 0.1f; + + const auto point_infos = get_closest_point_infos(inner_pos); + + float total_dominance = 0.0f; + for (const auto& point_info : point_infos) { + const auto index = get_biome_index(point_info.point.biome); + const float dominance = std::clamp( + -1.0f * std::pow(0.5f * point_info.distance - 1.0f, 21.0f), + 0.0f, 1.0f); + + auto& loc = array[x][z][static_cast(index)]; + if (loc > dominance) { + continue; + } + const float diff = dominance - loc; + loc += diff; + total_dominance += diff; + } + + for (float& dominance : array[x][z]) { + dominance *= (1.0f / total_dominance); + } + } + } + return array; +} + +static auto array_map_access(const auto& array_map, + const shared::math::coords& coords, const int x, + const int z) noexcept { + const shared::math::coords normalised_coords = + chunk::get_normalised_chunk(coords, x, z); + const auto [nx, nz] = chunk::get_normalised_coords(x, z); + return array_map.find(normalised_coords)->second[nx][nz]; +} + +// We take a std::function that generates a chunk array to fill an unordered +// map with a 3x3 chunk_array contents, where those contents refer to the +// values in the surrounding chunks. +static auto make_array_map(const std::uint64_t& seed, + const shared::math::coords& coords, + const auto& make_chunk_array_func) noexcept { + + std::unordered_map + array_map{9, chunk::hash, chunk::equal}; + for (int x = -1; x <= 1; ++x) { + for (int z = -1; z <= 1; ++z) { + const shared::math::coords pos{coords + shared::math::coords{x, z}}; + array_map.emplace(pos, make_chunk_array_func(seed, pos)); + } + } + + return array_map; +} + +// These are constexpr for our static assert. +static constexpr float +get_biome_offset(const enum chunk::biome biome) noexcept { + switch (biome) { + case chunk::biome::ocean: + case chunk::biome::islands: + return 0.0f; + default: + break; + } + return 10.0f; +} + +static constexpr float +get_biome_variation17(const enum chunk::biome biome) noexcept { + switch (biome) { + case chunk::biome::alpine: + return 80.0f; + case chunk::biome::tundra: + return 10.0f; + case chunk::biome::forest: + return 30.0f; + case chunk::biome::ocean: + return 0.0f; + case chunk::biome::islands: + return 5.0f; + default: + break; + } + return 15.0f; +} + +static constexpr float +get_biome_variation11(const enum chunk::biome biome) noexcept { + switch (biome) { + break; + case chunk::biome::alpine: + return 40.0f; + case chunk::biome::tundra: + return 30.0f; + default: + break; + } + return 20.0f; +} + +static constexpr float +get_biome_variation7(const enum chunk::biome biome) noexcept { + switch (biome) { + case chunk::biome::alpine: + return 20.0f; + case chunk::biome::islands: + return 30.0f; + case chunk::biome::desert: + case chunk::biome::plains: + return 15.0f; + default: + break; + } + return 10.0f; +} + +static constexpr float +get_biome_variation3(const enum chunk::biome biome) noexcept { + switch (biome) { + default: + break; + } + return 7.5f; +} + +constexpr float BASE_HEIGHT = 40.0f; +// Ensure any perlin values of our biome generation does not result in a y value +// that is outside our max height. +static_assert(std::ranges::all_of(biome_enums, [](const auto& biome) { + const float max_height = + BASE_HEIGHT + get_biome_offset(biome) + get_biome_variation3(biome) + + get_biome_variation7(biome) + get_biome_variation11(biome) + + get_biome_variation17(biome); + return max_height < static_cast(chunk::HEIGHT); +})); + +// Line that crosses at 0.5f, 0.5f with a variable gradient, should be clamped. +static float linear_gradient(const float x, const float m) noexcept { + return m * (x - (0.5f - (0.5f / m))); +} + +// The functions for ...these functions... should be domain and range [0, 1]. +static float process_variation(float variation, + const enum chunk::biome biome) noexcept { + switch (biome) { + case chunk::biome::alpine: + variation = linear_gradient(variation, 2.2f); + break; + default: + variation = linear_gradient(variation, 1.5f); + break; + } + return std::clamp(variation, 0.0f, 1.0f); +} + +chunk_array make_topography(const std::uint64_t& seed, + const shared::math::coords& coords, + const biome_array_map& biome_map) noexcept { + + chunk_array topography = {}; + + const biome_array& biomes = biome_map.find(coords)->second; + const chunk_array perlin17 = make_2d_perlin_array(seed, coords, 17); + const chunk_array perlin11 = make_2d_perlin_array(seed, coords, 11); + const chunk_array perlin7 = make_2d_perlin_array(seed, coords, 7); + const chunk_array perlin3 = make_2d_perlin_array(seed, coords, 3); + + for (auto x = 0ul; x < chunk::WIDTH; ++x) { + for (auto z = 0ul; z < chunk::WIDTH; ++z) { + + // Initial topography of 40.0f. + topography[x][z] = BASE_HEIGHT; + + const auto biome_dominance = biomes[x][z]; + for (auto i = 0u; i < std::size(biome_dominance); ++i) { + const enum chunk::biome biome = biome_enums[i]; + + const float dominance = biome_dominance[i]; + const float v3 = process_variation(perlin3[x][z], biome) * + get_biome_variation3(biome); + const float v7 = process_variation(perlin7[x][z], biome) * + get_biome_variation7(biome); + const float v11 = process_variation(perlin11[x][z], biome) * + get_biome_variation11(biome); + const float v17 = process_variation(perlin17[x][z], biome) * + get_biome_variation17(biome); + + topography[x][z] += + (get_biome_offset(biome) + v3 + v7 + v11 + v17) * dominance; + } + } + } + + return topography; +} + +static chunk_array +make_probabilities(const std::uint64_t& seed, + const shared::math::coords& coords) noexcept { + + chunk_array chunk_array; + + std::uniform_real_distribution uniform{ + 0.0f, std::nextafter(1.0f, std::numeric_limits::max())}; + std::ranlux48 generator(make_prandom(seed, coords)); + for (auto x = 0ul; x < chunk::WIDTH; ++x) { + for (auto z = 0ul; z < chunk::WIDTH; ++z) { + chunk_array[x][z] = uniform(generator); + } + } + + return chunk_array; +} + +static biome_array make_biomes(const std::uint64_t& seed, + const shared::math::coords& coords) noexcept { + + constexpr int BIOME_SCALE = 99; + return make_2d_biome_array(seed, coords, BIOME_SCALE); +} + +constexpr int SAND_HEIGHT = 65; +constexpr int WATER_HEIGHT = 63; + +constexpr int SAND_DEPTH = 5; +constexpr int SANDSTONE_DEPTH = 6; +constexpr int GRASS_DEPTH = 1; +constexpr int DIRT_DEPTH = 7; + +// Rulesets common to all chunks go here. Water inhabits all blocks below 63 +// and above the topography value. In addition, stone fills all blocks after +// the initial biome blocks. +static void generate_post_terrain_column(chunk::block_array& blocks, + const glm::ivec3& pos, + const int lowest) noexcept { + for (int y = lowest; y > WATER_HEIGHT; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::sand; + } + for (int y = WATER_HEIGHT; y > pos.y; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::water; + } + for (int y = lowest; y >= 0; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::stone; + } +} + +static int generate_sandy_terrain_column(chunk::block_array& blocks, + const glm::ivec3& pos) noexcept { + int y = pos.y; + for (const int lowest = y - SAND_DEPTH; y > lowest; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::sand; + } + for (const int lowest = y - SANDSTONE_DEPTH; y > lowest; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::sandstone; + } + return y; +} + +static int generate_grassy_terrain_column(chunk::block_array& blocks, + const glm::ivec3& pos, + const enum block::type top) noexcept { + int y = pos.y; + if (y <= SAND_HEIGHT) { + for (const int lowest = y - SAND_DEPTH; y > lowest; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::sand; + } + } else { + for (const int lowest = y - GRASS_DEPTH; y > lowest; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = top; + } + for (const int lowest = y - DIRT_DEPTH; y > lowest; --y) { + blocks[chunk::get_3d_index({pos.x, y, pos.z})] = block::type::dirt; + } + } + return y; +} + +static void generate_terrain_column(chunk::block_array& blocks, + const glm::ivec3& pos, + const enum chunk::biome biome) noexcept { + const int lowest = [&]() { + switch (biome) { + case chunk::biome::desert: + return generate_sandy_terrain_column(blocks, pos); + + case chunk::biome::islands: + case chunk::biome::forest: + case chunk::biome::plains: + case chunk::biome::ocean: + return generate_grassy_terrain_column(blocks, pos, + block::type::grass); + + case chunk::biome::tundra: + case chunk::biome::alpine: + return generate_grassy_terrain_column(blocks, pos, + block::type::snow); + } + }(); + + generate_post_terrain_column(blocks, pos, lowest); +} + +static enum chunk::biome get_dominant_biome(const auto& array) noexcept { + const auto max_it = + std::max_element(std::begin(array), std::end(array), + [](const auto& a, const auto& b) { return a < b; }); + return biome_enums[static_cast( + std::distance(std::begin(array), max_it))]; +} + +static void generate_terrain(chunk::block_array& blocks, + const shared::math::coords& coords, + const chunk_array_map& topography_map, + const biome_array_map& biome_map) noexcept { + + const biome_array& biomes = biome_map.find(coords)->second; + const chunk_array& topography = topography_map.find(coords)->second; + + // We fill in our chunk column by column, where the column refers to a + // function which maps to a biome. + for (unsigned long x = 0ul; x < chunk::WIDTH; ++x) { + for (unsigned long z = 0ul; z < chunk::WIDTH; ++z) { + generate_terrain_column(blocks, glm::vec3{x, topography[x][z], z}, + get_dominant_biome(biomes[x][z])); + } + } +} + +// Objects have a max WIDTH, but no max WIDTH. +constexpr int MAX_OBJECT_WIDTH = 5; +constexpr int OBJECT_HALFWIDTH = MAX_OBJECT_WIDTH / 2; +// A layer is an x, z slice of an object. +using object_layer = + std::array, MAX_OBJECT_WIDTH>; +using object = std::vector; +struct biome_object { + const object* const blocks; + const float probability; + const int altitude; // lowest alt we can gen at +}; +using biome_objects = std::vector; + +static object make_tree_object() noexcept { + object tree; + object_layer layer = {}; + + layer[OBJECT_HALFWIDTH][OBJECT_HALFWIDTH] = block::type::wood; + for (int i = 0; i < 3; ++i) { + tree.push_back(layer); + } + + for (unsigned x = 0; x < std::size(layer); ++x) { + for (unsigned z = 0; z < std::size(layer); ++z) { + if (x == OBJECT_HALFWIDTH && z == OBJECT_HALFWIDTH) { + continue; + } + layer[x][z] = block::type::leaves; + } + } + for (int i = 0; i < 2; ++i) { + tree.push_back(layer); + } + for (unsigned x = 0; x < std::size(layer); ++x) { + for (unsigned z = 0; z < std::size(layer); ++z) { + if (!(x == 0 || x == 4 || z == 0 || z == 4)) { + continue; + } + layer[x][z] = block::type::air; + } + } + tree.push_back(layer); + for (unsigned x = 0; x < std::size(layer); ++x) { + for (unsigned z = 0; z < std::size(layer); ++z) { + if (x < 1 || x > 3 || z < 1 || z > 3 || + (std::abs(int(x) - 2) + std::abs(int(z) - 2) == 2)) { + layer[x][z] = block::type::air; + continue; + } + layer[x][z] = block::type::leaves; + } + } + tree.push_back(layer); + return tree; +} + +static object make_alpine_tree() noexcept { + object tree; + object_layer layer = {}; + + layer[OBJECT_HALFWIDTH][OBJECT_HALFWIDTH] = block::type::snowy_wood; + constexpr int HEIGHT = 10; + for (int y = 0; y <= HEIGHT; ++y) { + + constexpr float BASE_RAD = static_cast(MAX_OBJECT_WIDTH) / 2.0f; + + const float radius = + BASE_RAD * std::exp(-1.0f * (static_cast(y) / + static_cast(HEIGHT))); + + for (unsigned x = 0; x < MAX_OBJECT_WIDTH; ++x) { + for (unsigned z = 0; z < MAX_OBJECT_WIDTH; ++z) { + if (x == OBJECT_HALFWIDTH && z == OBJECT_HALFWIDTH) { + if (y == HEIGHT) { + layer[x][z] = block::type::snowy_leaves; + } + + continue; // leave as wood + } + + if ((y + 1) % 2) { + layer[x][z] = block::type::air; + continue; + } + + const float lhs = std::pow((float)x - 2.0f, 2.0f) + + std::pow((float)z - 2.0f, 2.0f); + const float rhs = std::pow(radius, 2.0f); + + layer[x][z] = + lhs < rhs ? block::type::snowy_leaves : block::type::air; + } + } + + tree.push_back(layer); + } + + return tree; +} + +static object make_column_object(const enum block::type type, + const int WIDTH) noexcept { + object obj; + object_layer layer = {}; + + layer[OBJECT_HALFWIDTH][OBJECT_HALFWIDTH] = type; + for (int i = 0; i < WIDTH; ++i) { + obj.push_back(layer); + } + return obj; +} + +static const biome_objects& +get_biome_objects(const chunk::biome biome) noexcept { + using btype = enum block::type; + static const object tree = make_tree_object(); + static const object alpine_tree = make_alpine_tree(); + static const object cactus1 = make_column_object(btype::cactus, 1); + static const object cactus2 = make_column_object(btype::cactus, 2); + static const object cactus3 = make_column_object(btype::cactus, 3); + static const object grass = make_column_object(btype::shrub, 1); + static const object dead_shrub = make_column_object(btype::dead_shrub, 1); + static const object snowy_grass = make_column_object(btype::snowy_shrub, 1); + + switch (biome) { + case chunk::biome::islands: + static const biome_objects island_objects{ + biome_object{&tree, 0.0005f, SAND_HEIGHT}, + biome_object{&grass, 0.025f, SAND_HEIGHT}}; + return island_objects; + + case chunk::biome::plains: + static const biome_objects plains_objects{ + biome_object{&tree, 0.0005f, SAND_HEIGHT}, + biome_object{&grass, 0.1f, SAND_HEIGHT}}; + return plains_objects; + + case chunk::biome::forest: + static const biome_objects forest_objects{ + biome_object{&tree, 0.01f, SAND_HEIGHT}, + biome_object{&grass, 0.1f, SAND_HEIGHT}}; + return forest_objects; + + case chunk::biome::desert: + static const biome_objects desert_objects{ + biome_object{&cactus1, 0.0002f, WATER_HEIGHT}, + biome_object{&cactus2, 0.0005f, WATER_HEIGHT}, + biome_object{&cactus3, 0.0009f, WATER_HEIGHT}, + biome_object{&dead_shrub, 0.0012f, WATER_HEIGHT}}; + return desert_objects; + + case chunk::biome::alpine: + static const biome_objects alpine_objects{ + biome_object{&alpine_tree, 0.0008f, SAND_HEIGHT}, + biome_object{&snowy_grass, 0.0025f, SAND_HEIGHT}}; + return alpine_objects; + + case chunk::biome::tundra: + static const biome_objects tundra_objects{ + biome_object{&alpine_tree, 0.0008f, SAND_HEIGHT}, + biome_object{&snowy_grass, 0.004f, SAND_HEIGHT}}; + return tundra_objects; + + case chunk::biome::ocean: + static const biome_objects ocean_objects{ + biome_object{&tree, 0.001f, SAND_HEIGHT}, + biome_object{&grass, 0.1f, SAND_HEIGHT}}; + return ocean_objects; + } +} + +static std::optional +maybe_get_object(const float probability, const chunk::biome biome) noexcept { + const auto& biome_objects = get_biome_objects(biome); + + const auto find_it = + std::ranges::find_if(biome_objects, [&](const auto& object) { + return object.probability >= probability; + }); + + if (find_it != std::end(biome_objects)) { + return *find_it; + } + return std::nullopt; +} + +static int get_block_priority(const enum block::type& b) noexcept { + switch (b) { + case block::type::air: + return 0; + case block::type::leaves: + case block::type::snowy_leaves: + return 1; + default: + break; + } + return 2; +} + +static void generate_object(const object& object, chunk::block_array& blocks, + const glm::ivec3& pos) noexcept { + for (unsigned y = 0; y < std::size(object); ++y) { + + const auto& layer = object[y]; + for (unsigned x = 0; x < std::size(layer); ++x) { + for (unsigned z = 0; z < std::size(layer); ++z) { + + const block block = layer[x][z]; + if (block == block::type::air) { + continue; + } + + const glm::ivec3 block_pos = + pos + glm::ivec3{x - MAX_OBJECT_WIDTH / 2, y + 1, + z - MAX_OBJECT_WIDTH / 2}; + if (chunk::is_outside_chunk(block_pos)) { + continue; + } + + const auto index = chunk::get_3d_index(block_pos); + + const class block old_block = blocks[index]; + if (get_block_priority(block) < get_block_priority(old_block)) { + continue; + } + + blocks[index] = block; + } + } + } +} + +static void generate_objects(chunk::block_array& blocks, + const shared::math::coords& coords, + const chunk_array_map& topography_map, + const biome_array_map& biome_map, + const chunk_array_map& probability_map) noexcept { + + // This is really expensive as it is x^2 + // We don't want to create any structures that are very wide as a result. + // (at least, structures which generate via this method). + const int MAX_READ = MAX_OBJECT_WIDTH / 2; + for (int x = -MAX_READ; x < MAX_READ + chunk::WIDTH; ++x) { + for (int z = -MAX_READ; z < MAX_READ + chunk::WIDTH; ++z) { + const float probability = + array_map_access(probability_map, coords, x, z); + const chunk::biome biome = + get_dominant_biome(array_map_access(biome_map, coords, x, z)); + + const auto& object = maybe_get_object(probability, biome); + if (!object.has_value()) { + continue; + } + + const glm::ivec3 pos{ + x, array_map_access(topography_map, coords, x, z), z}; + + if (pos.y <= object->altitude) { + continue; + } + + generate_object(*object->blocks, blocks, pos); + } + } +} + +static chunk::block_array +generate_blocks(const std::uint64_t& seed, + const shared::math::coords& coords) noexcept { + + const biome_array_map biome_arrays = + make_array_map(seed, coords, make_biomes); + // Topography relies on block temperature so we bind it as a hidden + // third argument as to avoid unnecessary generation. + const chunk_array_map topography_arrays = + make_array_map(seed, coords, + std::bind(make_topography, std::placeholders::_1, + std::placeholders::_2, biome_arrays)); + + const chunk_array_map probability_map = + make_array_map(seed, coords, make_probabilities); + + chunk::block_array blocks = {}; + + // Must be called in order, generate_objects relies on generate terrain etc. + generate_terrain(blocks, coords, topography_arrays, biome_arrays); + generate_objects(blocks, coords, topography_arrays, biome_arrays, + probability_map); + // generate caves + // generate better terrain generation + return blocks; +} + +// Use perlin noise and extrapolation of eigen vectors along a mobius strip. +chunk::chunk(const std::uint64_t& seed, const shared::math::coords& coords, + std::optional blocks) noexcept + : pos(coords) { + if (blocks.has_value()) { + this->blocks = std::move(blocks.value()); + return; + } + + this->blocks = generate_blocks(seed, coords); +} + +} // namespace world +} // namespace shared diff --git a/src/shared/world.hh b/src/shared/world.hh new file mode 100644 index 0000000..3969992 --- /dev/null +++ b/src/shared/world.hh @@ -0,0 +1,224 @@ +#ifndef SHARED_WORLD_HH_ +#define SHARED_WORLD_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "shared/math.hh" +#include "shared/net/proto.hh" +#include "shared/shared.hh" + +namespace shared { +namespace world { + +class block { +public: + enum class type : std::uint8_t { + air, // zero means air which means don't render + dirt, // atlas should start from here + grass, + sand, + sandstone, + stone, + cobblestone, + wood, + leaves, + water, + shrub, + snow, + cactus, + dead_shrub, + snowy_wood, + snowy_leaves, + snowy_shrub, + }; + enum class visibility { solid, partial, translucent, invisible }; + +public: + type type; + +public: + static constexpr enum block::visibility + get_visibility(const enum block::type type) noexcept { + switch (type) { + case type::air: + return visibility::invisible; + case type::shrub: + case type::dead_shrub: + case type::leaves: + case type::snowy_leaves: + case type::snowy_shrub: + return visibility::partial; + case type::water: + return visibility::translucent; + default: + break; + } + return visibility::solid; + } + static constexpr bool is_tangible(const enum block::type type) noexcept { + switch (type) { + case type::air: + case type::shrub: + case type::dead_shrub: + case type::snowy_shrub: + return false; + default: + break; + } + return true; + } + static constexpr bool is_collidable(const enum block::type type) noexcept { + switch (type) { + case type::air: + case type::shrub: + case type::dead_shrub: + case type::snowy_shrub: + case type::water: + return false; + default: + break; + } + return true; + } + static constexpr bool is_liquid(const enum block::type type) noexcept { + switch (type) { + case type::water: + return true; + default: + break; + } + return false; + } + static constexpr bool is_replaceable(const enum block::type type) noexcept { + switch (type) { + case type::water: + case type::air: + return true; + default: + break; + } + return false; + } + static constexpr bool is_removable(const enum block::type type) noexcept { + switch (type) { + case type::water: + case type::air: + return false; + default: + break; + } + return true; + } + static constexpr float get_friction(const enum block::type type) noexcept { + switch (type) { + case type::water: + return 20.0f; + case type::air: + case type::shrub: + case type::dead_shrub: + case type::snowy_shrub: + return 0.1f; + default: + break; + } + return 10.0f; + } + +public: + block(const enum block::type t = type::air) noexcept : type(t) {} + + operator enum block::type() const noexcept { return this->type; } +}; + +class chunk { +public: + static constexpr int WIDTH = 16; + static constexpr int HEIGHT = 256; + static constexpr int VOLUME = WIDTH * WIDTH * HEIGHT; + + // Stuff for unordered_map. + static std::size_t hash(const shared::math::coords& c) noexcept { + std::size_t seed = 0; + boost::hash_combine(seed, boost::hash_value(c.x)); + boost::hash_combine(seed, boost::hash_value(c.z)); + return seed; + } + static std::size_t equal(const shared::math::coords& a, + const shared::math::coords& b) noexcept { + return a == b; + } + using map = std::unordered_map; + +protected: + shared::math::coords pos; + std::array blocks; // Use get_block for 3d index access. + +public: + using block_array = decltype(chunk::blocks); + enum class biome { desert, islands, ocean, plains, forest, tundra, alpine }; + + static bool is_outside_chunk(const glm::ivec3& v) noexcept { + return (std::min(v.x, v.z) < 0) || (std::max(v.x, v.z) >= WIDTH) || + (std::clamp(v.y, 0, HEIGHT - 1) != v.y); + } + static shared::math::coords + get_normalised_chunk(const shared::math::coords& coords, const int x, + const int z) noexcept { + return coords + shared::math::coords{(x >= WIDTH) - (x < 0), + (z >= WIDTH) - (z < 0)}; + } + static std::pair + get_normalised_coords(const int x, const int z) noexcept { + return {x + WIDTH * ((x < 0) - (x >= WIDTH)), + z + WIDTH * ((z < 0) - (z >= WIDTH))}; + } + static glm::ivec3 get_normalised_coords(const glm::ivec3& c) noexcept { + const auto [x, z] = get_normalised_coords(c.x, c.z); + return {x, c.y, z}; + } + static block_array + make_blocks_from_chunk(const proto::chunk& chunk) noexcept; + +public: + static unsigned long get_3d_index(const glm::ivec3& v) noexcept { +#ifndef NDEBUG + if (is_outside_chunk(v)) { + throw std::range_error("bad chunk block coordinate access"); + } +#endif + return static_cast(v.x + + (WIDTH * (v.y + (HEIGHT * v.z)))); + } + +public: + // If a third non-std::nullopt argument is provided, we use those blocks + // instead of what we might have otherwise generated. + chunk(const std::uint64_t& seed, const shared::math::coords& coords, + const std::optional blocks = std::nullopt) noexcept; + + shared::math::coords get_pos() const noexcept { return this->pos; } + block get_block(const glm::ivec3& v) const noexcept { + return this->blocks[get_3d_index(v)]; + } + block& get_block(const glm::ivec3& v) noexcept { + return this->blocks[get_3d_index(v)]; + } +}; + +} // namespace world +} // namespace shared + +#endif -- cgit v1.2.3