aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/client.cc515
-rw-r--r--src/client/client.hh28
-rw-r--r--src/client/draw.cc432
-rw-r--r--src/client/draw.hh59
-rw-r--r--src/client/input.cc111
-rw-r--r--src/client/input.hh48
-rw-r--r--src/client/math.cc26
-rw-r--r--src/client/math.hh22
-rw-r--r--src/client/movement.cc165
-rw-r--r--src/client/movement.hh23
-rw-r--r--src/client/player.cc58
-rw-r--r--src/client/player.hh64
-rw-r--r--src/client/render/camera.cc96
-rw-r--r--src/client/render/camera.hh38
-rw-r--r--src/client/render/lib/stb_image/stb_image.cc2
-rw-r--r--src/client/render/lib/stb_image/stb_image.hh7774
-rw-r--r--src/client/render/model.cc1
-rw-r--r--src/client/render/model.hh247
-rw-r--r--src/client/render/program.cc55
-rw-r--r--src/client/render/program.hh29
-rw-r--r--src/client/render/render.cc602
-rw-r--r--src/client/render/render.hh62
-rw-r--r--src/client/render/texture.cc1
-rw-r--r--src/client/render/texture.hh37
-rw-r--r--src/client/settings.cc139
-rw-r--r--src/client/settings.hh52
-rw-r--r--src/client/shared.cc1
-rw-r--r--src/client/shared.hh29
-rw-r--r--src/client/window.cc449
-rw-r--r--src/client/window.hh30
-rw-r--r--src/client/world.cc429
-rw-r--r--src/client/world.hh90
-rw-r--r--src/main.cc193
-rw-r--r--src/main.hh25
-rw-r--r--src/server/chunk_data.cc1
-rw-r--r--src/server/chunk_data.hh30
-rw-r--r--src/server/client.cc1
-rw-r--r--src/server/client.hh67
-rw-r--r--src/server/database.cc238
-rw-r--r--src/server/database.hh39
-rw-r--r--src/server/movement.cc87
-rw-r--r--src/server/movement.hh19
-rw-r--r--src/server/resources.cc59
-rw-r--r--src/server/resources.hh119
-rw-r--r--src/server/server.cc640
-rw-r--r--src/server/server.hh37
-rw-r--r--src/server/shared.cc1
-rw-r--r--src/server/shared.hh19
-rw-r--r--src/server/world.cc53
-rw-r--r--src/server/world.hh59
-rw-r--r--src/shared/math.cc23
-rw-r--r--src/shared/math.hh53
-rw-r--r--src/shared/movement.cc490
-rw-r--r--src/shared/movement.hh67
-rw-r--r--src/shared/net/connection.cc1
-rw-r--r--src/shared/net/connection.hh212
-rw-r--r--src/shared/net/lib/protobuf/net.pb.cc5548
-rw-r--r--src/shared/net/lib/protobuf/net.pb.h6386
-rw-r--r--src/shared/net/lib/protobuf/net.proto123
-rw-r--r--src/shared/net/net.cc138
-rw-r--r--src/shared/net/net.hh56
-rw-r--r--src/shared/net/proto.cc55
-rw-r--r--src/shared/net/proto.hh28
-rw-r--r--src/shared/player.cc1
-rw-r--r--src/shared/player.hh46
-rw-r--r--src/shared/shared.cc57
-rw-r--r--src/shared/shared.hh120
-rw-r--r--src/shared/world.cc932
-rw-r--r--src/shared/world.hh224
69 files changed, 27961 insertions, 0 deletions
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<std::uint32_t>(::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::uint32_t>(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<float>({"gameplay", "mouse_sensitivity"}, 0.0235f);
+
+ auto& lp = get_localplayer(::players);
+ auto& angles = lp.viewangles;
+
+ const float pitch_offset = static_cast<float>(event.motion.yrel) * sens;
+ const float yaw_offset = static_cast<float>(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<std::string>(
+ {"auth", "username"},
+ rand_alphanum_string(shared::MAX_USER_PASS_LENGTH));
+ const std::string password = settings::get<std::string>(
+ {"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 <algorithm>
+#include <cmath>
+#include <string_view>
+#include <unordered_map>
+
+#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<unsigned>(
+ 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<double>(lp.local_pos.x);
+ const auto y = static_cast<double>(lp.local_pos.y);
+ const auto z = static_cast<double>(lp.local_pos.z);
+ constexpr auto WIDTH = shared::world::chunk::WIDTH;
+ const auto abs_x = static_cast<double>(lp.chunk_pos.x) * WIDTH + x;
+ const auto abs_z = static_cast<double>(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<float, float> {
+ const float offset_x =
+ static_cast<float>(interact->first.x - localplayer.chunk_pos.x);
+ const float offset_z =
+ static_cast<float>(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<float>(interact->second.x),
+ interact->second.y,
+ world_z + static_cast<float>(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<float>(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<glm::vec2, 4> 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<unsigned, 6> 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 <string_view>
+
+#include <glm/glm.hpp>
+
+#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<client::input::event_callback> event_callbacks;
+
+struct keystate {
+ bool pressed;
+ bool toggled; // !'ed each keypress.
+};
+std::unordered_map<SDL_Keycode, keystate> 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 <functional>
+#include <optional>
+#include <string>
+#include <variant>
+
+#include <SDL2/SDL.h>
+#include <glm/glm.hpp>
+
+#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(const SDL_Event&)>;
+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<glm::vec2> 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 <optional>
+
+#include <glm/glm.hpp>
+
+#include "client/render/camera.hh"
+
+namespace client {
+namespace math {
+
+std::optional<glm::vec2> 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<shared::world::block>
+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<std::vector<shared::movement::blockinfo>>
+make_blockinfos(const shared::player& player,
+ const client::world::chunk::map& chunks, const int width,
+ const int height) noexcept {
+
+ std::vector<shared::movement::blockinfo> 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<std::pair<shared::math::coords, glm::ivec3>>
+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<std::pair<shared::movement::moving_aabb_ret,
+ shared::movement::blockinfo>>
+ 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<std::pair<shared::math::coords, glm::ivec3>>
+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<float>(this->chunk_pos.x - lp.chunk_pos.x) * shared::world::chunk::WIDTH + this->local_pos.x;
+ const float world_y = static_cast<float>(this->local_pos.y) + shared::player::HEIGHT / 2.0f;
+ const float world_z = static_cast<float>(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 <chrono>
+#include <optional>
+#include <string>
+#include <utility>
+
+#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<std::chrono::steady_clock> receive_time;
+ message(const std::string& message) noexcept {
+ this->text = message;
+ this->receive_time = std::chrono::steady_clock::now();
+ }
+ };
+ std::optional<message> message;
+
+private:
+ glm::vec3 get_world_pos(const shared::player& lp) noexcept;
+
+public:
+ player(shared::player&& p) noexcept
+ : shared::player(std::forward<shared::player>(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<struct message>& get_message() const noexcept {
+ return this->message;
+ }
+};
+
+using players = std::vector<player>;
+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 <array>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_access.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+#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<glm::vec4, 6>;
+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 <stdio.h>
+#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 <stdlib.h>
+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 <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h> // ldexp, pow
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#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 <stdint.h>
+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 <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400 // not VC6
+#include <intrin.h> // __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 <arm_neon.h>
+// 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<<n) + 1
+static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+ unsigned int k;
+ int sgn;
+ if (j->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; y<height; ++y) {
+ int packet_idx;
+
+ for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+ stbi__pic_packet *packet = &packets[packet_idx];
+ stbi_uc *dest = result+y*width*4;
+
+ switch (packet->type) {
+ default:
+ return stbi__errpuc("bad format","packet has bad compression type");
+
+ case 0: {//uncompressed
+ int x;
+
+ for(x=0;x<width;++x, dest+=4)
+ if (!stbi__readval(s,packet->channel,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; i<count; ++i,dest+=4)
+ stbi__copyval(packet->channel,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;i<count;++i, dest += 4)
+ stbi__copyval(packet->channel,dest,value);
+ } else { // Raw
+ ++count;
+ if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+ for(i=0;i<count;++i, dest+=4)
+ if (!stbi__readval(s,packet->channel,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 <string>
+#include <vector>
+
+#include <epoxy/glx.h>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+#include <assimp/Importer.hpp>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+
+#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<vertex> vertices;
+ std::vector<unsigned> indices;
+ std::vector<texture_info> 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<void*>(sizeof(glm::vec3)));
+ // texture
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(
+ 2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex),
+ reinterpret_cast<void*>(sizeof(glm::vec3) + sizeof(glm::vec3)));
+ }
+
+ public:
+ mesh(const std::vector<vertex>& v, const std::vector<unsigned>& i,
+ const std::vector<texture_info>& 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<mesh> 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<texture_info>
+ load_material_textures(const aiMaterial* const material,
+ const aiTextureType type,
+ const std::string& name) noexcept {
+ std::vector<texture_info> 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<vertex> vertices;
+ std::vector<unsigned> indices;
+ std::vector<texture_info> 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 <stdexcept>
+#include <string_view>
+
+#include <epoxy/glx.h>
+
+#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<glm::vec3, 8> 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<unsigned, 24> 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<glm::vec2, 4> 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<unsigned, 6> 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<char, character_info> 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<int>(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<unsigned>(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<unsigned>(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<unsigned long>(c),
+ flags | FT_LOAD_RENDER)) {
+ return this->operator[]('?'); // placeholder
+ }
+
+ const int width = static_cast<int>(face->glyph->bitmap.width);
+ const int height = static_cast<int>(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<float>(face->glyph->advance.x >> 6),
+ .advance_y = static_cast<float>(face->glyph->advance.y >> 6),
+ .bitmap_width = static_cast<float>(face->glyph->bitmap.width),
+ .bitmap_height = static_cast<float>(face->glyph->bitmap.rows),
+ .bitmap_left = static_cast<float>(face->glyph->bitmap_left),
+ .bitmap_top = static_cast<float>(face->glyph->bitmap_top),
+ .x_offset = static_cast<float>(this->texture.last_offset.x),
+ .y_offset = static_cast<float>(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<void*>(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<unsigned, font_atlas> 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<unsigned, unsigned>(size, size));
+ return emplace.first->second;
+ }();
+
+ const std::vector<vertex> vertices = [&]() {
+ std::vector<vertex> vertices;
+
+ const float atlas_width = static_cast<float>(atlas.get_width());
+ const float atlas_height = static_cast<float>(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<float>(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<glm::vec4, 6> 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<unsigned>(
+ (now - start) / std::chrono::milliseconds(1));
+ }(),
+ .xwindow = static_cast<float>(get_window_size().x),
+ .ywindow = static_cast<float>(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 <algorithm>
+#include <array>
+#include <chrono>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <optional>
+#include <ranges>
+#include <unordered_map>
+
+#include <epoxy/gl.h> // this has to go before SDL2
+#include <epoxy/glx.h>
+
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_opengl.h>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_access.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+#include <ft2build.h>
+#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 <stdexcept>
+#include <string>
+
+#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<char>(in),
+ std::istreambuf_iterator<char>()};
+ 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<std::string, std::string>;
+using setting_map = std::unordered_map<std::string, value_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<long>(split_pos)};
+ const std::string value{std::begin(line) +
+ static_cast<long>(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<const std::string&, const std::string&> 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<const std::string&, const std::string&> 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<std::string> 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<std::string> 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 <filesystem>
+#include <fstream>
+#include <optional>
+#include <stdlib.h>
+#include <string>
+
+#include <boost/lexical_cast.hpp>
+
+#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<const std::string&, const std::string&> loc,
+ const std::string& value) noexcept;
+
+std::string
+get_setting_str(const std::pair<const std::string&, const std::string&> 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 <typename T>
+T get(const std::pair<const std::string, const std::string>& loc,
+ const T& default_value) noexcept {
+ const std::string value =
+ get_setting_str(loc, boost::lexical_cast<std::string>(default_value));
+ return boost::lexical_cast<T>(value);
+}
+
+// Attempts to set the setting in the file, overwriting the pre-existing
+// value or writing a new entry.
+template <typename T>
+void set(const std::pair<const std::string, const std::string>& loc,
+ const T& value) noexcept {
+ set_setting_str(loc, boost::lexical_cast<std::string>(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 <cstdint>
+#include <string_view>
+
+#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<long>(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 <typename... Args>
+ text_input_window(Args&&... args) noexcept
+ : basic_window(std::forward<Args>(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<void()> 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 <typename... Args>
+ button_window(const std::string_view n, const decltype(callback)& c,
+ Args&&... args) noexcept
+ : basic_window(std::forward<Args>(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 <typename T>
+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 <typename... Args>
+ 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>(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<std::unique_ptr<basic_window>>;
+using layers = std::forward_list<layer>;
+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 <typename T, typename... Args>
+void push_window(Args&&... args) noexcept {
+ get_layers().front().push_front(
+ std::make_unique<T>(std::forward<Args>(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<float>>(
+ "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<button_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<button_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<button_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<button_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<button_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<button_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<text_input_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<int>(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 <algorithm>
+#include <forward_list>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+
+#include <SDL2/SDL.h>
+#include <glm/glm.hpp>
+
+#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<GLuint, GLuint> {
+ 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::glface, 6>
+chunk::make_glfaces(const glface_args& args) noexcept {
+
+ static constexpr std::array<glface, 6> 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<glface, 6> 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<int, int> {
+ 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<glface> solid_data;
+ std::vector<glface> 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<glface> 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<float>(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<void*>(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<glm::vec3, 8>& 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<glm::vec3, 8> box_vertices =
+ [&world_x, &world_z]() -> std::array<glm::vec3, 8> {
+ 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<float, float> {
+ const float offset_x = static_cast<float>(this->pos.x - lp.chunk_pos.x);
+ const float offset_z = static_cast<float>(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 <algorithm>
+#include <optional>
+#include <ranges>
+#include <unordered_map>
+#include <vector>
+
+#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<shared::math::coords,
+ std::optional<client::world::chunk>,
+ 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<gl_objects> 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<glface, 6> 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 <typename... Args>
+ chunk(Args&&... args) noexcept
+ : shared::world::chunk(std::forward<Args>(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 <typename T>
+static bool maybe_parse_arg(std::vector<std::string_view>& args,
+ const std::initializer_list<std::string_view>& 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<unsigned int>(find_it - std::begin(args));
+ dest = boost::lexical_cast<T>(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<std::string_view>& args,
+ const std::initializer_list<std::string_view>& 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<void*, BACKTRACE_BUF_SIZE> 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<std::string_view> 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 <string> : connect elsewhere\n"
+ " --port -p <int> : override the default port\n"
+ " --headless -H : run without a client\n"
+ " --singleplayer -s : avoid hosting a lan server\n"
+ " --seed -S <int> : manually set the worldseed\n"
+ " --directory -d <string> : manually set the directory\n"
+ " --tickrate -t <int> : override the default tickrate\n"
+ " --distance -D <int> : 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 <algorithm>
+#include <exception>
+#include <execinfo.h>
+#include <iostream>
+#include <iterator>
+#include <signal.h>
+#include <string_view>
+#include <thread>
+#include <vector>
+
+#include <boost/lexical_cast.hpp>
+
+#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 <memory>
+#include <optional>
+#include <unordered_set>
+
+#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<std::shared_ptr<server::world::chunk>> chunk;
+ // players associated with the chunk
+ std::unordered_set<shared::player::index_t> 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 <deque>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#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<std::string> 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<std::shared_ptr<player_info>> 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<shared::math::coords,
+ decltype(&shared::world::chunk::hash),
+ decltype(&shared::world::chunk::equal)>
+ 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<int>(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<std::int64_t>(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<int>(std::size(text)), SQLITE_STATIC);
+ status != SQLITE_OK) {
+ throw std::runtime_error(std::string{"sqlite bind text error \""} +
+ sqlite3_errstr(status) + '\"');
+ }
+}
+
+template <typename T>
+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<int>(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<std::uint64_t>(
+ htonl(std::bit_cast<std::uint32_t>(val)))
+ << lshift;
+ };
+
+ return to_64(coords.x, 32) + to_64(coords.z, 0);
+}
+
+std::optional<proto::chunk>
+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<const char*>(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<std::pair<proto::player, std::string>>
+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<const char*>(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 <bit>
+#include <filesystem>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include <sqlite3.h>
+
+#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<proto::chunk>
+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<std::pair<proto::player, std::string>> // 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<shared::world::block>
+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<std::vector<shared::movement::blockinfo>>
+make_blockinfos(server::client& client,
+ server::resources::chunk_map& chunks) noexcept {
+
+ std::vector<shared::movement::blockinfo> 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<float>(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<resources> get_resources_lock() noexcept {
+ return low_priority_lock<resources>{get_resources()};
+}
+high_priority_lock<resources> get_resources_lock_immediate() noexcept {
+ return high_priority_lock<resources>{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 <memory>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+
+#include <boost/asio.hpp>
+#include <boost/thread/thread_pool.hpp>
+
+#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 <typename T>
+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 <typename T>
+class low_priority_lock : public lock_base<T> {
+public:
+ low_priority_lock(T& t) noexcept : lock_base<T>(t) {
+ lock_base<T>::low_priority_mutex.lock();
+ lock_base<T>::next_mutex.lock();
+ lock_base<T>::data_mutex.lock();
+ lock_base<T>::next_mutex.unlock();
+ }
+ virtual ~low_priority_lock() noexcept {
+ lock_base<T>::data_mutex.unlock();
+ lock_base<T>::low_priority_mutex.unlock();
+ }
+};
+
+template <typename T>
+class high_priority_lock : public lock_base<T> {
+public:
+ high_priority_lock(T& t) noexcept : lock_base<T>(t) {
+ lock_base<T>::next_mutex.lock();
+ lock_base<T>::data_mutex.lock();
+ lock_base<T>::next_mutex.unlock();
+ }
+ virtual ~high_priority_lock() noexcept {
+ lock_base<T>::data_mutex.unlock();
+ }
+};
+
+using chunk_map_key = shared::math::coords;
+using chunk_map_value = std::unique_ptr<chunk_data>;
+using chunk_map = std::unordered_map<chunk_map_key, chunk_map_value,
+ decltype(&shared::world::chunk::hash),
+ decltype(&shared::world::chunk::equal)>;
+
+using client_map_key = shared::player::index_t;
+using client_map_value = std::unique_ptr<server::client>;
+using client_map = std::unordered_map<client_map_key, client_map_value>;
+
+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<resources> get_resources_lock() noexcept;
+high_priority_lock<resources> 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<int>((1.0 / static_cast<double>(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<shared::net::connection> 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<server::world::chunk> 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_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<server::world::chunk>(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<enum shared::world::block::type>(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<struct client::player_info>(
+ 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<server::client>(
+ 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<std::string>
+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 <algorithm>
+#include <atomic>
+#include <chrono>
+#include <csignal>
+#include <deque>
+#include <iostream>
+#include <memory>
+#include <queue>
+#include <ranges>
+#include <string>
+#include <string_view>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#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<bool> 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 <cstdint>
+#include <string>
+
+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<std::uint8_t>(this->blocks[i * 4 + j].type);
+ packed_blocks |= static_cast<unsigned>(block << j * 8);
+ }
+
+ chunk_packet->add_blocks(packed_blocks);
+ }
+
+ return ret_packet;
+}
+
+static std::optional<shared::world::chunk::block_array>
+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 <cstdint>
+
+#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 <compare>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+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<ray_aabb_ret> intersect_ray_aabb(const line& line,
+ const aabb& aabb) noexcept {
+ float tmin = -std::numeric_limits<float>::max();
+ float tmax = std::numeric_limits<float>::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<moving_aabb_ret>
+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<shared::world::block>
+get_ground(const aabb& player_aabb, const std::vector<blockinfo> 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<shared::world::block>
+get_collidable_ground(const aabb& player_aabb,
+ const std::vector<blockinfo> 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<blockinfo>& blockinfos,
+ const float deltatime,
+ const int n = 3) noexcept {
+
+ const moving_aabb player_moving_aabb{
+ .aabb = player_aabb, .velocity = player.velocity * deltatime};
+
+ std::optional<std::pair<moving_aabb_ret, shared::world::block>> 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<float>
+get_intersect_friction(const aabb& aabb,
+ const std::vector<blockinfo>& blockinfos) noexcept {
+ std::optional<float> 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<blockinfo>& blockinfos,
+ const std::optional<shared::world::block>& 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<blockinfo>& 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<shared::world::block>& 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<shared::world::block> ground;
+ std::optional<shared::world::block> 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<blockinfo>& 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<blockinfo>& 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<blockinfo>& 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 <algorithm>
+#include <array>
+
+#include <glm/glm.hpp>
+#include <glm/gtx/norm.hpp>
+
+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<ray_aabb_ret> 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<moving_aabb_ret>
+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<int>(1.0f + 2 * shared::player::HALFWIDTH + 1.0f);
+constexpr int move_height = static_cast<int>(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<blockinfo>& 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 <algorithm>
+#include <optional>
+#include <string>
+
+#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<sockets> socks;
+ std::optional<std::string> 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::uint32_t>(
+ std::size(data) + sizeof(packet_header)))};
+
+ return std::string{reinterpret_cast<char*>(&header),
+ reinterpret_cast<char*>(&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<proto::packet> 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<char*>(std::data(data)) + sizeof(packet_header),
+ reinterpret_cast<char*>(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<proto::packet> 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<char*>(std::data(data)) + sizeof(packet_header),
+ reinterpret_cast<char*>(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<proto::packet> 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 <algorithm>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+
+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<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_angles_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_coords_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_vec3_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_ivec3_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_player_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_auth_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_init_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_move_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_remove_player_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_say_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_hear_player_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_request_chunk_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_remove_chunk_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_chunk_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_add_block_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_remove_block_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::proto::_server_message_default_instance_),
+ reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Message*>(&::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<size_t>(reinterpret_cast<char*>(&yaw_) -
+ reinterpret_cast<char*>(&pitch_)) + sizeof(yaw_));
+ // @@protoc_insertion_point(copy_constructor:proto.angles)
+}
+
+inline void angles::SharedCtor() {
+::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&pitch_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&yaw_) -
+ reinterpret_cast<char*>(&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<size_t>(
+ reinterpret_cast<char*>(&yaw_) -
+ reinterpret_cast<char*>(&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<uint8_t>(tag) == 13)) {
+ pitch_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(ptr);
+ ptr += sizeof(float);
+ } else
+ goto handle_unusual;
+ continue;
+ // float yaw = 2;
+ case 2:
+ if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 21)) {
+ yaw_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(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<angles *>(to)->MergeFrom(
+ static_cast<const angles &>(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<char*>(&pitch_),
+ reinterpret_cast<char*>(&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<size_t>(reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&x_)) + sizeof(z_));
+ // @@protoc_insertion_point(copy_constructor:proto.coords)
+}
+
+inline void coords::SharedCtor() {
+::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&x_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&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<size_t>(
+ reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<coords *>(to)->MergeFrom(
+ static_cast<const coords &>(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<char*>(&x_),
+ reinterpret_cast<char*>(&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<size_t>(reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&x_)) + sizeof(z_));
+ // @@protoc_insertion_point(copy_constructor:proto.vec3)
+}
+
+inline void vec3::SharedCtor() {
+::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&x_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&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<size_t>(
+ reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&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<uint8_t>(tag) == 13)) {
+ x_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(ptr);
+ ptr += sizeof(float);
+ } else
+ goto handle_unusual;
+ continue;
+ // float y = 2;
+ case 2:
+ if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 21)) {
+ y_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(ptr);
+ ptr += sizeof(float);
+ } else
+ goto handle_unusual;
+ continue;
+ // float z = 3;
+ case 3:
+ if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 29)) {
+ z_ = ::PROTOBUF_NAMESPACE_ID::internal::UnalignedLoad<float>(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<vec3 *>(to)->MergeFrom(
+ static_cast<const vec3 &>(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<char*>(&x_),
+ reinterpret_cast<char*>(&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<size_t>(reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&x_)) + sizeof(z_));
+ // @@protoc_insertion_point(copy_constructor:proto.ivec3)
+}
+
+inline void ivec3::SharedCtor() {
+::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&x_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&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<size_t>(
+ reinterpret_cast<char*>(&z_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<uint8_t>(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<ivec3 *>(to)->MergeFrom(
+ static_cast<const ivec3 &>(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<char*>(&x_),
+ reinterpret_cast<char*>(&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<size_t>(reinterpret_cast<char*>(&commands_) -
+ reinterpret_cast<char*>(&index_)) + sizeof(commands_));
+ // @@protoc_insertion_point(copy_constructor:proto.player)
+}
+
+inline void player::SharedCtor() {
+::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&chunk_pos_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&commands_) -
+ reinterpret_cast<char*>(&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<size_t>(
+ reinterpret_cast<char*>(&commands_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<player *>(to)->MergeFrom(
+ static_cast<const player &>(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<char*>(&chunk_pos_),
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<int>(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<int>(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<auth *>(to)->MergeFrom(
+ static_cast<const auth &>(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<size_t>(reinterpret_cast<char*>(&draw_distance_) -
+ reinterpret_cast<char*>(&seed_)) + sizeof(draw_distance_));
+ // @@protoc_insertion_point(copy_constructor:proto.init)
+}
+
+inline void init::SharedCtor() {
+::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&localplayer_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&draw_distance_) -
+ reinterpret_cast<char*>(&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<size_t>(
+ reinterpret_cast<char*>(&draw_distance_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<uint8_t>(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<init *>(to)->MergeFrom(
+ static_cast<const init &>(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<char*>(&localplayer_),
+ reinterpret_cast<char*>(&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<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&viewangles_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&commands_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<move *>(to)->MergeFrom(
+ static_cast<const move &>(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<char*>(&viewangles_),
+ reinterpret_cast<char*>(&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<uint8_t>(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<remove_player *>(to)->MergeFrom(
+ static_cast<const remove_player &>(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<uint8_t>(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<int>(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<say *>(to)->MergeFrom(
+ static_cast<const say &>(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<uint8_t>(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<uint8_t>(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<int>(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<hear_player *>(to)->MergeFrom(
+ static_cast<const hear_player &>(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<uint8_t>(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<request_chunk *>(to)->MergeFrom(
+ static_cast<const request_chunk &>(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<uint8_t>(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<remove_chunk *>(to)->MergeFrom(
+ static_cast<const remove_chunk &>(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<uint8_t>(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<uint8_t>(tag) == 18)) {
+ ptr = ::PROTOBUF_NAMESPACE_ID::internal::PackedUInt32Parser(_internal_mutable_blocks(), ptr, ctx);
+ CHK_(ptr);
+ } else if (static_cast<uint8_t>(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<int32_t>(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<chunk *>(to)->MergeFrom(
+ static_cast<const chunk &>(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<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&chunk_pos_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&block_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<uint8_t>(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<add_block *>(to)->MergeFrom(
+ static_cast<const add_block &>(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<char*>(&chunk_pos_),
+ reinterpret_cast<char*>(&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<char*>(this) + static_cast<size_t>(
+ reinterpret_cast<char*>(&chunk_pos_) - reinterpret_cast<char*>(this)),
+ 0, static_cast<size_t>(reinterpret_cast<char*>(&block_pos_) -
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<remove_block *>(to)->MergeFrom(
+ static_cast<const remove_block &>(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<char*>(&chunk_pos_),
+ reinterpret_cast<char*>(&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<uint8_t>(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<uint8_t>(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<int>(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<server_message *>(to)->MergeFrom(
+ static_cast<const server_message &>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<packet *>(to)->MergeFrom(
+ static_cast<const packet &>(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 <google/protobuf/port_undef.inc>
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 <limits>
+#include <string>
+
+#include <google/protobuf/port_def.inc>
+#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 <google/protobuf/port_undef.inc>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata_lite.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h> // IWYU pragma: export
+#include <google/protobuf/extension_set.h> // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+#include <google/protobuf/port_def.inc>
+#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<const angles*>(
+ &_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<angles>(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 <typename T> 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<const coords*>(
+ &_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<coords>(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 <typename T> 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<const vec3*>(
+ &_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<vec3>(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 <typename T> 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<const ivec3*>(
+ &_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<ivec3>(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 <typename T> 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<const player*>(
+ &_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<player>(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 <typename T> 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<const auth*>(
+ &_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<auth>(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 <typename ArgT0 = const std::string&, typename... ArgT>
+ 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 <typename ArgT0 = const std::string&, typename... ArgT>
+ 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 <typename T> 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<const init*>(
+ &_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<init>(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 <typename T> 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<const move*>(
+ &_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<move>(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 <typename T> 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<const remove_player*>(
+ &_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<remove_player>(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 <typename T> 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<const say*>(
+ &_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<say>(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 <typename ArgT0 = const std::string&, typename... ArgT>
+ 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 <typename T> 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<const hear_player*>(
+ &_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<hear_player>(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 <typename ArgT0 = const std::string&, typename... ArgT>
+ 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 <typename T> 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<const request_chunk*>(
+ &_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<request_chunk>(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 <typename T> 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<const remove_chunk*>(
+ &_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<remove_chunk>(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 <typename T> 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<const chunk*>(
+ &_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<chunk>(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 <typename T> friend class ::PROTOBUF_NAMESPACE_ID::Arena::InternalHelper;
+ typedef void InternalArenaConstructable_;
+ typedef void DestructorSkippable_;
+ ::PROTOBUF_NAMESPACE_ID::RepeatedField< uint32_t > blocks_;
+ mutable std::atomic<int> _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<const add_block*>(
+ &_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<add_block>(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 <typename T> 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<const remove_block*>(
+ &_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<remove_block>(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 <typename T> 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<const server_message*>(
+ &_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<server_message>(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 <typename ArgT0 = const std::string&, typename... ArgT>
+ 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 <typename T> 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<const packet*>(
+ &_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<packet>(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 <typename T> 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<const ::proto::coords&>(
+ ::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<const ::proto::vec3&>(
+ ::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<const ::proto::angles&>(
+ ::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<const ::proto::vec3&>(
+ ::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 <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void auth::set_username(ArgT0&& arg0, ArgT... args) {
+
+ username_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(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 <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void auth::set_password(ArgT0&& arg0, ArgT... args) {
+
+ password_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(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<const ::proto::player&>(
+ ::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<const ::proto::angles&>(
+ ::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 <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void say::set_text(ArgT0&& arg0, ArgT... args) {
+
+ text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(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 <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void hear_player::set_text(ArgT0&& arg0, ArgT... args) {
+
+ text_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(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<const ::proto::coords&>(
+ ::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<const ::proto::coords&>(
+ ::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<const ::proto::coords&>(
+ ::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<const ::proto::coords&>(
+ ::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<const ::proto::ivec3&>(
+ ::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<const ::proto::coords&>(
+ ::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<const ::proto::ivec3&>(
+ ::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 <typename ArgT0, typename... ArgT>
+inline PROTOBUF_ALWAYS_INLINE
+void server_message::set_message(ArgT0&& arg0, ArgT... args) {
+
+ message_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, static_cast<ArgT0 &&>(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 <google/protobuf/port_undef.inc>
+#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<addrinfo> 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<addrinfo>{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<sockaddr_in*>(&info)->sin_addr);
+ }
+ return &(reinterpret_cast<sockaddr_in6*>(&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<accept_ret> get_accept(const int sock) {
+ accept_ret info;
+ socklen_t size = sizeof(info.storage);
+ info.socket =
+ accept(sock, reinterpret_cast<sockaddr*>(&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<sockaddr*>(&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<sockaddr*>(&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<sockaddr*>(&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<sockaddr*>(&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 <arpa/inet.h>
+#include <concepts>
+#include <cstdint>
+#include <cstring>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <optional>
+#include <stdexcept>
+#include <string.h>
+#include <string>
+#include <string_view>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <type_traits>
+#include <unistd.h>
+
+#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<addrinfo> 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<accept_ret> 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 <cstdint>
+
+#include <glm/glm.hpp>
+
+#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<char>(input),
+ std::istreambuf_iterator<char>()};
+}
+
+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<boost::iostreams::input> 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<boost::iostreams::input> 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 <algorithm>
+#include <atomic>
+#include <chrono>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <mutex>
+#include <ranges>
+#include <string>
+
+#include <boost/iostreams/copy.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/iostreams/filtering_streambuf.hpp>
+
+#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<std::mutex> 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<int>(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<bool> 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<enum shared::world::chunk::biome, 7> 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<unsigned>(i * 4 + j)] =
+ static_cast<enum block::type>(
+ static_cast<std::uint8_t>(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<unsigned long>(coords.x);
+ const auto ulz = static_cast<unsigned long>(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<float>(width - 1);
+ const float v1 = v.x - (static_cast<float>(x) / div);
+ const float v2 = v.y - (static_cast<float>(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<std::array<float, chunk::WIDTH>, chunk::WIDTH>;
+using chunk_array_map =
+ std::unordered_map<shared::math::coords, chunk_array,
+ decltype(&chunk::hash), decltype(&chunk::equal)>;
+
+// 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<unsigned>(x_offset);
+
+ for (auto z = 0u; z < chunk::WIDTH; ++z) {
+ const unsigned sz = z + static_cast<unsigned>(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<float>(swidth - 1);
+ const float fracx = (static_cast<float>(sx) + 0.5f) / fswidth;
+ const float fracz = (static_cast<float>(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<std::array<float, std::size(biome_enums)>, chunk::WIDTH>,
+ chunk::WIDTH>;
+using biome_array_map =
+ std::unordered_map<shared::math::coords, biome_array,
+ decltype(&chunk::hash), decltype(&chunk::equal)>;
+// 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<struct point, NUM_POINTS>;
+ 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<float>(MASK);
+ const auto biome = static_cast<chunk::biome>(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<std::array<point_array, 3>, 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<unsigned long>(x + 1);
+ const auto index_z = static_cast<unsigned long>(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<point_info>;
+ const auto get_closest_point_infos =
+ [&](const glm::vec2 pos) -> point_info_vector {
+ std::vector<point_info> 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<unsigned long>(x + 1)]
+ [static_cast<unsigned long>(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<unsigned>(x_offset);
+
+ for (auto z = 0u; z < chunk::WIDTH; ++z) {
+ const unsigned sz = z + static_cast<unsigned>(z_offset);
+
+ const glm::vec2 inner_pos =
+ glm::vec2{static_cast<float>(sx) + 0.5f,
+ static_cast<float>(sz) + 0.5f} /
+ static_cast<float>(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<unsigned long>(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<shared::math::coords,
+ decltype(make_chunk_array_func(seed, coords)),
+ decltype(&chunk::hash), decltype(&chunk::equal)>
+ 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<float>(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<float> uniform{
+ 0.0f, std::nextafter(1.0f, std::numeric_limits<float>::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<unsigned long>(
+ 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<std::array<block, MAX_OBJECT_WIDTH>, MAX_OBJECT_WIDTH>;
+using object = std::vector<object_layer>;
+struct biome_object {
+ const object* const blocks;
+ const float probability;
+ const int altitude; // lowest alt we can gen at
+};
+using biome_objects = std::vector<biome_object>;
+
+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<float>(MAX_OBJECT_WIDTH) / 2.0f;
+
+ const float radius =
+ BASE_RAD * std::exp(-1.0f * (static_cast<float>(y) /
+ static_cast<float>(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<biome_object>
+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<decltype(chunk::blocks)> 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 <algorithm>
+#include <array>
+#include <exception>
+#include <functional>
+#include <istream>
+#include <memory>
+#include <random>
+#include <type_traits>
+#include <vector>
+
+#include <boost/functional/hash.hpp>
+#include <glm/glm.hpp>
+
+#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<shared::math::coords, shared::world::chunk,
+ decltype(&shared::world::chunk::hash),
+ decltype(&shared::world::chunk::equal)>;
+
+protected:
+ shared::math::coords pos;
+ std::array<block, VOLUME> 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<unsigned short, unsigned short>
+ 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<unsigned long>(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<block_array> 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