From 91510e8ad06fe905a94c13db3b4f75fda46bb471 Mon Sep 17 00:00:00 2001 From: earthcrafterman Date: Sat, 11 Jul 2020 12:49:04 -0400 Subject: [PATCH] Physics can now be modified per-dimension. --- CONTRIBUTORS.md | 1 + docs/lua-api-dimension.md | 151 ++++++++++++++++-- mods/default/dimensions.lua | 6 +- source/client/states/GameState.cpp | 2 +- source/client/world/ClientPlayer.cpp | 83 ++++++---- source/client/world/ClientPlayer.hpp | 8 +- source/client/world/ClientWorld.hpp | 3 +- source/common/world/Dimension.cpp | 4 +- source/common/world/Dimension.hpp | 8 +- source/common/world/DimensionPhysics.cpp | 41 +++++ source/common/world/DimensionPhysics.hpp | 55 +++++++ .../server/lua/loader/LuaDimensionLoader.cpp | 32 +++- 12 files changed, 343 insertions(+), 51 deletions(-) create mode 100644 source/common/world/DimensionPhysics.cpp create mode 100644 source/common/world/DimensionPhysics.hpp diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1b3c11dcb..d5bd8a526 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -2,3 +2,4 @@ The following people have contributed code to this project and hold the copyrigh * Pedro Gimeno Fortea (pgimeno) \ * Nikola Schordinger (DeatHunter) \ * Kurt Spencer (K.jpg) \ +* Daniel Bradley (1SDAN) \ diff --git a/docs/lua-api-dimension.md b/docs/lua-api-dimension.md index 8b2daef19..179b35a35 100644 --- a/docs/lua-api-dimension.md +++ b/docs/lua-api-dimension.md @@ -24,7 +24,74 @@ Example: biomes = {"default:grassland", "default:desert"} ``` -### `gravity` +### `id` + +ID of the dimension. **Mandatory field.** + +Example: +```lua +id = "dimension_nether" +``` + +IDs are usually of the form `mod:dimension` but the `mod:` prefix is prepended automatically so it's not needed. + +### `name` + +Label of the dimension. **Mandatory field.** + +Example: +```lua +name = "Nether" +``` + +This label is the name that will appear everywhere in the game. + +### `player_physics` + +Table containing the physics properties of the dimension + +Example: +```lua +player_physics = { + gravity = 1.0, + jump_antigravity = 0.3, +} +``` + +#### `air_speed_mod` + +The movement speed of players in this dimension is multiplied by this amount while in the air. + +Example: +```lua +air_speed_mod = 0.75 +``` + +Default value is `0.75`. + +#### `fly_speed` + +Fly speed in this dimension. + +Example: +```lua +fly_speed = 0.75 +``` + +Default value is `0.75`. + +#### `glide_gravity` + +Fall speed while holding Jump key in this dimension. + +Example: +```lua +glide_gravity = 0.05 +``` + +Default value is `0.05`. + +#### `gravity` Gravity of the dimension. @@ -35,27 +102,93 @@ gravity = 0.5 Default value is `1`. -### `id` +#### `horizontal_sprint_mod` -ID of the dimension. **Mandatory field.** +Horizontal sprint speed multiplier. Example: ```lua -id = "dimension_nether" +horizontal_sprint_mod = 1.5 ``` -IDs are usually of the form `mod:dimension` but the `mod:` prefix is prepended automatically so it's not needed. +Default value is `1.5`. -### `name` +#### `is_sneak_always_mod` -Label of the dimension. **Mandatory field.** +Whether sneaking applies the horizontal mod while airborne. Example: ```lua -name = "Nether" +is_sneak_always_mod = false ``` -This label is the name that will appear everywhere in the game. +Default value is `false`. + +#### `jump_antigravity` + +Gravity is decreased by this amount while holding the jump key prior to the peak of the jump. + +Example: +```lua +jump_antigravity = 0.04 +``` + +Default value is `0.04`. + +#### `jump_speed` + +Jump speed of the dimension. + +Example: +```lua +jump_speed = 0.3 +``` + +Default value is `0.3`. + +#### `move_speed` + +Movement speed in this dimension. + +Example: +```lua +move_speed = 0.04 +``` + +Default value is `0.04`. + +#### `sneak_horizontal_mod` + +Horizontal movement speed is multiplied by this amount while sneaking. + +Example: +```lua +sneak_horizontal_mod = 0.1 +``` + +Default value is `0.1`. + +#### `sneak_vertical_speed` + +Downwards momentum of this amount is applied while sneaking. + +Example: +```lua +sneak_vertical_speed = 0.1 +``` + +Default value is `0.1`. + +#### `vertical_sprint_mod` + +Vertical sprint speed multiplier. + +Example: +```lua +vertical_sprint_mod = 1.5 +``` + +Default value is `1.5`. ### `sky` diff --git a/mods/default/dimensions.lua b/mods/default/dimensions.lua index 7567ecadd..86c1465fa 100644 --- a/mods/default/dimensions.lua +++ b/mods/default/dimensions.lua @@ -41,7 +41,9 @@ mod:dimension { biomes = {"default:netherland"}, sky = "default:sky_nether", - - gravity = 1.4, + + player_physics = { + gravity = 1.4, + } } diff --git a/source/client/states/GameState.cpp b/source/client/states/GameState.cpp index c3de47466..7e18f8766 100644 --- a/source/client/states/GameState.cpp +++ b/source/client/states/GameState.cpp @@ -159,7 +159,7 @@ void GameState::update() { m_camera.setFieldOfView(Config::cameraFOV); if (!m_stateStack->empty() && &m_stateStack->top() == this) { - m_player.processInputs(); + m_player.processInputs(*m_world.dimension()); } if (!m_areModKeysLoaded) { diff --git a/source/client/world/ClientPlayer.cpp b/source/client/world/ClientPlayer.cpp index f1f86e16e..df9ca6806 100644 --- a/source/client/world/ClientPlayer.cpp +++ b/source/client/world/ClientPlayer.cpp @@ -72,41 +72,61 @@ void ClientPlayer::updateCamera() { m_camera.setUpVector(gk::Vector3f{sh * sr - ch * sv * cr, -ch * sr - sh * sv * cr, cv * cr}); } -void ClientPlayer::move(float direction) { +void ClientPlayer::move(const Dimension &dimension, float direction) { direction += m_viewAngleH; - m_velocity.x = 0.04f * cosf(direction * RADIANS_PER_DEGREES); - m_velocity.y = 0.04f * sinf(direction * RADIANS_PER_DEGREES); + m_velocity.x = dimension.physics().moveSpeed * cosf(direction * RADIANS_PER_DEGREES); + m_velocity.y =dimension.physics().moveSpeed * sinf(direction * RADIANS_PER_DEGREES); } -void ClientPlayer::processInputs() { - if(gk::GamePad::isKeyPressed(GameKey::Jump) && !m_isJumping) { - m_isJumping = true; - m_velocity.z = m_jumpSpeed; - } +void ClientPlayer::processInputs(const Dimension &dimension) { + if(gk::GamePad::isKeyPressed(GameKey::Jump)) { + if (!m_isJumping) { + m_isJumping = true; + m_velocity.z = dimension.physics().jumpSpeed; + } - if(gk::GamePad::isKeyPressed(GameKey::Fly)) { - m_velocity.z = 0.1; - } + if (m_isJumping && m_velocity.z > 0.0f) { + m_velocity.z += dimension.physics().jumpAntigravity * 0.001f; + } - if(gk::GamePad::isKeyPressed(GameKey::Sneak)) { - m_velocity.z = -0.1; + if (m_velocity.z < 0.0f) { + if (!m_isGliding) m_isGliding = true; + } + } + else { + if (m_velocity.z < 0.0f) { + if (m_isGliding) m_isGliding = false; + } } - if(gk::GamePad::isKeyPressed(GameKey::Forward)) move(0.0f); - else if(gk::GamePad::isKeyPressed(GameKey::Back)) move(180.0f); + if(gk::GamePad::isKeyPressed(GameKey::Forward)) move(dimension, 0.0f); + else if(gk::GamePad::isKeyPressed(GameKey::Back)) move(dimension, 180.0f); - if(gk::GamePad::isKeyPressed(GameKey::Left)) move(90.0f); - else if(gk::GamePad::isKeyPressed(GameKey::Right)) move(-90.0f); + if(gk::GamePad::isKeyPressed(GameKey::Left)) move(dimension, 90.0f); + else if(gk::GamePad::isKeyPressed(GameKey::Right)) move(dimension, -90.0f); - if (gk::GamePad::isKeyPressed(GameKey::Left) && gk::GamePad::isKeyPressed(GameKey::Forward)) move(45.0f); - if (gk::GamePad::isKeyPressed(GameKey::Right) && gk::GamePad::isKeyPressed(GameKey::Forward)) move(-45.0f); - if (gk::GamePad::isKeyPressed(GameKey::Left) && gk::GamePad::isKeyPressed(GameKey::Back)) move(135.0f); - if (gk::GamePad::isKeyPressed(GameKey::Right) && gk::GamePad::isKeyPressed(GameKey::Back)) move(-135.0f); + if (gk::GamePad::isKeyPressed(GameKey::Left) && gk::GamePad::isKeyPressed(GameKey::Forward)) move(dimension, 45.0f); + if (gk::GamePad::isKeyPressed(GameKey::Right) && gk::GamePad::isKeyPressed(GameKey::Forward)) move(dimension, -45.0f); + if (gk::GamePad::isKeyPressed(GameKey::Left) && gk::GamePad::isKeyPressed(GameKey::Back)) move(dimension, 135.0f); + if (gk::GamePad::isKeyPressed(GameKey::Right) && gk::GamePad::isKeyPressed(GameKey::Back)) move(dimension, -135.0f); if (gk::GamePad::isKeyPressed(GameKey::Sprint)) { - m_velocity.x *= 1.5f; - m_velocity.y *= 1.5f; + m_velocity.x *= dimension.physics().horizontalSprintMod; + m_velocity.y *= dimension.physics().verticalSprintMod; + } + + if(gk::GamePad::isKeyPressed(GameKey::Fly)) { + m_velocity.z = dimension.physics().flySpeed; + } + + if(gk::GamePad::isKeyPressed(GameKey::Sneak)) { + if (m_velocity.z == 0 || dimension.physics().isSneakAlwaysMod) { + m_velocity.x *= dimension.physics().sneakHorizontalMod; + m_velocity.y *= dimension.physics().sneakHorizontalMod; + } + + m_velocity.z = -dimension.physics().sneakVerticalSpeed; } } @@ -114,12 +134,18 @@ void ClientPlayer::updatePosition(const ClientWorld &world) { ClientChunk *chunk = (ClientChunk *)world.getChunkAtBlockPos(m_x, m_y, m_z); if (chunk && chunk->isInitialized()) { if (!Config::isFlyModeEnabled) { - m_velocity.z -= chunk->dimension().gravity() * 0.001f; + m_velocity.z -= world.dimension()->physics().gravity * 0.001f; m_isJumping = true; - if (m_velocity.z < -m_jumpSpeed) // Limit max vertical speed to jump speed - m_velocity.z = -m_jumpSpeed; + if (m_isGliding) { + if (m_velocity.z < -world.dimension()->physics().glideGravity) // Limit max vertical speed to glide gravity + m_velocity.z = -world.dimension()->physics().glideGravity; + } + else { + if (m_velocity.z < -world.dimension()->physics().jumpSpeed) // Limit max vertical speed to jump speed + m_velocity.z = -world.dimension()->physics().jumpSpeed; + } } } else { @@ -131,8 +157,8 @@ void ClientPlayer::updatePosition(const ClientWorld &world) { checkCollisions(world); if (!Config::isFlyModeEnabled && m_velocity.z != 0.f) { - m_velocity.x *= 0.75f; - m_velocity.y *= 0.75f; + m_velocity.x *= world.dimension()->physics().airSpeedMod; + m_velocity.y *= world.dimension()->physics().airSpeedMod; } setPosition(m_x + m_velocity.x, m_y + m_velocity.y, m_z + m_velocity.z); @@ -194,6 +220,7 @@ void ClientPlayer::testPoint(const ClientWorld &world, double x, double y, doubl if(!passable(world, x, y + vel.y, z)) vel.y = 0.f; if(!passable(world, x, y, z + vel.z)) { if(vel.z < 0.f && m_isJumping) m_isJumping = false; + if(vel.z < 0.f && m_isGliding) m_isGliding = false; vel.z = 0.f; } } diff --git a/source/client/world/ClientPlayer.hpp b/source/client/world/ClientPlayer.hpp index 9789881fe..a7969f4ff 100644 --- a/source/client/world/ClientPlayer.hpp +++ b/source/client/world/ClientPlayer.hpp @@ -34,6 +34,7 @@ #include #include "Player.hpp" +#include "Dimension.hpp" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -54,9 +55,9 @@ class ClientPlayer : public Player { void updateCamera(); - void move(float direction); + void move(const Dimension &dimension, float direction); - void processInputs(); + void processInputs(const Dimension &dimension); void updatePosition(const ClientWorld &world); void checkCollisions(const ClientWorld &world); @@ -86,8 +87,7 @@ class ClientPlayer : public Player { glm::vec3 m_velocity{0.f}; bool m_isJumping = false; - - const float m_jumpSpeed = 0.06f; + bool m_isGliding = false; }; #endif // CLIENTPLAYER_HPP_ diff --git a/source/client/world/ClientWorld.hpp b/source/client/world/ClientWorld.hpp index d9aecc13b..57ee5603a 100644 --- a/source/client/world/ClientWorld.hpp +++ b/source/client/world/ClientWorld.hpp @@ -52,7 +52,8 @@ class ClientWorld : public World, public gk::Drawable { void checkPlayerChunk(double playerX, double playerY, double playerZ); void clear(); - + + const Dimension *dimension() const { return m_dimension; } void changeDimension(u16 dimensionID); void receiveChunkData(Network::Packet &packet); diff --git a/source/common/world/Dimension.cpp b/source/common/world/Dimension.cpp index a4826b973..a53fa11a4 100644 --- a/source/common/world/Dimension.cpp +++ b/source/common/world/Dimension.cpp @@ -28,11 +28,11 @@ #include "NetworkUtils.hpp" void Dimension::serialize(sf::Packet &packet) const { - packet << m_id << m_stringID << m_name << m_biomes << m_sky << m_gravity; + packet << m_id << m_stringID << m_name << m_biomes << m_sky << m_physics; } void Dimension::deserialize(sf::Packet &packet) { - packet >> m_id >> m_stringID >> m_name >> m_biomes >> m_sky >> m_gravity; + packet >> m_id >> m_stringID >> m_name >> m_biomes >> m_sky >> m_physics; } // Please update 'docs/lua-api-cpp.md' if you change this diff --git a/source/common/world/Dimension.hpp b/source/common/world/Dimension.hpp index 4d604c014..f31650073 100644 --- a/source/common/world/Dimension.hpp +++ b/source/common/world/Dimension.hpp @@ -35,6 +35,8 @@ #include +#include "DimensionPhysics.hpp" + class Dimension : public gk::ISerializable { public: Dimension() = default; @@ -55,8 +57,8 @@ class Dimension : public gk::ISerializable { const std::string &sky() const { return m_sky; } void setSky(const std::string &sky) { m_sky = sky; } - float gravity() const { return m_gravity; } - void setGravity(float gravity) { m_gravity = gravity; } + const DimensionPhysics &physics() const { return m_physics; } + void setPhysics(const DimensionPhysics &physics) { m_physics = physics; } static void initUsertype(sol::state &lua); @@ -70,7 +72,7 @@ class Dimension : public gk::ISerializable { std::string m_sky; - float m_gravity = 1.f; + DimensionPhysics m_physics; }; #endif // DIMENSION_HPP_ diff --git a/source/common/world/DimensionPhysics.cpp b/source/common/world/DimensionPhysics.cpp new file mode 100644 index 000000000..e0442476f --- /dev/null +++ b/source/common/world/DimensionPhysics.cpp @@ -0,0 +1,41 @@ +/* + * ===================================================================================== + * + * OpenMiner + * + * Copyright (C) 2018-2020 Unarelith, Quentin Bazin + * Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md) + * + * This file is part of OpenMiner. + * + * OpenMiner is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * OpenMiner is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenMiner; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * ===================================================================================== + */ +#include "DimensionPhysics.hpp" +#include "NetworkUtils.hpp" + +void DimensionPhysics::serialize(sf::Packet &packet) const { + packet << gravity << jumpSpeed << jumpAntigravity << glideGravity << horizontalSprintMod << + verticalSprintMod << moveSpeed << airSpeedMod << flySpeed << sneakVerticalSpeed << + sneakHorizontalMod << isSneakAlwaysMod; +} + +void DimensionPhysics::deserialize(sf::Packet &packet) { + packet >> gravity >> jumpSpeed >> jumpAntigravity >> glideGravity >> horizontalSprintMod >> + verticalSprintMod >> moveSpeed >> airSpeedMod >> flySpeed >> sneakVerticalSpeed >> + sneakHorizontalMod >> isSneakAlwaysMod; +} + diff --git a/source/common/world/DimensionPhysics.hpp b/source/common/world/DimensionPhysics.hpp new file mode 100644 index 000000000..e4fa6def1 --- /dev/null +++ b/source/common/world/DimensionPhysics.hpp @@ -0,0 +1,55 @@ +/* + * ===================================================================================== + * + * OpenMiner + * + * Copyright (C) 2018-2020 Unarelith, Quentin Bazin + * Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md) + * + * This file is part of OpenMiner. + * + * OpenMiner is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * OpenMiner is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with OpenMiner; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * ===================================================================================== + */ +#ifndef DIMENSIONPHYSICS_HPP_ +#define DIMENSIONPHYSICS_HPP_ + +#include + +struct DimensionPhysics : public gk::ISerializable { + void serialize(sf::Packet &packet) const override; + void deserialize(sf::Packet &packet) override; + + float gravity = 1.f; + float jumpSpeed = 0.05f; + + float jumpAntigravity = 0.3f; + float glideGravity = 0.04f; + + float horizontalSprintMod = 1.5f; + float verticalSprintMod = 1.5f; + + float moveSpeed = 0.04f; + float airSpeedMod = 0.75f; + + float flySpeed = 0.1f; + float sneakVerticalSpeed = 0.1f; + float sneakHorizontalMod = 0.5f; + + bool isSneakAlwaysMod = false; +}; + +#endif // DIMENSIONPHYSICS_HPP_ \ No newline at end of file diff --git a/source/server/lua/loader/LuaDimensionLoader.cpp b/source/server/lua/loader/LuaDimensionLoader.cpp index 9412f6755..9714894ea 100644 --- a/source/server/lua/loader/LuaDimensionLoader.cpp +++ b/source/server/lua/loader/LuaDimensionLoader.cpp @@ -38,8 +38,38 @@ void LuaDimensionLoader::loadDimension(const sol::table &table) const { if (biomesObject.valid() && biomesObject.get_type() == sol::type::table) { Dimension &dimension = Registry::getInstance().registerDimension(id, name); dimension.setSky(table["sky"].get()); - dimension.setGravity(table["gravity"].get_or(1.f)); + sol::object dimensionPhysicsObject = table["player_physics"]; + if (dimensionPhysicsObject.valid()) { + if(dimensionPhysicsObject.get_type() == sol::type::table) { + sol::table dimensionPhysicsTable = dimensionPhysicsObject.as(); + + DimensionPhysics dimensionPhysics; + + dimensionPhysics.gravity = table["gravity"].get_or(1.f); + dimensionPhysics.jumpSpeed = table["jump_speed"].get_or(0.05f); + + dimensionPhysics.jumpAntigravity = table["jump_antigravity"].get_or(0.3f); + dimensionPhysics.glideGravity = table["glide_gravity"].get_or(0.04f); + + dimensionPhysics.horizontalSprintMod = table["horizontal_sprint_mod"].get_or(1.5f); + dimensionPhysics.verticalSprintMod = table["vertical_sprint_mod"].get_or(1.5f); + + dimensionPhysics.moveSpeed = table["move_speed"].get_or(0.04f); + dimensionPhysics.airSpeedMod = table["air_speed_mod"].get_or(0.75f); + + dimensionPhysics.flySpeed = table["fly_speed"].get_or(0.1f); + dimensionPhysics.sneakVerticalSpeed = table["sneak_vertical_speed"].get_or(0.1f); + dimensionPhysics.sneakHorizontalMod = table["sneak_horizontal_mod"].get_or(0.5f); + + dimensionPhysics.isSneakAlwaysMod = table["is_sneak_always_mod"].get_or(false); + + dimension.setPhysics(dimensionPhysics); + } + else + gkError() << "For dimension" << name << ": Invalid player physics table"; + } + sol::table biomesTable = biomesObject.as(); for (auto &it : biomesTable) { if (it.second.get_type() == sol::type::string)