summaryrefslogtreecommitdiffstats
path: root/game/client/entity
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/entity')
-rw-r--r--game/client/entity/camera.cc228
-rw-r--r--game/client/entity/camera.hh62
-rw-r--r--game/client/entity/factory.cc60
-rw-r--r--game/client/entity/factory.hh22
-rw-r--r--game/client/entity/interpolation.cc126
-rw-r--r--game/client/entity/interpolation.hh12
-rw-r--r--game/client/entity/listener.cc84
-rw-r--r--game/client/entity/listener.hh12
-rw-r--r--game/client/entity/player_look.cc310
-rw-r--r--game/client/entity/player_look.hh14
-rw-r--r--game/client/entity/player_move.cc596
-rw-r--r--game/client/entity/player_move.hh30
-rw-r--r--game/client/entity/sound_emitter.cc126
-rw-r--r--game/client/entity/sound_emitter.hh40
14 files changed, 861 insertions, 861 deletions
diff --git a/game/client/entity/camera.cc b/game/client/entity/camera.cc
index c17291f..471f2b6 100644
--- a/game/client/entity/camera.cc
+++ b/game/client/entity/camera.cc
@@ -1,114 +1,114 @@
-#include "client/pch.hh"
-
-#include "client/entity/camera.hh"
-
-#include "core/config/number.hh"
-
-#include "core/io/config_map.hh"
-
-#include "core/math/angles.hh"
-
-#include "shared/entity/head.hh"
-#include "shared/entity/transform.hh"
-#include "shared/entity/velocity.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "client/entity/player_move.hh"
-
-#include "client/gui/settings.hh"
-
-#include "client/const.hh"
-#include "client/globals.hh"
-#include "client/session.hh"
-#include "client/toggles.hh"
-
-config::Float entity::camera::roll_angle(2.0f, 0.0f, 4.0f);
-config::Float entity::camera::vertical_fov(90.0f, 45.0f, 110.0f);
-config::Unsigned entity::camera::view_distance(16U, 4U, 32U);
-
-glm::fvec3 entity::camera::angles;
-glm::fvec3 entity::camera::direction;
-glm::fmat4x4 entity::camera::matrix;
-chunk_pos entity::camera::position_chunk;
-glm::fvec3 entity::camera::position_local;
-
-static void reset_camera(void)
-{
- entity::camera::angles = glm::fvec3(0.0f, 0.0f, 0.0f);
- entity::camera::direction = DIR_FORWARD<float>;
- entity::camera::matrix = glm::identity<glm::fmat4x4>();
- entity::camera::position_chunk = chunk_pos(0, 0, 0);
- entity::camera::position_local = glm::fvec3(0.0f, 0.0f, 0.0f);
-}
-
-// Gracefully contributed by PQCraft himself in 2024
-// making PlatinumSrc and Voxelius kind of related to each other
-static glm::fmat4x4 platinumsrc_viewmatrix(const glm::fvec3& position, const glm::fvec3& angles)
-{
- glm::fvec3 forward, up;
- math::vectors(angles, &forward, nullptr, &up);
-
- auto result = glm::identity<glm::fmat4x4>();
- result[0][0] = forward.y * up.z - forward.z * up.y;
- result[1][0] = forward.z * up.x - forward.x * up.z;
- result[2][0] = forward.x * up.y - forward.y * up.x;
- result[3][0] = -result[0][0] * position.x - result[1][0] * position.y - result[2][0] * position.z;
- result[0][1] = up.x;
- result[1][1] = up.y;
- result[2][1] = up.z;
- result[3][1] = -up.x * position.x - up.y * position.y - up.z * position.z;
- result[0][2] = -forward.x;
- result[1][2] = -forward.y;
- result[2][2] = -forward.z;
- result[3][2] = forward.x * position.x + forward.y * position.y + forward.z * position.z;
- return result;
-}
-
-void entity::camera::init(void)
-{
- globals::client_config.add_value("camera.roll_angle", entity::camera::roll_angle);
- globals::client_config.add_value("camera.vertical_fov", entity::camera::vertical_fov);
- globals::client_config.add_value("camera.view_distance", entity::camera::view_distance);
-
- settings::add_slider(1, entity::camera::vertical_fov, settings_location::GENERAL, "camera.vertical_fov", true, "%.0f");
- settings::add_slider(0, entity::camera::view_distance, settings_location::VIDEO, "camera.view_distance", false);
- settings::add_slider(10, entity::camera::roll_angle, settings_location::VIDEO, "camera.roll_angle", true, "%.01f");
-
- reset_camera();
-}
-
-void entity::camera::update(void)
-{
- if(!session::is_ingame()) {
- reset_camera();
- return;
- }
-
- const auto& head = globals::dimension->entities.get<entity::client::HeadIntr>(globals::player);
- const auto& transform = globals::dimension->entities.get<entity::client::TransformIntr>(globals::player);
- const auto& velocity = globals::dimension->entities.get<entity::Velocity>(globals::player);
-
- entity::camera::angles = transform.angles + head.angles;
- entity::camera::position_chunk = transform.chunk;
- entity::camera::position_local = transform.local + head.offset;
-
- glm::fvec3 right_vector, up_vector;
- math::vectors(entity::camera::angles, &entity::camera::direction, &right_vector, &up_vector);
-
- auto client_angles = entity::camera::angles;
-
- if(!toggles::get(TOGGLE_PM_FLIGHT)) {
- // Apply the quake-like view rolling
- client_angles[2] = math::radians(
- -entity::camera::roll_angle.get_value() * glm::dot(velocity.value / PMOVE_MAX_SPEED_GROUND, right_vector));
- }
-
- const auto z_near = 0.01f;
- const auto z_far = 1.25f * static_cast<float>(CHUNK_SIZE * entity::camera::view_distance.get_value());
-
- auto proj = glm::perspective(math::radians(entity::camera::vertical_fov.get_value()), globals::aspect, z_near, z_far);
- auto view = platinumsrc_viewmatrix(entity::camera::position_local, client_angles);
-
- entity::camera::matrix = proj * view;
-}
+#include "client/pch.hh"
+
+#include "client/entity/camera.hh"
+
+#include "core/config/number.hh"
+
+#include "core/io/config_map.hh"
+
+#include "core/math/angles.hh"
+
+#include "shared/entity/head.hh"
+#include "shared/entity/transform.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "client/entity/player_move.hh"
+
+#include "client/gui/settings.hh"
+
+#include "client/const.hh"
+#include "client/globals.hh"
+#include "client/session.hh"
+#include "client/toggles.hh"
+
+config::Float entity::camera::roll_angle(2.0f, 0.0f, 4.0f);
+config::Float entity::camera::vertical_fov(90.0f, 45.0f, 110.0f);
+config::Unsigned entity::camera::view_distance(16U, 4U, 32U);
+
+glm::fvec3 entity::camera::angles;
+glm::fvec3 entity::camera::direction;
+glm::fmat4x4 entity::camera::matrix;
+chunk_pos entity::camera::position_chunk;
+glm::fvec3 entity::camera::position_local;
+
+static void reset_camera(void)
+{
+ entity::camera::angles = glm::fvec3(0.0f, 0.0f, 0.0f);
+ entity::camera::direction = DIR_FORWARD<float>;
+ entity::camera::matrix = glm::identity<glm::fmat4x4>();
+ entity::camera::position_chunk = chunk_pos(0, 0, 0);
+ entity::camera::position_local = glm::fvec3(0.0f, 0.0f, 0.0f);
+}
+
+// Gracefully contributed by PQCraft himself in 2024
+// making PlatinumSrc and Voxelius kind of related to each other
+static glm::fmat4x4 platinumsrc_viewmatrix(const glm::fvec3& position, const glm::fvec3& angles)
+{
+ glm::fvec3 forward, up;
+ math::vectors(angles, &forward, nullptr, &up);
+
+ auto result = glm::identity<glm::fmat4x4>();
+ result[0][0] = forward.y * up.z - forward.z * up.y;
+ result[1][0] = forward.z * up.x - forward.x * up.z;
+ result[2][0] = forward.x * up.y - forward.y * up.x;
+ result[3][0] = -result[0][0] * position.x - result[1][0] * position.y - result[2][0] * position.z;
+ result[0][1] = up.x;
+ result[1][1] = up.y;
+ result[2][1] = up.z;
+ result[3][1] = -up.x * position.x - up.y * position.y - up.z * position.z;
+ result[0][2] = -forward.x;
+ result[1][2] = -forward.y;
+ result[2][2] = -forward.z;
+ result[3][2] = forward.x * position.x + forward.y * position.y + forward.z * position.z;
+ return result;
+}
+
+void entity::camera::init(void)
+{
+ globals::client_config.add_value("camera.roll_angle", entity::camera::roll_angle);
+ globals::client_config.add_value("camera.vertical_fov", entity::camera::vertical_fov);
+ globals::client_config.add_value("camera.view_distance", entity::camera::view_distance);
+
+ settings::add_slider(1, entity::camera::vertical_fov, settings_location::GENERAL, "camera.vertical_fov", true, "%.0f");
+ settings::add_slider(0, entity::camera::view_distance, settings_location::VIDEO, "camera.view_distance", false);
+ settings::add_slider(10, entity::camera::roll_angle, settings_location::VIDEO, "camera.roll_angle", true, "%.01f");
+
+ reset_camera();
+}
+
+void entity::camera::update(void)
+{
+ if(!session::is_ingame()) {
+ reset_camera();
+ return;
+ }
+
+ const auto& head = globals::dimension->entities.get<entity::client::HeadIntr>(globals::player);
+ const auto& transform = globals::dimension->entities.get<entity::client::TransformIntr>(globals::player);
+ const auto& velocity = globals::dimension->entities.get<entity::Velocity>(globals::player);
+
+ entity::camera::angles = transform.angles + head.angles;
+ entity::camera::position_chunk = transform.chunk;
+ entity::camera::position_local = transform.local + head.offset;
+
+ glm::fvec3 right_vector, up_vector;
+ math::vectors(entity::camera::angles, &entity::camera::direction, &right_vector, &up_vector);
+
+ auto client_angles = entity::camera::angles;
+
+ if(!toggles::get(TOGGLE_PM_FLIGHT)) {
+ // Apply the quake-like view rolling
+ client_angles[2] = math::radians(-entity::camera::roll_angle.get_value()
+ * glm::dot(velocity.value / PMOVE_MAX_SPEED_GROUND, right_vector));
+ }
+
+ const auto z_near = 0.01f;
+ const auto z_far = 1.25f * static_cast<float>(CHUNK_SIZE * entity::camera::view_distance.get_value());
+
+ auto proj = glm::perspective(math::radians(entity::camera::vertical_fov.get_value()), globals::aspect, z_near, z_far);
+ auto view = platinumsrc_viewmatrix(entity::camera::position_local, client_angles);
+
+ entity::camera::matrix = proj * view;
+}
diff --git a/game/client/entity/camera.hh b/game/client/entity/camera.hh
index 67baf72..faefe78 100644
--- a/game/client/entity/camera.hh
+++ b/game/client/entity/camera.hh
@@ -1,31 +1,31 @@
-#pragma once
-
-#include "shared/types.hh"
-
-namespace config
-{
-class Float;
-class Unsigned;
-} // namespace config
-
-namespace entity::camera
-{
-extern config::Float roll_angle;
-extern config::Float vertical_fov;
-extern config::Unsigned view_distance;
-} // namespace entity::camera
-
-namespace entity::camera
-{
-extern glm::fvec3 angles;
-extern glm::fvec3 direction;
-extern glm::fmat4x4 matrix;
-extern chunk_pos position_chunk;
-extern glm::fvec3 position_local;
-} // namespace entity::camera
-
-namespace entity::camera
-{
-void init(void);
-void update(void);
-} // namespace entity::camera
+#pragma once
+
+#include "shared/types.hh"
+
+namespace config
+{
+class Float;
+class Unsigned;
+} // namespace config
+
+namespace entity::camera
+{
+extern config::Float roll_angle;
+extern config::Float vertical_fov;
+extern config::Unsigned view_distance;
+} // namespace entity::camera
+
+namespace entity::camera
+{
+extern glm::fvec3 angles;
+extern glm::fvec3 direction;
+extern glm::fmat4x4 matrix;
+extern chunk_pos position_chunk;
+extern glm::fvec3 position_local;
+} // namespace entity::camera
+
+namespace entity::camera
+{
+void init(void);
+void update(void);
+} // namespace entity::camera
diff --git a/game/client/entity/factory.cc b/game/client/entity/factory.cc
index f6f6079..5a1785a 100644
--- a/game/client/entity/factory.cc
+++ b/game/client/entity/factory.cc
@@ -1,30 +1,30 @@
-#include "client/pch.hh"
-
-#include "client/entity/factory.hh"
-
-#include "shared/entity/factory.hh"
-#include "shared/entity/head.hh"
-#include "shared/entity/transform.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "client/entity/sound_emitter.hh"
-
-#include "client/globals.hh"
-
-void entity::client::create_player(world::Dimension* dimension, entt::entity entity)
-{
- entity::shared::create_player(dimension, entity);
-
- const auto& head = dimension->entities.get<entity::Head>(entity);
- dimension->entities.emplace_or_replace<entity::client::HeadIntr>(entity, head);
- dimension->entities.emplace_or_replace<entity::client::HeadPrev>(entity, head);
-
- const auto& transform = dimension->entities.get<entity::Transform>(entity);
- dimension->entities.emplace_or_replace<entity::client::TransformIntr>(entity, transform);
- dimension->entities.emplace_or_replace<entity::client::TransformPrev>(entity, transform);
-
- if(globals::sound_ctx) {
- dimension->entities.emplace_or_replace<entity::SoundEmitter>(entity);
- }
-}
+#include "client/pch.hh"
+
+#include "client/entity/factory.hh"
+
+#include "shared/entity/factory.hh"
+#include "shared/entity/head.hh"
+#include "shared/entity/transform.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "client/entity/sound_emitter.hh"
+
+#include "client/globals.hh"
+
+void entity::client::create_player(world::Dimension* dimension, entt::entity entity)
+{
+ entity::shared::create_player(dimension, entity);
+
+ const auto& head = dimension->entities.get<entity::Head>(entity);
+ dimension->entities.emplace_or_replace<entity::client::HeadIntr>(entity, head);
+ dimension->entities.emplace_or_replace<entity::client::HeadPrev>(entity, head);
+
+ const auto& transform = dimension->entities.get<entity::Transform>(entity);
+ dimension->entities.emplace_or_replace<entity::client::TransformIntr>(entity, transform);
+ dimension->entities.emplace_or_replace<entity::client::TransformPrev>(entity, transform);
+
+ if(globals::sound_ctx) {
+ dimension->entities.emplace_or_replace<entity::SoundEmitter>(entity);
+ }
+}
diff --git a/game/client/entity/factory.hh b/game/client/entity/factory.hh
index 63e6e44..8cc8208 100644
--- a/game/client/entity/factory.hh
+++ b/game/client/entity/factory.hh
@@ -1,11 +1,11 @@
-#pragma once
-
-namespace world
-{
-class Dimension;
-} // namespace world
-
-namespace entity::client
-{
-void create_player(world::Dimension* dimension, entt::entity entity);
-} // namespace entity::client
+#pragma once
+
+namespace world
+{
+class Dimension;
+} // namespace world
+
+namespace entity::client
+{
+void create_player(world::Dimension* dimension, entt::entity entity);
+} // namespace entity::client
diff --git a/game/client/entity/interpolation.cc b/game/client/entity/interpolation.cc
index 9eca735..ef23a4c 100644
--- a/game/client/entity/interpolation.cc
+++ b/game/client/entity/interpolation.cc
@@ -1,64 +1,64 @@
-#include "client/pch.hh"
-
-#include "client/entity/interpolation.hh"
-
-#include "core/math/constexpr.hh"
-
-#include "shared/entity/head.hh"
-#include "shared/entity/transform.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "shared/coord.hh"
-
-#include "client/globals.hh"
-
-static void transform_interpolate(float alpha)
-{
- auto group = globals::dimension->entities.group<entity::client::TransformIntr>(
- entt::get<entity::Transform, entity::client::TransformPrev>);
-
- for(auto [entity, interp, current, previous] : group.each()) {
- interp.angles[0] = math::lerp(previous.angles[0], current.angles[0], alpha);
- interp.angles[1] = math::lerp(previous.angles[1], current.angles[1], alpha);
- interp.angles[2] = math::lerp(previous.angles[2], current.angles[2], alpha);
-
- // Figure out previous chunk-local floating-point coordinates transformed
- // to the current WorldCoord's chunk domain coordinates; we're interpolating
- // against these instead of using previous.position.local to prevent jittering
- auto previous_shift = coord::to_relative(current.chunk, current.local, previous.chunk, previous.local);
- auto previous_local = current.local + previous_shift;
-
- interp.chunk.x = current.chunk.x;
- interp.chunk.y = current.chunk.y;
- interp.chunk.z = current.chunk.z;
-
- interp.local.x = math::lerp(previous_local.x, current.local.x, alpha);
- interp.local.y = math::lerp(previous_local.y, current.local.y, alpha);
- interp.local.z = math::lerp(previous_local.z, current.local.z, alpha);
- }
-}
-
-static void head_interpolate(float alpha)
-{
- auto group = globals::dimension->entities.group<entity::client::HeadIntr>(entt::get<entity::Head, entity::client::HeadPrev>);
-
- for(auto [entity, interp, current, previous] : group.each()) {
- interp.angles[0] = math::lerp(previous.angles[0], current.angles[0], alpha);
- interp.angles[1] = math::lerp(previous.angles[1], current.angles[1], alpha);
- interp.angles[2] = math::lerp(previous.angles[2], current.angles[2], alpha);
-
- interp.offset.x = math::lerp(previous.offset.x, current.offset.x, alpha);
- interp.offset.y = math::lerp(previous.offset.y, current.offset.y, alpha);
- interp.offset.z = math::lerp(previous.offset.z, current.offset.z, alpha);
- }
-}
-
-void entity::interpolation::update(void)
-{
- if(globals::dimension) {
- auto alpha = static_cast<float>(globals::fixed_accumulator) / static_cast<float>(globals::fixed_frametime_us);
- transform_interpolate(alpha);
- head_interpolate(alpha);
- }
+#include "client/pch.hh"
+
+#include "client/entity/interpolation.hh"
+
+#include "core/math/constexpr.hh"
+
+#include "shared/entity/head.hh"
+#include "shared/entity/transform.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/coord.hh"
+
+#include "client/globals.hh"
+
+static void transform_interpolate(float alpha)
+{
+ auto group = globals::dimension->entities.group<entity::client::TransformIntr>(
+ entt::get<entity::Transform, entity::client::TransformPrev>);
+
+ for(auto [entity, interp, current, previous] : group.each()) {
+ interp.angles[0] = math::lerp(previous.angles[0], current.angles[0], alpha);
+ interp.angles[1] = math::lerp(previous.angles[1], current.angles[1], alpha);
+ interp.angles[2] = math::lerp(previous.angles[2], current.angles[2], alpha);
+
+ // Figure out previous chunk-local floating-point coordinates transformed
+ // to the current WorldCoord's chunk domain coordinates; we're interpolating
+ // against these instead of using previous.position.local to prevent jittering
+ auto previous_shift = coord::to_relative(current.chunk, current.local, previous.chunk, previous.local);
+ auto previous_local = current.local + previous_shift;
+
+ interp.chunk.x = current.chunk.x;
+ interp.chunk.y = current.chunk.y;
+ interp.chunk.z = current.chunk.z;
+
+ interp.local.x = math::lerp(previous_local.x, current.local.x, alpha);
+ interp.local.y = math::lerp(previous_local.y, current.local.y, alpha);
+ interp.local.z = math::lerp(previous_local.z, current.local.z, alpha);
+ }
+}
+
+static void head_interpolate(float alpha)
+{
+ auto group = globals::dimension->entities.group<entity::client::HeadIntr>(entt::get<entity::Head, entity::client::HeadPrev>);
+
+ for(auto [entity, interp, current, previous] : group.each()) {
+ interp.angles[0] = math::lerp(previous.angles[0], current.angles[0], alpha);
+ interp.angles[1] = math::lerp(previous.angles[1], current.angles[1], alpha);
+ interp.angles[2] = math::lerp(previous.angles[2], current.angles[2], alpha);
+
+ interp.offset.x = math::lerp(previous.offset.x, current.offset.x, alpha);
+ interp.offset.y = math::lerp(previous.offset.y, current.offset.y, alpha);
+ interp.offset.z = math::lerp(previous.offset.z, current.offset.z, alpha);
+ }
+}
+
+void entity::interpolation::update(void)
+{
+ if(globals::dimension) {
+ auto alpha = static_cast<float>(globals::fixed_accumulator) / static_cast<float>(globals::fixed_frametime_us);
+ transform_interpolate(alpha);
+ head_interpolate(alpha);
+ }
} \ No newline at end of file
diff --git a/game/client/entity/interpolation.hh b/game/client/entity/interpolation.hh
index 6935fe8..a7c4dac 100644
--- a/game/client/entity/interpolation.hh
+++ b/game/client/entity/interpolation.hh
@@ -1,6 +1,6 @@
-#pragma once
-
-namespace entity::interpolation
-{
-void update(void);
-} // namespace entity::interpolation
+#pragma once
+
+namespace entity::interpolation
+{
+void update(void);
+} // namespace entity::interpolation
diff --git a/game/client/entity/listener.cc b/game/client/entity/listener.cc
index 3b1a35b..3d732ae 100644
--- a/game/client/entity/listener.cc
+++ b/game/client/entity/listener.cc
@@ -1,42 +1,42 @@
-#include "client/pch.hh"
-
-#include "client/entity/listener.hh"
-
-#include "core/config/number.hh"
-
-#include "core/math/constexpr.hh"
-
-#include "shared/entity/velocity.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "client/entity/camera.hh"
-
-#include "client/sound/sound.hh"
-
-#include "client/const.hh"
-#include "client/globals.hh"
-#include "client/session.hh"
-
-void entity::listener::update(void)
-{
- if(session::is_ingame()) {
- const auto& velocity = globals::dimension->entities.get<entity::Velocity>(globals::player).value;
- const auto& position = entity::camera::position_local;
-
- alListener3f(AL_POSITION, position.x, position.y, position.z);
- alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
-
- float orientation[6];
- orientation[0] = entity::camera::direction.x;
- orientation[1] = entity::camera::direction.y;
- orientation[2] = entity::camera::direction.z;
- orientation[3] = DIR_UP<float>.x;
- orientation[4] = DIR_UP<float>.y;
- orientation[5] = DIR_UP<float>.z;
-
- alListenerfv(AL_ORIENTATION, orientation);
- }
-
- alListenerf(AL_GAIN, math::clamp(sound::volume_master.get_value() * 0.01f, 0.0f, 1.0f));
-}
+#include "client/pch.hh"
+
+#include "client/entity/listener.hh"
+
+#include "core/config/number.hh"
+
+#include "core/math/constexpr.hh"
+
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "client/entity/camera.hh"
+
+#include "client/sound/sound.hh"
+
+#include "client/const.hh"
+#include "client/globals.hh"
+#include "client/session.hh"
+
+void entity::listener::update(void)
+{
+ if(session::is_ingame()) {
+ const auto& velocity = globals::dimension->entities.get<entity::Velocity>(globals::player).value;
+ const auto& position = entity::camera::position_local;
+
+ alListener3f(AL_POSITION, position.x, position.y, position.z);
+ alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
+
+ float orientation[6];
+ orientation[0] = entity::camera::direction.x;
+ orientation[1] = entity::camera::direction.y;
+ orientation[2] = entity::camera::direction.z;
+ orientation[3] = DIR_UP<float>.x;
+ orientation[4] = DIR_UP<float>.y;
+ orientation[5] = DIR_UP<float>.z;
+
+ alListenerfv(AL_ORIENTATION, orientation);
+ }
+
+ alListenerf(AL_GAIN, math::clamp(sound::volume_master.get_value() * 0.01f, 0.0f, 1.0f));
+}
diff --git a/game/client/entity/listener.hh b/game/client/entity/listener.hh
index 594cde1..817e2fd 100644
--- a/game/client/entity/listener.hh
+++ b/game/client/entity/listener.hh
@@ -1,6 +1,6 @@
-#pragma once
-
-namespace entity::listener
-{
-void update(void);
-} // namespace entity::listener
+#pragma once
+
+namespace entity::listener
+{
+void update(void);
+} // namespace entity::listener
diff --git a/game/client/entity/player_look.cc b/game/client/entity/player_look.cc
index 715475b..caa367e 100644
--- a/game/client/entity/player_look.cc
+++ b/game/client/entity/player_look.cc
@@ -1,155 +1,155 @@
-#include "client/pch.hh"
-
-#include "client/entity/player_look.hh"
-
-#include "core/config/boolean.hh"
-#include "core/config/number.hh"
-
-#include "core/io/config_map.hh"
-
-#include "core/math/angles.hh"
-
-#include "shared/entity/head.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "client/config/gamepad_axis.hh"
-#include "client/config/gamepad_button.hh"
-#include "client/config/keybind.hh"
-
-#include "client/gui/settings.hh"
-
-#include "client/io/gamepad.hh"
-#include "client/io/glfw.hh"
-
-#include "client/const.hh"
-#include "client/globals.hh"
-#include "client/session.hh"
-
-constexpr static float PITCH_MIN = -1.0f * math::radians(90.0f);
-constexpr static float PITCH_MAX = +1.0f * math::radians(90.0f);
-
-// Mouse options
-static config::Boolean mouse_raw_input(true);
-static config::Unsigned mouse_sensitivity(25U, 1U, 100U);
-
-// Gamepad options
-static config::Float gamepad_fastlook_factor(1.5f, 1.0f, 5.0f);
-static config::Unsigned gamepad_accel_pitch(15U, 1U, 100U);
-static config::Unsigned gamepad_accel_yaw(25U, 1U, 100U);
-
-// Gamepad axes
-static config::GamepadAxis axis_pitch(GLFW_GAMEPAD_AXIS_LEFT_Y, false);
-static config::GamepadAxis axis_yaw(GLFW_GAMEPAD_AXIS_LEFT_X, false);
-
-// Gamepad buttons
-static config::GamepadButton button_fastlook(GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
-
-static bool fastlook_enabled;
-static glm::fvec2 last_cursor;
-
-static void add_angles(float pitch, float yaw)
-{
- if(session::is_ingame()) {
- auto& head = globals::dimension->entities.get<entity::Head>(globals::player);
-
- head.angles[0] += pitch;
- head.angles[1] += yaw;
- head.angles[0] = math::clamp(head.angles[0], PITCH_MIN, PITCH_MAX);
- head.angles = math::wrap_180(head.angles);
-
- // Client-side head angles are not interpolated;
- // Re-assigning the previous state after the current
- // state has been already modified is certainly a way
- // to circumvent the interpolation applied to anything with a head
- globals::dimension->entities.emplace_or_replace<entity::client::HeadPrev>(globals::player, head);
- }
-}
-
-static void on_glfw_cursor_pos(const io::GlfwCursorPosEvent& event)
-{
- if(io::gamepad::available && io::gamepad::active.get_value()) {
- // The player is assumed to be using
- // a gamepad instead of mouse and keyboard
- last_cursor = event.pos;
- return;
- }
-
- if(globals::gui_screen || !session::is_ingame()) {
- // UI is visible or we're not in-game
- last_cursor = event.pos;
- return;
- }
-
- auto dx = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * math::radians(event.pos.x - last_cursor.x);
- auto dy = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * math::radians(event.pos.y - last_cursor.y);
- add_angles(dy, dx);
-
- last_cursor = event.pos;
-}
-
-static void on_gamepad_button(const io::GamepadButtonEvent& event)
-{
- if(button_fastlook.equals(event.button)) {
- fastlook_enabled = event.action == GLFW_PRESS;
- }
-}
-
-void entity::player_look::init(void)
-{
- globals::client_config.add_value("player_look.mouse.raw_input", mouse_raw_input);
- globals::client_config.add_value("player_look.mouse.sensitivity", mouse_sensitivity);
- globals::client_config.add_value("player_look.gamepad.fastlook_factor", gamepad_fastlook_factor);
- globals::client_config.add_value("player_look.gamepad.accel_pitch", gamepad_accel_pitch);
- globals::client_config.add_value("player_look.gamepad.accel_yaw", gamepad_accel_yaw);
- globals::client_config.add_value("player_look.gp_axis.pitch", axis_pitch);
- globals::client_config.add_value("player_look.gp_axis.yaw", axis_yaw);
- globals::client_config.add_value("player_look.gp_button.fastlook", button_fastlook);
-
- settings::add_slider(0, mouse_sensitivity, settings_location::MOUSE, "player_look.mouse.sensitivity", true);
- settings::add_checkbox(1, mouse_raw_input, settings_location::MOUSE, "player_look.mouse.raw_input", true);
-
- settings::add_slider(0, gamepad_accel_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_pitch", false);
- settings::add_slider(1, gamepad_accel_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_yaw", false);
- settings::add_gamepad_axis(2, axis_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.pitch");
- settings::add_gamepad_axis(3, axis_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.yaw");
- settings::add_slider(
- 4, gamepad_fastlook_factor, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.fastlook_factor", true, "%.02f");
- settings::add_gamepad_button(5, button_fastlook, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_button.fastlook");
-
- fastlook_enabled = false;
- last_cursor.x = 0.5f * static_cast<float>(globals::width);
- last_cursor.y = 0.5f * static_cast<float>(globals::height);
-
- globals::dispatcher.sink<io::GlfwCursorPosEvent>().connect<&on_glfw_cursor_pos>();
- globals::dispatcher.sink<io::GamepadButtonEvent>().connect<&on_gamepad_button>();
-}
-
-void entity::player_look::update_late(void)
-{
- if(io::gamepad::available && io::gamepad::active.get_value() && !globals::gui_screen) {
- auto pitch_value = axis_pitch.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
- auto yaw_value = axis_yaw.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
-
- if(fastlook_enabled) {
- // Fastlook allows the camera to
- // rotate quicker when a button is held down
- pitch_value *= gamepad_fastlook_factor.get_value();
- yaw_value *= gamepad_fastlook_factor.get_value();
- }
-
- pitch_value *= 0.001f * static_cast<float>(gamepad_accel_pitch.get_value());
- yaw_value *= 0.001f * static_cast<float>(gamepad_accel_yaw.get_value());
-
- add_angles(pitch_value, yaw_value);
- }
-
- if(!globals::gui_screen && session::is_ingame()) {
- glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, mouse_raw_input.get_value());
- }
- else {
- glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
- glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, false);
- }
-}
+#include "client/pch.hh"
+
+#include "client/entity/player_look.hh"
+
+#include "core/config/boolean.hh"
+#include "core/config/number.hh"
+
+#include "core/io/config_map.hh"
+
+#include "core/math/angles.hh"
+
+#include "shared/entity/head.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "client/config/gamepad_axis.hh"
+#include "client/config/gamepad_button.hh"
+#include "client/config/keybind.hh"
+
+#include "client/gui/settings.hh"
+
+#include "client/io/gamepad.hh"
+#include "client/io/glfw.hh"
+
+#include "client/const.hh"
+#include "client/globals.hh"
+#include "client/session.hh"
+
+constexpr static float PITCH_MIN = -1.0f * math::radians(90.0f);
+constexpr static float PITCH_MAX = +1.0f * math::radians(90.0f);
+
+// Mouse options
+static config::Boolean mouse_raw_input(true);
+static config::Unsigned mouse_sensitivity(25U, 1U, 100U);
+
+// Gamepad options
+static config::Float gamepad_fastlook_factor(1.5f, 1.0f, 5.0f);
+static config::Unsigned gamepad_accel_pitch(15U, 1U, 100U);
+static config::Unsigned gamepad_accel_yaw(25U, 1U, 100U);
+
+// Gamepad axes
+static config::GamepadAxis axis_pitch(GLFW_GAMEPAD_AXIS_LEFT_Y, false);
+static config::GamepadAxis axis_yaw(GLFW_GAMEPAD_AXIS_LEFT_X, false);
+
+// Gamepad buttons
+static config::GamepadButton button_fastlook(GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
+
+static bool fastlook_enabled;
+static glm::fvec2 last_cursor;
+
+static void add_angles(float pitch, float yaw)
+{
+ if(session::is_ingame()) {
+ auto& head = globals::dimension->entities.get<entity::Head>(globals::player);
+
+ head.angles[0] += pitch;
+ head.angles[1] += yaw;
+ head.angles[0] = math::clamp(head.angles[0], PITCH_MIN, PITCH_MAX);
+ head.angles = math::wrap_180(head.angles);
+
+ // Client-side head angles are not interpolated;
+ // Re-assigning the previous state after the current
+ // state has been already modified is certainly a way
+ // to circumvent the interpolation applied to anything with a head
+ globals::dimension->entities.emplace_or_replace<entity::client::HeadPrev>(globals::player, head);
+ }
+}
+
+static void on_glfw_cursor_pos(const io::GlfwCursorPosEvent& event)
+{
+ if(io::gamepad::available && io::gamepad::active.get_value()) {
+ // The player is assumed to be using
+ // a gamepad instead of mouse and keyboard
+ last_cursor = event.pos;
+ return;
+ }
+
+ if(globals::gui_screen || !session::is_ingame()) {
+ // UI is visible or we're not in-game
+ last_cursor = event.pos;
+ return;
+ }
+
+ auto dx = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * math::radians(event.pos.x - last_cursor.x);
+ auto dy = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * math::radians(event.pos.y - last_cursor.y);
+ add_angles(dy, dx);
+
+ last_cursor = event.pos;
+}
+
+static void on_gamepad_button(const io::GamepadButtonEvent& event)
+{
+ if(button_fastlook.equals(event.button)) {
+ fastlook_enabled = event.action == GLFW_PRESS;
+ }
+}
+
+void entity::player_look::init(void)
+{
+ globals::client_config.add_value("player_look.mouse.raw_input", mouse_raw_input);
+ globals::client_config.add_value("player_look.mouse.sensitivity", mouse_sensitivity);
+ globals::client_config.add_value("player_look.gamepad.fastlook_factor", gamepad_fastlook_factor);
+ globals::client_config.add_value("player_look.gamepad.accel_pitch", gamepad_accel_pitch);
+ globals::client_config.add_value("player_look.gamepad.accel_yaw", gamepad_accel_yaw);
+ globals::client_config.add_value("player_look.gp_axis.pitch", axis_pitch);
+ globals::client_config.add_value("player_look.gp_axis.yaw", axis_yaw);
+ globals::client_config.add_value("player_look.gp_button.fastlook", button_fastlook);
+
+ settings::add_slider(0, mouse_sensitivity, settings_location::MOUSE, "player_look.mouse.sensitivity", true);
+ settings::add_checkbox(1, mouse_raw_input, settings_location::MOUSE, "player_look.mouse.raw_input", true);
+
+ settings::add_slider(0, gamepad_accel_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_pitch", false);
+ settings::add_slider(1, gamepad_accel_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_yaw", false);
+ settings::add_gamepad_axis(2, axis_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.pitch");
+ settings::add_gamepad_axis(3, axis_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.yaw");
+ settings::add_slider(4, gamepad_fastlook_factor, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.fastlook_factor", true,
+ "%.02f");
+ settings::add_gamepad_button(5, button_fastlook, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_button.fastlook");
+
+ fastlook_enabled = false;
+ last_cursor.x = 0.5f * static_cast<float>(globals::width);
+ last_cursor.y = 0.5f * static_cast<float>(globals::height);
+
+ globals::dispatcher.sink<io::GlfwCursorPosEvent>().connect<&on_glfw_cursor_pos>();
+ globals::dispatcher.sink<io::GamepadButtonEvent>().connect<&on_gamepad_button>();
+}
+
+void entity::player_look::update_late(void)
+{
+ if(io::gamepad::available && io::gamepad::active.get_value() && !globals::gui_screen) {
+ auto pitch_value = axis_pitch.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
+ auto yaw_value = axis_yaw.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
+
+ if(fastlook_enabled) {
+ // Fastlook allows the camera to
+ // rotate quicker when a button is held down
+ pitch_value *= gamepad_fastlook_factor.get_value();
+ yaw_value *= gamepad_fastlook_factor.get_value();
+ }
+
+ pitch_value *= 0.001f * static_cast<float>(gamepad_accel_pitch.get_value());
+ yaw_value *= 0.001f * static_cast<float>(gamepad_accel_yaw.get_value());
+
+ add_angles(pitch_value, yaw_value);
+ }
+
+ if(!globals::gui_screen && session::is_ingame()) {
+ glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+ glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, mouse_raw_input.get_value());
+ }
+ else {
+ glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+ glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, false);
+ }
+}
diff --git a/game/client/entity/player_look.hh b/game/client/entity/player_look.hh
index 0ae18db..b347031 100644
--- a/game/client/entity/player_look.hh
+++ b/game/client/entity/player_look.hh
@@ -1,7 +1,7 @@
-#pragma once
-
-namespace entity::player_look
-{
-void init(void);
-void update_late(void);
-} // namespace entity::player_look
+#pragma once
+
+namespace entity::player_look
+{
+void init(void);
+void update_late(void);
+} // namespace entity::player_look
diff --git a/game/client/entity/player_move.cc b/game/client/entity/player_move.cc
index fb49754..2570780 100644
--- a/game/client/entity/player_move.cc
+++ b/game/client/entity/player_move.cc
@@ -1,298 +1,298 @@
-#include "client/pch.hh"
-
-#include "client/entity/player_move.hh"
-
-#include "core/config/boolean.hh"
-#include "core/config/number.hh"
-
-#include "core/io/config_map.hh"
-
-#include "core/math/angles.hh"
-#include "core/math/constexpr.hh"
-
-#include "shared/entity/grounded.hh"
-#include "shared/entity/head.hh"
-#include "shared/entity/transform.hh"
-#include "shared/entity/velocity.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "client/config/gamepad_axis.hh"
-#include "client/config/gamepad_button.hh"
-#include "client/config/keybind.hh"
-
-#include "client/gui/gui_screen.hh"
-#include "client/gui/settings.hh"
-#include "client/gui/status_lines.hh"
-
-#include "client/io/gamepad.hh"
-
-#include "client/sound/sound.hh"
-
-#include "client/world/voxel_sounds.hh"
-
-#include "client/const.hh"
-#include "client/globals.hh"
-#include "client/session.hh"
-#include "client/toggles.hh"
-
-constexpr static std::uint64_t PMOVE_JUMP_COOLDOWN = 500000; // 0.5 seconds
-
-constexpr static float PMOVE_FOOTSTEP_SIZE = 2.0f;
-
-// Movement keys
-static config::KeyBind key_move_forward(GLFW_KEY_W);
-static config::KeyBind key_move_back(GLFW_KEY_S);
-static config::KeyBind key_move_left(GLFW_KEY_A);
-static config::KeyBind key_move_right(GLFW_KEY_D);
-static config::KeyBind key_move_down(GLFW_KEY_LEFT_SHIFT);
-static config::KeyBind key_move_up(GLFW_KEY_SPACE);
-
-// Movement gamepad axes
-static config::GamepadAxis axis_move_forward(GLFW_GAMEPAD_AXIS_RIGHT_X, false);
-static config::GamepadAxis axis_move_sideways(GLFW_GAMEPAD_AXIS_RIGHT_Y, false);
-
-// Movement gamepad buttons
-static config::GamepadButton button_move_down(GLFW_GAMEPAD_BUTTON_DPAD_DOWN);
-static config::GamepadButton button_move_up(GLFW_GAMEPAD_BUTTON_DPAD_UP);
-
-// General movement options
-static config::Boolean enable_speedometer(true);
-
-static glm::fvec3 movement_direction;
-
-static std::uint64_t next_jump_us;
-static float speedometer_value;
-static float footsteps_distance;
-
-static std::mt19937_64 pitch_random;
-static std::uniform_real_distribution<float> pitch_distrib;
-
-// Quake III's PM_Accelerate-ish function used for
-// conventional (gravity-affected non-flight) movement
-static glm::fvec3 pm_accelerate(const glm::fvec3& wishdir, const glm::fvec3& velocity, float wishspeed, float accel)
-{
- auto current_speed = glm::dot(velocity, wishdir);
- auto add_speed = wishspeed - current_speed;
-
- if(add_speed <= 0.0f) {
- // Not accelerating
- return velocity;
- }
-
- auto accel_speed = math::min(add_speed, accel * globals::fixed_frametime * wishspeed);
-
- auto result = glm::fvec3(velocity);
- result.x += accel_speed * wishdir.x;
- result.z += accel_speed * wishdir.z;
- return result;
-}
-
-// Conventional movement - velocity update when not on the ground
-static glm::fvec3 pm_air_move(const glm::fvec3& wishdir, const glm::fvec3& velocity)
-{
- return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_AIR, PMOVE_MAX_SPEED_AIR);
-}
-
-// Conventional movement - velocity uodate when on the ground
-static glm::fvec3 pm_ground_move(const glm::fvec3& wishdir, const glm::fvec3& velocity)
-{
- if(auto speed = glm::length(velocity)) {
- auto speed_drop = speed * PMOVE_FRICTION_GROUND * globals::fixed_frametime;
- auto speed_factor = math::max(speed - speed_drop, 0.0f) / speed;
- return pm_accelerate(wishdir, velocity * speed_factor, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND);
- }
-
- return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND);
-}
-
-// A simpler minecraft-like acceleration model
-// used whenever the TOGGLE_PM_FLIGHT is enabled
-static glm::fvec3 pm_flight_move(const glm::fvec3& wishdir)
-{
- // FIXME: make it smoother
- return wishdir * PMOVE_MAX_SPEED_AIR;
-}
-
-void entity::player_move::init(void)
-{
- movement_direction = ZERO_VEC3<float>;
-
- next_jump_us = 0x0000000000000000U;
- speedometer_value = 0.0f;
- footsteps_distance = 0.0f;
-
- // UNDONE: make this a separate subsystem
- pitch_random.seed(std::random_device()());
- pitch_distrib = std::uniform_real_distribution<float>(0.9f, 1.1f);
-
- globals::client_config.add_value("player_move.key.forward", key_move_forward);
- globals::client_config.add_value("player_move.key.back", key_move_back);
- globals::client_config.add_value("player_move.key.left", key_move_left);
- globals::client_config.add_value("player_move.key.right", key_move_right);
- globals::client_config.add_value("player_move.key.down", key_move_down);
- globals::client_config.add_value("player_move.key.up", key_move_up);
- globals::client_config.add_value("player_move.gp_axis.move_forward", axis_move_forward);
- globals::client_config.add_value("player_move.gp_axis.move_sideways", axis_move_sideways);
- globals::client_config.add_value("player_move.gp_button.move_down", button_move_down);
- globals::client_config.add_value("player_move.gp_button.move_up", button_move_up);
- globals::client_config.add_value("player_move.enable_speedometer", enable_speedometer);
-
- settings::add_keybind(1, key_move_forward, settings_location::KEYBOARD_MOVEMENT, "player_move.key.forward");
- settings::add_keybind(2, key_move_back, settings_location::KEYBOARD_MOVEMENT, "player_move.key.back");
- settings::add_keybind(3, key_move_left, settings_location::KEYBOARD_MOVEMENT, "player_move.key.left");
- settings::add_keybind(4, key_move_right, settings_location::KEYBOARD_MOVEMENT, "player_move.key.right");
- settings::add_keybind(5, key_move_down, settings_location::KEYBOARD_MOVEMENT, "player_move.key.down");
- settings::add_keybind(6, key_move_up, settings_location::KEYBOARD_MOVEMENT, "player_move.key.up");
-
- settings::add_gamepad_axis(0, axis_move_forward, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_forward");
- settings::add_gamepad_axis(1, axis_move_sideways, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_sideways");
- settings::add_gamepad_button(2, button_move_down, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_down");
- settings::add_gamepad_button(3, button_move_up, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_up");
-
- settings::add_checkbox(2, enable_speedometer, settings_location::VIDEO_GUI, "player_move.enable_speedometer", true);
-}
-
-void entity::player_move::fixed_update(void)
-{
- const auto& head = globals::dimension->entities.get<entity::Head>(globals::player);
- auto& transform = globals::dimension->entities.get<entity::Transform>(globals::player);
- auto& velocity = globals::dimension->entities.get<entity::Velocity>(globals::player);
-
- // Interpolation - preserve current component states
- globals::dimension->entities.emplace_or_replace<entity::client::TransformPrev>(globals::player, transform);
-
- glm::fvec3 forward, right;
- math::vectors(glm::fvec3(0.0f, head.angles[1], 0.0f), &forward, &right, nullptr);
-
- glm::fvec3 wishdir = ZERO_VEC3<float>;
- glm::fvec3 movevars = glm::fvec3(movement_direction.x, 0.0f, movement_direction.z);
- wishdir.x = glm::dot(movevars, right);
- wishdir.z = glm::dot(movevars, forward);
-
- if(toggles::get(TOGGLE_PM_FLIGHT)) {
- velocity.value = pm_flight_move(glm::fvec3(wishdir.x, movement_direction.y, wishdir.z));
- return;
- }
-
- auto grounded = globals::dimension->entities.try_get<entity::Grounded>(globals::player);
- auto velocity_horizontal = glm::fvec3(velocity.value.x, 0.0f, velocity.value.z);
-
- if(grounded) {
- auto new_velocity = pm_ground_move(wishdir, velocity_horizontal);
- velocity.value.x = new_velocity.x;
- velocity.value.z = new_velocity.z;
-
- auto new_speed = glm::length(new_velocity);
-
- if(new_speed > 0.01f) {
- footsteps_distance += globals::fixed_frametime * new_speed;
- }
- else {
- footsteps_distance = 0.0f;
- }
-
- if(footsteps_distance >= PMOVE_FOOTSTEP_SIZE) {
- if(auto effect = world::voxel_sounds::get_footsteps(grounded->surface)) {
- sound::play_player(effect, false, pitch_distrib(pitch_random));
- }
-
- footsteps_distance = 0.0f;
- }
- }
- else {
- auto new_velocity = pm_air_move(wishdir, velocity_horizontal);
- velocity.value.x = new_velocity.x;
- velocity.value.z = new_velocity.z;
- }
-
- if(movement_direction.y == 0.0f) {
- // Allow players to queue bunny-jumps by quickly
- // releasing and pressing the jump key again without a cooldown
- next_jump_us = 0x0000000000000000U;
- return;
- }
-
- if(grounded && (movement_direction.y > 0.0f) && (globals::curtime >= next_jump_us)) {
- velocity.value.y = -PMOVE_JUMP_FORCE * globals::dimension->get_gravity();
-
- auto new_speed = glm::length(glm::fvec2(velocity.value.x, velocity.value.z));
- auto new_speed_text = std::format("{:.02f} M/S", new_speed);
- auto speed_change = new_speed - speedometer_value;
-
- speedometer_value = new_speed;
-
- next_jump_us = globals::curtime + PMOVE_JUMP_COOLDOWN;
-
- if(enable_speedometer.get_value()) {
- if(math::abs(speed_change) < 0.01f) {
- // No considerable speed increase within
- // the precision we use to draw the speedometer
- gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f), 1.0f);
- }
- else if(speed_change < 0.0f) {
- // Speed change is negative, we are actively
- // slowing down; use the red color for the status line
- gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.0f);
- }
- else {
- // Speed change is positive, we are actively
- // speeding up; use the green color for the status line
- gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f);
- }
- }
-
- if(auto effect = world::voxel_sounds::get_footsteps(grounded->surface)) {
- sound::play_player(effect, false, 1.0f);
- }
- }
-}
-
-void entity::player_move::update_late(void)
-{
- movement_direction = ZERO_VEC3<float>;
-
- if(globals::gui_screen || !session::is_ingame()) {
- // We're either disconnected or have the
- // UI opened up; anyways we shouldn't move
- return;
- }
-
- if(io::gamepad::available && io::gamepad::active.get_value()) {
- if(button_move_down.is_pressed(io::gamepad::state)) {
- movement_direction += DIR_DOWN<float>;
- }
-
- if(button_move_up.is_pressed(io::gamepad::state)) {
- movement_direction += DIR_UP<float>;
- }
-
- movement_direction.x += axis_move_sideways.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
- movement_direction.z -= axis_move_forward.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
- }
- else {
- if(GLFW_PRESS == glfwGetKey(globals::window, key_move_forward.get_key())) {
- movement_direction += DIR_FORWARD<float>;
- }
-
- if(GLFW_PRESS == glfwGetKey(globals::window, key_move_back.get_key())) {
- movement_direction += DIR_BACK<float>;
- }
-
- if(GLFW_PRESS == glfwGetKey(globals::window, key_move_left.get_key())) {
- movement_direction += DIR_LEFT<float>;
- }
-
- if(GLFW_PRESS == glfwGetKey(globals::window, key_move_right.get_key())) {
- movement_direction += DIR_RIGHT<float>;
- }
-
- if(GLFW_PRESS == glfwGetKey(globals::window, key_move_down.get_key())) {
- movement_direction += DIR_DOWN<float>;
- }
-
- if(GLFW_PRESS == glfwGetKey(globals::window, key_move_up.get_key())) {
- movement_direction += DIR_UP<float>;
- }
- }
-}
+#include "client/pch.hh"
+
+#include "client/entity/player_move.hh"
+
+#include "core/config/boolean.hh"
+#include "core/config/number.hh"
+
+#include "core/io/config_map.hh"
+
+#include "core/math/angles.hh"
+#include "core/math/constexpr.hh"
+
+#include "shared/entity/grounded.hh"
+#include "shared/entity/head.hh"
+#include "shared/entity/transform.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "client/config/gamepad_axis.hh"
+#include "client/config/gamepad_button.hh"
+#include "client/config/keybind.hh"
+
+#include "client/gui/gui_screen.hh"
+#include "client/gui/settings.hh"
+#include "client/gui/status_lines.hh"
+
+#include "client/io/gamepad.hh"
+
+#include "client/sound/sound.hh"
+
+#include "client/world/voxel_sounds.hh"
+
+#include "client/const.hh"
+#include "client/globals.hh"
+#include "client/session.hh"
+#include "client/toggles.hh"
+
+constexpr static std::uint64_t PMOVE_JUMP_COOLDOWN = 500000; // 0.5 seconds
+
+constexpr static float PMOVE_FOOTSTEP_SIZE = 2.0f;
+
+// Movement keys
+static config::KeyBind key_move_forward(GLFW_KEY_W);
+static config::KeyBind key_move_back(GLFW_KEY_S);
+static config::KeyBind key_move_left(GLFW_KEY_A);
+static config::KeyBind key_move_right(GLFW_KEY_D);
+static config::KeyBind key_move_down(GLFW_KEY_LEFT_SHIFT);
+static config::KeyBind key_move_up(GLFW_KEY_SPACE);
+
+// Movement gamepad axes
+static config::GamepadAxis axis_move_forward(GLFW_GAMEPAD_AXIS_RIGHT_X, false);
+static config::GamepadAxis axis_move_sideways(GLFW_GAMEPAD_AXIS_RIGHT_Y, false);
+
+// Movement gamepad buttons
+static config::GamepadButton button_move_down(GLFW_GAMEPAD_BUTTON_DPAD_DOWN);
+static config::GamepadButton button_move_up(GLFW_GAMEPAD_BUTTON_DPAD_UP);
+
+// General movement options
+static config::Boolean enable_speedometer(true);
+
+static glm::fvec3 movement_direction;
+
+static std::uint64_t next_jump_us;
+static float speedometer_value;
+static float footsteps_distance;
+
+static std::mt19937_64 pitch_random;
+static std::uniform_real_distribution<float> pitch_distrib;
+
+// Quake III's PM_Accelerate-ish function used for
+// conventional (gravity-affected non-flight) movement
+static glm::fvec3 pm_accelerate(const glm::fvec3& wishdir, const glm::fvec3& velocity, float wishspeed, float accel)
+{
+ auto current_speed = glm::dot(velocity, wishdir);
+ auto add_speed = wishspeed - current_speed;
+
+ if(add_speed <= 0.0f) {
+ // Not accelerating
+ return velocity;
+ }
+
+ auto accel_speed = math::min(add_speed, accel * globals::fixed_frametime * wishspeed);
+
+ auto result = glm::fvec3(velocity);
+ result.x += accel_speed * wishdir.x;
+ result.z += accel_speed * wishdir.z;
+ return result;
+}
+
+// Conventional movement - velocity update when not on the ground
+static glm::fvec3 pm_air_move(const glm::fvec3& wishdir, const glm::fvec3& velocity)
+{
+ return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_AIR, PMOVE_MAX_SPEED_AIR);
+}
+
+// Conventional movement - velocity uodate when on the ground
+static glm::fvec3 pm_ground_move(const glm::fvec3& wishdir, const glm::fvec3& velocity)
+{
+ if(auto speed = glm::length(velocity)) {
+ auto speed_drop = speed * PMOVE_FRICTION_GROUND * globals::fixed_frametime;
+ auto speed_factor = math::max(speed - speed_drop, 0.0f) / speed;
+ return pm_accelerate(wishdir, velocity * speed_factor, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND);
+ }
+
+ return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND);
+}
+
+// A simpler minecraft-like acceleration model
+// used whenever the TOGGLE_PM_FLIGHT is enabled
+static glm::fvec3 pm_flight_move(const glm::fvec3& wishdir)
+{
+ // FIXME: make it smoother
+ return wishdir * PMOVE_MAX_SPEED_AIR;
+}
+
+void entity::player_move::init(void)
+{
+ movement_direction = ZERO_VEC3<float>;
+
+ next_jump_us = 0x0000000000000000U;
+ speedometer_value = 0.0f;
+ footsteps_distance = 0.0f;
+
+ // UNDONE: make this a separate subsystem
+ pitch_random.seed(std::random_device()());
+ pitch_distrib = std::uniform_real_distribution<float>(0.9f, 1.1f);
+
+ globals::client_config.add_value("player_move.key.forward", key_move_forward);
+ globals::client_config.add_value("player_move.key.back", key_move_back);
+ globals::client_config.add_value("player_move.key.left", key_move_left);
+ globals::client_config.add_value("player_move.key.right", key_move_right);
+ globals::client_config.add_value("player_move.key.down", key_move_down);
+ globals::client_config.add_value("player_move.key.up", key_move_up);
+ globals::client_config.add_value("player_move.gp_axis.move_forward", axis_move_forward);
+ globals::client_config.add_value("player_move.gp_axis.move_sideways", axis_move_sideways);
+ globals::client_config.add_value("player_move.gp_button.move_down", button_move_down);
+ globals::client_config.add_value("player_move.gp_button.move_up", button_move_up);
+ globals::client_config.add_value("player_move.enable_speedometer", enable_speedometer);
+
+ settings::add_keybind(1, key_move_forward, settings_location::KEYBOARD_MOVEMENT, "player_move.key.forward");
+ settings::add_keybind(2, key_move_back, settings_location::KEYBOARD_MOVEMENT, "player_move.key.back");
+ settings::add_keybind(3, key_move_left, settings_location::KEYBOARD_MOVEMENT, "player_move.key.left");
+ settings::add_keybind(4, key_move_right, settings_location::KEYBOARD_MOVEMENT, "player_move.key.right");
+ settings::add_keybind(5, key_move_down, settings_location::KEYBOARD_MOVEMENT, "player_move.key.down");
+ settings::add_keybind(6, key_move_up, settings_location::KEYBOARD_MOVEMENT, "player_move.key.up");
+
+ settings::add_gamepad_axis(0, axis_move_forward, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_forward");
+ settings::add_gamepad_axis(1, axis_move_sideways, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_sideways");
+ settings::add_gamepad_button(2, button_move_down, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_down");
+ settings::add_gamepad_button(3, button_move_up, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_up");
+
+ settings::add_checkbox(2, enable_speedometer, settings_location::VIDEO_GUI, "player_move.enable_speedometer", true);
+}
+
+void entity::player_move::fixed_update(void)
+{
+ const auto& head = globals::dimension->entities.get<entity::Head>(globals::player);
+ auto& transform = globals::dimension->entities.get<entity::Transform>(globals::player);
+ auto& velocity = globals::dimension->entities.get<entity::Velocity>(globals::player);
+
+ // Interpolation - preserve current component states
+ globals::dimension->entities.emplace_or_replace<entity::client::TransformPrev>(globals::player, transform);
+
+ glm::fvec3 forward, right;
+ math::vectors(glm::fvec3(0.0f, head.angles[1], 0.0f), &forward, &right, nullptr);
+
+ glm::fvec3 wishdir = ZERO_VEC3<float>;
+ glm::fvec3 movevars = glm::fvec3(movement_direction.x, 0.0f, movement_direction.z);
+ wishdir.x = glm::dot(movevars, right);
+ wishdir.z = glm::dot(movevars, forward);
+
+ if(toggles::get(TOGGLE_PM_FLIGHT)) {
+ velocity.value = pm_flight_move(glm::fvec3(wishdir.x, movement_direction.y, wishdir.z));
+ return;
+ }
+
+ auto grounded = globals::dimension->entities.try_get<entity::Grounded>(globals::player);
+ auto velocity_horizontal = glm::fvec3(velocity.value.x, 0.0f, velocity.value.z);
+
+ if(grounded) {
+ auto new_velocity = pm_ground_move(wishdir, velocity_horizontal);
+ velocity.value.x = new_velocity.x;
+ velocity.value.z = new_velocity.z;
+
+ auto new_speed = glm::length(new_velocity);
+
+ if(new_speed > 0.01f) {
+ footsteps_distance += globals::fixed_frametime * new_speed;
+ }
+ else {
+ footsteps_distance = 0.0f;
+ }
+
+ if(footsteps_distance >= PMOVE_FOOTSTEP_SIZE) {
+ if(auto effect = world::voxel_sounds::get_footsteps(grounded->surface)) {
+ sound::play_player(effect, false, pitch_distrib(pitch_random));
+ }
+
+ footsteps_distance = 0.0f;
+ }
+ }
+ else {
+ auto new_velocity = pm_air_move(wishdir, velocity_horizontal);
+ velocity.value.x = new_velocity.x;
+ velocity.value.z = new_velocity.z;
+ }
+
+ if(movement_direction.y == 0.0f) {
+ // Allow players to queue bunny-jumps by quickly
+ // releasing and pressing the jump key again without a cooldown
+ next_jump_us = 0x0000000000000000U;
+ return;
+ }
+
+ if(grounded && (movement_direction.y > 0.0f) && (globals::curtime >= next_jump_us)) {
+ velocity.value.y = -PMOVE_JUMP_FORCE * globals::dimension->get_gravity();
+
+ auto new_speed = glm::length(glm::fvec2(velocity.value.x, velocity.value.z));
+ auto new_speed_text = std::format("{:.02f} M/S", new_speed);
+ auto speed_change = new_speed - speedometer_value;
+
+ speedometer_value = new_speed;
+
+ next_jump_us = globals::curtime + PMOVE_JUMP_COOLDOWN;
+
+ if(enable_speedometer.get_value()) {
+ if(math::abs(speed_change) < 0.01f) {
+ // No considerable speed increase within
+ // the precision we use to draw the speedometer
+ gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f), 1.0f);
+ }
+ else if(speed_change < 0.0f) {
+ // Speed change is negative, we are actively
+ // slowing down; use the red color for the status line
+ gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.0f);
+ }
+ else {
+ // Speed change is positive, we are actively
+ // speeding up; use the green color for the status line
+ gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f);
+ }
+ }
+
+ if(auto effect = world::voxel_sounds::get_footsteps(grounded->surface)) {
+ sound::play_player(effect, false, 1.0f);
+ }
+ }
+}
+
+void entity::player_move::update_late(void)
+{
+ movement_direction = ZERO_VEC3<float>;
+
+ if(globals::gui_screen || !session::is_ingame()) {
+ // We're either disconnected or have the
+ // UI opened up; anyways we shouldn't move
+ return;
+ }
+
+ if(io::gamepad::available && io::gamepad::active.get_value()) {
+ if(button_move_down.is_pressed(io::gamepad::state)) {
+ movement_direction += DIR_DOWN<float>;
+ }
+
+ if(button_move_up.is_pressed(io::gamepad::state)) {
+ movement_direction += DIR_UP<float>;
+ }
+
+ movement_direction.x += axis_move_sideways.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
+ movement_direction.z -= axis_move_forward.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
+ }
+ else {
+ if(GLFW_PRESS == glfwGetKey(globals::window, key_move_forward.get_key())) {
+ movement_direction += DIR_FORWARD<float>;
+ }
+
+ if(GLFW_PRESS == glfwGetKey(globals::window, key_move_back.get_key())) {
+ movement_direction += DIR_BACK<float>;
+ }
+
+ if(GLFW_PRESS == glfwGetKey(globals::window, key_move_left.get_key())) {
+ movement_direction += DIR_LEFT<float>;
+ }
+
+ if(GLFW_PRESS == glfwGetKey(globals::window, key_move_right.get_key())) {
+ movement_direction += DIR_RIGHT<float>;
+ }
+
+ if(GLFW_PRESS == glfwGetKey(globals::window, key_move_down.get_key())) {
+ movement_direction += DIR_DOWN<float>;
+ }
+
+ if(GLFW_PRESS == glfwGetKey(globals::window, key_move_up.get_key())) {
+ movement_direction += DIR_UP<float>;
+ }
+ }
+}
diff --git a/game/client/entity/player_move.hh b/game/client/entity/player_move.hh
index 8c033cc..8026acf 100644
--- a/game/client/entity/player_move.hh
+++ b/game/client/entity/player_move.hh
@@ -1,15 +1,15 @@
-#pragma once
-
-constexpr static float PMOVE_MAX_SPEED_AIR = 16.0f;
-constexpr static float PMOVE_MAX_SPEED_GROUND = 8.0f;
-constexpr static float PMOVE_ACCELERATION_AIR = 3.0f;
-constexpr static float PMOVE_ACCELERATION_GROUND = 6.0f;
-constexpr static float PMOVE_FRICTION_GROUND = 10.0f;
-constexpr static float PMOVE_JUMP_FORCE = 0.275f;
-
-namespace entity::player_move
-{
-void init(void);
-void fixed_update(void);
-void update_late(void);
-} // namespace entity::player_move
+#pragma once
+
+constexpr static float PMOVE_MAX_SPEED_AIR = 16.0f;
+constexpr static float PMOVE_MAX_SPEED_GROUND = 8.0f;
+constexpr static float PMOVE_ACCELERATION_AIR = 3.0f;
+constexpr static float PMOVE_ACCELERATION_GROUND = 6.0f;
+constexpr static float PMOVE_FRICTION_GROUND = 10.0f;
+constexpr static float PMOVE_JUMP_FORCE = 0.275f;
+
+namespace entity::player_move
+{
+void init(void);
+void fixed_update(void);
+void update_late(void);
+} // namespace entity::player_move
diff --git a/game/client/entity/sound_emitter.cc b/game/client/entity/sound_emitter.cc
index eeb7294..c2a93a1 100644
--- a/game/client/entity/sound_emitter.cc
+++ b/game/client/entity/sound_emitter.cc
@@ -1,63 +1,63 @@
-#include "client/pch.hh"
-
-#include "client/entity/sound_emitter.hh"
-
-#include "core/config/number.hh"
-
-#include "core/math/constexpr.hh"
-
-#include "shared/entity/transform.hh"
-#include "shared/entity/velocity.hh"
-
-#include "shared/world/dimension.hh"
-
-#include "shared/coord.hh"
-
-#include "client/entity/camera.hh"
-
-#include "client/sound/sound.hh"
-
-#include "client/globals.hh"
-
-entity::SoundEmitter::SoundEmitter(void)
-{
- alGenSources(1, &source);
- sound = nullptr;
-}
-
-entity::SoundEmitter::~SoundEmitter(void)
-{
- alSourceStop(source);
- alDeleteSources(1, &source);
-}
-
-void entity::SoundEmitter::update(void)
-{
- if(globals::dimension) {
- const auto view = globals::dimension->entities.view<entity::SoundEmitter>();
-
- const auto& pivot = entity::camera::position_chunk;
- const auto gain = math::clamp(sound::volume_effects.get_value() * 0.01f, 0.0f, 1.0f);
-
- for(const auto [entity, emitter] : view.each()) {
- alSourcef(emitter.source, AL_GAIN, gain);
-
- if(const auto transform = globals::dimension->entities.try_get<entity::client::TransformIntr>(entity)) {
- auto position = coord::to_relative(pivot, transform->chunk, transform->local);
- alSource3f(emitter.source, AL_POSITION, position.x, position.y, position.z);
- }
-
- if(const auto velocity = globals::dimension->entities.try_get<entity::Velocity>(entity)) {
- alSource3f(emitter.source, AL_VELOCITY, velocity->value.x, velocity->value.y, velocity->value.z);
- }
-
- ALint source_state;
- alGetSourcei(emitter.source, AL_SOURCE_STATE, &source_state);
-
- if(source_state == AL_STOPPED) {
- alSourceRewind(emitter.source);
- emitter.sound = nullptr;
- }
- }
- }
-}
+#include "client/pch.hh"
+
+#include "client/entity/sound_emitter.hh"
+
+#include "core/config/number.hh"
+
+#include "core/math/constexpr.hh"
+
+#include "shared/entity/transform.hh"
+#include "shared/entity/velocity.hh"
+
+#include "shared/world/dimension.hh"
+
+#include "shared/coord.hh"
+
+#include "client/entity/camera.hh"
+
+#include "client/sound/sound.hh"
+
+#include "client/globals.hh"
+
+entity::SoundEmitter::SoundEmitter(void)
+{
+ alGenSources(1, &source);
+ sound = nullptr;
+}
+
+entity::SoundEmitter::~SoundEmitter(void)
+{
+ alSourceStop(source);
+ alDeleteSources(1, &source);
+}
+
+void entity::SoundEmitter::update(void)
+{
+ if(globals::dimension) {
+ const auto view = globals::dimension->entities.view<entity::SoundEmitter>();
+
+ const auto& pivot = entity::camera::position_chunk;
+ const auto gain = math::clamp(sound::volume_effects.get_value() * 0.01f, 0.0f, 1.0f);
+
+ for(const auto [entity, emitter] : view.each()) {
+ alSourcef(emitter.source, AL_GAIN, gain);
+
+ if(const auto transform = globals::dimension->entities.try_get<entity::client::TransformIntr>(entity)) {
+ auto position = coord::to_relative(pivot, transform->chunk, transform->local);
+ alSource3f(emitter.source, AL_POSITION, position.x, position.y, position.z);
+ }
+
+ if(const auto velocity = globals::dimension->entities.try_get<entity::Velocity>(entity)) {
+ alSource3f(emitter.source, AL_VELOCITY, velocity->value.x, velocity->value.y, velocity->value.z);
+ }
+
+ ALint source_state;
+ alGetSourcei(emitter.source, AL_SOURCE_STATE, &source_state);
+
+ if(source_state == AL_STOPPED) {
+ alSourceRewind(emitter.source);
+ emitter.sound = nullptr;
+ }
+ }
+ }
+}
diff --git a/game/client/entity/sound_emitter.hh b/game/client/entity/sound_emitter.hh
index 72a3f74..14093db 100644
--- a/game/client/entity/sound_emitter.hh
+++ b/game/client/entity/sound_emitter.hh
@@ -1,20 +1,20 @@
-#pragma once
-
-#include "core/resource/resource.hh"
-
-struct SoundEffect;
-
-namespace entity
-{
-struct SoundEmitter final {
- resource_ptr<SoundEffect> sound;
- ALuint source;
-
-public:
- explicit SoundEmitter(void);
- virtual ~SoundEmitter(void);
-
-public:
- static void update(void);
-};
-} // namespace entity
+#pragma once
+
+#include "core/resource/resource.hh"
+
+struct SoundEffect;
+
+namespace entity
+{
+struct SoundEmitter final {
+ resource_ptr<SoundEffect> sound;
+ ALuint source;
+
+public:
+ explicit SoundEmitter(void);
+ virtual ~SoundEmitter(void);
+
+public:
+ static void update(void);
+};
+} // namespace entity