diff options
| author | untodesu <kirill@untode.su> | 2025-09-11 15:48:53 +0500 |
|---|---|---|
| committer | untodesu <kirill@untode.su> | 2025-09-11 15:48:53 +0500 |
| commit | d0fbd68055e3f4a796330cc8acc6c0954b5327ff (patch) | |
| tree | e581014ea02711efa5e71f00f9862e5bca58f2ed /game/shared | |
| parent | cbd823aa2154a956e7da4319eecbf7afc10441ae (diff) | |
| download | voxelius-d0fbd68055e3f4a796330cc8acc6c0954b5327ff.tar.bz2 voxelius-d0fbd68055e3f4a796330cc8acc6c0954b5327ff.zip | |
Run clang-format across the project
Diffstat (limited to 'game/shared')
47 files changed, 3178 insertions, 3188 deletions
diff --git a/game/shared/const.hh b/game/shared/const.hh index 187962a..6851ff7 100644 --- a/game/shared/const.hh +++ b/game/shared/const.hh @@ -1,43 +1,43 @@ -#pragma once - -#include "core/math/constexpr.hh" - -constexpr static unsigned int CHUNK_SIZE = 16; -constexpr static unsigned int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE; -constexpr static unsigned int CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; -constexpr static unsigned int CHUNK_BITSHIFT = math::log2(CHUNK_SIZE); - -template<typename T> -constexpr static glm::vec<3, T> DIR_NORTH = glm::vec<3, T>(0, 0, +1); -template<typename T> -constexpr static glm::vec<3, T> DIR_SOUTH = glm::vec<3, T>(0, 0, -1); -template<typename T> -constexpr static glm::vec<3, T> DIR_EAST = glm::vec<3, T>(-1, 0, 0); -template<typename T> -constexpr static glm::vec<3, T> DIR_WEST = glm::vec<3, T>(+1, 0, 0); -template<typename T> -constexpr static glm::vec<3, T> DIR_DOWN = glm::vec<3, T>(0, -1, 0); -template<typename T> -constexpr static glm::vec<3, T> DIR_UP = glm::vec<3, T>(0, +1, 0); - -template<typename T> -constexpr static glm::vec<3, T> DIR_FORWARD = glm::vec<3, T>(0, 0, +1); -template<typename T> -constexpr static glm::vec<3, T> DIR_BACK = glm::vec<3, T>(0, 0, -1); -template<typename T> -constexpr static glm::vec<3, T> DIR_LEFT = glm::vec<3, T>(-1, 0, 0); -template<typename T> -constexpr static glm::vec<3, T> DIR_RIGHT = glm::vec<3, T>(+1, 0, 0); - -template<typename T> -constexpr static glm::vec<3, T> UNIT_X = glm::vec<3, T>(1, 0, 0); -template<typename T> -constexpr static glm::vec<3, T> UNIT_Y = glm::vec<3, T>(0, 1, 0); -template<typename T> -constexpr static glm::vec<3, T> UNIT_Z = glm::vec<3, T>(0, 0, 1); - -template<typename T> -constexpr static glm::vec<2, T> ZERO_VEC2 = glm::vec<2, T>(0, 0); - -template<typename T> -constexpr static glm::vec<3, T> ZERO_VEC3 = glm::vec<3, T>(0, 0, 0); +#pragma once
+
+#include "core/math/constexpr.hh"
+
+constexpr static unsigned int CHUNK_SIZE = 16;
+constexpr static unsigned int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
+constexpr static unsigned int CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
+constexpr static unsigned int CHUNK_BITSHIFT = math::log2(CHUNK_SIZE);
+
+template<typename T>
+constexpr static glm::vec<3, T> DIR_NORTH = glm::vec<3, T>(0, 0, +1);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_SOUTH = glm::vec<3, T>(0, 0, -1);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_EAST = glm::vec<3, T>(-1, 0, 0);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_WEST = glm::vec<3, T>(+1, 0, 0);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_DOWN = glm::vec<3, T>(0, -1, 0);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_UP = glm::vec<3, T>(0, +1, 0);
+
+template<typename T>
+constexpr static glm::vec<3, T> DIR_FORWARD = glm::vec<3, T>(0, 0, +1);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_BACK = glm::vec<3, T>(0, 0, -1);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_LEFT = glm::vec<3, T>(-1, 0, 0);
+template<typename T>
+constexpr static glm::vec<3, T> DIR_RIGHT = glm::vec<3, T>(+1, 0, 0);
+
+template<typename T>
+constexpr static glm::vec<3, T> UNIT_X = glm::vec<3, T>(1, 0, 0);
+template<typename T>
+constexpr static glm::vec<3, T> UNIT_Y = glm::vec<3, T>(0, 1, 0);
+template<typename T>
+constexpr static glm::vec<3, T> UNIT_Z = glm::vec<3, T>(0, 0, 1);
+
+template<typename T>
+constexpr static glm::vec<2, T> ZERO_VEC2 = glm::vec<2, T>(0, 0);
+
+template<typename T>
+constexpr static glm::vec<3, T> ZERO_VEC3 = glm::vec<3, T>(0, 0, 0);
diff --git a/game/shared/coord.hh b/game/shared/coord.hh index 9d9be18..9f9afc7 100644 --- a/game/shared/coord.hh +++ b/game/shared/coord.hh @@ -1,145 +1,145 @@ -#pragma once - -#include "shared/const.hh" -#include "shared/types.hh" - -namespace coord -{ -constexpr chunk_pos to_chunk(const voxel_pos& vpos); -} // namespace coord - -namespace coord -{ -constexpr local_pos to_local(const voxel_pos& vpos); -constexpr local_pos to_local(const glm::fvec3& fvec); -constexpr local_pos to_local(std::size_t index); -} // namespace coord - -namespace coord -{ -constexpr voxel_pos to_voxel(const chunk_pos& cpos, const local_pos& lpos); -constexpr voxel_pos to_voxel(const chunk_pos& cpos, const glm::fvec3& fvec); -} // namespace coord - -namespace coord -{ -constexpr std::size_t to_index(const local_pos& lpos); -} // namespace coord - -namespace coord -{ -constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const chunk_pos& cpos, const glm::fvec3& fvec); -constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos); -constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos, const glm::fvec3& fvec); -} // namespace coord - -namespace coord -{ -constexpr glm::fvec3 to_fvec3(const chunk_pos& cpos); -constexpr glm::fvec3 to_fvec3(const chunk_pos& cpos, const glm::fvec3& fpos); -} // namespace coord - -inline constexpr chunk_pos coord::to_chunk(const voxel_pos& vpos) -{ - return chunk_pos { - static_cast<chunk_pos::value_type>(vpos.x >> CHUNK_BITSHIFT), - static_cast<chunk_pos::value_type>(vpos.y >> CHUNK_BITSHIFT), - static_cast<chunk_pos::value_type>(vpos.z >> CHUNK_BITSHIFT), - }; -} - -inline constexpr local_pos coord::to_local(const voxel_pos& vpos) -{ - return local_pos { - static_cast<local_pos::value_type>(math::mod_signed<voxel_pos::value_type>(vpos.x, CHUNK_SIZE)), - static_cast<local_pos::value_type>(math::mod_signed<voxel_pos::value_type>(vpos.y, CHUNK_SIZE)), - static_cast<local_pos::value_type>(math::mod_signed<voxel_pos::value_type>(vpos.z, CHUNK_SIZE)), - }; -} - -inline constexpr local_pos coord::to_local(const glm::fvec3& fvec) -{ - return local_pos { - static_cast<local_pos::value_type>(fvec.x), - static_cast<local_pos::value_type>(fvec.y), - static_cast<local_pos::value_type>(fvec.z), - }; -} - -inline constexpr local_pos coord::to_local(std::size_t index) -{ - return local_pos { - static_cast<local_pos::value_type>((index % CHUNK_SIZE)), - static_cast<local_pos::value_type>((index / CHUNK_SIZE) / CHUNK_SIZE), - static_cast<local_pos::value_type>((index / CHUNK_SIZE) % CHUNK_SIZE), - }; -} - -inline constexpr voxel_pos coord::to_voxel(const chunk_pos& cpos, const local_pos& lpos) -{ - return voxel_pos { - lpos.x + (static_cast<voxel_pos::value_type>(cpos.x) << CHUNK_BITSHIFT), - lpos.y + (static_cast<voxel_pos::value_type>(cpos.y) << CHUNK_BITSHIFT), - lpos.z + (static_cast<voxel_pos::value_type>(cpos.z) << CHUNK_BITSHIFT), - }; -} - -inline constexpr voxel_pos coord::to_voxel(const chunk_pos& cpos, const glm::fvec3& fvec) -{ - return voxel_pos { - static_cast<voxel_pos::value_type>(fvec.x) + (static_cast<voxel_pos::value_type>(cpos.x) << CHUNK_BITSHIFT), - static_cast<voxel_pos::value_type>(fvec.y) + (static_cast<voxel_pos::value_type>(cpos.y) << CHUNK_BITSHIFT), - static_cast<voxel_pos::value_type>(fvec.z) + (static_cast<voxel_pos::value_type>(cpos.z) << CHUNK_BITSHIFT), - }; -} - -inline constexpr std::size_t coord::to_index(const local_pos& lpos) -{ - return static_cast<std::size_t>((lpos.y * CHUNK_SIZE + lpos.z) * CHUNK_SIZE + lpos.x); -} - -inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const chunk_pos& cpos, const glm::fvec3& fvec) -{ - return glm::fvec3 { - static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) + fvec.x, - static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) + fvec.y, - static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) + fvec.z, - }; -} - -inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos) -{ - return glm::fvec3 { - static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) - pivot_fvec.x, - static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) - pivot_fvec.y, - static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) - pivot_fvec.z, - }; -} - -inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos, - const glm::fvec3& fvec) -{ - return glm::fvec3 { - static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) + (fvec.x - pivot_fvec.x), - static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) + (fvec.y - pivot_fvec.y), - static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) + (fvec.z - pivot_fvec.z), - }; -} - -inline constexpr glm::fvec3 coord::to_fvec3(const chunk_pos& cpos) -{ - return glm::fvec3 { - static_cast<float>(cpos.x << CHUNK_BITSHIFT), - static_cast<float>(cpos.y << CHUNK_BITSHIFT), - static_cast<float>(cpos.z << CHUNK_BITSHIFT), - }; -} - -inline constexpr glm::fvec3 coord::to_fvec3(const chunk_pos& cpos, const glm::fvec3& fpos) -{ - return glm::fvec3 { - fpos.x + static_cast<float>(cpos.x << CHUNK_BITSHIFT), - fpos.y + static_cast<float>(cpos.y << CHUNK_BITSHIFT), - fpos.z + static_cast<float>(cpos.z << CHUNK_BITSHIFT), - }; -} +#pragma once
+
+#include "shared/const.hh"
+#include "shared/types.hh"
+
+namespace coord
+{
+constexpr chunk_pos to_chunk(const voxel_pos& vpos);
+} // namespace coord
+
+namespace coord
+{
+constexpr local_pos to_local(const voxel_pos& vpos);
+constexpr local_pos to_local(const glm::fvec3& fvec);
+constexpr local_pos to_local(std::size_t index);
+} // namespace coord
+
+namespace coord
+{
+constexpr voxel_pos to_voxel(const chunk_pos& cpos, const local_pos& lpos);
+constexpr voxel_pos to_voxel(const chunk_pos& cpos, const glm::fvec3& fvec);
+} // namespace coord
+
+namespace coord
+{
+constexpr std::size_t to_index(const local_pos& lpos);
+} // namespace coord
+
+namespace coord
+{
+constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const chunk_pos& cpos, const glm::fvec3& fvec);
+constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos);
+constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos, const glm::fvec3& fvec);
+} // namespace coord
+
+namespace coord
+{
+constexpr glm::fvec3 to_fvec3(const chunk_pos& cpos);
+constexpr glm::fvec3 to_fvec3(const chunk_pos& cpos, const glm::fvec3& fpos);
+} // namespace coord
+
+inline constexpr chunk_pos coord::to_chunk(const voxel_pos& vpos)
+{
+ return chunk_pos {
+ static_cast<chunk_pos::value_type>(vpos.x >> CHUNK_BITSHIFT),
+ static_cast<chunk_pos::value_type>(vpos.y >> CHUNK_BITSHIFT),
+ static_cast<chunk_pos::value_type>(vpos.z >> CHUNK_BITSHIFT),
+ };
+}
+
+inline constexpr local_pos coord::to_local(const voxel_pos& vpos)
+{
+ return local_pos {
+ static_cast<local_pos::value_type>(math::mod_signed<voxel_pos::value_type>(vpos.x, CHUNK_SIZE)),
+ static_cast<local_pos::value_type>(math::mod_signed<voxel_pos::value_type>(vpos.y, CHUNK_SIZE)),
+ static_cast<local_pos::value_type>(math::mod_signed<voxel_pos::value_type>(vpos.z, CHUNK_SIZE)),
+ };
+}
+
+inline constexpr local_pos coord::to_local(const glm::fvec3& fvec)
+{
+ return local_pos {
+ static_cast<local_pos::value_type>(fvec.x),
+ static_cast<local_pos::value_type>(fvec.y),
+ static_cast<local_pos::value_type>(fvec.z),
+ };
+}
+
+inline constexpr local_pos coord::to_local(std::size_t index)
+{
+ return local_pos {
+ static_cast<local_pos::value_type>((index % CHUNK_SIZE)),
+ static_cast<local_pos::value_type>((index / CHUNK_SIZE) / CHUNK_SIZE),
+ static_cast<local_pos::value_type>((index / CHUNK_SIZE) % CHUNK_SIZE),
+ };
+}
+
+inline constexpr voxel_pos coord::to_voxel(const chunk_pos& cpos, const local_pos& lpos)
+{
+ return voxel_pos {
+ lpos.x + (static_cast<voxel_pos::value_type>(cpos.x) << CHUNK_BITSHIFT),
+ lpos.y + (static_cast<voxel_pos::value_type>(cpos.y) << CHUNK_BITSHIFT),
+ lpos.z + (static_cast<voxel_pos::value_type>(cpos.z) << CHUNK_BITSHIFT),
+ };
+}
+
+inline constexpr voxel_pos coord::to_voxel(const chunk_pos& cpos, const glm::fvec3& fvec)
+{
+ return voxel_pos {
+ static_cast<voxel_pos::value_type>(fvec.x) + (static_cast<voxel_pos::value_type>(cpos.x) << CHUNK_BITSHIFT),
+ static_cast<voxel_pos::value_type>(fvec.y) + (static_cast<voxel_pos::value_type>(cpos.y) << CHUNK_BITSHIFT),
+ static_cast<voxel_pos::value_type>(fvec.z) + (static_cast<voxel_pos::value_type>(cpos.z) << CHUNK_BITSHIFT),
+ };
+}
+
+inline constexpr std::size_t coord::to_index(const local_pos& lpos)
+{
+ return static_cast<std::size_t>((lpos.y * CHUNK_SIZE + lpos.z) * CHUNK_SIZE + lpos.x);
+}
+
+inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const chunk_pos& cpos, const glm::fvec3& fvec)
+{
+ return glm::fvec3 {
+ static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) + fvec.x,
+ static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) + fvec.y,
+ static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) + fvec.z,
+ };
+}
+
+inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos)
+{
+ return glm::fvec3 {
+ static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) - pivot_fvec.x,
+ static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) - pivot_fvec.y,
+ static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) - pivot_fvec.z,
+ };
+}
+
+inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos,
+ const glm::fvec3& fvec)
+{
+ return glm::fvec3 {
+ static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) + (fvec.x - pivot_fvec.x),
+ static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) + (fvec.y - pivot_fvec.y),
+ static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) + (fvec.z - pivot_fvec.z),
+ };
+}
+
+inline constexpr glm::fvec3 coord::to_fvec3(const chunk_pos& cpos)
+{
+ return glm::fvec3 {
+ static_cast<float>(cpos.x << CHUNK_BITSHIFT),
+ static_cast<float>(cpos.y << CHUNK_BITSHIFT),
+ static_cast<float>(cpos.z << CHUNK_BITSHIFT),
+ };
+}
+
+inline constexpr glm::fvec3 coord::to_fvec3(const chunk_pos& cpos, const glm::fvec3& fpos)
+{
+ return glm::fvec3 {
+ fpos.x + static_cast<float>(cpos.x << CHUNK_BITSHIFT),
+ fpos.y + static_cast<float>(cpos.y << CHUNK_BITSHIFT),
+ fpos.z + static_cast<float>(cpos.z << CHUNK_BITSHIFT),
+ };
+}
diff --git a/game/shared/entity/collision.cc b/game/shared/entity/collision.cc index 4346b68..dbe7d30 100644 --- a/game/shared/entity/collision.cc +++ b/game/shared/entity/collision.cc @@ -1,175 +1,175 @@ -#include "shared/pch.hh" - -#include "shared/entity/collision.hh" - -#include "core/math/constexpr.hh" - -#include "shared/entity/gravity.hh" -#include "shared/entity/grounded.hh" -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" -#include "shared/world/voxel_registry.hh" - -#include "shared/coord.hh" -#include "shared/globals.hh" - -static int vgrid_collide(const world::Dimension* dimension, int d, entity::Collision& collision, entity::Transform& transform, - entity::Velocity& velocity, world::voxel_surface& touch_surface) -{ - const auto move = globals::fixed_frametime * velocity.value[d]; - const auto move_sign = math::sign<int>(move); - - const auto& ref_aabb = collision.aabb; - const auto current_aabb = ref_aabb.push(transform.local); - - auto next_aabb = math::AABB(current_aabb); - next_aabb.min[d] += move; - next_aabb.max[d] += move; - - local_pos lpos_min; - lpos_min.x = math::floor<local_pos::value_type>(next_aabb.min.x); - lpos_min.y = math::floor<local_pos::value_type>(next_aabb.min.y); - lpos_min.z = math::floor<local_pos::value_type>(next_aabb.min.z); - - local_pos lpos_max; - lpos_max.x = math::ceil<local_pos::value_type>(next_aabb.max.x); - lpos_max.y = math::ceil<local_pos::value_type>(next_aabb.max.y); - lpos_max.z = math::ceil<local_pos::value_type>(next_aabb.max.z); - - // Other axes - const int u = (d + 1) % 3; - const int v = (d + 2) % 3; - - local_pos::value_type ddir; - local_pos::value_type dmin; - local_pos::value_type dmax; - - if(move < 0.0f) { - ddir = local_pos::value_type(+1); - dmin = lpos_min[d]; - dmax = lpos_max[d]; - } - else { - ddir = local_pos::value_type(-1); - dmin = lpos_max[d]; - dmax = lpos_min[d]; - } - - world::voxel_touch latch_touch = world::voxel_touch::NOTHING; - glm::fvec3 latch_values = glm::fvec3(0.0f, 0.0f, 0.0f); - world::voxel_surface latch_surface = world::voxel_surface::UNKNOWN; - math::AABB latch_vbox; - - for(auto i = dmin; i != dmax; i += ddir) { - for(auto j = lpos_min[u]; j < lpos_max[u]; ++j) - for(auto k = lpos_min[v]; k < lpos_max[v]; ++k) { - local_pos lpos; - lpos[d] = i; - lpos[u] = j; - lpos[v] = k; - - const auto vpos = coord::to_voxel(transform.chunk, lpos); - const auto info = world::voxel_registry::find(dimension->get_voxel(vpos)); - - if(info == nullptr) { - // Don't collide with something - // that we assume to be nothing - continue; - } - - math::AABB vbox; - vbox.min = glm::fvec3(lpos); - vbox.max = glm::fvec3(lpos) + 1.0f; - - if(!next_aabb.intersect(vbox)) { - // No intersection between the voxel - // and the entity's collision hull - continue; - } - - if(info->touch_type == world::voxel_touch::SOLID) { - // Solid touch type makes a collision - // response whenever it is encountered - velocity.value[d] = 0.0f; - touch_surface = info->surface; - return move_sign; - } - - // In case of other touch types, they - // are latched and the last ever touch - // type is then responded to - if(info->touch_type != world::voxel_touch::NOTHING) { - latch_touch = info->touch_type; - latch_values = info->touch_values; - latch_surface = info->surface; - latch_vbox = vbox; - continue; - } - } - } - - if(latch_touch != world::voxel_touch::NOTHING) { - if(latch_touch == world::voxel_touch::BOUNCE) { - const auto move_distance = math::abs(current_aabb.min[d] - next_aabb.min[d]); - const auto threshold = 2.0f * globals::fixed_frametime; - - if(move_distance > threshold) { - velocity.value[d] *= -latch_values[d]; - } - else { - velocity.value[d] = 0.0f; - } - - touch_surface = latch_surface; - - return move_sign; - } - - if(latch_touch == world::voxel_touch::SINK) { - velocity.value[d] *= latch_values[d]; - touch_surface = latch_surface; - return move_sign; - } - } - - return 0; -} - -void entity::Collision::fixed_update(world::Dimension* dimension) -{ - // FIXME: this isn't particularly accurate considering - // some voxels might be passable and some other voxels - // might apply some slowing factor; what I might do in the - // future is to add a specific value to the voxel registry - // entries that would specify the amount of force we apply - // to prevent player movement inside a specific voxel, plus - // we shouldn't treat all voxels as full cubes if we want - // to support slabs, stairs and non-full liquid voxels in the future - - auto group = dimension->entities.group<entity::Collision>(entt::get<entity::Transform, entity::Velocity>); - - for(auto [entity, collision, transform, velocity] : group.each()) { - auto surface = world::voxel_surface::UNKNOWN; - auto vertical_move = vgrid_collide(dimension, 1, collision, transform, velocity, surface); - - if(dimension->entities.any_of<entity::Gravity>(entity)) { - if(vertical_move == math::sign<int>(dimension->get_gravity())) { - dimension->entities.emplace_or_replace<entity::Grounded>(entity, entity::Grounded { surface }); - } - else { - dimension->entities.remove<entity::Grounded>(entity); - } - } - else { - // The entity cannot be grounded because the component - // setup of said entity should not let it comprehend the - // concept of resting on the ground (it flies around) - dimension->entities.remove<entity::Grounded>(entity); - } - - vgrid_collide(dimension, 0, collision, transform, velocity, surface); - vgrid_collide(dimension, 2, collision, transform, velocity, surface); - } -} +#include "shared/pch.hh"
+
+#include "shared/entity/collision.hh"
+
+#include "core/math/constexpr.hh"
+
+#include "shared/entity/gravity.hh"
+#include "shared/entity/grounded.hh"
+#include "shared/entity/transform.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+#include "shared/world/voxel_registry.hh"
+
+#include "shared/coord.hh"
+#include "shared/globals.hh"
+
+static int vgrid_collide(const world::Dimension* dimension, int d, entity::Collision& collision, entity::Transform& transform,
+ entity::Velocity& velocity, world::voxel_surface& touch_surface)
+{
+ const auto move = globals::fixed_frametime * velocity.value[d];
+ const auto move_sign = math::sign<int>(move);
+
+ const auto& ref_aabb = collision.aabb;
+ const auto current_aabb = ref_aabb.push(transform.local);
+
+ auto next_aabb = math::AABB(current_aabb);
+ next_aabb.min[d] += move;
+ next_aabb.max[d] += move;
+
+ local_pos lpos_min;
+ lpos_min.x = math::floor<local_pos::value_type>(next_aabb.min.x);
+ lpos_min.y = math::floor<local_pos::value_type>(next_aabb.min.y);
+ lpos_min.z = math::floor<local_pos::value_type>(next_aabb.min.z);
+
+ local_pos lpos_max;
+ lpos_max.x = math::ceil<local_pos::value_type>(next_aabb.max.x);
+ lpos_max.y = math::ceil<local_pos::value_type>(next_aabb.max.y);
+ lpos_max.z = math::ceil<local_pos::value_type>(next_aabb.max.z);
+
+ // Other axes
+ const int u = (d + 1) % 3;
+ const int v = (d + 2) % 3;
+
+ local_pos::value_type ddir;
+ local_pos::value_type dmin;
+ local_pos::value_type dmax;
+
+ if(move < 0.0f) {
+ ddir = local_pos::value_type(+1);
+ dmin = lpos_min[d];
+ dmax = lpos_max[d];
+ }
+ else {
+ ddir = local_pos::value_type(-1);
+ dmin = lpos_max[d];
+ dmax = lpos_min[d];
+ }
+
+ world::voxel_touch latch_touch = world::voxel_touch::NOTHING;
+ glm::fvec3 latch_values = glm::fvec3(0.0f, 0.0f, 0.0f);
+ world::voxel_surface latch_surface = world::voxel_surface::UNKNOWN;
+ math::AABB latch_vbox;
+
+ for(auto i = dmin; i != dmax; i += ddir) {
+ for(auto j = lpos_min[u]; j < lpos_max[u]; ++j)
+ for(auto k = lpos_min[v]; k < lpos_max[v]; ++k) {
+ local_pos lpos;
+ lpos[d] = i;
+ lpos[u] = j;
+ lpos[v] = k;
+
+ const auto vpos = coord::to_voxel(transform.chunk, lpos);
+ const auto info = world::voxel_registry::find(dimension->get_voxel(vpos));
+
+ if(info == nullptr) {
+ // Don't collide with something
+ // that we assume to be nothing
+ continue;
+ }
+
+ math::AABB vbox;
+ vbox.min = glm::fvec3(lpos);
+ vbox.max = glm::fvec3(lpos) + 1.0f;
+
+ if(!next_aabb.intersect(vbox)) {
+ // No intersection between the voxel
+ // and the entity's collision hull
+ continue;
+ }
+
+ if(info->touch_type == world::voxel_touch::SOLID) {
+ // Solid touch type makes a collision
+ // response whenever it is encountered
+ velocity.value[d] = 0.0f;
+ touch_surface = info->surface;
+ return move_sign;
+ }
+
+ // In case of other touch types, they
+ // are latched and the last ever touch
+ // type is then responded to
+ if(info->touch_type != world::voxel_touch::NOTHING) {
+ latch_touch = info->touch_type;
+ latch_values = info->touch_values;
+ latch_surface = info->surface;
+ latch_vbox = vbox;
+ continue;
+ }
+ }
+ }
+
+ if(latch_touch != world::voxel_touch::NOTHING) {
+ if(latch_touch == world::voxel_touch::BOUNCE) {
+ const auto move_distance = math::abs(current_aabb.min[d] - next_aabb.min[d]);
+ const auto threshold = 2.0f * globals::fixed_frametime;
+
+ if(move_distance > threshold) {
+ velocity.value[d] *= -latch_values[d];
+ }
+ else {
+ velocity.value[d] = 0.0f;
+ }
+
+ touch_surface = latch_surface;
+
+ return move_sign;
+ }
+
+ if(latch_touch == world::voxel_touch::SINK) {
+ velocity.value[d] *= latch_values[d];
+ touch_surface = latch_surface;
+ return move_sign;
+ }
+ }
+
+ return 0;
+}
+
+void entity::Collision::fixed_update(world::Dimension* dimension)
+{
+ // FIXME: this isn't particularly accurate considering
+ // some voxels might be passable and some other voxels
+ // might apply some slowing factor; what I might do in the
+ // future is to add a specific value to the voxel registry
+ // entries that would specify the amount of force we apply
+ // to prevent player movement inside a specific voxel, plus
+ // we shouldn't treat all voxels as full cubes if we want
+ // to support slabs, stairs and non-full liquid voxels in the future
+
+ auto group = dimension->entities.group<entity::Collision>(entt::get<entity::Transform, entity::Velocity>);
+
+ for(auto [entity, collision, transform, velocity] : group.each()) {
+ auto surface = world::voxel_surface::UNKNOWN;
+ auto vertical_move = vgrid_collide(dimension, 1, collision, transform, velocity, surface);
+
+ if(dimension->entities.any_of<entity::Gravity>(entity)) {
+ if(vertical_move == math::sign<int>(dimension->get_gravity())) {
+ dimension->entities.emplace_or_replace<entity::Grounded>(entity, entity::Grounded { surface });
+ }
+ else {
+ dimension->entities.remove<entity::Grounded>(entity);
+ }
+ }
+ else {
+ // The entity cannot be grounded because the component
+ // setup of said entity should not let it comprehend the
+ // concept of resting on the ground (it flies around)
+ dimension->entities.remove<entity::Grounded>(entity);
+ }
+
+ vgrid_collide(dimension, 0, collision, transform, velocity, surface);
+ vgrid_collide(dimension, 2, collision, transform, velocity, surface);
+ }
+}
diff --git a/game/shared/entity/collision.hh b/game/shared/entity/collision.hh index 33ddaac..ca94665 100644 --- a/game/shared/entity/collision.hh +++ b/game/shared/entity/collision.hh @@ -1,21 +1,21 @@ -#pragma once - -#include "core/math/aabb.hh" - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity -{ -struct Collision final { - math::AABB aabb; - -public: - // NOTE: entity::Collision::fixed_update must be called - // before entity::Transform::fixed_update and entity::Velocity::fixed_update - // because both transform and velocity may be updated internally - static void fixed_update(world::Dimension* dimension); -}; -} // namespace entity +#pragma once
+
+#include "core/math/aabb.hh"
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity
+{
+struct Collision final {
+ math::AABB aabb;
+
+public:
+ // NOTE: entity::Collision::fixed_update must be called
+ // before entity::Transform::fixed_update and entity::Velocity::fixed_update
+ // because both transform and velocity may be updated internally
+ static void fixed_update(world::Dimension* dimension);
+};
+} // namespace entity
diff --git a/game/shared/entity/factory.cc b/game/shared/entity/factory.cc index 619a418..ba95b73 100644 --- a/game/shared/entity/factory.cc +++ b/game/shared/entity/factory.cc @@ -1,37 +1,37 @@ -#include "shared/pch.hh" - -#include "shared/entity/factory.hh" - -#include "shared/entity/collision.hh" -#include "shared/entity/gravity.hh" -#include "shared/entity/head.hh" -#include "shared/entity/player.hh" -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" - -#include "shared/globals.hh" - -void entity::shared::create_player(world::Dimension* dimension, entt::entity entity) -{ - spdlog::debug("factory[{}]: assigning player components to {}", dimension->get_name(), static_cast<std::uint64_t>(entity)); - - auto& collision = dimension->entities.emplace_or_replace<entity::Collision>(entity); - collision.aabb.min = glm::fvec3(-0.4f, -1.6f, -0.4f); - collision.aabb.max = glm::fvec3(+0.4f, +0.2f, +0.4f); - - auto& head = dimension->entities.emplace_or_replace<entity::Head>(entity); - head.angles = glm::fvec3(0.0f, 0.0f, 0.0f); - head.offset = glm::fvec3(0.0f, 0.0f, 0.0f); - - dimension->entities.emplace_or_replace<entity::Player>(entity); - - auto& transform = dimension->entities.emplace_or_replace<entity::Transform>(entity); - transform.chunk = chunk_pos(0, 2, 0); - transform.local = glm::fvec3(0.0f, 0.0f, 0.0f); - transform.angles = glm::fvec3(0.0f, 0.0f, 0.0f); - - auto& velocity = dimension->entities.emplace_or_replace<entity::Velocity>(entity); - velocity.value = glm::fvec3(0.0f, 0.0f, 0.0f); -} +#include "shared/pch.hh"
+
+#include "shared/entity/factory.hh"
+
+#include "shared/entity/collision.hh"
+#include "shared/entity/gravity.hh"
+#include "shared/entity/head.hh"
+#include "shared/entity/player.hh"
+#include "shared/entity/transform.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/globals.hh"
+
+void entity::shared::create_player(world::Dimension* dimension, entt::entity entity)
+{
+ spdlog::debug("factory[{}]: assigning player components to {}", dimension->get_name(), static_cast<std::uint64_t>(entity));
+
+ auto& collision = dimension->entities.emplace_or_replace<entity::Collision>(entity);
+ collision.aabb.min = glm::fvec3(-0.4f, -1.6f, -0.4f);
+ collision.aabb.max = glm::fvec3(+0.4f, +0.2f, +0.4f);
+
+ auto& head = dimension->entities.emplace_or_replace<entity::Head>(entity);
+ head.angles = glm::fvec3(0.0f, 0.0f, 0.0f);
+ head.offset = glm::fvec3(0.0f, 0.0f, 0.0f);
+
+ dimension->entities.emplace_or_replace<entity::Player>(entity);
+
+ auto& transform = dimension->entities.emplace_or_replace<entity::Transform>(entity);
+ transform.chunk = chunk_pos(0, 2, 0);
+ transform.local = glm::fvec3(0.0f, 0.0f, 0.0f);
+ transform.angles = glm::fvec3(0.0f, 0.0f, 0.0f);
+
+ auto& velocity = dimension->entities.emplace_or_replace<entity::Velocity>(entity);
+ velocity.value = glm::fvec3(0.0f, 0.0f, 0.0f);
+}
diff --git a/game/shared/entity/factory.hh b/game/shared/entity/factory.hh index e709060..be33045 100644 --- a/game/shared/entity/factory.hh +++ b/game/shared/entity/factory.hh @@ -1,11 +1,11 @@ -#pragma once - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity::shared -{ -void create_player(world::Dimension* dimension, entt::entity entity); -} // namespace entity::shared +#pragma once
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity::shared
+{
+void create_player(world::Dimension* dimension, entt::entity entity);
+} // namespace entity::shared
diff --git a/game/shared/entity/gravity.cc b/game/shared/entity/gravity.cc index f1708aa..09bc379 100644 --- a/game/shared/entity/gravity.cc +++ b/game/shared/entity/gravity.cc @@ -1,20 +1,20 @@ -#include "shared/pch.hh" - -#include "shared/entity/gravity.hh" - -#include "shared/entity/stasis.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" - -#include "shared/globals.hh" - -void entity::Gravity::fixed_update(world::Dimension* dimension) -{ - auto fixed_acceleration = globals::fixed_frametime * dimension->get_gravity(); - auto group = dimension->entities.group<entity::Gravity>(entt::get<entity::Velocity>, entt::exclude<entity::Stasis>); - - for(auto [entity, velocity] : group.each()) { - velocity.value.y += fixed_acceleration; - } -} +#include "shared/pch.hh"
+
+#include "shared/entity/gravity.hh"
+
+#include "shared/entity/stasis.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/globals.hh"
+
+void entity::Gravity::fixed_update(world::Dimension* dimension)
+{
+ auto fixed_acceleration = globals::fixed_frametime * dimension->get_gravity();
+ auto group = dimension->entities.group<entity::Gravity>(entt::get<entity::Velocity>, entt::exclude<entity::Stasis>);
+
+ for(auto [entity, velocity] : group.each()) {
+ velocity.value.y += fixed_acceleration;
+ }
+}
diff --git a/game/shared/entity/gravity.hh b/game/shared/entity/gravity.hh index 21f4582..2cbcbbc 100644 --- a/game/shared/entity/gravity.hh +++ b/game/shared/entity/gravity.hh @@ -1,14 +1,14 @@ -#pragma once - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity -{ -struct Gravity final { -public: - static void fixed_update(world::Dimension* dimension); -}; -} // namespace entity +#pragma once
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity
+{
+struct Gravity final {
+public:
+ static void fixed_update(world::Dimension* dimension);
+};
+} // namespace entity
diff --git a/game/shared/entity/grounded.hh b/game/shared/entity/grounded.hh index 22340db..e86e3a8 100644 --- a/game/shared/entity/grounded.hh +++ b/game/shared/entity/grounded.hh @@ -1,16 +1,16 @@ -#ifndef SHARED_ENTITY_GROUNDED -#define SHARED_ENTITY_GROUNDED 1 -#pragma once - -#include "shared/world/voxel_registry.hh" - -namespace entity -{ -// Assigned to entities which are grounded -// according to the collision and gravity system -struct Grounded final { - world::voxel_surface surface; -}; -} // namespace entity - -#endif // SHARED_ENTITY_GROUNDED +#ifndef SHARED_ENTITY_GROUNDED
+#define SHARED_ENTITY_GROUNDED 1
+#pragma once
+
+#include "shared/world/voxel_registry.hh"
+
+namespace entity
+{
+// Assigned to entities which are grounded
+// according to the collision and gravity system
+struct Grounded final {
+ world::voxel_surface surface;
+};
+} // namespace entity
+
+#endif // SHARED_ENTITY_GROUNDED
diff --git a/game/shared/entity/head.hh b/game/shared/entity/head.hh index 3f5d6d1..15ce7e5 100644 --- a/game/shared/entity/head.hh +++ b/game/shared/entity/head.hh @@ -1,16 +1,16 @@ -#pragma once - -namespace entity -{ -struct Head { - glm::fvec3 angles; - glm::fvec3 offset; -}; -} // namespace entity - -namespace entity::client -{ -// Client-side only - interpolated and previous head -struct HeadIntr final : public Head {}; -struct HeadPrev final : public Head {}; -} // namespace entity::client +#pragma once
+
+namespace entity
+{
+struct Head {
+ glm::fvec3 angles;
+ glm::fvec3 offset;
+};
+} // namespace entity
+
+namespace entity::client
+{
+// Client-side only - interpolated and previous head
+struct HeadIntr final : public Head {};
+struct HeadPrev final : public Head {};
+} // namespace entity::client
diff --git a/game/shared/entity/player.hh b/game/shared/entity/player.hh index 4bd0217..abffd85 100644 --- a/game/shared/entity/player.hh +++ b/game/shared/entity/player.hh @@ -1,6 +1,6 @@ -#pragma once - -namespace entity -{ -struct Player final {}; -} // namespace entity +#pragma once
+
+namespace entity
+{
+struct Player final {};
+} // namespace entity
diff --git a/game/shared/entity/stasis.cc b/game/shared/entity/stasis.cc index 3b86294..eab8744 100644 --- a/game/shared/entity/stasis.cc +++ b/game/shared/entity/stasis.cc @@ -1,21 +1,21 @@ -#include "shared/pch.hh" - -#include "shared/entity/stasis.hh" - -#include "shared/entity/transform.hh" - -#include "shared/world/dimension.hh" - -void entity::Stasis::fixed_update(world::Dimension* dimension) -{ - auto view = dimension->entities.view<entity::Transform>(); - - for(auto [entity, transform] : view.each()) { - if(dimension->find_chunk(transform.chunk)) { - dimension->entities.remove<entity::Stasis>(entity); - } - else { - dimension->entities.emplace_or_replace<entity::Stasis>(entity); - } - } -} +#include "shared/pch.hh"
+
+#include "shared/entity/stasis.hh"
+
+#include "shared/entity/transform.hh"
+
+#include "shared/world/dimension.hh"
+
+void entity::Stasis::fixed_update(world::Dimension* dimension)
+{
+ auto view = dimension->entities.view<entity::Transform>();
+
+ for(auto [entity, transform] : view.each()) {
+ if(dimension->find_chunk(transform.chunk)) {
+ dimension->entities.remove<entity::Stasis>(entity);
+ }
+ else {
+ dimension->entities.emplace_or_replace<entity::Stasis>(entity);
+ }
+ }
+}
diff --git a/game/shared/entity/stasis.hh b/game/shared/entity/stasis.hh index e6cb9e4..cb364ce 100644 --- a/game/shared/entity/stasis.hh +++ b/game/shared/entity/stasis.hh @@ -1,16 +1,16 @@ -#pragma once - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity -{ -// Attached to entities with transform values -// out of bounds in a specific dimension -struct Stasis final { -public: - static void fixed_update(world::Dimension* dimension); -}; -} // namespace entity +#pragma once
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity
+{
+// Attached to entities with transform values
+// out of bounds in a specific dimension
+struct Stasis final {
+public:
+ static void fixed_update(world::Dimension* dimension);
+};
+} // namespace entity
diff --git a/game/shared/entity/transform.cc b/game/shared/entity/transform.cc index 379ddd5..0339b9e 100644 --- a/game/shared/entity/transform.cc +++ b/game/shared/entity/transform.cc @@ -1,33 +1,33 @@ -#include "shared/pch.hh" - -#include "shared/entity/transform.hh" - -#include "shared/world/dimension.hh" - -#include "shared/const.hh" - -constexpr inline static void update_component(unsigned int dim, entity::Transform& component) -{ - if(component.local[dim] >= CHUNK_SIZE) { - component.local[dim] -= CHUNK_SIZE; - component.chunk[dim] += 1; - return; - } - - if(component.local[dim] < 0.0f) { - component.local[dim] += CHUNK_SIZE; - component.chunk[dim] -= 1; - return; - } -} - -void entity::Transform::fixed_update(world::Dimension* dimension) -{ - auto view = dimension->entities.view<entity::Transform>(); - - for(auto [entity, transform] : view.each()) { - update_component(0U, transform); - update_component(1U, transform); - update_component(2U, transform); - } -} +#include "shared/pch.hh"
+
+#include "shared/entity/transform.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/const.hh"
+
+constexpr inline static void update_component(unsigned int dim, entity::Transform& component)
+{
+ if(component.local[dim] >= CHUNK_SIZE) {
+ component.local[dim] -= CHUNK_SIZE;
+ component.chunk[dim] += 1;
+ return;
+ }
+
+ if(component.local[dim] < 0.0f) {
+ component.local[dim] += CHUNK_SIZE;
+ component.chunk[dim] -= 1;
+ return;
+ }
+}
+
+void entity::Transform::fixed_update(world::Dimension* dimension)
+{
+ auto view = dimension->entities.view<entity::Transform>();
+
+ for(auto [entity, transform] : view.each()) {
+ update_component(0U, transform);
+ update_component(1U, transform);
+ update_component(2U, transform);
+ }
+}
diff --git a/game/shared/entity/transform.hh b/game/shared/entity/transform.hh index 2b357f8..f7db095 100644 --- a/game/shared/entity/transform.hh +++ b/game/shared/entity/transform.hh @@ -1,30 +1,30 @@ -#pragma once - -#include "shared/types.hh" - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity -{ -struct Transform { - chunk_pos chunk; - glm::fvec3 local; - glm::fvec3 angles; - -public: - // Updates entity::Transform values so that - // the local translation field is always within - // local coodrinates; [floating-point precision] - static void fixed_update(world::Dimension* dimension); -}; -} // namespace entity - -namespace entity::client -{ -// Client-side only - interpolated and previous transform -struct TransformIntr final : public Transform {}; -struct TransformPrev final : public Transform {}; -} // namespace entity::client +#pragma once
+
+#include "shared/types.hh"
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity
+{
+struct Transform {
+ chunk_pos chunk;
+ glm::fvec3 local;
+ glm::fvec3 angles;
+
+public:
+ // Updates entity::Transform values so that
+ // the local translation field is always within
+ // local coodrinates; [floating-point precision]
+ static void fixed_update(world::Dimension* dimension);
+};
+} // namespace entity
+
+namespace entity::client
+{
+// Client-side only - interpolated and previous transform
+struct TransformIntr final : public Transform {};
+struct TransformPrev final : public Transform {};
+} // namespace entity::client
diff --git a/game/shared/entity/velocity.cc b/game/shared/entity/velocity.cc index 86df445..85ad53b 100644 --- a/game/shared/entity/velocity.cc +++ b/game/shared/entity/velocity.cc @@ -1,19 +1,19 @@ -#include "shared/pch.hh" - -#include "shared/entity/velocity.hh" - -#include "shared/entity/stasis.hh" -#include "shared/entity/transform.hh" - -#include "shared/world/dimension.hh" - -#include "shared/globals.hh" - -void entity::Velocity::fixed_update(world::Dimension* dimension) -{ - auto group = dimension->entities.group<entity::Velocity>(entt::get<entity::Transform>, entt::exclude<entity::Stasis>); - - for(auto [entity, velocity, transform] : group.each()) { - transform.local += velocity.value * globals::fixed_frametime; - } -} +#include "shared/pch.hh"
+
+#include "shared/entity/velocity.hh"
+
+#include "shared/entity/stasis.hh"
+#include "shared/entity/transform.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/globals.hh"
+
+void entity::Velocity::fixed_update(world::Dimension* dimension)
+{
+ auto group = dimension->entities.group<entity::Velocity>(entt::get<entity::Transform>, entt::exclude<entity::Stasis>);
+
+ for(auto [entity, velocity, transform] : group.each()) {
+ transform.local += velocity.value * globals::fixed_frametime;
+ }
+}
diff --git a/game/shared/entity/velocity.hh b/game/shared/entity/velocity.hh index c8a1c91..e57e555 100644 --- a/game/shared/entity/velocity.hh +++ b/game/shared/entity/velocity.hh @@ -1,19 +1,19 @@ -#pragma once - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity -{ -struct Velocity final { - glm::fvec3 value; - -public: - // Updates entities entity::Transform values - // according to velocities multiplied by fixed_frametime. - // NOTE: This system was previously called inertial - static void fixed_update(world::Dimension* dimension); -}; -} // namespace entity +#pragma once
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity
+{
+struct Velocity final {
+ glm::fvec3 value;
+
+public:
+ // Updates entities entity::Transform values
+ // according to velocities multiplied by fixed_frametime.
+ // NOTE: This system was previously called inertial
+ static void fixed_update(world::Dimension* dimension);
+};
+} // namespace entity
diff --git a/game/shared/game.cc b/game/shared/game.cc index 94c2c1f..f7b9da4 100644 --- a/game/shared/game.cc +++ b/game/shared/game.cc @@ -1,123 +1,123 @@ -#include "shared/pch.hh" - -#include "shared/game.hh" - -#include "core/io/cmdline.hh" - -static std::filesystem::path get_gamepath(void) -{ - if(auto gamepath = io::cmdline::get_cstr("gamepath")) { - // Allow users and third-party launchers to override - // content location. Perhaps this would work to allow - // for a Minecraft-like versioning approach? - return std::filesystem::path(gamepath); - } - - return std::filesystem::current_path() / "data"; -} - -static std::filesystem::path get_userpath(void) -{ - if(auto userpath = io::cmdline::get_cstr("userpath")) { - // Allow users and third-party launchers to override - // user data location. Perhaps this would work to allow - // for a Minecraft-like versioning approach? - return std::filesystem::path(userpath); - } - - if(auto win_appdata = std::getenv("APPDATA")) { - // On pre-seven Windows systems it's just AppData - // On post-seven Windows systems it's AppData/Roaming - return std::filesystem::path(win_appdata) / "voxelius"; - } - - if(auto xdg_home = std::getenv("XDG_DATA_HOME")) { - // Systems with an active X11/Wayland session - // theoretically should have this defined, and - // it can be different from ${HOME} (I think). - return std::filesystem::path(xdg_home) / ".voxelius"; - } - - if(auto unix_home = std::getenv("HOME")) { - // Any spherical UNIX/UNIX-like system in vacuum - // has this defined for every single user process. - return std::filesystem::path(unix_home) / ".voxelius"; - } - - // Give up and save stuff into CWD - return std::filesystem::current_path(); -} - -void shared_game::init(int argc, char** argv) -{ - auto logger = spdlog::default_logger(); - auto& logger_sinks = logger->sinks(); - - logger_sinks.clear(); - logger_sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); - logger_sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("voxelius.log", false)); - -#if defined(NDEBUG) - constexpr auto default_loglevel = spdlog::level::info; -#else - constexpr auto default_loglevel = spdlog::level::trace; -#endif - - if(io::cmdline::contains("quiet")) { - logger->set_level(spdlog::level::warn); - } - else if(io::cmdline::contains("verbose")) { - logger->set_level(spdlog::level::trace); - } - else { - logger->set_level(default_loglevel); - } - - logger->set_pattern("%H:%M:%S.%e %^[%L]%$ %v"); - logger->flush(); - - if(!PHYSFS_init(argv[0])) { - spdlog::critical("physfs: init failed: {}", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - std::terminate(); - } - - auto gamepath = get_gamepath(); - auto userpath = get_userpath(); - - spdlog::info("shared_game: set gamepath to {}", gamepath.string()); - spdlog::info("shared_game: set userpath to {}", userpath.string()); - - std::error_code ignore_error = {}; - std::filesystem::create_directories(gamepath, ignore_error); - std::filesystem::create_directories(userpath, ignore_error); - - if(!PHYSFS_mount(gamepath.string().c_str(), nullptr, false)) { - spdlog::critical("physfs: mount {} failed: {}", gamepath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - std::terminate(); - } - - if(!PHYSFS_mount(userpath.string().c_str(), nullptr, false)) { - spdlog::critical("physfs: mount {} failed: {}", userpath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - std::terminate(); - } - - if(!PHYSFS_setWriteDir(userpath.string().c_str())) { - spdlog::critical("physfs: setwritedir {} failed: {}", userpath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - std::terminate(); - } - - if(enet_initialize()) { - spdlog::critical("enet: init failed"); - std::terminate(); - } -} - -void shared_game::shutdown(void) -{ - enet_deinitialize(); - - if(!PHYSFS_deinit()) { - spdlog::critical("physfs: deinit failed: {}", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - std::terminate(); - } -} +#include "shared/pch.hh"
+
+#include "shared/game.hh"
+
+#include "core/io/cmdline.hh"
+
+static std::filesystem::path get_gamepath(void)
+{
+ if(auto gamepath = io::cmdline::get_cstr("gamepath")) {
+ // Allow users and third-party launchers to override
+ // content location. Perhaps this would work to allow
+ // for a Minecraft-like versioning approach?
+ return std::filesystem::path(gamepath);
+ }
+
+ return std::filesystem::current_path() / "data";
+}
+
+static std::filesystem::path get_userpath(void)
+{
+ if(auto userpath = io::cmdline::get_cstr("userpath")) {
+ // Allow users and third-party launchers to override
+ // user data location. Perhaps this would work to allow
+ // for a Minecraft-like versioning approach?
+ return std::filesystem::path(userpath);
+ }
+
+ if(auto win_appdata = std::getenv("APPDATA")) {
+ // On pre-seven Windows systems it's just AppData
+ // On post-seven Windows systems it's AppData/Roaming
+ return std::filesystem::path(win_appdata) / "voxelius";
+ }
+
+ if(auto xdg_home = std::getenv("XDG_DATA_HOME")) {
+ // Systems with an active X11/Wayland session
+ // theoretically should have this defined, and
+ // it can be different from ${HOME} (I think).
+ return std::filesystem::path(xdg_home) / ".voxelius";
+ }
+
+ if(auto unix_home = std::getenv("HOME")) {
+ // Any spherical UNIX/UNIX-like system in vacuum
+ // has this defined for every single user process.
+ return std::filesystem::path(unix_home) / ".voxelius";
+ }
+
+ // Give up and save stuff into CWD
+ return std::filesystem::current_path();
+}
+
+void shared_game::init(int argc, char** argv)
+{
+ auto logger = spdlog::default_logger();
+ auto& logger_sinks = logger->sinks();
+
+ logger_sinks.clear();
+ logger_sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>());
+ logger_sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("voxelius.log", false));
+
+#if defined(NDEBUG)
+ constexpr auto default_loglevel = spdlog::level::info;
+#else
+ constexpr auto default_loglevel = spdlog::level::trace;
+#endif
+
+ if(io::cmdline::contains("quiet")) {
+ logger->set_level(spdlog::level::warn);
+ }
+ else if(io::cmdline::contains("verbose")) {
+ logger->set_level(spdlog::level::trace);
+ }
+ else {
+ logger->set_level(default_loglevel);
+ }
+
+ logger->set_pattern("%H:%M:%S.%e %^[%L]%$ %v");
+ logger->flush();
+
+ if(!PHYSFS_init(argv[0])) {
+ spdlog::critical("physfs: init failed: {}", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+ std::terminate();
+ }
+
+ auto gamepath = get_gamepath();
+ auto userpath = get_userpath();
+
+ spdlog::info("shared_game: set gamepath to {}", gamepath.string());
+ spdlog::info("shared_game: set userpath to {}", userpath.string());
+
+ std::error_code ignore_error = {};
+ std::filesystem::create_directories(gamepath, ignore_error);
+ std::filesystem::create_directories(userpath, ignore_error);
+
+ if(!PHYSFS_mount(gamepath.string().c_str(), nullptr, false)) {
+ spdlog::critical("physfs: mount {} failed: {}", gamepath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+ std::terminate();
+ }
+
+ if(!PHYSFS_mount(userpath.string().c_str(), nullptr, false)) {
+ spdlog::critical("physfs: mount {} failed: {}", userpath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+ std::terminate();
+ }
+
+ if(!PHYSFS_setWriteDir(userpath.string().c_str())) {
+ spdlog::critical("physfs: setwritedir {} failed: {}", userpath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+ std::terminate();
+ }
+
+ if(enet_initialize()) {
+ spdlog::critical("enet: init failed");
+ std::terminate();
+ }
+}
+
+void shared_game::shutdown(void)
+{
+ enet_deinitialize();
+
+ if(!PHYSFS_deinit()) {
+ spdlog::critical("physfs: deinit failed: {}", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
+ std::terminate();
+ }
+}
diff --git a/game/shared/game.hh b/game/shared/game.hh index 06c1f51..21286e8 100644 --- a/game/shared/game.hh +++ b/game/shared/game.hh @@ -1,11 +1,11 @@ -#ifndef SHARED_GAME -#define SHARED_GAME 1 -#pragma once - -namespace shared_game -{ -void init(int argc, char** argv); -void shutdown(void); -} // namespace shared_game - -#endif // SHARED_GAME +#ifndef SHARED_GAME
+#define SHARED_GAME 1
+#pragma once
+
+namespace shared_game
+{
+void init(int argc, char** argv);
+void shutdown(void);
+} // namespace shared_game
+
+#endif // SHARED_GAME
diff --git a/game/shared/game_items.cc b/game/shared/game_items.cc index 58f379f..6073117 100644 --- a/game/shared/game_items.cc +++ b/game/shared/game_items.cc @@ -1,69 +1,66 @@ -#include "shared/pch.hh" - -#include "shared/game_items.hh" - -#include "shared/world/item_registry.hh" - -#include "shared/game_voxels.hh" - -item_id game_items::stone = NULL_ITEM_ID; -item_id game_items::cobblestone = NULL_ITEM_ID; -item_id game_items::dirt = NULL_ITEM_ID; -item_id game_items::grass = NULL_ITEM_ID; -item_id game_items::oak_leaves = NULL_ITEM_ID; -item_id game_items::oak_planks = NULL_ITEM_ID; -item_id game_items::oak_log = NULL_ITEM_ID; -item_id game_items::glass = NULL_ITEM_ID; -item_id game_items::slime = NULL_ITEM_ID; -item_id game_items::mud = NULL_ITEM_ID; - -void game_items::populate(void) -{ - // Stone; a hardened slate rock - game_items::stone = - world::item_registry::construct("stone").set_texture("textures/item/stone.png").set_place_voxel(game_voxels::stone).build(); - - // Cobblestone; a bunch of small stones - game_items::cobblestone = - world::item_registry::construct("cobblestone") - .set_texture("textures/item/cobblestone.png") - .set_place_voxel(game_voxels::cobblestone) - .build(); - - // Dirt; it's very dirty - game_items::dirt = - world::item_registry::construct("dirt").set_texture("textures/item/dirt.png").set_place_voxel(game_voxels::dirt).build(); - - // Grass; literally just grassy dirt - game_items::grass = - world::item_registry::construct("grass").set_texture("textures/item/grass.png").set_place_voxel(game_voxels::grass).build(); - - // Oak leaves; they're bushy! - game_items::oak_leaves = - world::item_registry::construct("oak_leaves") - .set_texture("textures/item/oak_leaves.png") - .set_place_voxel(game_voxels::oak_leaves) - .build(); - - // Oak planks; watch for splinters! - game_items::oak_planks = - world::item_registry::construct("oak_planks") - .set_texture("textures/item/oak_planks.png") - .set_place_voxel(game_voxels::oak_planks) - .build(); - - // Oak log; a big wad of wood - game_items::oak_log = - world::item_registry::construct("oak_log").set_texture("textures/item/oak_log.png").set_place_voxel(game_voxels::oak_log).build(); - - // Glass; used for windowing - game_items::glass = - world::item_registry::construct("glass").set_texture("textures/item/glass.png").set_place_voxel(game_voxels::glass).build(); - - // Slime; it's bouncy! - game_items::slime = - world::item_registry::construct("slime").set_texture("textures/item/slime.png").set_place_voxel(game_voxels::slime).build(); - - // Mud; you sink in it! - game_items::mud = world::item_registry::construct("mud").set_texture("textures/item/mud.png").build(); -} +#include "shared/pch.hh"
+
+#include "shared/game_items.hh"
+
+#include "shared/world/item_registry.hh"
+
+#include "shared/game_voxels.hh"
+
+item_id game_items::stone = NULL_ITEM_ID;
+item_id game_items::cobblestone = NULL_ITEM_ID;
+item_id game_items::dirt = NULL_ITEM_ID;
+item_id game_items::grass = NULL_ITEM_ID;
+item_id game_items::oak_leaves = NULL_ITEM_ID;
+item_id game_items::oak_planks = NULL_ITEM_ID;
+item_id game_items::oak_log = NULL_ITEM_ID;
+item_id game_items::glass = NULL_ITEM_ID;
+item_id game_items::slime = NULL_ITEM_ID;
+item_id game_items::mud = NULL_ITEM_ID;
+
+void game_items::populate(void)
+{
+ // Stone; a hardened slate rock
+ game_items::stone =
+ world::item_registry::construct("stone").set_texture("textures/item/stone.png").set_place_voxel(game_voxels::stone).build();
+
+ // Cobblestone; a bunch of small stones
+ game_items::cobblestone = world::item_registry::construct("cobblestone")
+ .set_texture("textures/item/cobblestone.png")
+ .set_place_voxel(game_voxels::cobblestone)
+ .build();
+
+ // Dirt; it's very dirty
+ game_items::dirt =
+ world::item_registry::construct("dirt").set_texture("textures/item/dirt.png").set_place_voxel(game_voxels::dirt).build();
+
+ // Grass; literally just grassy dirt
+ game_items::grass =
+ world::item_registry::construct("grass").set_texture("textures/item/grass.png").set_place_voxel(game_voxels::grass).build();
+
+ // Oak leaves; they're bushy!
+ game_items::oak_leaves = world::item_registry::construct("oak_leaves")
+ .set_texture("textures/item/oak_leaves.png")
+ .set_place_voxel(game_voxels::oak_leaves)
+ .build();
+
+ // Oak planks; watch for splinters!
+ game_items::oak_planks = world::item_registry::construct("oak_planks")
+ .set_texture("textures/item/oak_planks.png")
+ .set_place_voxel(game_voxels::oak_planks)
+ .build();
+
+ // Oak log; a big wad of wood
+ game_items::oak_log =
+ world::item_registry::construct("oak_log").set_texture("textures/item/oak_log.png").set_place_voxel(game_voxels::oak_log).build();
+
+ // Glass; used for windowing
+ game_items::glass =
+ world::item_registry::construct("glass").set_texture("textures/item/glass.png").set_place_voxel(game_voxels::glass).build();
+
+ // Slime; it's bouncy!
+ game_items::slime =
+ world::item_registry::construct("slime").set_texture("textures/item/slime.png").set_place_voxel(game_voxels::slime).build();
+
+ // Mud; you sink in it!
+ game_items::mud = world::item_registry::construct("mud").set_texture("textures/item/mud.png").build();
+}
diff --git a/game/shared/game_items.hh b/game/shared/game_items.hh index 2b5c19a..099923f 100644 --- a/game/shared/game_items.hh +++ b/game/shared/game_items.hh @@ -1,26 +1,26 @@ -#ifndef SHARED_GAME_ITEMS -#define SHARED_GAME_ITEMS 1 -#pragma once - -#include "shared/types.hh" - -namespace game_items -{ -extern item_id stone; -extern item_id cobblestone; -extern item_id dirt; -extern item_id grass; -extern item_id oak_leaves; -extern item_id oak_planks; -extern item_id oak_log; -extern item_id glass; -extern item_id slime; -extern item_id mud; -} // namespace game_items - -namespace game_items -{ -void populate(void); -} // namespace game_items - -#endif // SHARED_GAME_ITEMS +#ifndef SHARED_GAME_ITEMS
+#define SHARED_GAME_ITEMS 1
+#pragma once
+
+#include "shared/types.hh"
+
+namespace game_items
+{
+extern item_id stone;
+extern item_id cobblestone;
+extern item_id dirt;
+extern item_id grass;
+extern item_id oak_leaves;
+extern item_id oak_planks;
+extern item_id oak_log;
+extern item_id glass;
+extern item_id slime;
+extern item_id mud;
+} // namespace game_items
+
+namespace game_items
+{
+void populate(void);
+} // namespace game_items
+
+#endif // SHARED_GAME_ITEMS
diff --git a/game/shared/game_voxels.cc b/game/shared/game_voxels.cc index 2d9655b..51de1a1 100644 --- a/game/shared/game_voxels.cc +++ b/game/shared/game_voxels.cc @@ -1,126 +1,119 @@ -#include "shared/pch.hh" - -#include "shared/game_voxels.hh" - -#include "shared/world/voxel_registry.hh" - -voxel_id game_voxels::cobblestone = NULL_VOXEL_ID; -voxel_id game_voxels::dirt = NULL_VOXEL_ID; -voxel_id game_voxels::grass = NULL_VOXEL_ID; -voxel_id game_voxels::stone = NULL_VOXEL_ID; -voxel_id game_voxels::vtest = NULL_VOXEL_ID; -voxel_id game_voxels::vtest_ck = NULL_VOXEL_ID; -voxel_id game_voxels::oak_leaves = NULL_VOXEL_ID; -voxel_id game_voxels::oak_planks = NULL_VOXEL_ID; -voxel_id game_voxels::oak_log = NULL_VOXEL_ID; -voxel_id game_voxels::glass = NULL_VOXEL_ID; -voxel_id game_voxels::slime = NULL_VOXEL_ID; -voxel_id game_voxels::mud = NULL_VOXEL_ID; - -void game_voxels::populate(void) -{ - // Stone; the backbone of the generated world - game_voxels::stone = - world::voxel_registry::construct("stone", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/stone_01.png") - .add_texture_default("textures/voxel/stone_02.png") - .add_texture_default("textures/voxel/stone_03.png") - .add_texture_default("textures/voxel/stone_04.png") - .set_surface(world::voxel_surface::STONE) - .build(); - - // Cobblestone; should drop when a stone is broken, might also be present in surface features - game_voxels::cobblestone = - world::voxel_registry::construct("cobblestone", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/cobblestone_01.png") - .add_texture_default("textures/voxel/cobblestone_02.png") - .set_surface(world::voxel_surface::STONE) - .build(); - - // Dirt with a grass layer on top; the top layer of plains biome - game_voxels::grass = - world::voxel_registry::construct("grass", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/grass_side_01.png") - .add_texture_default("textures/voxel/grass_side_02.png") - .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_01.png") - .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_02.png") - .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_03.png") - .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_04.png") - .add_texture(world::voxel_face::CUBE_TOP, "textures/voxel/grass_01.png") - .add_texture(world::voxel_face::CUBE_TOP, "textures/voxel/grass_02.png") - .set_surface(world::voxel_surface::GRASS) - .build(); - - // Dirt; the under-surface layer of some biomes - game_voxels::dirt = - world::voxel_registry::construct("dirt", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/dirt_01.png") - .add_texture_default("textures/voxel/dirt_02.png") - .add_texture_default("textures/voxel/dirt_03.png") - .add_texture_default("textures/voxel/dirt_04.png") - .set_surface(world::voxel_surface::DIRT) - .build(); - - // VTest; a test voxel to ensure animations work - game_voxels::vtest = - world::voxel_registry::construct("vtest", world::voxel_type::CUBE, true, false) - .add_texture_default("textures/voxel/vtest_F1.png") - .add_texture_default("textures/voxel/vtest_F2.png") - .add_texture_default("textures/voxel/vtest_F3.png") - .add_texture_default("textures/voxel/vtest_F4.png") - .build(); - - // VTest-CK; a pure blue chromakey I used to make the game's logo - game_voxels::vtest_ck = - world::voxel_registry::construct("vtest_ck", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/chromakey.png") - .build(); - - // Oak leaves; greenery. TODO: add trees as surface features - game_voxels::oak_leaves = - world::voxel_registry::construct("oak_leaves", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/oak_leaves.png") - .set_surface(world::voxel_surface::GRASS) - .build(); - - // Oak planks; the thing that comes out of oak logs - game_voxels::oak_planks = - world::voxel_registry::construct("oak_planks", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/oak_planks_01.png") - .add_texture_default("textures/voxel/oak_planks_02.png") - .set_surface(world::voxel_surface::WOOD) - .build(); - - // Oak logs; greenery. TODO: add trees as surface features - game_voxels::oak_log = - world::voxel_registry::construct("oak_log", world::voxel_type::CUBE, false, false) - .add_texture_default("textures/voxel/oak_wood_01.png") - .add_texture_default("textures/voxel/oak_wood_02.png") - .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/oak_wood_top.png") - .add_texture(world::voxel_face::CUBE_TOP, "textures/voxel/oak_wood_top.png") - .set_surface(world::voxel_surface::WOOD) - .build(); - - // Glass; blend rendering test - game_voxels::glass = - world::voxel_registry::construct("glass", world::voxel_type::CUBE, false, true) - .add_texture_default("textures/voxel/glass_01.png") - .set_surface(world::voxel_surface::GLASS) - .build(); - - // Slime; it's bouncy! - game_voxels::slime = - world::voxel_registry::construct("slime", world::voxel_type::CUBE, false, true) - .set_touch(world::voxel_touch::BOUNCE, glm::fvec3(0.00f, 0.60f, 0.00f)) - .add_texture_default("textures/voxel/slime_01.png") - .build(); - - // Mud; you sink in it - game_voxels::mud = - world::voxel_registry::construct("mud", world::voxel_type::CUBE, false, false) - .set_touch(world::voxel_touch::SINK, glm::fvec3(0.50f, 0.75f, 0.50f)) - .add_texture_default("textures/voxel/mud_01.png") - .add_texture_default("textures/voxel/mud_02.png") - .set_surface(world::voxel_surface::DIRT) - .build(); -} +#include "shared/pch.hh"
+
+#include "shared/game_voxels.hh"
+
+#include "shared/world/voxel_registry.hh"
+
+voxel_id game_voxels::cobblestone = NULL_VOXEL_ID;
+voxel_id game_voxels::dirt = NULL_VOXEL_ID;
+voxel_id game_voxels::grass = NULL_VOXEL_ID;
+voxel_id game_voxels::stone = NULL_VOXEL_ID;
+voxel_id game_voxels::vtest = NULL_VOXEL_ID;
+voxel_id game_voxels::vtest_ck = NULL_VOXEL_ID;
+voxel_id game_voxels::oak_leaves = NULL_VOXEL_ID;
+voxel_id game_voxels::oak_planks = NULL_VOXEL_ID;
+voxel_id game_voxels::oak_log = NULL_VOXEL_ID;
+voxel_id game_voxels::glass = NULL_VOXEL_ID;
+voxel_id game_voxels::slime = NULL_VOXEL_ID;
+voxel_id game_voxels::mud = NULL_VOXEL_ID;
+
+void game_voxels::populate(void)
+{
+ // Stone; the backbone of the generated world
+ game_voxels::stone =
+ world::voxel_registry::construct("stone", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/stone_01.png")
+ .add_texture_default("textures/voxel/stone_02.png")
+ .add_texture_default("textures/voxel/stone_03.png")
+ .add_texture_default("textures/voxel/stone_04.png")
+ .set_surface(world::voxel_surface::STONE)
+ .build();
+
+ // Cobblestone; should drop when a stone is broken, might also be present in surface features
+ game_voxels::cobblestone =
+ world::voxel_registry::construct("cobblestone", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/cobblestone_01.png")
+ .add_texture_default("textures/voxel/cobblestone_02.png")
+ .set_surface(world::voxel_surface::STONE)
+ .build();
+
+ // Dirt with a grass layer on top; the top layer of plains biome
+ game_voxels::grass =
+ world::voxel_registry::construct("grass", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/grass_side_01.png")
+ .add_texture_default("textures/voxel/grass_side_02.png")
+ .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_01.png")
+ .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_02.png")
+ .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_03.png")
+ .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_04.png")
+ .add_texture(world::voxel_face::CUBE_TOP, "textures/voxel/grass_01.png")
+ .add_texture(world::voxel_face::CUBE_TOP, "textures/voxel/grass_02.png")
+ .set_surface(world::voxel_surface::GRASS)
+ .build();
+
+ // Dirt; the under-surface layer of some biomes
+ game_voxels::dirt =
+ world::voxel_registry::construct("dirt", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/dirt_01.png")
+ .add_texture_default("textures/voxel/dirt_02.png")
+ .add_texture_default("textures/voxel/dirt_03.png")
+ .add_texture_default("textures/voxel/dirt_04.png")
+ .set_surface(world::voxel_surface::DIRT)
+ .build();
+
+ // VTest; a test voxel to ensure animations work
+ game_voxels::vtest = world::voxel_registry::construct("vtest", world::voxel_type::CUBE, true, false)
+ .add_texture_default("textures/voxel/vtest_F1.png")
+ .add_texture_default("textures/voxel/vtest_F2.png")
+ .add_texture_default("textures/voxel/vtest_F3.png")
+ .add_texture_default("textures/voxel/vtest_F4.png")
+ .build();
+
+ // VTest-CK; a pure blue chromakey I used to make the game's logo
+ game_voxels::vtest_ck = world::voxel_registry::construct("vtest_ck", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/chromakey.png")
+ .build();
+
+ // Oak leaves; greenery. TODO: add trees as surface features
+ game_voxels::oak_leaves = world::voxel_registry::construct("oak_leaves", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/oak_leaves.png")
+ .set_surface(world::voxel_surface::GRASS)
+ .build();
+
+ // Oak planks; the thing that comes out of oak logs
+ game_voxels::oak_planks = world::voxel_registry::construct("oak_planks", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/oak_planks_01.png")
+ .add_texture_default("textures/voxel/oak_planks_02.png")
+ .set_surface(world::voxel_surface::WOOD)
+ .build();
+
+ // Oak logs; greenery. TODO: add trees as surface features
+ game_voxels::oak_log =
+ world::voxel_registry::construct("oak_log", world::voxel_type::CUBE, false, false)
+ .add_texture_default("textures/voxel/oak_wood_01.png")
+ .add_texture_default("textures/voxel/oak_wood_02.png")
+ .add_texture(world::voxel_face::CUBE_BOTTOM, "textures/voxel/oak_wood_top.png")
+ .add_texture(world::voxel_face::CUBE_TOP, "textures/voxel/oak_wood_top.png")
+ .set_surface(world::voxel_surface::WOOD)
+ .build();
+
+ // Glass; blend rendering test
+ game_voxels::glass = world::voxel_registry::construct("glass", world::voxel_type::CUBE, false, true)
+ .add_texture_default("textures/voxel/glass_01.png")
+ .set_surface(world::voxel_surface::GLASS)
+ .build();
+
+ // Slime; it's bouncy!
+ game_voxels::slime = world::voxel_registry::construct("slime", world::voxel_type::CUBE, false, true)
+ .set_touch(world::voxel_touch::BOUNCE, glm::fvec3(0.00f, 0.60f, 0.00f))
+ .add_texture_default("textures/voxel/slime_01.png")
+ .build();
+
+ // Mud; you sink in it
+ game_voxels::mud = world::voxel_registry::construct("mud", world::voxel_type::CUBE, false, false)
+ .set_touch(world::voxel_touch::SINK, glm::fvec3(0.50f, 0.75f, 0.50f))
+ .add_texture_default("textures/voxel/mud_01.png")
+ .add_texture_default("textures/voxel/mud_02.png")
+ .set_surface(world::voxel_surface::DIRT)
+ .build();
+}
diff --git a/game/shared/game_voxels.hh b/game/shared/game_voxels.hh index e96e141..21102d0 100644 --- a/game/shared/game_voxels.hh +++ b/game/shared/game_voxels.hh @@ -1,28 +1,28 @@ -#ifndef SHARED_GAME_VOXELS -#define SHARED_GAME_VOXELS 1 -#pragma once - -#include "shared/types.hh" - -namespace game_voxels -{ -extern voxel_id cobblestone; -extern voxel_id dirt; -extern voxel_id grass; -extern voxel_id stone; -extern voxel_id vtest; -extern voxel_id vtest_ck; -extern voxel_id oak_leaves; -extern voxel_id oak_planks; -extern voxel_id oak_log; -extern voxel_id glass; -extern voxel_id slime; -extern voxel_id mud; -} // namespace game_voxels - -namespace game_voxels -{ -void populate(void); -} // namespace game_voxels - -#endif // SHARED_GAME_VOXELS +#ifndef SHARED_GAME_VOXELS
+#define SHARED_GAME_VOXELS 1
+#pragma once
+
+#include "shared/types.hh"
+
+namespace game_voxels
+{
+extern voxel_id cobblestone;
+extern voxel_id dirt;
+extern voxel_id grass;
+extern voxel_id stone;
+extern voxel_id vtest;
+extern voxel_id vtest_ck;
+extern voxel_id oak_leaves;
+extern voxel_id oak_planks;
+extern voxel_id oak_log;
+extern voxel_id glass;
+extern voxel_id slime;
+extern voxel_id mud;
+} // namespace game_voxels
+
+namespace game_voxels
+{
+void populate(void);
+} // namespace game_voxels
+
+#endif // SHARED_GAME_VOXELS
diff --git a/game/shared/globals.cc b/game/shared/globals.cc index 8552214..1651402 100644 --- a/game/shared/globals.cc +++ b/game/shared/globals.cc @@ -1,12 +1,12 @@ -#include "shared/pch.hh" - -#include "shared/globals.hh" - -entt::dispatcher globals::dispatcher; - -float globals::fixed_frametime; -float globals::fixed_frametime_avg; -std::uint64_t globals::fixed_frametime_us; -std::size_t globals::fixed_framecount; - -std::uint64_t globals::curtime; +#include "shared/pch.hh"
+
+#include "shared/globals.hh"
+
+entt::dispatcher globals::dispatcher;
+
+float globals::fixed_frametime;
+float globals::fixed_frametime_avg;
+std::uint64_t globals::fixed_frametime_us;
+std::size_t globals::fixed_framecount;
+
+std::uint64_t globals::curtime;
diff --git a/game/shared/globals.hh b/game/shared/globals.hh index 39a12a7..4a5afd1 100644 --- a/game/shared/globals.hh +++ b/game/shared/globals.hh @@ -1,19 +1,19 @@ -#pragma once - -namespace globals -{ -extern entt::dispatcher dispatcher; -} // namespace globals - -namespace globals -{ -extern float fixed_frametime; -extern float fixed_frametime_avg; -extern std::uint64_t fixed_frametime_us; -extern std::size_t fixed_framecount; -} // namespace globals - -namespace globals -{ -extern std::uint64_t curtime; -} // namespace globals +#pragma once
+
+namespace globals
+{
+extern entt::dispatcher dispatcher;
+} // namespace globals
+
+namespace globals
+{
+extern float fixed_frametime;
+extern float fixed_frametime_avg;
+extern std::uint64_t fixed_frametime_us;
+extern std::size_t fixed_framecount;
+} // namespace globals
+
+namespace globals
+{
+extern std::uint64_t curtime;
+} // namespace globals
diff --git a/game/shared/pch.hh b/game/shared/pch.hh index e978e0f..438f82a 100644 --- a/game/shared/pch.hh +++ b/game/shared/pch.hh @@ -1,19 +1,19 @@ -#pragma once - -#include <core/pch.hh> // inherit dependent includes from core.lib - -#include <csignal> - -#include <enet/enet.h> - -#include <entt/entity/registry.hpp> -#include <entt/signal/dispatcher.hpp> - -#include <fastnoiselite.h> - -#include <miniz.h> - -#include <parson.h> - -#include <spdlog/sinks/basic_file_sink.h> -#include <spdlog/sinks/stdout_color_sinks.h> +#pragma once
+
+#include <core/pch.hh> // inherit dependent includes from core.lib
+
+#include <csignal>
+
+#include <enet/enet.h>
+
+#include <entt/entity/registry.hpp>
+#include <entt/signal/dispatcher.hpp>
+
+#include <fastnoiselite.h>
+
+#include <miniz.h>
+
+#include <parson.h>
+
+#include <spdlog/sinks/basic_file_sink.h>
+#include <spdlog/sinks/stdout_color_sinks.h>
diff --git a/game/shared/protocol.cc b/game/shared/protocol.cc index 6c18658..576502e 100644 --- a/game/shared/protocol.cc +++ b/game/shared/protocol.cc @@ -1,510 +1,510 @@ -#include "shared/pch.hh" - -#include "shared/protocol.hh" - -#include "core/io/buffer.hh" - -#include "shared/entity/head.hh" -#include "shared/entity/player.hh" -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/chunk.hh" -#include "shared/world/dimension.hh" - -#include "shared/globals.hh" - -static io::ReadBuffer read_buffer; -static io::WriteBuffer write_buffer; - -ENetPacket* protocol::encode(const protocol::StatusRequest& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::StatusRequest::ID); - write_buffer.write<std::uint32_t>(packet.version); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::StatusResponse& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::StatusResponse::ID); - write_buffer.write<std::uint32_t>(packet.version); - write_buffer.write<std::uint16_t>(packet.max_players); - write_buffer.write<std::uint16_t>(packet.num_players); - write_buffer.write<std::string_view>(packet.motd); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::LoginRequest& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::LoginRequest::ID); - write_buffer.write<std::uint32_t>(packet.version); - write_buffer.write<std::uint64_t>(packet.voxel_registry_checksum); - write_buffer.write<std::uint64_t>(packet.item_registry_checksum); - write_buffer.write<std::uint64_t>(packet.password_hash); - write_buffer.write<std::string_view>(packet.username.substr(0, protocol::MAX_USERNAME)); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::LoginResponse& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::LoginResponse::ID); - write_buffer.write<std::uint16_t>(packet.client_index); - write_buffer.write<std::uint64_t>(packet.client_identity); - write_buffer.write<std::uint16_t>(packet.server_tickrate); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::Disconnect& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::Disconnect::ID); - write_buffer.write<std::string_view>(packet.reason); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::ChunkVoxels& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::ChunkVoxels::ID); - write_buffer.write<std::int32_t>(packet.chunk.x); - write_buffer.write<std::int32_t>(packet.chunk.y); - write_buffer.write<std::int32_t>(packet.chunk.z); - packet.voxels.serialize(write_buffer); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::EntityTransform& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::EntityTransform::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - write_buffer.write<std::int32_t>(packet.chunk.x); - write_buffer.write<std::int32_t>(packet.chunk.y); - write_buffer.write<std::int32_t>(packet.chunk.z); - write_buffer.write<float>(packet.local.x); - write_buffer.write<float>(packet.local.y); - write_buffer.write<float>(packet.local.z); - write_buffer.write<float>(packet.angles.x); - write_buffer.write<float>(packet.angles.y); - write_buffer.write<float>(packet.angles.z); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::EntityHead& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::EntityHead::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - write_buffer.write<float>(packet.angles.x); - write_buffer.write<float>(packet.angles.y); - write_buffer.write<float>(packet.angles.z); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::EntityVelocity& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::EntityVelocity::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - write_buffer.write<float>(packet.value.x); - write_buffer.write<float>(packet.value.y); - write_buffer.write<float>(packet.value.z); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::SpawnPlayer& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::SpawnPlayer::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::ChatMessage& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::ChatMessage::ID); - write_buffer.write<std::uint16_t>(packet.type); - write_buffer.write<std::string_view>(packet.sender.substr(0, protocol::MAX_USERNAME)); - write_buffer.write<std::string_view>(packet.message.substr(0, protocol::MAX_CHAT)); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::SetVoxel& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::SetVoxel::ID); - write_buffer.write<std::int64_t>(packet.vpos.x); - write_buffer.write<std::int64_t>(packet.vpos.y); - write_buffer.write<std::int64_t>(packet.vpos.z); - write_buffer.write<std::uint16_t>(packet.voxel); - write_buffer.write<std::uint16_t>(packet.flags); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::RemoveEntity& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::RemoveEntity::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::EntityPlayer& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::EntityPlayer::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::ScoreboardUpdate& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::ScoreboardUpdate::ID); - write_buffer.write<std::uint16_t>(static_cast<std::uint16_t>(packet.names.size())); - for(const std::string& username : packet.names) - write_buffer.write<std::string_view>(username.substr(0, protocol::MAX_USERNAME)); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::RequestChunk& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::RequestChunk::ID); - write_buffer.write<std::int32_t>(packet.cpos.x); - write_buffer.write<std::int32_t>(packet.cpos.y); - write_buffer.write<std::int32_t>(packet.cpos.z); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::GenericSound& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::GenericSound::ID); - write_buffer.write<std::string_view>(packet.sound.substr(0, protocol::MAX_SOUNDNAME)); - write_buffer.write<std::uint8_t>(packet.looping); - write_buffer.write<float>(packet.pitch); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::EntitySound& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::EntitySound::ID); - write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity)); - write_buffer.write<std::string_view>(packet.sound.substr(0, protocol::MAX_SOUNDNAME)); - write_buffer.write<std::uint8_t>(packet.looping); - write_buffer.write<float>(packet.pitch); - return write_buffer.to_packet(flags); -} - -ENetPacket* protocol::encode(const protocol::DimensionInfo& packet, enet_uint32 flags) -{ - write_buffer.reset(); - write_buffer.write<std::uint16_t>(protocol::DimensionInfo::ID); - write_buffer.write<std::string_view>(packet.name); - write_buffer.write<float>(packet.gravity); - return write_buffer.to_packet(flags); -} - -void protocol::broadcast(ENetHost* host, ENetPacket* packet) -{ - if(packet) { - enet_host_broadcast(host, protocol::CHANNEL, packet); - } -} - -void protocol::broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except) -{ - if(packet) { - for(unsigned int i = 0U; i < host->peerCount; ++i) { - if(host->peers[i].state == ENET_PEER_STATE_CONNECTED) { - if(&host->peers[i] != except) { - enet_peer_send(&host->peers[i], protocol::CHANNEL, packet); - } - } - } - } -} - -void protocol::send(ENetPeer* peer, ENetPacket* packet) -{ - if(packet) { - enet_peer_send(peer, protocol::CHANNEL, packet); - } -} - -void protocol::decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer) -{ - read_buffer.reset(packet); - - protocol::StatusRequest status_request; - protocol::StatusResponse status_response; - protocol::LoginRequest login_request; - protocol::LoginResponse login_response; - protocol::Disconnect disconnect; - protocol::ChunkVoxels chunk_voxels; - protocol::EntityTransform entity_transform; - protocol::EntityHead entity_head; - protocol::EntityVelocity entity_velocity; - protocol::SpawnPlayer spawn_player; - protocol::ChatMessage chat_message; - protocol::SetVoxel set_voxel; - protocol::RemoveEntity remove_entity; - protocol::EntityPlayer entity_player; - protocol::ScoreboardUpdate scoreboard_update; - protocol::RequestChunk request_chunk; - protocol::GenericSound generic_sound; - protocol::EntitySound entity_sound; - protocol::DimensionInfo dimension_info; - - auto id = read_buffer.read<std::uint16_t>(); - - switch(id) { - case protocol::StatusRequest::ID: - status_request.peer = peer; - status_request.version = read_buffer.read<std::uint32_t>(); - dispatcher.trigger(status_request); - break; - - case protocol::StatusResponse::ID: - status_response.peer = peer; - status_response.version = read_buffer.read<std::uint32_t>(); - status_response.max_players = read_buffer.read<std::uint16_t>(); - status_response.num_players = read_buffer.read<std::uint16_t>(); - status_response.motd = read_buffer.read<std::string>(); - dispatcher.trigger(status_response); - break; - - case protocol::LoginRequest::ID: - login_request.peer = peer; - login_request.version = read_buffer.read<std::uint32_t>(); - login_request.voxel_registry_checksum = read_buffer.read<std::uint64_t>(); - login_request.item_registry_checksum = read_buffer.read<std::uint64_t>(); - login_request.password_hash = read_buffer.read<std::uint64_t>(); - login_request.username = read_buffer.read<std::string>(); - dispatcher.trigger(login_request); - break; - - case protocol::LoginResponse::ID: - login_response.peer = peer; - login_response.client_index = read_buffer.read<std::uint16_t>(); - login_response.client_identity = read_buffer.read<std::uint64_t>(); - login_response.server_tickrate = read_buffer.read<std::uint16_t>(); - dispatcher.trigger(login_response); - break; - - case protocol::Disconnect::ID: - disconnect.peer = peer; - disconnect.reason = read_buffer.read<std::string>(); - dispatcher.trigger(disconnect); - break; - - case protocol::ChunkVoxels::ID: - chunk_voxels.peer = peer; - chunk_voxels.chunk.x = read_buffer.read<std::int32_t>(); - chunk_voxels.chunk.y = read_buffer.read<std::int32_t>(); - chunk_voxels.chunk.z = read_buffer.read<std::int32_t>(); - chunk_voxels.voxels.deserialize(read_buffer); - dispatcher.trigger(chunk_voxels); - break; - - case protocol::EntityTransform::ID: - entity_transform.peer = peer; - entity_transform.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - entity_transform.chunk.x = read_buffer.read<std::int32_t>(); - entity_transform.chunk.y = read_buffer.read<std::int32_t>(); - entity_transform.chunk.z = read_buffer.read<std::int32_t>(); - entity_transform.local.x = read_buffer.read<float>(); - entity_transform.local.y = read_buffer.read<float>(); - entity_transform.local.z = read_buffer.read<float>(); - entity_transform.angles.x = read_buffer.read<float>(); - entity_transform.angles.y = read_buffer.read<float>(); - entity_transform.angles.z = read_buffer.read<float>(); - dispatcher.trigger(entity_transform); - break; - - case protocol::EntityHead::ID: - entity_head.peer = peer; - entity_head.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - entity_head.angles[0] = read_buffer.read<float>(); - entity_head.angles[1] = read_buffer.read<float>(); - entity_head.angles[2] = read_buffer.read<float>(); - dispatcher.trigger(entity_head); - break; - - case protocol::EntityVelocity::ID: - entity_velocity.peer = peer; - entity_velocity.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - entity_velocity.value.x = read_buffer.read<float>(); - entity_velocity.value.y = read_buffer.read<float>(); - entity_velocity.value.z = read_buffer.read<float>(); - dispatcher.trigger(entity_velocity); - break; - - case protocol::SpawnPlayer::ID: - spawn_player.peer = peer; - spawn_player.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - dispatcher.trigger(spawn_player); - break; - - case protocol::ChatMessage::ID: - chat_message.peer = peer; - chat_message.type = read_buffer.read<std::uint16_t>(); - chat_message.sender = read_buffer.read<std::string>(); - chat_message.message = read_buffer.read<std::string>(); - dispatcher.trigger(chat_message); - break; - - case protocol::SetVoxel::ID: - set_voxel.peer = peer; - set_voxel.vpos.x = read_buffer.read<std::int64_t>(); - set_voxel.vpos.y = read_buffer.read<std::int64_t>(); - set_voxel.vpos.z = read_buffer.read<std::int64_t>(); - set_voxel.voxel = read_buffer.read<std::uint16_t>(); - set_voxel.flags = read_buffer.read<std::uint16_t>(); - dispatcher.trigger(set_voxel); - break; - - case protocol::RemoveEntity::ID: - remove_entity.peer = peer; - remove_entity.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - dispatcher.trigger(remove_entity); - break; - - case protocol::EntityPlayer::ID: - entity_player.peer = peer; - entity_player.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - dispatcher.trigger(entity_player); - break; - - case protocol::ScoreboardUpdate::ID: - scoreboard_update.peer = peer; - scoreboard_update.names.resize(read_buffer.read<std::uint16_t>()); - for(std::size_t i = 0; i < scoreboard_update.names.size(); ++i) - scoreboard_update.names[i] = read_buffer.read<std::string>(); - dispatcher.trigger(scoreboard_update); - break; - - case protocol::RequestChunk::ID: - request_chunk.peer = peer; - request_chunk.cpos.x = read_buffer.read<std::uint32_t>(); - request_chunk.cpos.y = read_buffer.read<std::uint32_t>(); - request_chunk.cpos.z = read_buffer.read<std::uint32_t>(); - dispatcher.trigger(request_chunk); - break; - - case protocol::GenericSound::ID: - generic_sound.peer = peer; - generic_sound.sound = read_buffer.read<std::string>(); - generic_sound.looping = read_buffer.read<std::uint8_t>(); - generic_sound.pitch = read_buffer.read<float>(); - dispatcher.trigger(generic_sound); - break; - - case protocol::EntitySound::ID: - entity_sound.peer = peer; - entity_sound.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>()); - entity_sound.sound = read_buffer.read<std::string>(); - entity_sound.looping = read_buffer.read<std::uint8_t>(); - entity_sound.pitch = read_buffer.read<float>(); - dispatcher.trigger(entity_sound); - break; - - case protocol::DimensionInfo::ID: - dimension_info.peer = peer; - dimension_info.name = read_buffer.read<std::string>(); - dimension_info.gravity = read_buffer.read<float>(); - dispatcher.trigger(dimension_info); - break; - } -} - -ENetPacket* protocol::utils::make_disconnect(std::string_view reason, enet_uint32 flags) -{ - protocol::Disconnect packet; - packet.reason = reason; - return protocol::encode(packet, flags); -} - -ENetPacket* protocol::utils::make_chat_message(std::string_view message, enet_uint32 flags) -{ - protocol::ChatMessage packet; - packet.type = protocol::ChatMessage::TEXT_MESSAGE; - packet.message = message; - return protocol::encode(packet, flags); -} - -ENetPacket* protocol::utils::make_chunk_voxels(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) -{ - if(auto component = dimension->chunks.try_get<world::ChunkComponent>(entity)) { - protocol::ChunkVoxels packet; - packet.chunk = component->cpos; - packet.voxels = component->chunk->get_voxels(); - return protocol::encode(packet, flags); - } - - return nullptr; -} - -ENetPacket* protocol::utils::make_entity_head(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) -{ - if(auto component = dimension->entities.try_get<entity::Head>(entity)) { - protocol::EntityHead packet; - packet.entity = entity; - packet.angles = component->angles; - return protocol::encode(packet, flags); - } - - return nullptr; -} - -ENetPacket* protocol::utils::make_entity_transform(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) -{ - if(auto component = dimension->entities.try_get<entity::Transform>(entity)) { - protocol::EntityTransform packet; - packet.entity = entity; - packet.chunk = component->chunk; - packet.local = component->local; - packet.angles = component->angles; - return protocol::encode(packet, flags); - } - - return nullptr; -} - -ENetPacket* protocol::utils::make_entity_velocity(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) -{ - if(auto component = dimension->entities.try_get<entity::Velocity>(entity)) { - protocol::EntityVelocity packet; - packet.entity = entity; - packet.value = component->value; - return protocol::encode(packet, flags); - } - - return nullptr; -} - -ENetPacket* protocol::utils::make_entity_player(world::Dimension* dimension, entt::entity entity, enet_uint32 flags) -{ - if(dimension->entities.any_of<entity::Player>(entity)) { - protocol::EntityPlayer packet; - packet.entity = entity; - return protocol::encode(packet, flags); - } - - return nullptr; -} - -ENetPacket* protocol::utils::make_dimension_info(const world::Dimension* dimension) -{ - protocol::DimensionInfo packet; - packet.name = dimension->get_name(); - packet.gravity = dimension->get_gravity(); - return protocol::encode(packet, ENET_PACKET_FLAG_RELIABLE); -} +#include "shared/pch.hh"
+
+#include "shared/protocol.hh"
+
+#include "core/io/buffer.hh"
+
+#include "shared/entity/head.hh"
+#include "shared/entity/player.hh"
+#include "shared/entity/transform.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/chunk.hh"
+#include "shared/world/dimension.hh"
+
+#include "shared/globals.hh"
+
+static io::ReadBuffer read_buffer;
+static io::WriteBuffer write_buffer;
+
+ENetPacket* protocol::encode(const protocol::StatusRequest& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::StatusRequest::ID);
+ write_buffer.write<std::uint32_t>(packet.version);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::StatusResponse& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::StatusResponse::ID);
+ write_buffer.write<std::uint32_t>(packet.version);
+ write_buffer.write<std::uint16_t>(packet.max_players);
+ write_buffer.write<std::uint16_t>(packet.num_players);
+ write_buffer.write<std::string_view>(packet.motd);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::LoginRequest& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::LoginRequest::ID);
+ write_buffer.write<std::uint32_t>(packet.version);
+ write_buffer.write<std::uint64_t>(packet.voxel_registry_checksum);
+ write_buffer.write<std::uint64_t>(packet.item_registry_checksum);
+ write_buffer.write<std::uint64_t>(packet.password_hash);
+ write_buffer.write<std::string_view>(packet.username.substr(0, protocol::MAX_USERNAME));
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::LoginResponse& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::LoginResponse::ID);
+ write_buffer.write<std::uint16_t>(packet.client_index);
+ write_buffer.write<std::uint64_t>(packet.client_identity);
+ write_buffer.write<std::uint16_t>(packet.server_tickrate);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::Disconnect& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::Disconnect::ID);
+ write_buffer.write<std::string_view>(packet.reason);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::ChunkVoxels& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::ChunkVoxels::ID);
+ write_buffer.write<std::int32_t>(packet.chunk.x);
+ write_buffer.write<std::int32_t>(packet.chunk.y);
+ write_buffer.write<std::int32_t>(packet.chunk.z);
+ packet.voxels.serialize(write_buffer);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::EntityTransform& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::EntityTransform::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ write_buffer.write<std::int32_t>(packet.chunk.x);
+ write_buffer.write<std::int32_t>(packet.chunk.y);
+ write_buffer.write<std::int32_t>(packet.chunk.z);
+ write_buffer.write<float>(packet.local.x);
+ write_buffer.write<float>(packet.local.y);
+ write_buffer.write<float>(packet.local.z);
+ write_buffer.write<float>(packet.angles.x);
+ write_buffer.write<float>(packet.angles.y);
+ write_buffer.write<float>(packet.angles.z);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::EntityHead& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::EntityHead::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ write_buffer.write<float>(packet.angles.x);
+ write_buffer.write<float>(packet.angles.y);
+ write_buffer.write<float>(packet.angles.z);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::EntityVelocity& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::EntityVelocity::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ write_buffer.write<float>(packet.value.x);
+ write_buffer.write<float>(packet.value.y);
+ write_buffer.write<float>(packet.value.z);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::SpawnPlayer& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::SpawnPlayer::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::ChatMessage& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::ChatMessage::ID);
+ write_buffer.write<std::uint16_t>(packet.type);
+ write_buffer.write<std::string_view>(packet.sender.substr(0, protocol::MAX_USERNAME));
+ write_buffer.write<std::string_view>(packet.message.substr(0, protocol::MAX_CHAT));
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::SetVoxel& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::SetVoxel::ID);
+ write_buffer.write<std::int64_t>(packet.vpos.x);
+ write_buffer.write<std::int64_t>(packet.vpos.y);
+ write_buffer.write<std::int64_t>(packet.vpos.z);
+ write_buffer.write<std::uint16_t>(packet.voxel);
+ write_buffer.write<std::uint16_t>(packet.flags);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::RemoveEntity& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::RemoveEntity::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::EntityPlayer& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::EntityPlayer::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::ScoreboardUpdate& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::ScoreboardUpdate::ID);
+ write_buffer.write<std::uint16_t>(static_cast<std::uint16_t>(packet.names.size()));
+ for(const std::string& username : packet.names)
+ write_buffer.write<std::string_view>(username.substr(0, protocol::MAX_USERNAME));
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::RequestChunk& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::RequestChunk::ID);
+ write_buffer.write<std::int32_t>(packet.cpos.x);
+ write_buffer.write<std::int32_t>(packet.cpos.y);
+ write_buffer.write<std::int32_t>(packet.cpos.z);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::GenericSound& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::GenericSound::ID);
+ write_buffer.write<std::string_view>(packet.sound.substr(0, protocol::MAX_SOUNDNAME));
+ write_buffer.write<std::uint8_t>(packet.looping);
+ write_buffer.write<float>(packet.pitch);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::EntitySound& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::EntitySound::ID);
+ write_buffer.write<std::uint64_t>(static_cast<std::uint64_t>(packet.entity));
+ write_buffer.write<std::string_view>(packet.sound.substr(0, protocol::MAX_SOUNDNAME));
+ write_buffer.write<std::uint8_t>(packet.looping);
+ write_buffer.write<float>(packet.pitch);
+ return write_buffer.to_packet(flags);
+}
+
+ENetPacket* protocol::encode(const protocol::DimensionInfo& packet, enet_uint32 flags)
+{
+ write_buffer.reset();
+ write_buffer.write<std::uint16_t>(protocol::DimensionInfo::ID);
+ write_buffer.write<std::string_view>(packet.name);
+ write_buffer.write<float>(packet.gravity);
+ return write_buffer.to_packet(flags);
+}
+
+void protocol::broadcast(ENetHost* host, ENetPacket* packet)
+{
+ if(packet) {
+ enet_host_broadcast(host, protocol::CHANNEL, packet);
+ }
+}
+
+void protocol::broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except)
+{
+ if(packet) {
+ for(unsigned int i = 0U; i < host->peerCount; ++i) {
+ if(host->peers[i].state == ENET_PEER_STATE_CONNECTED) {
+ if(&host->peers[i] != except) {
+ enet_peer_send(&host->peers[i], protocol::CHANNEL, packet);
+ }
+ }
+ }
+ }
+}
+
+void protocol::send(ENetPeer* peer, ENetPacket* packet)
+{
+ if(packet) {
+ enet_peer_send(peer, protocol::CHANNEL, packet);
+ }
+}
+
+void protocol::decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer)
+{
+ read_buffer.reset(packet);
+
+ protocol::StatusRequest status_request;
+ protocol::StatusResponse status_response;
+ protocol::LoginRequest login_request;
+ protocol::LoginResponse login_response;
+ protocol::Disconnect disconnect;
+ protocol::ChunkVoxels chunk_voxels;
+ protocol::EntityTransform entity_transform;
+ protocol::EntityHead entity_head;
+ protocol::EntityVelocity entity_velocity;
+ protocol::SpawnPlayer spawn_player;
+ protocol::ChatMessage chat_message;
+ protocol::SetVoxel set_voxel;
+ protocol::RemoveEntity remove_entity;
+ protocol::EntityPlayer entity_player;
+ protocol::ScoreboardUpdate scoreboard_update;
+ protocol::RequestChunk request_chunk;
+ protocol::GenericSound generic_sound;
+ protocol::EntitySound entity_sound;
+ protocol::DimensionInfo dimension_info;
+
+ auto id = read_buffer.read<std::uint16_t>();
+
+ switch(id) {
+ case protocol::StatusRequest::ID:
+ status_request.peer = peer;
+ status_request.version = read_buffer.read<std::uint32_t>();
+ dispatcher.trigger(status_request);
+ break;
+
+ case protocol::StatusResponse::ID:
+ status_response.peer = peer;
+ status_response.version = read_buffer.read<std::uint32_t>();
+ status_response.max_players = read_buffer.read<std::uint16_t>();
+ status_response.num_players = read_buffer.read<std::uint16_t>();
+ status_response.motd = read_buffer.read<std::string>();
+ dispatcher.trigger(status_response);
+ break;
+
+ case protocol::LoginRequest::ID:
+ login_request.peer = peer;
+ login_request.version = read_buffer.read<std::uint32_t>();
+ login_request.voxel_registry_checksum = read_buffer.read<std::uint64_t>();
+ login_request.item_registry_checksum = read_buffer.read<std::uint64_t>();
+ login_request.password_hash = read_buffer.read<std::uint64_t>();
+ login_request.username = read_buffer.read<std::string>();
+ dispatcher.trigger(login_request);
+ break;
+
+ case protocol::LoginResponse::ID:
+ login_response.peer = peer;
+ login_response.client_index = read_buffer.read<std::uint16_t>();
+ login_response.client_identity = read_buffer.read<std::uint64_t>();
+ login_response.server_tickrate = read_buffer.read<std::uint16_t>();
+ dispatcher.trigger(login_response);
+ break;
+
+ case protocol::Disconnect::ID:
+ disconnect.peer = peer;
+ disconnect.reason = read_buffer.read<std::string>();
+ dispatcher.trigger(disconnect);
+ break;
+
+ case protocol::ChunkVoxels::ID:
+ chunk_voxels.peer = peer;
+ chunk_voxels.chunk.x = read_buffer.read<std::int32_t>();
+ chunk_voxels.chunk.y = read_buffer.read<std::int32_t>();
+ chunk_voxels.chunk.z = read_buffer.read<std::int32_t>();
+ chunk_voxels.voxels.deserialize(read_buffer);
+ dispatcher.trigger(chunk_voxels);
+ break;
+
+ case protocol::EntityTransform::ID:
+ entity_transform.peer = peer;
+ entity_transform.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ entity_transform.chunk.x = read_buffer.read<std::int32_t>();
+ entity_transform.chunk.y = read_buffer.read<std::int32_t>();
+ entity_transform.chunk.z = read_buffer.read<std::int32_t>();
+ entity_transform.local.x = read_buffer.read<float>();
+ entity_transform.local.y = read_buffer.read<float>();
+ entity_transform.local.z = read_buffer.read<float>();
+ entity_transform.angles.x = read_buffer.read<float>();
+ entity_transform.angles.y = read_buffer.read<float>();
+ entity_transform.angles.z = read_buffer.read<float>();
+ dispatcher.trigger(entity_transform);
+ break;
+
+ case protocol::EntityHead::ID:
+ entity_head.peer = peer;
+ entity_head.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ entity_head.angles[0] = read_buffer.read<float>();
+ entity_head.angles[1] = read_buffer.read<float>();
+ entity_head.angles[2] = read_buffer.read<float>();
+ dispatcher.trigger(entity_head);
+ break;
+
+ case protocol::EntityVelocity::ID:
+ entity_velocity.peer = peer;
+ entity_velocity.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ entity_velocity.value.x = read_buffer.read<float>();
+ entity_velocity.value.y = read_buffer.read<float>();
+ entity_velocity.value.z = read_buffer.read<float>();
+ dispatcher.trigger(entity_velocity);
+ break;
+
+ case protocol::SpawnPlayer::ID:
+ spawn_player.peer = peer;
+ spawn_player.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ dispatcher.trigger(spawn_player);
+ break;
+
+ case protocol::ChatMessage::ID:
+ chat_message.peer = peer;
+ chat_message.type = read_buffer.read<std::uint16_t>();
+ chat_message.sender = read_buffer.read<std::string>();
+ chat_message.message = read_buffer.read<std::string>();
+ dispatcher.trigger(chat_message);
+ break;
+
+ case protocol::SetVoxel::ID:
+ set_voxel.peer = peer;
+ set_voxel.vpos.x = read_buffer.read<std::int64_t>();
+ set_voxel.vpos.y = read_buffer.read<std::int64_t>();
+ set_voxel.vpos.z = read_buffer.read<std::int64_t>();
+ set_voxel.voxel = read_buffer.read<std::uint16_t>();
+ set_voxel.flags = read_buffer.read<std::uint16_t>();
+ dispatcher.trigger(set_voxel);
+ break;
+
+ case protocol::RemoveEntity::ID:
+ remove_entity.peer = peer;
+ remove_entity.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ dispatcher.trigger(remove_entity);
+ break;
+
+ case protocol::EntityPlayer::ID:
+ entity_player.peer = peer;
+ entity_player.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ dispatcher.trigger(entity_player);
+ break;
+
+ case protocol::ScoreboardUpdate::ID:
+ scoreboard_update.peer = peer;
+ scoreboard_update.names.resize(read_buffer.read<std::uint16_t>());
+ for(std::size_t i = 0; i < scoreboard_update.names.size(); ++i)
+ scoreboard_update.names[i] = read_buffer.read<std::string>();
+ dispatcher.trigger(scoreboard_update);
+ break;
+
+ case protocol::RequestChunk::ID:
+ request_chunk.peer = peer;
+ request_chunk.cpos.x = read_buffer.read<std::uint32_t>();
+ request_chunk.cpos.y = read_buffer.read<std::uint32_t>();
+ request_chunk.cpos.z = read_buffer.read<std::uint32_t>();
+ dispatcher.trigger(request_chunk);
+ break;
+
+ case protocol::GenericSound::ID:
+ generic_sound.peer = peer;
+ generic_sound.sound = read_buffer.read<std::string>();
+ generic_sound.looping = read_buffer.read<std::uint8_t>();
+ generic_sound.pitch = read_buffer.read<float>();
+ dispatcher.trigger(generic_sound);
+ break;
+
+ case protocol::EntitySound::ID:
+ entity_sound.peer = peer;
+ entity_sound.entity = static_cast<entt::entity>(read_buffer.read<std::uint64_t>());
+ entity_sound.sound = read_buffer.read<std::string>();
+ entity_sound.looping = read_buffer.read<std::uint8_t>();
+ entity_sound.pitch = read_buffer.read<float>();
+ dispatcher.trigger(entity_sound);
+ break;
+
+ case protocol::DimensionInfo::ID:
+ dimension_info.peer = peer;
+ dimension_info.name = read_buffer.read<std::string>();
+ dimension_info.gravity = read_buffer.read<float>();
+ dispatcher.trigger(dimension_info);
+ break;
+ }
+}
+
+ENetPacket* protocol::utils::make_disconnect(std::string_view reason, enet_uint32 flags)
+{
+ protocol::Disconnect packet;
+ packet.reason = reason;
+ return protocol::encode(packet, flags);
+}
+
+ENetPacket* protocol::utils::make_chat_message(std::string_view message, enet_uint32 flags)
+{
+ protocol::ChatMessage packet;
+ packet.type = protocol::ChatMessage::TEXT_MESSAGE;
+ packet.message = message;
+ return protocol::encode(packet, flags);
+}
+
+ENetPacket* protocol::utils::make_chunk_voxels(world::Dimension* dimension, entt::entity entity, enet_uint32 flags)
+{
+ if(auto component = dimension->chunks.try_get<world::ChunkComponent>(entity)) {
+ protocol::ChunkVoxels packet;
+ packet.chunk = component->cpos;
+ packet.voxels = component->chunk->get_voxels();
+ return protocol::encode(packet, flags);
+ }
+
+ return nullptr;
+}
+
+ENetPacket* protocol::utils::make_entity_head(world::Dimension* dimension, entt::entity entity, enet_uint32 flags)
+{
+ if(auto component = dimension->entities.try_get<entity::Head>(entity)) {
+ protocol::EntityHead packet;
+ packet.entity = entity;
+ packet.angles = component->angles;
+ return protocol::encode(packet, flags);
+ }
+
+ return nullptr;
+}
+
+ENetPacket* protocol::utils::make_entity_transform(world::Dimension* dimension, entt::entity entity, enet_uint32 flags)
+{
+ if(auto component = dimension->entities.try_get<entity::Transform>(entity)) {
+ protocol::EntityTransform packet;
+ packet.entity = entity;
+ packet.chunk = component->chunk;
+ packet.local = component->local;
+ packet.angles = component->angles;
+ return protocol::encode(packet, flags);
+ }
+
+ return nullptr;
+}
+
+ENetPacket* protocol::utils::make_entity_velocity(world::Dimension* dimension, entt::entity entity, enet_uint32 flags)
+{
+ if(auto component = dimension->entities.try_get<entity::Velocity>(entity)) {
+ protocol::EntityVelocity packet;
+ packet.entity = entity;
+ packet.value = component->value;
+ return protocol::encode(packet, flags);
+ }
+
+ return nullptr;
+}
+
+ENetPacket* protocol::utils::make_entity_player(world::Dimension* dimension, entt::entity entity, enet_uint32 flags)
+{
+ if(dimension->entities.any_of<entity::Player>(entity)) {
+ protocol::EntityPlayer packet;
+ packet.entity = entity;
+ return protocol::encode(packet, flags);
+ }
+
+ return nullptr;
+}
+
+ENetPacket* protocol::utils::make_dimension_info(const world::Dimension* dimension)
+{
+ protocol::DimensionInfo packet;
+ packet.name = dimension->get_name();
+ packet.gravity = dimension->get_gravity();
+ return protocol::encode(packet, ENET_PACKET_FLAG_RELIABLE);
+}
diff --git a/game/shared/protocol.hh b/game/shared/protocol.hh index 21f9da9..3133275 100644 --- a/game/shared/protocol.hh +++ b/game/shared/protocol.hh @@ -1,212 +1,212 @@ -#pragma once - -#include "shared/world/chunk.hh" - -namespace world -{ -class Dimension; -} // namespace world - -namespace protocol -{ -constexpr static std::size_t MAX_CHAT = 16384; -constexpr static std::size_t MAX_USERNAME = 64; -constexpr static std::size_t MAX_SOUNDNAME = 1024; -constexpr static std::uint16_t TICKRATE = 60; -constexpr static std::uint16_t PORT = 43103; -constexpr static std::uint32_t VERSION = 15; -constexpr static std::uint8_t CHANNEL = 0; -} // namespace protocol - -namespace protocol -{ -template<std::uint16_t packet_id> -struct Base { - constexpr static std::uint16_t ID = packet_id; - virtual ~Base(void) = default; - ENetPeer* peer { nullptr }; -}; -} // namespace protocol - -namespace protocol -{ -struct StatusRequest; -struct StatusResponse; -struct LoginRequest; -struct LoginResponse; -struct Disconnect; -struct ChunkVoxels; -struct EntityTransform; -struct EntityHead; -struct EntityVelocity; -struct SpawnPlayer; -struct ChatMessage; -struct SetVoxel; -struct RemoveEntity; -struct EntityPlayer; -struct ScoreboardUpdate; -struct RequestChunk; -struct GenericSound; -struct EntitySound; -struct DimensionInfo; -} // namespace protocol - -namespace protocol -{ -ENetPacket* encode(const StatusRequest& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const StatusResponse& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const LoginRequest& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const LoginResponse& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const Disconnect& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const ChunkVoxels& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const EntityTransform& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const EntityHead& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const EntityVelocity& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const SpawnPlayer& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const ChatMessage& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const SetVoxel& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const RemoveEntity& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const EntityPlayer& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const ScoreboardUpdate& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const RequestChunk& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const GenericSound& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const EntitySound& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* encode(const DimensionInfo& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -} // namespace protocol - -namespace protocol -{ -void broadcast(ENetHost* host, ENetPacket* packet); -void broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except); -void send(ENetPeer* peer, ENetPacket* packet); -} // namespace protocol - -namespace protocol -{ -void decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer); -} // namespace protocol - -namespace protocol::utils -{ -ENetPacket* make_disconnect(std::string_view reason, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* make_chat_message(std::string_view message, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -} // namespace protocol::utils - -namespace protocol::utils -{ -ENetPacket* make_chunk_voxels(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -} // namespace protocol::utils - -namespace protocol::utils -{ -ENetPacket* make_entity_head(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* make_entity_transform(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* make_entity_velocity(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* make_entity_player(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE); -ENetPacket* make_dimension_info(const world::Dimension* dimension); -} // namespace protocol::utils - -struct protocol::StatusRequest final : public protocol::Base<0x0000> { - std::uint32_t version; -}; - -struct protocol::StatusResponse final : public protocol::Base<0x0001> { - std::uint32_t version; - std::uint16_t max_players; - std::uint16_t num_players; - std::string motd; -}; - -struct protocol::LoginRequest final : public protocol::Base<0x0002> { - std::uint32_t version; - std::uint64_t voxel_registry_checksum; - std::uint64_t item_registry_checksum; - std::uint64_t password_hash; - std::string username; -}; - -struct protocol::LoginResponse final : public protocol::Base<0x0003> { - std::uint16_t client_index; - std::uint64_t client_identity; - std::uint16_t server_tickrate; -}; - -struct protocol::Disconnect final : public protocol::Base<0x0004> { - std::string reason; -}; - -struct protocol::ChunkVoxels final : public protocol::Base<0x0005> { - chunk_pos chunk; - world::VoxelStorage voxels; -}; - -struct protocol::EntityTransform final : public protocol::Base<0x0006> { - entt::entity entity; - chunk_pos chunk; - glm::fvec3 local; - glm::fvec3 angles; -}; - -struct protocol::EntityHead final : public protocol::Base<0x0007> { - entt::entity entity; - glm::fvec3 angles; -}; - -struct protocol::EntityVelocity final : public protocol::Base<0x0008> { - entt::entity entity; - glm::fvec3 value; -}; - -struct protocol::SpawnPlayer final : public protocol::Base<0x0009> { - entt::entity entity; -}; - -struct protocol::ChatMessage final : public protocol::Base<0x000A> { - constexpr static std::uint16_t TEXT_MESSAGE = 0x0000; - constexpr static std::uint16_t PLAYER_JOIN = 0x0001; - constexpr static std::uint16_t PLAYER_LEAVE = 0x0002; - - std::uint16_t type; - std::string sender; - std::string message; -}; - -struct protocol::SetVoxel final : public protocol::Base<0x000B> { - voxel_pos vpos; - voxel_id voxel; - std::uint16_t flags; -}; - -struct protocol::RemoveEntity final : public protocol::Base<0x000C> { - entt::entity entity; -}; - -struct protocol::EntityPlayer final : public protocol::Base<0x000D> { - entt::entity entity; -}; - -struct protocol::ScoreboardUpdate final : public protocol::Base<0x000E> { - std::vector<std::string> names; -}; - -struct protocol::RequestChunk final : public protocol::Base<0x000F> { - chunk_pos cpos; -}; - -struct protocol::GenericSound final : public protocol::Base<0x0010> { - std::string sound; - bool looping; - float pitch; -}; - -struct protocol::EntitySound final : public protocol::Base<0x0011> { - entt::entity entity; - std::string sound; - bool looping; - float pitch; -}; - -struct protocol::DimensionInfo final : public protocol::Base<0x0012> { - std::string name; - float gravity; -}; +#pragma once
+
+#include "shared/world/chunk.hh"
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace protocol
+{
+constexpr static std::size_t MAX_CHAT = 16384;
+constexpr static std::size_t MAX_USERNAME = 64;
+constexpr static std::size_t MAX_SOUNDNAME = 1024;
+constexpr static std::uint16_t TICKRATE = 60;
+constexpr static std::uint16_t PORT = 43103;
+constexpr static std::uint32_t VERSION = 15;
+constexpr static std::uint8_t CHANNEL = 0;
+} // namespace protocol
+
+namespace protocol
+{
+template<std::uint16_t packet_id>
+struct Base {
+ constexpr static std::uint16_t ID = packet_id;
+ virtual ~Base(void) = default;
+ ENetPeer* peer { nullptr };
+};
+} // namespace protocol
+
+namespace protocol
+{
+struct StatusRequest;
+struct StatusResponse;
+struct LoginRequest;
+struct LoginResponse;
+struct Disconnect;
+struct ChunkVoxels;
+struct EntityTransform;
+struct EntityHead;
+struct EntityVelocity;
+struct SpawnPlayer;
+struct ChatMessage;
+struct SetVoxel;
+struct RemoveEntity;
+struct EntityPlayer;
+struct ScoreboardUpdate;
+struct RequestChunk;
+struct GenericSound;
+struct EntitySound;
+struct DimensionInfo;
+} // namespace protocol
+
+namespace protocol
+{
+ENetPacket* encode(const StatusRequest& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const StatusResponse& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const LoginRequest& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const LoginResponse& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const Disconnect& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const ChunkVoxels& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const EntityTransform& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const EntityHead& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const EntityVelocity& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const SpawnPlayer& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const ChatMessage& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const SetVoxel& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const RemoveEntity& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const EntityPlayer& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const ScoreboardUpdate& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const RequestChunk& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const GenericSound& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const EntitySound& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* encode(const DimensionInfo& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+} // namespace protocol
+
+namespace protocol
+{
+void broadcast(ENetHost* host, ENetPacket* packet);
+void broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except);
+void send(ENetPeer* peer, ENetPacket* packet);
+} // namespace protocol
+
+namespace protocol
+{
+void decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer);
+} // namespace protocol
+
+namespace protocol::utils
+{
+ENetPacket* make_disconnect(std::string_view reason, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* make_chat_message(std::string_view message, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+} // namespace protocol::utils
+
+namespace protocol::utils
+{
+ENetPacket* make_chunk_voxels(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+} // namespace protocol::utils
+
+namespace protocol::utils
+{
+ENetPacket* make_entity_head(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* make_entity_transform(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* make_entity_velocity(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* make_entity_player(world::Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
+ENetPacket* make_dimension_info(const world::Dimension* dimension);
+} // namespace protocol::utils
+
+struct protocol::StatusRequest final : public protocol::Base<0x0000> {
+ std::uint32_t version;
+};
+
+struct protocol::StatusResponse final : public protocol::Base<0x0001> {
+ std::uint32_t version;
+ std::uint16_t max_players;
+ std::uint16_t num_players;
+ std::string motd;
+};
+
+struct protocol::LoginRequest final : public protocol::Base<0x0002> {
+ std::uint32_t version;
+ std::uint64_t voxel_registry_checksum;
+ std::uint64_t item_registry_checksum;
+ std::uint64_t password_hash;
+ std::string username;
+};
+
+struct protocol::LoginResponse final : public protocol::Base<0x0003> {
+ std::uint16_t client_index;
+ std::uint64_t client_identity;
+ std::uint16_t server_tickrate;
+};
+
+struct protocol::Disconnect final : public protocol::Base<0x0004> {
+ std::string reason;
+};
+
+struct protocol::ChunkVoxels final : public protocol::Base<0x0005> {
+ chunk_pos chunk;
+ world::VoxelStorage voxels;
+};
+
+struct protocol::EntityTransform final : public protocol::Base<0x0006> {
+ entt::entity entity;
+ chunk_pos chunk;
+ glm::fvec3 local;
+ glm::fvec3 angles;
+};
+
+struct protocol::EntityHead final : public protocol::Base<0x0007> {
+ entt::entity entity;
+ glm::fvec3 angles;
+};
+
+struct protocol::EntityVelocity final : public protocol::Base<0x0008> {
+ entt::entity entity;
+ glm::fvec3 value;
+};
+
+struct protocol::SpawnPlayer final : public protocol::Base<0x0009> {
+ entt::entity entity;
+};
+
+struct protocol::ChatMessage final : public protocol::Base<0x000A> {
+ constexpr static std::uint16_t TEXT_MESSAGE = 0x0000;
+ constexpr static std::uint16_t PLAYER_JOIN = 0x0001;
+ constexpr static std::uint16_t PLAYER_LEAVE = 0x0002;
+
+ std::uint16_t type;
+ std::string sender;
+ std::string message;
+};
+
+struct protocol::SetVoxel final : public protocol::Base<0x000B> {
+ voxel_pos vpos;
+ voxel_id voxel;
+ std::uint16_t flags;
+};
+
+struct protocol::RemoveEntity final : public protocol::Base<0x000C> {
+ entt::entity entity;
+};
+
+struct protocol::EntityPlayer final : public protocol::Base<0x000D> {
+ entt::entity entity;
+};
+
+struct protocol::ScoreboardUpdate final : public protocol::Base<0x000E> {
+ std::vector<std::string> names;
+};
+
+struct protocol::RequestChunk final : public protocol::Base<0x000F> {
+ chunk_pos cpos;
+};
+
+struct protocol::GenericSound final : public protocol::Base<0x0010> {
+ std::string sound;
+ bool looping;
+ float pitch;
+};
+
+struct protocol::EntitySound final : public protocol::Base<0x0011> {
+ entt::entity entity;
+ std::string sound;
+ bool looping;
+ float pitch;
+};
+
+struct protocol::DimensionInfo final : public protocol::Base<0x0012> {
+ std::string name;
+ float gravity;
+};
diff --git a/game/shared/splash.cc b/game/shared/splash.cc index d5b0a6e..7515358 100644 --- a/game/shared/splash.cc +++ b/game/shared/splash.cc @@ -1,65 +1,65 @@ -#include "shared/pch.hh" - -#include "shared/splash.hh" - -constexpr static std::string_view SPLASHES_FILENAME_CLIENT = "misc/splashes_client.txt"; -constexpr static std::string_view SPLASHES_FILENAME_SERVER = "misc/splashes_server.txt"; -constexpr static std::size_t SPLASH_SERVER_MAX_LENGTH = 32; - -static std::mt19937_64 splash_random; -static std::vector<std::string> splash_lines; - -static std::string sanitize_line(const std::string& line) -{ - std::string result; - - for(auto chr : line) { - if(chr != '\r' && chr != '\n') { - result.push_back(chr); - } - } - - return result; -} - -static void splash_init_filename(std::string_view filename) -{ - if(auto file = PHYSFS_openRead(std::string(filename).c_str())) { - auto source = std::string(PHYSFS_fileLength(file), char(0x00)); - PHYSFS_readBytes(file, source.data(), source.size()); - PHYSFS_close(file); - - std::string line; - std::istringstream stream(source); - - while(std::getline(stream, line)) - splash_lines.push_back(sanitize_line(line)); - splash_random.seed(std::random_device()()); - } - else { - splash_lines.push_back(std::format("{}: {}", filename, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()))); - splash_random.seed(std::random_device()()); - } -} - -void splash::init_client(void) -{ - splash_init_filename(SPLASHES_FILENAME_CLIENT); -} - -void splash::init_server(void) -{ - splash_init_filename(SPLASHES_FILENAME_SERVER); - - // Server browser GUI should be able to display - // these splash messages without text clipping over - for(int i = 0; i < splash_lines.size(); i++) { - splash_lines[i] = splash_lines[i].substr(0, SPLASH_SERVER_MAX_LENGTH); - } -} - -std::string_view splash::get(void) -{ - std::uniform_int_distribution<std::size_t> dist(0, splash_lines.size() - 1); - return splash_lines.at(dist(splash_random)); -} +#include "shared/pch.hh"
+
+#include "shared/splash.hh"
+
+constexpr static std::string_view SPLASHES_FILENAME_CLIENT = "misc/splashes_client.txt";
+constexpr static std::string_view SPLASHES_FILENAME_SERVER = "misc/splashes_server.txt";
+constexpr static std::size_t SPLASH_SERVER_MAX_LENGTH = 32;
+
+static std::mt19937_64 splash_random;
+static std::vector<std::string> splash_lines;
+
+static std::string sanitize_line(const std::string& line)
+{
+ std::string result;
+
+ for(auto chr : line) {
+ if(chr != '\r' && chr != '\n') {
+ result.push_back(chr);
+ }
+ }
+
+ return result;
+}
+
+static void splash_init_filename(std::string_view filename)
+{
+ if(auto file = PHYSFS_openRead(std::string(filename).c_str())) {
+ auto source = std::string(PHYSFS_fileLength(file), char(0x00));
+ PHYSFS_readBytes(file, source.data(), source.size());
+ PHYSFS_close(file);
+
+ std::string line;
+ std::istringstream stream(source);
+
+ while(std::getline(stream, line))
+ splash_lines.push_back(sanitize_line(line));
+ splash_random.seed(std::random_device()());
+ }
+ else {
+ splash_lines.push_back(std::format("{}: {}", filename, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())));
+ splash_random.seed(std::random_device()());
+ }
+}
+
+void splash::init_client(void)
+{
+ splash_init_filename(SPLASHES_FILENAME_CLIENT);
+}
+
+void splash::init_server(void)
+{
+ splash_init_filename(SPLASHES_FILENAME_SERVER);
+
+ // Server browser GUI should be able to display
+ // these splash messages without text clipping over
+ for(int i = 0; i < splash_lines.size(); i++) {
+ splash_lines[i] = splash_lines[i].substr(0, SPLASH_SERVER_MAX_LENGTH);
+ }
+}
+
+std::string_view splash::get(void)
+{
+ std::uniform_int_distribution<std::size_t> dist(0, splash_lines.size() - 1);
+ return splash_lines.at(dist(splash_random));
+}
diff --git a/game/shared/splash.hh b/game/shared/splash.hh index be80cd6..2572d53 100644 --- a/game/shared/splash.hh +++ b/game/shared/splash.hh @@ -1,8 +1,8 @@ -#pragma once - -namespace splash -{ -void init_client(void); -void init_server(void); -std::string_view get(void); -} // namespace splash +#pragma once
+
+namespace splash
+{
+void init_client(void);
+void init_server(void);
+std::string_view get(void);
+} // namespace splash
diff --git a/game/shared/types.hh b/game/shared/types.hh index 792ed0f..332eede 100644 --- a/game/shared/types.hh +++ b/game/shared/types.hh @@ -1,40 +1,40 @@ -#pragma once - -using item_id = std::uint32_t; -constexpr static item_id NULL_ITEM_ID = UINT32_C(0x00000000); -constexpr static item_id MAX_ITEM_ID = UINT32_C(0xFFFFFFFF); - -using voxel_id = std::uint16_t; -constexpr static voxel_id NULL_VOXEL_ID = UINT16_C(0x0000); -constexpr static voxel_id MAX_VOXEL_ID = UINT16_C(0xFFFF); - -using chunk_pos = glm::vec<3, std::int32_t>; -using local_pos = glm::vec<3, std::int16_t>; -using voxel_pos = glm::vec<3, std::int64_t>; - -using chunk_pos_xz = glm::vec<2, chunk_pos::value_type>; -using local_pos_xz = glm::vec<2, local_pos::value_type>; -using voxel_pos_xz = glm::vec<2, local_pos::value_type>; - -template<> -struct std::hash<chunk_pos> final { - constexpr inline std::size_t operator()(const chunk_pos& cpos) const - { - std::size_t value = 0; - value ^= cpos.x * 73856093; - value ^= cpos.y * 19349663; - value ^= cpos.z * 83492791; - return value; - } -}; - -template<> -struct std::hash<chunk_pos_xz> final { - constexpr inline std::size_t operator()(const chunk_pos_xz& cwpos) const - { - std::size_t value = 0; - value ^= cwpos.x * 73856093; - value ^= cwpos.y * 19349663; - return value; - } -}; +#pragma once
+
+using item_id = std::uint32_t;
+constexpr static item_id NULL_ITEM_ID = UINT32_C(0x00000000);
+constexpr static item_id MAX_ITEM_ID = UINT32_C(0xFFFFFFFF);
+
+using voxel_id = std::uint16_t;
+constexpr static voxel_id NULL_VOXEL_ID = UINT16_C(0x0000);
+constexpr static voxel_id MAX_VOXEL_ID = UINT16_C(0xFFFF);
+
+using chunk_pos = glm::vec<3, std::int32_t>;
+using local_pos = glm::vec<3, std::int16_t>;
+using voxel_pos = glm::vec<3, std::int64_t>;
+
+using chunk_pos_xz = glm::vec<2, chunk_pos::value_type>;
+using local_pos_xz = glm::vec<2, local_pos::value_type>;
+using voxel_pos_xz = glm::vec<2, local_pos::value_type>;
+
+template<>
+struct std::hash<chunk_pos> final {
+ constexpr inline std::size_t operator()(const chunk_pos& cpos) const
+ {
+ std::size_t value = 0;
+ value ^= cpos.x * 73856093;
+ value ^= cpos.y * 19349663;
+ value ^= cpos.z * 83492791;
+ return value;
+ }
+};
+
+template<>
+struct std::hash<chunk_pos_xz> final {
+ constexpr inline std::size_t operator()(const chunk_pos_xz& cwpos) const
+ {
+ std::size_t value = 0;
+ value ^= cwpos.x * 73856093;
+ value ^= cwpos.y * 19349663;
+ return value;
+ }
+};
diff --git a/game/shared/world/chunk.cc b/game/shared/world/chunk.cc index f689fc1..e59b68d 100644 --- a/game/shared/world/chunk.cc +++ b/game/shared/world/chunk.cc @@ -1,70 +1,70 @@ -#include "shared/pch.hh" - -#include "shared/world/chunk.hh" - -#include "shared/coord.hh" - -world::Chunk::Chunk(entt::entity entity, Dimension* dimension) -{ - m_entity = entity; - m_dimension = dimension; - m_voxels.fill(NULL_VOXEL_ID); - m_biome = BIOME_VOID; -} - -voxel_id world::Chunk::get_voxel(const local_pos& lpos) const -{ - return get_voxel(coord::to_index(lpos)); -} - -voxel_id world::Chunk::get_voxel(const std::size_t index) const -{ - if(index >= CHUNK_VOLUME) { - return NULL_VOXEL_ID; - } - else { - return m_voxels[index]; - } -} - -void world::Chunk::set_voxel(voxel_id voxel, const local_pos& lpos) -{ - set_voxel(voxel, coord::to_index(lpos)); -} - -void world::Chunk::set_voxel(voxel_id voxel, const std::size_t index) -{ - if(index < CHUNK_VOLUME) { - m_voxels[index] = voxel; - } -} - -const world::VoxelStorage& world::Chunk::get_voxels(void) const -{ - return m_voxels; -} - -void world::Chunk::set_voxels(const VoxelStorage& voxels) -{ - m_voxels = voxels; -} - -unsigned int world::Chunk::get_biome(void) const -{ - return m_biome; -} - -void world::Chunk::set_biome(unsigned int biome) -{ - m_biome = biome; -} - -entt::entity world::Chunk::get_entity(void) const -{ - return m_entity; -} - -world::Dimension* world::Chunk::get_dimension(void) const -{ - return m_dimension; -} +#include "shared/pch.hh"
+
+#include "shared/world/chunk.hh"
+
+#include "shared/coord.hh"
+
+world::Chunk::Chunk(entt::entity entity, Dimension* dimension)
+{
+ m_entity = entity;
+ m_dimension = dimension;
+ m_voxels.fill(NULL_VOXEL_ID);
+ m_biome = BIOME_VOID;
+}
+
+voxel_id world::Chunk::get_voxel(const local_pos& lpos) const
+{
+ return get_voxel(coord::to_index(lpos));
+}
+
+voxel_id world::Chunk::get_voxel(const std::size_t index) const
+{
+ if(index >= CHUNK_VOLUME) {
+ return NULL_VOXEL_ID;
+ }
+ else {
+ return m_voxels[index];
+ }
+}
+
+void world::Chunk::set_voxel(voxel_id voxel, const local_pos& lpos)
+{
+ set_voxel(voxel, coord::to_index(lpos));
+}
+
+void world::Chunk::set_voxel(voxel_id voxel, const std::size_t index)
+{
+ if(index < CHUNK_VOLUME) {
+ m_voxels[index] = voxel;
+ }
+}
+
+const world::VoxelStorage& world::Chunk::get_voxels(void) const
+{
+ return m_voxels;
+}
+
+void world::Chunk::set_voxels(const VoxelStorage& voxels)
+{
+ m_voxels = voxels;
+}
+
+unsigned int world::Chunk::get_biome(void) const
+{
+ return m_biome;
+}
+
+void world::Chunk::set_biome(unsigned int biome)
+{
+ m_biome = biome;
+}
+
+entt::entity world::Chunk::get_entity(void) const
+{
+ return m_entity;
+}
+
+world::Dimension* world::Chunk::get_dimension(void) const
+{
+ return m_dimension;
+}
diff --git a/game/shared/world/chunk.hh b/game/shared/world/chunk.hh index 439694c..c5bba12 100644 --- a/game/shared/world/chunk.hh +++ b/game/shared/world/chunk.hh @@ -1,42 +1,42 @@ -#pragma once - -#include "shared/world/voxel_storage.hh" - -#include "shared/types.hh" - -constexpr static unsigned int BIOME_VOID = 0U; - -namespace world -{ -class Dimension; -} // namespace world - -namespace world -{ -class Chunk final { -public: - explicit Chunk(entt::entity entity, Dimension* dimension); - virtual ~Chunk(void) = default; - - voxel_id get_voxel(const local_pos& lpos) const; - voxel_id get_voxel(const std::size_t index) const; - - void set_voxel(voxel_id voxel, const local_pos& lpos); - void set_voxel(voxel_id voxel, const std::size_t index); - - const VoxelStorage& get_voxels(void) const; - void set_voxels(const VoxelStorage& voxels); - - unsigned int get_biome(void) const; - void set_biome(unsigned int biome); - - entt::entity get_entity(void) const; - Dimension* get_dimension(void) const; - -private: - entt::entity m_entity; - Dimension* m_dimension; - VoxelStorage m_voxels; - unsigned int m_biome; -}; -} // namespace world +#pragma once
+
+#include "shared/world/voxel_storage.hh"
+
+#include "shared/types.hh"
+
+constexpr static unsigned int BIOME_VOID = 0U;
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace world
+{
+class Chunk final {
+public:
+ explicit Chunk(entt::entity entity, Dimension* dimension);
+ virtual ~Chunk(void) = default;
+
+ voxel_id get_voxel(const local_pos& lpos) const;
+ voxel_id get_voxel(const std::size_t index) const;
+
+ void set_voxel(voxel_id voxel, const local_pos& lpos);
+ void set_voxel(voxel_id voxel, const std::size_t index);
+
+ const VoxelStorage& get_voxels(void) const;
+ void set_voxels(const VoxelStorage& voxels);
+
+ unsigned int get_biome(void) const;
+ void set_biome(unsigned int biome);
+
+ entt::entity get_entity(void) const;
+ Dimension* get_dimension(void) const;
+
+private:
+ entt::entity m_entity;
+ Dimension* m_dimension;
+ VoxelStorage m_voxels;
+ unsigned int m_biome;
+};
+} // namespace world
diff --git a/game/shared/world/chunk_aabb.cc b/game/shared/world/chunk_aabb.cc index c0e540e..634b230 100644 --- a/game/shared/world/chunk_aabb.cc +++ b/game/shared/world/chunk_aabb.cc @@ -1,54 +1,54 @@ -#include "shared/pch.hh" - -#include "shared/world/chunk_aabb.hh" - -void world::ChunkAABB::set_bounds(const chunk_pos& min, const chunk_pos& max) -{ - this->min = min; - this->max = max; -} - -void world::ChunkAABB::set_offset(const chunk_pos& base, const chunk_pos& size) -{ - this->min = base; - this->max = base + size; -} - -bool world::ChunkAABB::contains(const chunk_pos& point) const -{ - auto result = true; - result = result && (point.x >= min.x) && (point.x <= max.x); - result = result && (point.y >= min.y) && (point.y <= max.y); - result = result && (point.z >= min.z) && (point.z <= max.z); - return result; -} - -bool world::ChunkAABB::intersect(const ChunkAABB& other_box) const -{ - auto result = true; - result = result && (min.x < other_box.max.x) && (max.x > other_box.min.x); - result = result && (min.y < other_box.max.y) && (max.y > other_box.min.y); - result = result && (min.z < other_box.max.z) && (max.z > other_box.min.z); - return result; -} - -world::ChunkAABB world::ChunkAABB::combine_with(const ChunkAABB& other_box) const -{ - ChunkAABB result; - result.set_bounds(min, other_box.max); - return result; -} - -world::ChunkAABB world::ChunkAABB::multiply_with(const ChunkAABB& other_box) const -{ - ChunkAABB result; - result.set_bounds(other_box.min, max); - return result; -} - -world::ChunkAABB world::ChunkAABB::push(const chunk_pos& vector) const -{ - ChunkAABB result; - result.set_bounds(min + vector, max + vector); - return result; -} +#include "shared/pch.hh"
+
+#include "shared/world/chunk_aabb.hh"
+
+void world::ChunkAABB::set_bounds(const chunk_pos& min, const chunk_pos& max)
+{
+ this->min = min;
+ this->max = max;
+}
+
+void world::ChunkAABB::set_offset(const chunk_pos& base, const chunk_pos& size)
+{
+ this->min = base;
+ this->max = base + size;
+}
+
+bool world::ChunkAABB::contains(const chunk_pos& point) const
+{
+ auto result = true;
+ result = result && (point.x >= min.x) && (point.x <= max.x);
+ result = result && (point.y >= min.y) && (point.y <= max.y);
+ result = result && (point.z >= min.z) && (point.z <= max.z);
+ return result;
+}
+
+bool world::ChunkAABB::intersect(const ChunkAABB& other_box) const
+{
+ auto result = true;
+ result = result && (min.x < other_box.max.x) && (max.x > other_box.min.x);
+ result = result && (min.y < other_box.max.y) && (max.y > other_box.min.y);
+ result = result && (min.z < other_box.max.z) && (max.z > other_box.min.z);
+ return result;
+}
+
+world::ChunkAABB world::ChunkAABB::combine_with(const ChunkAABB& other_box) const
+{
+ ChunkAABB result;
+ result.set_bounds(min, other_box.max);
+ return result;
+}
+
+world::ChunkAABB world::ChunkAABB::multiply_with(const ChunkAABB& other_box) const
+{
+ ChunkAABB result;
+ result.set_bounds(other_box.min, max);
+ return result;
+}
+
+world::ChunkAABB world::ChunkAABB::push(const chunk_pos& vector) const
+{
+ ChunkAABB result;
+ result.set_bounds(min + vector, max + vector);
+ return result;
+}
diff --git a/game/shared/world/chunk_aabb.hh b/game/shared/world/chunk_aabb.hh index bd4a0c5..a9e0205 100644 --- a/game/shared/world/chunk_aabb.hh +++ b/game/shared/world/chunk_aabb.hh @@ -1,33 +1,33 @@ -#ifndef SHARED_CHUNK_AABB -#define SHARED_CHUNK_AABB 1 -#pragma once - -#include "shared/types.hh" - -namespace world -{ -class ChunkAABB final { -public: - ChunkAABB(void) = default; - virtual ~ChunkAABB(void) = default; - - void set_bounds(const chunk_pos& min, const chunk_pos& max); - void set_offset(const chunk_pos& base, const chunk_pos& size); - - const chunk_pos& get_min(void) const; - const chunk_pos& get_max(void) const; - - bool contains(const chunk_pos& point) const; - bool intersect(const ChunkAABB& other_box) const; - - ChunkAABB combine_with(const ChunkAABB& other_box) const; - ChunkAABB multiply_with(const ChunkAABB& other_box) const; - ChunkAABB push(const chunk_pos& vector) const; - -public: - chunk_pos min; - chunk_pos max; -}; -} // namespace world - -#endif // SHARED_CHUNK_AABB +#ifndef SHARED_CHUNK_AABB
+#define SHARED_CHUNK_AABB 1
+#pragma once
+
+#include "shared/types.hh"
+
+namespace world
+{
+class ChunkAABB final {
+public:
+ ChunkAABB(void) = default;
+ virtual ~ChunkAABB(void) = default;
+
+ void set_bounds(const chunk_pos& min, const chunk_pos& max);
+ void set_offset(const chunk_pos& base, const chunk_pos& size);
+
+ const chunk_pos& get_min(void) const;
+ const chunk_pos& get_max(void) const;
+
+ bool contains(const chunk_pos& point) const;
+ bool intersect(const ChunkAABB& other_box) const;
+
+ ChunkAABB combine_with(const ChunkAABB& other_box) const;
+ ChunkAABB multiply_with(const ChunkAABB& other_box) const;
+ ChunkAABB push(const chunk_pos& vector) const;
+
+public:
+ chunk_pos min;
+ chunk_pos max;
+};
+} // namespace world
+
+#endif // SHARED_CHUNK_AABB
diff --git a/game/shared/world/dimension.cc b/game/shared/world/dimension.cc index 2d193fc..dd28449 100644 --- a/game/shared/world/dimension.cc +++ b/game/shared/world/dimension.cc @@ -1,173 +1,173 @@ -#include "shared/pch.hh" - -#include "shared/world/dimension.hh" - -#include "shared/world/chunk.hh" - -#include "shared/coord.hh" -#include "shared/globals.hh" - -world::Dimension::Dimension(std::string_view name, float gravity) -{ - m_name = name; - m_gravity = gravity; -} - -world::Dimension::~Dimension(void) -{ - for(const auto it : m_chunkmap) - delete it.second; - entities.clear(); - chunks.clear(); -} - -std::string_view world::Dimension::get_name(void) const -{ - return m_name; -} - -float world::Dimension::get_gravity(void) const -{ - return m_gravity; -} - -world::Chunk* world::Dimension::create_chunk(const chunk_pos& cpos) -{ - auto it = m_chunkmap.find(cpos); - - if(it != m_chunkmap.cend()) { - // Chunk already exists - return it->second; - } - - auto entity = chunks.create(); - auto chunk = new Chunk(entity, this); - - auto& component = chunks.emplace<ChunkComponent>(entity); - component.chunk = chunk; - component.cpos = cpos; - - ChunkCreateEvent event; - event.dimension = this; - event.chunk = chunk; - event.cpos = cpos; - - globals::dispatcher.trigger(event); - - return m_chunkmap.insert_or_assign(cpos, std::move(chunk)).first->second; -} - -world::Chunk* world::Dimension::find_chunk(entt::entity entity) const -{ - if(chunks.valid(entity)) { - return chunks.get<ChunkComponent>(entity).chunk; - } - else { - return nullptr; - } -} - -world::Chunk* world::Dimension::find_chunk(const chunk_pos& cpos) const -{ - auto it = m_chunkmap.find(cpos); - - if(it != m_chunkmap.cend()) { - return it->second; - } - else { - return nullptr; - } -} - -void world::Dimension::remove_chunk(entt::entity entity) -{ - if(chunks.valid(entity)) { - auto& component = chunks.get<ChunkComponent>(entity); - m_chunkmap.erase(component.cpos); - chunks.destroy(entity); - } -} - -void world::Dimension::remove_chunk(const chunk_pos& cpos) -{ - auto it = m_chunkmap.find(cpos); - - if(it != m_chunkmap.cend()) { - chunks.destroy(it->second->get_entity()); - m_chunkmap.erase(it); - } -} - -void world::Dimension::remove_chunk(Chunk* chunk) -{ - if(chunk) { - const auto& component = chunks.get<ChunkComponent>(chunk->get_entity()); - m_chunkmap.erase(component.cpos); - chunks.destroy(chunk->get_entity()); - } -} - -voxel_id world::Dimension::get_voxel(const voxel_pos& vpos) const -{ - auto cpos = coord::to_chunk(vpos); - auto lpos = coord::to_local(vpos); - - if(auto chunk = find_chunk(cpos)) { - return chunk->get_voxel(lpos); - } - else { - return NULL_VOXEL_ID; - } -} - -voxel_id world::Dimension::get_voxel(const chunk_pos& cpos, const local_pos& lpos) const -{ - // This allows accessing get_voxel with negative - // local coordinates that usually would result in an - // out-of-range values; this is useful for per-voxel update logic - return get_voxel(coord::to_voxel(cpos, lpos)); -} - -bool world::Dimension::set_voxel(voxel_id voxel, const voxel_pos& vpos) -{ - auto cpos = coord::to_chunk(vpos); - auto lpos = coord::to_local(vpos); - - if(auto chunk = find_chunk(cpos)) { - chunk->set_voxel(voxel, lpos); - - VoxelSetEvent event; - event.dimension = this; - event.cpos = cpos; - event.lpos = lpos; - event.voxel = voxel; - event.chunk = chunk; - - globals::dispatcher.trigger(event); - - return true; - } - - return false; -} - -bool world::Dimension::set_voxel(voxel_id voxel, const chunk_pos& cpos, const local_pos& lpos) -{ - // This allows accessing set_voxel with negative - // local coordinates that usually would result in an - // out-of-range values; this is useful for per-voxel update logic - return set_voxel(voxel, coord::to_voxel(cpos, lpos)); -} - -void world::Dimension::init(io::ConfigMap& config) -{ -} - -void world::Dimension::init_late(std::uint64_t global_seed) -{ -} - -bool world::Dimension::generate(const chunk_pos& cpos, VoxelStorage& voxels) -{ - return false; -} +#include "shared/pch.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/world/chunk.hh"
+
+#include "shared/coord.hh"
+#include "shared/globals.hh"
+
+world::Dimension::Dimension(std::string_view name, float gravity)
+{
+ m_name = name;
+ m_gravity = gravity;
+}
+
+world::Dimension::~Dimension(void)
+{
+ for(const auto it : m_chunkmap)
+ delete it.second;
+ entities.clear();
+ chunks.clear();
+}
+
+std::string_view world::Dimension::get_name(void) const
+{
+ return m_name;
+}
+
+float world::Dimension::get_gravity(void) const
+{
+ return m_gravity;
+}
+
+world::Chunk* world::Dimension::create_chunk(const chunk_pos& cpos)
+{
+ auto it = m_chunkmap.find(cpos);
+
+ if(it != m_chunkmap.cend()) {
+ // Chunk already exists
+ return it->second;
+ }
+
+ auto entity = chunks.create();
+ auto chunk = new Chunk(entity, this);
+
+ auto& component = chunks.emplace<ChunkComponent>(entity);
+ component.chunk = chunk;
+ component.cpos = cpos;
+
+ ChunkCreateEvent event;
+ event.dimension = this;
+ event.chunk = chunk;
+ event.cpos = cpos;
+
+ globals::dispatcher.trigger(event);
+
+ return m_chunkmap.insert_or_assign(cpos, std::move(chunk)).first->second;
+}
+
+world::Chunk* world::Dimension::find_chunk(entt::entity entity) const
+{
+ if(chunks.valid(entity)) {
+ return chunks.get<ChunkComponent>(entity).chunk;
+ }
+ else {
+ return nullptr;
+ }
+}
+
+world::Chunk* world::Dimension::find_chunk(const chunk_pos& cpos) const
+{
+ auto it = m_chunkmap.find(cpos);
+
+ if(it != m_chunkmap.cend()) {
+ return it->second;
+ }
+ else {
+ return nullptr;
+ }
+}
+
+void world::Dimension::remove_chunk(entt::entity entity)
+{
+ if(chunks.valid(entity)) {
+ auto& component = chunks.get<ChunkComponent>(entity);
+ m_chunkmap.erase(component.cpos);
+ chunks.destroy(entity);
+ }
+}
+
+void world::Dimension::remove_chunk(const chunk_pos& cpos)
+{
+ auto it = m_chunkmap.find(cpos);
+
+ if(it != m_chunkmap.cend()) {
+ chunks.destroy(it->second->get_entity());
+ m_chunkmap.erase(it);
+ }
+}
+
+void world::Dimension::remove_chunk(Chunk* chunk)
+{
+ if(chunk) {
+ const auto& component = chunks.get<ChunkComponent>(chunk->get_entity());
+ m_chunkmap.erase(component.cpos);
+ chunks.destroy(chunk->get_entity());
+ }
+}
+
+voxel_id world::Dimension::get_voxel(const voxel_pos& vpos) const
+{
+ auto cpos = coord::to_chunk(vpos);
+ auto lpos = coord::to_local(vpos);
+
+ if(auto chunk = find_chunk(cpos)) {
+ return chunk->get_voxel(lpos);
+ }
+ else {
+ return NULL_VOXEL_ID;
+ }
+}
+
+voxel_id world::Dimension::get_voxel(const chunk_pos& cpos, const local_pos& lpos) const
+{
+ // This allows accessing get_voxel with negative
+ // local coordinates that usually would result in an
+ // out-of-range values; this is useful for per-voxel update logic
+ return get_voxel(coord::to_voxel(cpos, lpos));
+}
+
+bool world::Dimension::set_voxel(voxel_id voxel, const voxel_pos& vpos)
+{
+ auto cpos = coord::to_chunk(vpos);
+ auto lpos = coord::to_local(vpos);
+
+ if(auto chunk = find_chunk(cpos)) {
+ chunk->set_voxel(voxel, lpos);
+
+ VoxelSetEvent event;
+ event.dimension = this;
+ event.cpos = cpos;
+ event.lpos = lpos;
+ event.voxel = voxel;
+ event.chunk = chunk;
+
+ globals::dispatcher.trigger(event);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool world::Dimension::set_voxel(voxel_id voxel, const chunk_pos& cpos, const local_pos& lpos)
+{
+ // This allows accessing set_voxel with negative
+ // local coordinates that usually would result in an
+ // out-of-range values; this is useful for per-voxel update logic
+ return set_voxel(voxel, coord::to_voxel(cpos, lpos));
+}
+
+void world::Dimension::init(io::ConfigMap& config)
+{
+}
+
+void world::Dimension::init_late(std::uint64_t global_seed)
+{
+}
+
+bool world::Dimension::generate(const chunk_pos& cpos, VoxelStorage& voxels)
+{
+ return false;
+}
diff --git a/game/shared/world/dimension.hh b/game/shared/world/dimension.hh index 8b6691d..bf9bfe1 100644 --- a/game/shared/world/dimension.hh +++ b/game/shared/world/dimension.hh @@ -1,100 +1,100 @@ -#pragma once - -#include "shared/const.hh" -#include "shared/types.hh" - -namespace io -{ -class ConfigMap; -} // namespace io - -namespace world -{ -class Chunk; -class VoxelStorage; -} // namespace world - -namespace world -{ -using dimension_entropy_map = std::array<std::uint64_t, CHUNK_AREA>; -using dimension_height_map = std::array<voxel_pos::value_type, CHUNK_AREA>; -} // namespace world - -namespace world -{ -class Dimension { -public: - explicit Dimension(std::string_view name, float gravity); - virtual ~Dimension(void); - - std::string_view get_name(void) const; - float get_gravity(void) const; - -public: - Chunk* create_chunk(const chunk_pos& cpos); - Chunk* find_chunk(entt::entity entity) const; - Chunk* find_chunk(const chunk_pos& cpos) const; - - void remove_chunk(entt::entity entity); - void remove_chunk(const chunk_pos& cpos); - void remove_chunk(Chunk* chunk); - -public: - voxel_id get_voxel(const voxel_pos& vpos) const; - voxel_id get_voxel(const chunk_pos& cpos, const local_pos& lpos) const; - - bool set_voxel(voxel_id voxel, const voxel_pos& vpos); - bool set_voxel(voxel_id voxel, const chunk_pos& cpos, const local_pos& lpos); - -public: - virtual void init(io::ConfigMap& config); - virtual void init_late(std::uint64_t global_seed); - virtual bool generate(const chunk_pos& cpos, VoxelStorage& voxels); - -public: - entt::registry chunks; - entt::registry entities; - -private: - std::string m_name; - emhash8::HashMap<chunk_pos, Chunk*> m_chunkmap; - float m_gravity; -}; -} // namespace world - -namespace world -{ -struct ChunkComponent final { - chunk_pos cpos; - Chunk* chunk; -}; -} // namespace world - -namespace world -{ -struct ChunkCreateEvent final { - Dimension* dimension; - chunk_pos cpos; - Chunk* chunk; -}; - -struct ChunkDestroyEvent final { - Dimension* dimension; - chunk_pos cpos; - Chunk* chunk; -}; - -struct ChunkUpdateEvent final { - Dimension* dimension; - chunk_pos cpos; - Chunk* chunk; -}; - -struct VoxelSetEvent final { - Dimension* dimension; - chunk_pos cpos; - local_pos lpos; - voxel_id voxel; - Chunk* chunk; -}; -} // namespace world +#pragma once
+
+#include "shared/const.hh"
+#include "shared/types.hh"
+
+namespace io
+{
+class ConfigMap;
+} // namespace io
+
+namespace world
+{
+class Chunk;
+class VoxelStorage;
+} // namespace world
+
+namespace world
+{
+using dimension_entropy_map = std::array<std::uint64_t, CHUNK_AREA>;
+using dimension_height_map = std::array<voxel_pos::value_type, CHUNK_AREA>;
+} // namespace world
+
+namespace world
+{
+class Dimension {
+public:
+ explicit Dimension(std::string_view name, float gravity);
+ virtual ~Dimension(void);
+
+ std::string_view get_name(void) const;
+ float get_gravity(void) const;
+
+public:
+ Chunk* create_chunk(const chunk_pos& cpos);
+ Chunk* find_chunk(entt::entity entity) const;
+ Chunk* find_chunk(const chunk_pos& cpos) const;
+
+ void remove_chunk(entt::entity entity);
+ void remove_chunk(const chunk_pos& cpos);
+ void remove_chunk(Chunk* chunk);
+
+public:
+ voxel_id get_voxel(const voxel_pos& vpos) const;
+ voxel_id get_voxel(const chunk_pos& cpos, const local_pos& lpos) const;
+
+ bool set_voxel(voxel_id voxel, const voxel_pos& vpos);
+ bool set_voxel(voxel_id voxel, const chunk_pos& cpos, const local_pos& lpos);
+
+public:
+ virtual void init(io::ConfigMap& config);
+ virtual void init_late(std::uint64_t global_seed);
+ virtual bool generate(const chunk_pos& cpos, VoxelStorage& voxels);
+
+public:
+ entt::registry chunks;
+ entt::registry entities;
+
+private:
+ std::string m_name;
+ emhash8::HashMap<chunk_pos, Chunk*> m_chunkmap;
+ float m_gravity;
+};
+} // namespace world
+
+namespace world
+{
+struct ChunkComponent final {
+ chunk_pos cpos;
+ Chunk* chunk;
+};
+} // namespace world
+
+namespace world
+{
+struct ChunkCreateEvent final {
+ Dimension* dimension;
+ chunk_pos cpos;
+ Chunk* chunk;
+};
+
+struct ChunkDestroyEvent final {
+ Dimension* dimension;
+ chunk_pos cpos;
+ Chunk* chunk;
+};
+
+struct ChunkUpdateEvent final {
+ Dimension* dimension;
+ chunk_pos cpos;
+ Chunk* chunk;
+};
+
+struct VoxelSetEvent final {
+ Dimension* dimension;
+ chunk_pos cpos;
+ local_pos lpos;
+ voxel_id voxel;
+ Chunk* chunk;
+};
+} // namespace world
diff --git a/game/shared/world/feature.cc b/game/shared/world/feature.cc index cbdc183..4212043 100644 --- a/game/shared/world/feature.cc +++ b/game/shared/world/feature.cc @@ -1,53 +1,53 @@ -#include "shared/pch.hh" - -#include "shared/world/feature.hh" - -#include "shared/world/chunk.hh" -#include "shared/world/dimension.hh" -#include "shared/world/voxel_storage.hh" - -#include "shared/coord.hh" - -void world::Feature::place(const voxel_pos& vpos, Dimension* dimension) const -{ - for(const auto [rpos, voxel, overwrite] : (*this)) { - auto it_vpos = vpos + rpos; - auto it_cpos = coord::to_chunk(it_vpos); - - if(auto chunk = dimension->create_chunk(it_cpos)) { - auto it_lpos = coord::to_local(it_vpos); - auto it_index = coord::to_index(it_lpos); - - if(chunk->get_voxel(it_index) && !overwrite) { - // There is something in the way - // and the called intentionally requested - // we do not force feature to overwrite voxels - continue; - } - - chunk->set_voxel(voxel, it_index); - } - } -} - -void world::Feature::place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const -{ - for(const auto [rpos, voxel, overwrite] : (*this)) { - auto it_vpos = vpos + rpos; - auto it_cpos = coord::to_chunk(it_vpos); - - if(it_cpos == cpos) { - auto it_lpos = coord::to_local(it_vpos); - auto it_index = coord::to_index(it_lpos); - - if(voxels[it_index] && !overwrite) { - // There is something in the way - // and the called intentionally requested - // we do not force feature to overwrite voxels - continue; - } - - voxels[it_index] = voxel; - } - } -} +#include "shared/pch.hh"
+
+#include "shared/world/feature.hh"
+
+#include "shared/world/chunk.hh"
+#include "shared/world/dimension.hh"
+#include "shared/world/voxel_storage.hh"
+
+#include "shared/coord.hh"
+
+void world::Feature::place(const voxel_pos& vpos, Dimension* dimension) const
+{
+ for(const auto [rpos, voxel, overwrite] : (*this)) {
+ auto it_vpos = vpos + rpos;
+ auto it_cpos = coord::to_chunk(it_vpos);
+
+ if(auto chunk = dimension->create_chunk(it_cpos)) {
+ auto it_lpos = coord::to_local(it_vpos);
+ auto it_index = coord::to_index(it_lpos);
+
+ if(chunk->get_voxel(it_index) && !overwrite) {
+ // There is something in the way
+ // and the called intentionally requested
+ // we do not force feature to overwrite voxels
+ continue;
+ }
+
+ chunk->set_voxel(voxel, it_index);
+ }
+ }
+}
+
+void world::Feature::place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const
+{
+ for(const auto [rpos, voxel, overwrite] : (*this)) {
+ auto it_vpos = vpos + rpos;
+ auto it_cpos = coord::to_chunk(it_vpos);
+
+ if(it_cpos == cpos) {
+ auto it_lpos = coord::to_local(it_vpos);
+ auto it_index = coord::to_index(it_lpos);
+
+ if(voxels[it_index] && !overwrite) {
+ // There is something in the way
+ // and the called intentionally requested
+ // we do not force feature to overwrite voxels
+ continue;
+ }
+
+ voxels[it_index] = voxel;
+ }
+ }
+}
diff --git a/game/shared/world/feature.hh b/game/shared/world/feature.hh index 5008223..20a809b 100644 --- a/game/shared/world/feature.hh +++ b/game/shared/world/feature.hh @@ -1,22 +1,22 @@ -#pragma once - -#include "shared/types.hh" - -namespace world -{ -class Dimension; -class VoxelStorage; -} // namespace world - -namespace world -{ -class Feature final : public std::vector<std::tuple<voxel_pos, voxel_id, bool>> { -public: - Feature(void) = default; - virtual ~Feature(void) = default; - -public: - void place(const voxel_pos& vpos, Dimension* dimension) const; - void place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const; -}; -} // namespace world +#pragma once
+
+#include "shared/types.hh"
+
+namespace world
+{
+class Dimension;
+class VoxelStorage;
+} // namespace world
+
+namespace world
+{
+class Feature final : public std::vector<std::tuple<voxel_pos, voxel_id, bool>> {
+public:
+ Feature(void) = default;
+ virtual ~Feature(void) = default;
+
+public:
+ void place(const voxel_pos& vpos, Dimension* dimension) const;
+ void place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const;
+};
+} // namespace world
diff --git a/game/shared/world/item_registry.cc b/game/shared/world/item_registry.cc index e0d30cc..d1b9ff4 100644 --- a/game/shared/world/item_registry.cc +++ b/game/shared/world/item_registry.cc @@ -1,106 +1,106 @@ -#include "shared/pch.hh" - -#include "shared/world/item_registry.hh" - -#include "core/math/crc64.hh" - -#include "shared/world/voxel_registry.hh" - -std::unordered_map<std::string, world::ItemInfoBuilder> world::item_registry::builders = {}; -std::unordered_map<std::string, item_id> world::item_registry::names = {}; -std::vector<std::shared_ptr<world::ItemInfo>> world::item_registry::items = {}; - -world::ItemInfoBuilder::ItemInfoBuilder(std::string_view name) -{ - prototype.name = name; - prototype.texture = std::string(); - prototype.place_voxel = NULL_VOXEL_ID; - prototype.cached_texture = nullptr; -} - -world::ItemInfoBuilder& world::ItemInfoBuilder::set_texture(std::string_view texture) -{ - prototype.texture = texture; - prototype.cached_texture = nullptr; - return *this; -} - -world::ItemInfoBuilder& world::ItemInfoBuilder::set_place_voxel(voxel_id place_voxel) -{ - prototype.place_voxel = place_voxel; - return *this; -} - -item_id world::ItemInfoBuilder::build(void) const -{ - const auto it = world::item_registry::names.find(prototype.name); - - if(it != world::item_registry::names.cend()) { - spdlog::warn("item_registry: cannot build {}: name already present", prototype.name); - return it->second; - } - - auto new_info = std::make_shared<ItemInfo>(); - new_info->name = prototype.name; - new_info->texture = prototype.texture; - new_info->place_voxel = prototype.place_voxel; - new_info->cached_texture = nullptr; - - world::item_registry::items.push_back(new_info); - world::item_registry::names.insert_or_assign(prototype.name, static_cast<item_id>(world::item_registry::items.size())); - - return static_cast<item_id>(world::item_registry::items.size()); -} - -world::ItemInfoBuilder& world::item_registry::construct(std::string_view name) -{ - const auto it = world::item_registry::builders.find(std::string(name)); - - if(it != world::item_registry::builders.cend()) { - return it->second; - } - else { - return world::item_registry::builders.emplace(std::string(name), ItemInfoBuilder(name)).first->second; - } -} - -world::ItemInfo* world::item_registry::find(std::string_view name) -{ - const auto it = world::item_registry::names.find(std::string(name)); - - if(it != world::item_registry::names.cend()) { - return world::item_registry::find(it->second); - } - else { - return nullptr; - } -} - -world::ItemInfo* world::item_registry::find(const item_id item) -{ - if((item != NULL_ITEM_ID) && (item <= world::item_registry::items.size())) { - return world::item_registry::items[item - 1].get(); - } - else { - return nullptr; - } -} - -void world::item_registry::purge(void) -{ - world::item_registry::builders.clear(); - world::item_registry::names.clear(); - world::item_registry::items.clear(); -} - -std::uint64_t world::item_registry::calculate_checksum(void) -{ - std::uint64_t result = 0; - - for(const auto& info : world::item_registry::items) { - result = math::crc64(info->name, result); - result += static_cast<std::uint64_t>(info->place_voxel); - } - - return result; -} +#include "shared/pch.hh"
+
+#include "shared/world/item_registry.hh"
+
+#include "core/math/crc64.hh"
+
+#include "shared/world/voxel_registry.hh"
+
+std::unordered_map<std::string, world::ItemInfoBuilder> world::item_registry::builders = {};
+std::unordered_map<std::string, item_id> world::item_registry::names = {};
+std::vector<std::shared_ptr<world::ItemInfo>> world::item_registry::items = {};
+
+world::ItemInfoBuilder::ItemInfoBuilder(std::string_view name)
+{
+ prototype.name = name;
+ prototype.texture = std::string();
+ prototype.place_voxel = NULL_VOXEL_ID;
+ prototype.cached_texture = nullptr;
+}
+
+world::ItemInfoBuilder& world::ItemInfoBuilder::set_texture(std::string_view texture)
+{
+ prototype.texture = texture;
+ prototype.cached_texture = nullptr;
+ return *this;
+}
+
+world::ItemInfoBuilder& world::ItemInfoBuilder::set_place_voxel(voxel_id place_voxel)
+{
+ prototype.place_voxel = place_voxel;
+ return *this;
+}
+
+item_id world::ItemInfoBuilder::build(void) const
+{
+ const auto it = world::item_registry::names.find(prototype.name);
+
+ if(it != world::item_registry::names.cend()) {
+ spdlog::warn("item_registry: cannot build {}: name already present", prototype.name);
+ return it->second;
+ }
+
+ auto new_info = std::make_shared<ItemInfo>();
+ new_info->name = prototype.name;
+ new_info->texture = prototype.texture;
+ new_info->place_voxel = prototype.place_voxel;
+ new_info->cached_texture = nullptr;
+
+ world::item_registry::items.push_back(new_info);
+ world::item_registry::names.insert_or_assign(prototype.name, static_cast<item_id>(world::item_registry::items.size()));
+
+ return static_cast<item_id>(world::item_registry::items.size());
+}
+
+world::ItemInfoBuilder& world::item_registry::construct(std::string_view name)
+{
+ const auto it = world::item_registry::builders.find(std::string(name));
+
+ if(it != world::item_registry::builders.cend()) {
+ return it->second;
+ }
+ else {
+ return world::item_registry::builders.emplace(std::string(name), ItemInfoBuilder(name)).first->second;
+ }
+}
+
+world::ItemInfo* world::item_registry::find(std::string_view name)
+{
+ const auto it = world::item_registry::names.find(std::string(name));
+
+ if(it != world::item_registry::names.cend()) {
+ return world::item_registry::find(it->second);
+ }
+ else {
+ return nullptr;
+ }
+}
+
+world::ItemInfo* world::item_registry::find(const item_id item)
+{
+ if((item != NULL_ITEM_ID) && (item <= world::item_registry::items.size())) {
+ return world::item_registry::items[item - 1].get();
+ }
+ else {
+ return nullptr;
+ }
+}
+
+void world::item_registry::purge(void)
+{
+ world::item_registry::builders.clear();
+ world::item_registry::names.clear();
+ world::item_registry::items.clear();
+}
+
+std::uint64_t world::item_registry::calculate_checksum(void)
+{
+ std::uint64_t result = 0;
+
+ for(const auto& info : world::item_registry::items) {
+ result = math::crc64(info->name, result);
+ result += static_cast<std::uint64_t>(info->place_voxel);
+ }
+
+ return result;
+}
diff --git a/game/shared/world/item_registry.hh b/game/shared/world/item_registry.hh index 74bd60a..c3e6cf9 100644 --- a/game/shared/world/item_registry.hh +++ b/game/shared/world/item_registry.hh @@ -1,64 +1,64 @@ -#pragma once - -#include "core/resource/resource.hh" - -#include "shared/types.hh" - -// This resource is only defined client-side and -// resource_ptr<TextureGUI> should remain set to null -// anywhere else in the shared and server code -struct TextureGUI; - -namespace world -{ -struct ItemInfo final { - std::string name; - std::string texture; - voxel_id place_voxel; - - resource_ptr<TextureGUI> cached_texture; // Client-side only -}; -} // namespace world - -namespace world -{ -class ItemInfoBuilder final { -public: - explicit ItemInfoBuilder(std::string_view name); - virtual ~ItemInfoBuilder(void) = default; - -public: - ItemInfoBuilder& set_texture(std::string_view texture); - ItemInfoBuilder& set_place_voxel(voxel_id place_voxel); - -public: - item_id build(void) const; - -private: - ItemInfo prototype; -}; -} // namespace world - -namespace world::item_registry -{ -extern std::unordered_map<std::string, ItemInfoBuilder> builders; -extern std::unordered_map<std::string, item_id> names; -extern std::vector<std::shared_ptr<ItemInfo>> items; -} // namespace world::item_registry - -namespace world::item_registry -{ -ItemInfoBuilder& construct(std::string_view name); -ItemInfo* find(std::string_view name); -ItemInfo* find(const item_id item); -} // namespace world::item_registry - -namespace world::item_registry -{ -void purge(void); -} // namespace world::item_registry - -namespace world::item_registry -{ -std::uint64_t calculate_checksum(void); -} // namespace world::item_registry +#pragma once
+
+#include "core/resource/resource.hh"
+
+#include "shared/types.hh"
+
+// This resource is only defined client-side and
+// resource_ptr<TextureGUI> should remain set to null
+// anywhere else in the shared and server code
+struct TextureGUI;
+
+namespace world
+{
+struct ItemInfo final {
+ std::string name;
+ std::string texture;
+ voxel_id place_voxel;
+
+ resource_ptr<TextureGUI> cached_texture; // Client-side only
+};
+} // namespace world
+
+namespace world
+{
+class ItemInfoBuilder final {
+public:
+ explicit ItemInfoBuilder(std::string_view name);
+ virtual ~ItemInfoBuilder(void) = default;
+
+public:
+ ItemInfoBuilder& set_texture(std::string_view texture);
+ ItemInfoBuilder& set_place_voxel(voxel_id place_voxel);
+
+public:
+ item_id build(void) const;
+
+private:
+ ItemInfo prototype;
+};
+} // namespace world
+
+namespace world::item_registry
+{
+extern std::unordered_map<std::string, ItemInfoBuilder> builders;
+extern std::unordered_map<std::string, item_id> names;
+extern std::vector<std::shared_ptr<ItemInfo>> items;
+} // namespace world::item_registry
+
+namespace world::item_registry
+{
+ItemInfoBuilder& construct(std::string_view name);
+ItemInfo* find(std::string_view name);
+ItemInfo* find(const item_id item);
+} // namespace world::item_registry
+
+namespace world::item_registry
+{
+void purge(void);
+} // namespace world::item_registry
+
+namespace world::item_registry
+{
+std::uint64_t calculate_checksum(void);
+} // namespace world::item_registry
diff --git a/game/shared/world/ray_dda.cc b/game/shared/world/ray_dda.cc index 9f85e6b..b337e9d 100644 --- a/game/shared/world/ray_dda.cc +++ b/game/shared/world/ray_dda.cc @@ -1,107 +1,107 @@ -#include "shared/pch.hh" - -#include "shared/world/ray_dda.hh" - -#include "shared/world/dimension.hh" - -#include "shared/coord.hh" - -world::RayDDA::RayDDA( - const world::Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction) -{ - reset(dimension, start_chunk, start_fpos, direction); -} - -world::RayDDA::RayDDA( - const world::Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction) -{ - reset(dimension, start_chunk, start_fpos, direction); -} - -void world::RayDDA::reset( - const world::Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction) -{ - this->dimension = dimension; - this->start_chunk = start_chunk; - this->start_fpos = start_fpos; - this->direction = direction; - - this->delta_dist.x = direction.x ? math::abs(1.0f / direction.x) : std::numeric_limits<float>::max(); - this->delta_dist.y = direction.y ? math::abs(1.0f / direction.y) : std::numeric_limits<float>::max(); - this->delta_dist.z = direction.z ? math::abs(1.0f / direction.z) : std::numeric_limits<float>::max(); - - this->distance = 0.0f; - this->vpos = coord::to_voxel(start_chunk, start_fpos); - this->vnormal = voxel_pos(0, 0, 0); - - // Need this for initial direction calculations - auto lpos = coord::to_local(start_fpos); - - if(direction.x < 0.0f) { - this->side_dist.x = this->delta_dist.x * (start_fpos.x - lpos.x); - this->vstep.x = voxel_pos::value_type(-1); - } - else { - this->side_dist.x = this->delta_dist.x * (lpos.x + 1.0f - start_fpos.x); - this->vstep.x = voxel_pos::value_type(+1); - } - - if(direction.y < 0.0f) { - this->side_dist.y = this->delta_dist.y * (start_fpos.y - lpos.y); - this->vstep.y = voxel_pos::value_type(-1); - } - else { - this->side_dist.y = this->delta_dist.y * (lpos.y + 1.0f - start_fpos.y); - this->vstep.y = voxel_pos::value_type(+1); - } - - if(direction.z < 0.0f) { - this->side_dist.z = this->delta_dist.z * (start_fpos.z - lpos.z); - this->vstep.z = voxel_pos::value_type(-1); - } - else { - this->side_dist.z = this->delta_dist.z * (lpos.z + 1.0f - start_fpos.z); - this->vstep.z = voxel_pos::value_type(+1); - } -} - -void world::RayDDA::reset( - const world::Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction) -{ - reset(&dimension, start_chunk, start_fpos, direction); -} - -voxel_id world::RayDDA::step(void) -{ - if(side_dist.x < side_dist.z) { - if(side_dist.x < side_dist.y) { - vnormal = voxel_pos(-vstep.x, 0, 0); - distance = side_dist.x; - side_dist.x += delta_dist.x; - vpos.x += vstep.x; - } - else { - vnormal = voxel_pos(0, -vstep.y, 0); - distance = side_dist.y; - side_dist.y += delta_dist.y; - vpos.y += vstep.y; - } - } - else { - if(side_dist.z < side_dist.y) { - vnormal = voxel_pos(0, 0, -vstep.z); - distance = side_dist.z; - side_dist.z += delta_dist.z; - vpos.z += vstep.z; - } - else { - vnormal = voxel_pos(0, -vstep.y, 0); - distance = side_dist.y; - side_dist.y += delta_dist.y; - vpos.y += vstep.y; - } - } - - // This is slower than I want it to be - return dimension->get_voxel(vpos); -} +#include "shared/pch.hh"
+
+#include "shared/world/ray_dda.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/coord.hh"
+
+world::RayDDA::RayDDA(const world::Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos,
+ const glm::fvec3& direction)
+{
+ reset(dimension, start_chunk, start_fpos, direction);
+}
+
+world::RayDDA::RayDDA(const world::Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos,
+ const glm::fvec3& direction)
+{
+ reset(dimension, start_chunk, start_fpos, direction);
+}
+
+void world::RayDDA::reset(const world::Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos,
+ const glm::fvec3& direction)
+{
+ this->dimension = dimension;
+ this->start_chunk = start_chunk;
+ this->start_fpos = start_fpos;
+ this->direction = direction;
+
+ this->delta_dist.x = direction.x ? math::abs(1.0f / direction.x) : std::numeric_limits<float>::max();
+ this->delta_dist.y = direction.y ? math::abs(1.0f / direction.y) : std::numeric_limits<float>::max();
+ this->delta_dist.z = direction.z ? math::abs(1.0f / direction.z) : std::numeric_limits<float>::max();
+
+ this->distance = 0.0f;
+ this->vpos = coord::to_voxel(start_chunk, start_fpos);
+ this->vnormal = voxel_pos(0, 0, 0);
+
+ // Need this for initial direction calculations
+ auto lpos = coord::to_local(start_fpos);
+
+ if(direction.x < 0.0f) {
+ this->side_dist.x = this->delta_dist.x * (start_fpos.x - lpos.x);
+ this->vstep.x = voxel_pos::value_type(-1);
+ }
+ else {
+ this->side_dist.x = this->delta_dist.x * (lpos.x + 1.0f - start_fpos.x);
+ this->vstep.x = voxel_pos::value_type(+1);
+ }
+
+ if(direction.y < 0.0f) {
+ this->side_dist.y = this->delta_dist.y * (start_fpos.y - lpos.y);
+ this->vstep.y = voxel_pos::value_type(-1);
+ }
+ else {
+ this->side_dist.y = this->delta_dist.y * (lpos.y + 1.0f - start_fpos.y);
+ this->vstep.y = voxel_pos::value_type(+1);
+ }
+
+ if(direction.z < 0.0f) {
+ this->side_dist.z = this->delta_dist.z * (start_fpos.z - lpos.z);
+ this->vstep.z = voxel_pos::value_type(-1);
+ }
+ else {
+ this->side_dist.z = this->delta_dist.z * (lpos.z + 1.0f - start_fpos.z);
+ this->vstep.z = voxel_pos::value_type(+1);
+ }
+}
+
+void world::RayDDA::reset(const world::Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos,
+ const glm::fvec3& direction)
+{
+ reset(&dimension, start_chunk, start_fpos, direction);
+}
+
+voxel_id world::RayDDA::step(void)
+{
+ if(side_dist.x < side_dist.z) {
+ if(side_dist.x < side_dist.y) {
+ vnormal = voxel_pos(-vstep.x, 0, 0);
+ distance = side_dist.x;
+ side_dist.x += delta_dist.x;
+ vpos.x += vstep.x;
+ }
+ else {
+ vnormal = voxel_pos(0, -vstep.y, 0);
+ distance = side_dist.y;
+ side_dist.y += delta_dist.y;
+ vpos.y += vstep.y;
+ }
+ }
+ else {
+ if(side_dist.z < side_dist.y) {
+ vnormal = voxel_pos(0, 0, -vstep.z);
+ distance = side_dist.z;
+ side_dist.z += delta_dist.z;
+ vpos.z += vstep.z;
+ }
+ else {
+ vnormal = voxel_pos(0, -vstep.y, 0);
+ distance = side_dist.y;
+ side_dist.y += delta_dist.y;
+ vpos.y += vstep.y;
+ }
+ }
+
+ // This is slower than I want it to be
+ return dimension->get_voxel(vpos);
+}
diff --git a/game/shared/world/ray_dda.hh b/game/shared/world/ray_dda.hh index 927c74d..54bd48a 100644 --- a/game/shared/world/ray_dda.hh +++ b/game/shared/world/ray_dda.hh @@ -1,41 +1,41 @@ -#ifndef SHARED_RAY_DDA -#define SHARED_RAY_DDA 1 -#pragma once - -#include "shared/types.hh" - -namespace world -{ -class Dimension; -} // namespace world - -namespace world -{ -class RayDDA final { -public: - RayDDA(void) = default; - explicit RayDDA(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction); - explicit RayDDA(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction); - - void reset(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction); - void reset(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction); - - voxel_id step(void); - -public: - const Dimension* dimension; - chunk_pos start_chunk; - glm::fvec3 start_fpos; - glm::fvec3 direction; - - glm::fvec3 delta_dist; - glm::fvec3 side_dist; - voxel_pos vstep; - - double distance; - voxel_pos vnormal; - voxel_pos vpos; -}; -} // namespace world - -#endif // SHARED_RAY_DDA +#ifndef SHARED_RAY_DDA
+#define SHARED_RAY_DDA 1
+#pragma once
+
+#include "shared/types.hh"
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace world
+{
+class RayDDA final {
+public:
+ RayDDA(void) = default;
+ explicit RayDDA(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
+ explicit RayDDA(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
+
+ void reset(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
+ void reset(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
+
+ voxel_id step(void);
+
+public:
+ const Dimension* dimension;
+ chunk_pos start_chunk;
+ glm::fvec3 start_fpos;
+ glm::fvec3 direction;
+
+ glm::fvec3 delta_dist;
+ glm::fvec3 side_dist;
+ voxel_pos vstep;
+
+ double distance;
+ voxel_pos vnormal;
+ voxel_pos vpos;
+};
+} // namespace world
+
+#endif // SHARED_RAY_DDA
diff --git a/game/shared/world/voxel_registry.cc b/game/shared/world/voxel_registry.cc index 46737d6..b44845e 100644 --- a/game/shared/world/voxel_registry.cc +++ b/game/shared/world/voxel_registry.cc @@ -1,196 +1,196 @@ -#include "shared/pch.hh" - -#include "shared/world/voxel_registry.hh" - -#include "core/math/crc64.hh" - -std::unordered_map<std::string, world::VoxelInfoBuilder> world::voxel_registry::builders = {}; -std::unordered_map<std::string, voxel_id> world::voxel_registry::names = {}; -std::vector<std::shared_ptr<world::VoxelInfo>> world::voxel_registry::voxels = {}; - -world::VoxelInfoBuilder::VoxelInfoBuilder(std::string_view name, voxel_type type, bool animated, bool blending) -{ - prototype.name = name; - prototype.type = type; - prototype.animated = animated; - prototype.blending = blending; - - switch(type) { - case voxel_type::CUBE: - prototype.textures.resize(static_cast<std::size_t>(voxel_face::CUBE__NR)); - break; - case voxel_type::CROSS: - prototype.textures.resize(static_cast<std::size_t>(voxel_face::CROSS__NR)); - break; - case voxel_type::MODEL: - // Custom models should use a different texture - // resource management that is not a voxel atlas - // TODO: actually implement custom models lol - prototype.textures.resize(0); - break; - default: - // Something really bad should happen if we end up here. - // The outside code would static_cast an int to VoxelType - // and possibly fuck a lot of things up to cause this - spdlog::critical("voxel_registry: {}: unknown voxel type {}", name, static_cast<int>(type)); - std::terminate(); - } - - // Physics properties - prototype.touch_type = voxel_touch::SOLID; - prototype.touch_values = glm::fvec3(0.0f, 0.0f, 0.0f); - prototype.surface = voxel_surface::DEFAULT; - - // Things set in future by item_def - prototype.item_pick = NULL_ITEM_ID; -} - -world::VoxelInfoBuilder& world::VoxelInfoBuilder::add_texture_default(std::string_view texture) -{ - default_texture.paths.push_back(std::string(texture)); - return *this; -} - -world::VoxelInfoBuilder& world::VoxelInfoBuilder::add_texture(voxel_face face, std::string_view texture) -{ - const auto index = static_cast<std::size_t>(face); - prototype.textures[index].paths.push_back(std::string(texture)); - return *this; -} - -world::VoxelInfoBuilder& world::VoxelInfoBuilder::set_touch(voxel_touch type, const glm::fvec3& values) -{ - prototype.touch_type = type; - prototype.touch_values = values; - return *this; -} - -world::VoxelInfoBuilder& world::VoxelInfoBuilder::set_surface(voxel_surface surface) -{ - prototype.surface = surface; - return *this; -} - -voxel_id world::VoxelInfoBuilder::build(void) const -{ - const auto it = world::voxel_registry::names.find(prototype.name); - - if(it != world::voxel_registry::names.cend()) { - spdlog::warn("voxel_registry: cannot build {}: name already present", prototype.name); - return it->second; - } - - std::size_t state_count; - - switch(prototype.type) { - case voxel_type::CUBE: - case voxel_type::CROSS: - case voxel_type::MODEL: - state_count = 1; - break; - default: - // Something really bad should happen if we end up here. - // The outside code would static_cast an int to VoxelType - // and possibly fuck a lot of things up to cause this - spdlog::critical("voxel_registry: {}: unknown voxel type {}", prototype.name, static_cast<int>(prototype.type)); - std::terminate(); - } - - if((world::voxel_registry::voxels.size() + state_count) >= MAX_VOXEL_ID) { - spdlog::critical("voxel_registry: voxel registry overflow"); - std::terminate(); - } - - auto new_info = std::make_shared<VoxelInfo>(); - new_info->name = prototype.name; - new_info->type = prototype.type; - new_info->animated = prototype.animated; - new_info->blending = prototype.blending; - - new_info->textures.resize(prototype.textures.size()); - - for(std::size_t i = 0; i < prototype.textures.size(); ++i) { - if(prototype.textures[i].paths.empty()) { - new_info->textures[i].paths = default_texture.paths; - new_info->textures[i].cached_offset = SIZE_MAX; - new_info->textures[i].cached_plane = SIZE_MAX; - } - else { - new_info->textures[i].paths = prototype.textures[i].paths; - new_info->textures[i].cached_offset = SIZE_MAX; - new_info->textures[i].cached_plane = SIZE_MAX; - } - } - - // Physics properties - new_info->touch_type = prototype.touch_type; - new_info->touch_values = prototype.touch_values; - new_info->surface = prototype.surface; - - // Things set in future by item_def - new_info->item_pick = prototype.item_pick; - - // Base voxel identifier offset - new_info->base_voxel = world::voxel_registry::voxels.size() + 1; - - for(std::size_t i = 0; i < state_count; ++i) - world::voxel_registry::voxels.push_back(new_info); - world::voxel_registry::names.insert_or_assign(new_info->name, new_info->base_voxel); - - return new_info->base_voxel; -} - -world::VoxelInfoBuilder& world::voxel_registry::construct(std::string_view name, voxel_type type, bool animated, bool blending) -{ - const auto it = world::voxel_registry::builders.find(std::string(name)); - - if(it != world::voxel_registry::builders.cend()) { - return it->second; - } - else { - return world::voxel_registry::builders.emplace(std::string(name), VoxelInfoBuilder(name, type, animated, blending)).first->second; - } -} - -world::VoxelInfo* world::voxel_registry::find(std::string_view name) -{ - const auto it = world::voxel_registry::names.find(std::string(name)); - - if(it != world::voxel_registry::names.cend()) { - return world::voxel_registry::find(it->second); - } - else { - return nullptr; - } -} - -world::VoxelInfo* world::voxel_registry::find(const voxel_id voxel) -{ - if((voxel != NULL_VOXEL_ID) && (voxel <= world::voxel_registry::voxels.size())) { - return world::voxel_registry::voxels[voxel - 1].get(); - } - else { - return nullptr; - } -} - -void world::voxel_registry::purge(void) -{ - world::voxel_registry::builders.clear(); - world::voxel_registry::names.clear(); - world::voxel_registry::voxels.clear(); -} - -std::uint64_t world::voxel_registry::calculate_checksum(void) -{ - std::uint64_t result = 0; - - for(const std::shared_ptr<VoxelInfo>& info : world::voxel_registry::voxels) { - result = math::crc64(info->name, result); - result += static_cast<std::uint64_t>(info->type); - result += static_cast<std::uint64_t>(info->base_voxel); - result += info->blending ? 256 : 1; - } - - return result; -} +#include "shared/pch.hh"
+
+#include "shared/world/voxel_registry.hh"
+
+#include "core/math/crc64.hh"
+
+std::unordered_map<std::string, world::VoxelInfoBuilder> world::voxel_registry::builders = {};
+std::unordered_map<std::string, voxel_id> world::voxel_registry::names = {};
+std::vector<std::shared_ptr<world::VoxelInfo>> world::voxel_registry::voxels = {};
+
+world::VoxelInfoBuilder::VoxelInfoBuilder(std::string_view name, voxel_type type, bool animated, bool blending)
+{
+ prototype.name = name;
+ prototype.type = type;
+ prototype.animated = animated;
+ prototype.blending = blending;
+
+ switch(type) {
+ case voxel_type::CUBE:
+ prototype.textures.resize(static_cast<std::size_t>(voxel_face::CUBE__NR));
+ break;
+ case voxel_type::CROSS:
+ prototype.textures.resize(static_cast<std::size_t>(voxel_face::CROSS__NR));
+ break;
+ case voxel_type::MODEL:
+ // Custom models should use a different texture
+ // resource management that is not a voxel atlas
+ // TODO: actually implement custom models lol
+ prototype.textures.resize(0);
+ break;
+ default:
+ // Something really bad should happen if we end up here.
+ // The outside code would static_cast an int to VoxelType
+ // and possibly fuck a lot of things up to cause this
+ spdlog::critical("voxel_registry: {}: unknown voxel type {}", name, static_cast<int>(type));
+ std::terminate();
+ }
+
+ // Physics properties
+ prototype.touch_type = voxel_touch::SOLID;
+ prototype.touch_values = glm::fvec3(0.0f, 0.0f, 0.0f);
+ prototype.surface = voxel_surface::DEFAULT;
+
+ // Things set in future by item_def
+ prototype.item_pick = NULL_ITEM_ID;
+}
+
+world::VoxelInfoBuilder& world::VoxelInfoBuilder::add_texture_default(std::string_view texture)
+{
+ default_texture.paths.push_back(std::string(texture));
+ return *this;
+}
+
+world::VoxelInfoBuilder& world::VoxelInfoBuilder::add_texture(voxel_face face, std::string_view texture)
+{
+ const auto index = static_cast<std::size_t>(face);
+ prototype.textures[index].paths.push_back(std::string(texture));
+ return *this;
+}
+
+world::VoxelInfoBuilder& world::VoxelInfoBuilder::set_touch(voxel_touch type, const glm::fvec3& values)
+{
+ prototype.touch_type = type;
+ prototype.touch_values = values;
+ return *this;
+}
+
+world::VoxelInfoBuilder& world::VoxelInfoBuilder::set_surface(voxel_surface surface)
+{
+ prototype.surface = surface;
+ return *this;
+}
+
+voxel_id world::VoxelInfoBuilder::build(void) const
+{
+ const auto it = world::voxel_registry::names.find(prototype.name);
+
+ if(it != world::voxel_registry::names.cend()) {
+ spdlog::warn("voxel_registry: cannot build {}: name already present", prototype.name);
+ return it->second;
+ }
+
+ std::size_t state_count;
+
+ switch(prototype.type) {
+ case voxel_type::CUBE:
+ case voxel_type::CROSS:
+ case voxel_type::MODEL:
+ state_count = 1;
+ break;
+ default:
+ // Something really bad should happen if we end up here.
+ // The outside code would static_cast an int to VoxelType
+ // and possibly fuck a lot of things up to cause this
+ spdlog::critical("voxel_registry: {}: unknown voxel type {}", prototype.name, static_cast<int>(prototype.type));
+ std::terminate();
+ }
+
+ if((world::voxel_registry::voxels.size() + state_count) >= MAX_VOXEL_ID) {
+ spdlog::critical("voxel_registry: voxel registry overflow");
+ std::terminate();
+ }
+
+ auto new_info = std::make_shared<VoxelInfo>();
+ new_info->name = prototype.name;
+ new_info->type = prototype.type;
+ new_info->animated = prototype.animated;
+ new_info->blending = prototype.blending;
+
+ new_info->textures.resize(prototype.textures.size());
+
+ for(std::size_t i = 0; i < prototype.textures.size(); ++i) {
+ if(prototype.textures[i].paths.empty()) {
+ new_info->textures[i].paths = default_texture.paths;
+ new_info->textures[i].cached_offset = SIZE_MAX;
+ new_info->textures[i].cached_plane = SIZE_MAX;
+ }
+ else {
+ new_info->textures[i].paths = prototype.textures[i].paths;
+ new_info->textures[i].cached_offset = SIZE_MAX;
+ new_info->textures[i].cached_plane = SIZE_MAX;
+ }
+ }
+
+ // Physics properties
+ new_info->touch_type = prototype.touch_type;
+ new_info->touch_values = prototype.touch_values;
+ new_info->surface = prototype.surface;
+
+ // Things set in future by item_def
+ new_info->item_pick = prototype.item_pick;
+
+ // Base voxel identifier offset
+ new_info->base_voxel = world::voxel_registry::voxels.size() + 1;
+
+ for(std::size_t i = 0; i < state_count; ++i)
+ world::voxel_registry::voxels.push_back(new_info);
+ world::voxel_registry::names.insert_or_assign(new_info->name, new_info->base_voxel);
+
+ return new_info->base_voxel;
+}
+
+world::VoxelInfoBuilder& world::voxel_registry::construct(std::string_view name, voxel_type type, bool animated, bool blending)
+{
+ const auto it = world::voxel_registry::builders.find(std::string(name));
+
+ if(it != world::voxel_registry::builders.cend()) {
+ return it->second;
+ }
+ else {
+ return world::voxel_registry::builders.emplace(std::string(name), VoxelInfoBuilder(name, type, animated, blending)).first->second;
+ }
+}
+
+world::VoxelInfo* world::voxel_registry::find(std::string_view name)
+{
+ const auto it = world::voxel_registry::names.find(std::string(name));
+
+ if(it != world::voxel_registry::names.cend()) {
+ return world::voxel_registry::find(it->second);
+ }
+ else {
+ return nullptr;
+ }
+}
+
+world::VoxelInfo* world::voxel_registry::find(const voxel_id voxel)
+{
+ if((voxel != NULL_VOXEL_ID) && (voxel <= world::voxel_registry::voxels.size())) {
+ return world::voxel_registry::voxels[voxel - 1].get();
+ }
+ else {
+ return nullptr;
+ }
+}
+
+void world::voxel_registry::purge(void)
+{
+ world::voxel_registry::builders.clear();
+ world::voxel_registry::names.clear();
+ world::voxel_registry::voxels.clear();
+}
+
+std::uint64_t world::voxel_registry::calculate_checksum(void)
+{
+ std::uint64_t result = 0;
+
+ for(const std::shared_ptr<VoxelInfo>& info : world::voxel_registry::voxels) {
+ result = math::crc64(info->name, result);
+ result += static_cast<std::uint64_t>(info->type);
+ result += static_cast<std::uint64_t>(info->base_voxel);
+ result += info->blending ? 256 : 1;
+ }
+
+ return result;
+}
diff --git a/game/shared/world/voxel_registry.hh b/game/shared/world/voxel_registry.hh index 6ab8c97..a75f59f 100644 --- a/game/shared/world/voxel_registry.hh +++ b/game/shared/world/voxel_registry.hh @@ -1,149 +1,149 @@ -#pragma once - -#include "shared/types.hh" - -namespace world -{ -enum class voxel_face : unsigned short { - CUBE_NORTH = 0x0000, - CUBE_SOUTH = 0x0001, - CUBE_EAST = 0x0002, - CUBE_WEST = 0x0003, - CUBE_TOP = 0x0004, - CUBE_BOTTOM = 0x0005, - CUBE__NR = 0x0006, - - CROSS_NESW = 0x0000, - CROSS_NWSE = 0x0001, - CROSS__NR = 0x0002, -}; - -enum class voxel_type : unsigned short { - CUBE = 0x0000, - CROSS = 0x0001, // TODO - MODEL = 0x0002, // TODO -}; - -enum class voxel_facing : unsigned short { - NORTH = 0x0000, - SOUTH = 0x0001, - EAST = 0x0002, - WEST = 0x0003, - UP = 0x0004, - DOWN = 0x0005, - NESW = 0x0006, - NWSE = 0x0007, -}; - -enum class voxel_touch : unsigned short { - SOLID = 0x0000, // The entity is stopped in its tracks - BOUNCE = 0x0001, // The entity bounces back with some energy loss - SINK = 0x0002, // The entity phases/sinks through the voxel - NOTHING = 0xFFFF, -}; - -enum class voxel_surface : unsigned short { - DEFAULT = 0x0000, - STONE = 0x0001, - DIRT = 0x0002, - GLASS = 0x0003, - GRASS = 0x0004, - GRAVEL = 0x0005, - METAL = 0x0006, - SAND = 0x0007, - WOOD = 0x0008, - SLOSH = 0x0009, - COUNT = 0x000A, - UNKNOWN = 0xFFFF, -}; - -using voxel_vis = unsigned short; -constexpr static voxel_vis VIS_NORTH = 1 << static_cast<unsigned int>(voxel_facing::NORTH); -constexpr static voxel_vis VIS_SOUTH = 1 << static_cast<unsigned int>(voxel_facing::SOUTH); -constexpr static voxel_vis VIS_EAST = 1 << static_cast<unsigned int>(voxel_facing::EAST); -constexpr static voxel_vis VIS_WEST = 1 << static_cast<unsigned int>(voxel_facing::WEST); -constexpr static voxel_vis VIS_UP = 1 << static_cast<unsigned int>(voxel_facing::UP); -constexpr static voxel_vis VIS_DOWN = 1 << static_cast<unsigned int>(voxel_facing::DOWN); -} // namespace world - -namespace world -{ -struct VoxelTexture final { - std::vector<std::string> paths; - std::size_t cached_offset; // client-side only - std::size_t cached_plane; // client-side only -}; - -struct VoxelInfo final { - std::string name; - voxel_type type; - bool animated; - bool blending; - - std::vector<VoxelTexture> textures; - - // Physics properties go here - // TODO: player_move friction modifiers - // that would make the voxel very sticky or - // very slippery to walk on - voxel_touch touch_type; - glm::fvec3 touch_values; - voxel_surface surface; - - // Some voxel types might occupy multiple voxel_id - // values that reference to the exact same VoxelInfo - // structure; the actual numeric state is figured out by - // subtracting base_voxel from the checking voxel_id - voxel_id base_voxel; - - // These will be set by item_registry - // and by default set to NULL_ITEM_ID - item_id item_pick; -}; -} // namespace world - -namespace world -{ -class VoxelInfoBuilder final { -public: - explicit VoxelInfoBuilder(std::string_view name, voxel_type type, bool animated, bool blending); - virtual ~VoxelInfoBuilder(void) = default; - -public: - VoxelInfoBuilder& add_texture_default(std::string_view texture); - VoxelInfoBuilder& add_texture(voxel_face face, std::string_view texture); - VoxelInfoBuilder& set_touch(voxel_touch type, const glm::fvec3& values); - VoxelInfoBuilder& set_surface(voxel_surface surface); - -public: - voxel_id build(void) const; - -private: - VoxelTexture default_texture; - VoxelInfo prototype; -}; -} // namespace world - -namespace world::voxel_registry -{ -extern std::unordered_map<std::string, VoxelInfoBuilder> builders; -extern std::unordered_map<std::string, voxel_id> names; -extern std::vector<std::shared_ptr<VoxelInfo>> voxels; -} // namespace world::voxel_registry - -namespace world::voxel_registry -{ -VoxelInfoBuilder& construct(std::string_view name, voxel_type type, bool animated, bool blending); -VoxelInfo* find(std::string_view name); -VoxelInfo* find(const voxel_id voxel); -} // namespace world::voxel_registry - -namespace world::voxel_registry -{ -void purge(void); -} // namespace world::voxel_registry - -namespace world::voxel_registry -{ -std::uint64_t calculate_checksum(void); -} // namespace world::voxel_registry +#pragma once
+
+#include "shared/types.hh"
+
+namespace world
+{
+enum class voxel_face : unsigned short {
+ CUBE_NORTH = 0x0000,
+ CUBE_SOUTH = 0x0001,
+ CUBE_EAST = 0x0002,
+ CUBE_WEST = 0x0003,
+ CUBE_TOP = 0x0004,
+ CUBE_BOTTOM = 0x0005,
+ CUBE__NR = 0x0006,
+
+ CROSS_NESW = 0x0000,
+ CROSS_NWSE = 0x0001,
+ CROSS__NR = 0x0002,
+};
+
+enum class voxel_type : unsigned short {
+ CUBE = 0x0000,
+ CROSS = 0x0001, // TODO
+ MODEL = 0x0002, // TODO
+};
+
+enum class voxel_facing : unsigned short {
+ NORTH = 0x0000,
+ SOUTH = 0x0001,
+ EAST = 0x0002,
+ WEST = 0x0003,
+ UP = 0x0004,
+ DOWN = 0x0005,
+ NESW = 0x0006,
+ NWSE = 0x0007,
+};
+
+enum class voxel_touch : unsigned short {
+ SOLID = 0x0000, // The entity is stopped in its tracks
+ BOUNCE = 0x0001, // The entity bounces back with some energy loss
+ SINK = 0x0002, // The entity phases/sinks through the voxel
+ NOTHING = 0xFFFF,
+};
+
+enum class voxel_surface : unsigned short {
+ DEFAULT = 0x0000,
+ STONE = 0x0001,
+ DIRT = 0x0002,
+ GLASS = 0x0003,
+ GRASS = 0x0004,
+ GRAVEL = 0x0005,
+ METAL = 0x0006,
+ SAND = 0x0007,
+ WOOD = 0x0008,
+ SLOSH = 0x0009,
+ COUNT = 0x000A,
+ UNKNOWN = 0xFFFF,
+};
+
+using voxel_vis = unsigned short;
+constexpr static voxel_vis VIS_NORTH = 1 << static_cast<unsigned int>(voxel_facing::NORTH);
+constexpr static voxel_vis VIS_SOUTH = 1 << static_cast<unsigned int>(voxel_facing::SOUTH);
+constexpr static voxel_vis VIS_EAST = 1 << static_cast<unsigned int>(voxel_facing::EAST);
+constexpr static voxel_vis VIS_WEST = 1 << static_cast<unsigned int>(voxel_facing::WEST);
+constexpr static voxel_vis VIS_UP = 1 << static_cast<unsigned int>(voxel_facing::UP);
+constexpr static voxel_vis VIS_DOWN = 1 << static_cast<unsigned int>(voxel_facing::DOWN);
+} // namespace world
+
+namespace world
+{
+struct VoxelTexture final {
+ std::vector<std::string> paths;
+ std::size_t cached_offset; // client-side only
+ std::size_t cached_plane; // client-side only
+};
+
+struct VoxelInfo final {
+ std::string name;
+ voxel_type type;
+ bool animated;
+ bool blending;
+
+ std::vector<VoxelTexture> textures;
+
+ // Physics properties go here
+ // TODO: player_move friction modifiers
+ // that would make the voxel very sticky or
+ // very slippery to walk on
+ voxel_touch touch_type;
+ glm::fvec3 touch_values;
+ voxel_surface surface;
+
+ // Some voxel types might occupy multiple voxel_id
+ // values that reference to the exact same VoxelInfo
+ // structure; the actual numeric state is figured out by
+ // subtracting base_voxel from the checking voxel_id
+ voxel_id base_voxel;
+
+ // These will be set by item_registry
+ // and by default set to NULL_ITEM_ID
+ item_id item_pick;
+};
+} // namespace world
+
+namespace world
+{
+class VoxelInfoBuilder final {
+public:
+ explicit VoxelInfoBuilder(std::string_view name, voxel_type type, bool animated, bool blending);
+ virtual ~VoxelInfoBuilder(void) = default;
+
+public:
+ VoxelInfoBuilder& add_texture_default(std::string_view texture);
+ VoxelInfoBuilder& add_texture(voxel_face face, std::string_view texture);
+ VoxelInfoBuilder& set_touch(voxel_touch type, const glm::fvec3& values);
+ VoxelInfoBuilder& set_surface(voxel_surface surface);
+
+public:
+ voxel_id build(void) const;
+
+private:
+ VoxelTexture default_texture;
+ VoxelInfo prototype;
+};
+} // namespace world
+
+namespace world::voxel_registry
+{
+extern std::unordered_map<std::string, VoxelInfoBuilder> builders;
+extern std::unordered_map<std::string, voxel_id> names;
+extern std::vector<std::shared_ptr<VoxelInfo>> voxels;
+} // namespace world::voxel_registry
+
+namespace world::voxel_registry
+{
+VoxelInfoBuilder& construct(std::string_view name, voxel_type type, bool animated, bool blending);
+VoxelInfo* find(std::string_view name);
+VoxelInfo* find(const voxel_id voxel);
+} // namespace world::voxel_registry
+
+namespace world::voxel_registry
+{
+void purge(void);
+} // namespace world::voxel_registry
+
+namespace world::voxel_registry
+{
+std::uint64_t calculate_checksum(void);
+} // namespace world::voxel_registry
diff --git a/game/shared/world/voxel_storage.cc b/game/shared/world/voxel_storage.cc index 68e261c..75013b4 100644 --- a/game/shared/world/voxel_storage.cc +++ b/game/shared/world/voxel_storage.cc @@ -1,48 +1,48 @@ -#include "shared/pch.hh" - -#include "shared/world/voxel_storage.hh" - -#include "core/io/buffer.hh" - -void world::VoxelStorage::serialize(io::WriteBuffer& buffer) const -{ - auto bound = mz_compressBound(sizeof(VoxelStorage)); - auto zdata = std::vector<unsigned char>(bound); - - VoxelStorage net_storage; - - for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) { - // Convert voxel indices into network byte order; - // We're going to compress them but we still want - // the order to be consistent across all the platforms - net_storage[i] = ENET_HOST_TO_NET_16(at(i)); - } - - mz_compress(zdata.data(), &bound, reinterpret_cast<unsigned char*>(net_storage.data()), sizeof(VoxelStorage)); - - buffer.write<std::uint64_t>(bound); - - // Write all the compressed data into the buffer - for(std::size_t i = 0; i < bound; buffer.write<std::uint8_t>(zdata[i++])) { - // empty - } -} - -void world::VoxelStorage::deserialize(io::ReadBuffer& buffer) -{ - auto size = static_cast<mz_ulong>(sizeof(VoxelStorage)); - auto bound = static_cast<mz_ulong>(buffer.read<std::uint64_t>()); - auto zdata = std::vector<unsigned char>(bound); - - // Read all the compressed data from the buffer - for(std::size_t i = 0; i < bound; zdata[i++] = buffer.read<std::uint8_t>()) { - // empty - } - - mz_uncompress(reinterpret_cast<unsigned char*>(data()), &size, zdata.data(), bound); - - for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) { - // Convert voxel indices back into the host byte order - at(i) = ENET_NET_TO_HOST_16(at(i)); - } -} +#include "shared/pch.hh"
+
+#include "shared/world/voxel_storage.hh"
+
+#include "core/io/buffer.hh"
+
+void world::VoxelStorage::serialize(io::WriteBuffer& buffer) const
+{
+ auto bound = mz_compressBound(sizeof(VoxelStorage));
+ auto zdata = std::vector<unsigned char>(bound);
+
+ VoxelStorage net_storage;
+
+ for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) {
+ // Convert voxel indices into network byte order;
+ // We're going to compress them but we still want
+ // the order to be consistent across all the platforms
+ net_storage[i] = ENET_HOST_TO_NET_16(at(i));
+ }
+
+ mz_compress(zdata.data(), &bound, reinterpret_cast<unsigned char*>(net_storage.data()), sizeof(VoxelStorage));
+
+ buffer.write<std::uint64_t>(bound);
+
+ // Write all the compressed data into the buffer
+ for(std::size_t i = 0; i < bound; buffer.write<std::uint8_t>(zdata[i++])) {
+ // empty
+ }
+}
+
+void world::VoxelStorage::deserialize(io::ReadBuffer& buffer)
+{
+ auto size = static_cast<mz_ulong>(sizeof(VoxelStorage));
+ auto bound = static_cast<mz_ulong>(buffer.read<std::uint64_t>());
+ auto zdata = std::vector<unsigned char>(bound);
+
+ // Read all the compressed data from the buffer
+ for(std::size_t i = 0; i < bound; zdata[i++] = buffer.read<std::uint8_t>()) {
+ // empty
+ }
+
+ mz_uncompress(reinterpret_cast<unsigned char*>(data()), &size, zdata.data(), bound);
+
+ for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) {
+ // Convert voxel indices back into the host byte order
+ at(i) = ENET_NET_TO_HOST_16(at(i));
+ }
+}
diff --git a/game/shared/world/voxel_storage.hh b/game/shared/world/voxel_storage.hh index ac7f03d..98e85a3 100644 --- a/game/shared/world/voxel_storage.hh +++ b/game/shared/world/voxel_storage.hh @@ -1,20 +1,20 @@ -#pragma once - -#include "shared/const.hh" -#include "shared/types.hh" - -namespace io -{ -class ReadBuffer; -class WriteBuffer; -} // namespace io - -namespace world -{ -class VoxelStorage final : public std::array<voxel_id, CHUNK_VOLUME> { -public: - using std::array<voxel_id, CHUNK_VOLUME>::array; - void serialize(io::WriteBuffer& buffer) const; - void deserialize(io::ReadBuffer& buffer); -}; -} // namespace world +#pragma once
+
+#include "shared/const.hh"
+#include "shared/types.hh"
+
+namespace io
+{
+class ReadBuffer;
+class WriteBuffer;
+} // namespace io
+
+namespace world
+{
+class VoxelStorage final : public std::array<voxel_id, CHUNK_VOLUME> {
+public:
+ using std::array<voxel_id, CHUNK_VOLUME>::array;
+ void serialize(io::WriteBuffer& buffer) const;
+ void deserialize(io::ReadBuffer& buffer);
+};
+} // namespace world
|
