Improved Player Physics
authorMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Fri, 8 Feb 2013 20:54:01 +0000 (22:54 +0200)
committerdarkrose <lisa@ltmnet.com>
Wed, 13 Feb 2013 20:21:30 +0000 (06:21 +1000)
minetest.conf.example
src/client.cpp
src/clientserver.h
src/defaultsettings.cpp
src/environment.cpp
src/localplayer.cpp
src/player.cpp
src/player.h
src/server.cpp
src/server.h

index 49fc95ba2f01395497f31fef48940d7123015408..2957258763c29f811326b21f90d2250730cb7e51 100644 (file)
 # Files that are not present would be fetched the usual way
 #remote_media =
 
+# Physics stuff
+#movement_acceleration_default = 2
+#movement_acceleration_air = 0.5
+#movement_acceleration_fast = 4
+#movement_speed_walk = 4
+#movement_speed_crouch = 1.35
+#movement_speed_fast = 20
+#movement_speed_climb = 2
+#movement_speed_jump = 6.5
+#movement_speed_descend = 6
+#movement_liquid_fluidity = 1
+#movement_liquid_fluidity_smooth = 0.5
+#movement_liquid_sink = 10
+#movement_gravity = 9.81
+
 # Mapgen stuff
 #mg_name = v6
 #water_level = 1
index 9969ef538060bd20f30087ead7d1ee9117ae6a2e..415f073116d41aff5afdda8498a9d5eb6ae8c9a3 100644 (file)
@@ -1514,6 +1514,26 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                        }
                }
        }
+       else if(command == TOCLIENT_MOVEMENT)
+       {
+               std::string datastring((char*)&data[2], datasize-2);
+               std::istringstream is(datastring, std::ios_base::binary);
+               Player *player = m_env.getLocalPlayer();
+               assert(player != NULL);
+
+               player->movement_acceleration_default = readF1000(is) * BS;
+               player->movement_acceleration_air = readF1000(is) * BS;
+               player->movement_acceleration_fast = readF1000(is) * BS;
+               player->movement_speed_walk = readF1000(is) * BS;
+               player->movement_speed_crouch = readF1000(is) * BS;
+               player->movement_speed_fast = readF1000(is) * BS;
+               player->movement_speed_climb = readF1000(is) * BS;
+               player->movement_speed_jump = readF1000(is) * BS;
+               player->movement_liquid_fluidity = readF1000(is) * BS;
+               player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
+               player->movement_liquid_sink = readF1000(is) * BS;
+               player->movement_gravity = readF1000(is) * BS;
+       }
        else if(command == TOCLIENT_HP)
        {
                std::string datastring((char*)&data[2], datasize-2);
index 52b9dc7b044c6f7073261895762fdc8bad24a93d..7fb3e83d25b1e5b5c8af2e8a62dea9cdc4eb8127 100644 (file)
@@ -364,6 +364,23 @@ enum ToClientCommand
                u16 len
                u8[len] formname
        */
+
+       TOCLIENT_MOVEMENT = 0x45,
+       /*
+               u16 command
+               f1000 movement_acceleration_default
+               f1000 movement_acceleration_air
+               f1000 movement_acceleration_fast
+               f1000 movement_speed_walk
+               f1000 movement_speed_crouch
+               f1000 movement_speed_fast
+               f1000 movement_speed_climb
+               f1000 movement_speed_jump
+               f1000 movement_liquid_fluidity
+               f1000 movement_liquid_fluidity_smooth
+               f1000 movement_liquid_sink
+               f1000 movement_gravity
+       */
 };
 
 enum ToServerCommand
index a164d0693e805ea3824ef319691e6621d3580a9c..1c673f76c07d31423ac32506a337b7cf0e9e6486 100644 (file)
@@ -172,6 +172,20 @@ void set_default_settings(Settings *settings)
        settings->setDefault("congestion_control_max_rate", "400");
        settings->setDefault("congestion_control_min_rate", "10");
        settings->setDefault("remote_media", "");
+
+       // physics stuff
+       settings->setDefault("movement_acceleration_default", "2");
+       settings->setDefault("movement_acceleration_air", "0.5");
+       settings->setDefault("movement_acceleration_fast", "8");
+       settings->setDefault("movement_speed_walk", "4");
+       settings->setDefault("movement_speed_crouch", "1.35");
+       settings->setDefault("movement_speed_fast", "20");
+       settings->setDefault("movement_speed_climb", "2");
+       settings->setDefault("movement_speed_jump", "6.5");
+       settings->setDefault("movement_liquid_fluidity", "1");
+       settings->setDefault("movement_liquid_fluidity_smooth", "0.5");
+       settings->setDefault("movement_liquid_sink", "10");
+       settings->setDefault("movement_gravity", "9.81");
        
        //mapgen related things
        settings->setDefault("mg_name", "v6");
index 51255b91847113885e552db5febe0a9a07a167f5..ebf5e9a63cf0499ecc0d7961912f49afd99b88de 100644 (file)
@@ -2065,20 +2065,37 @@ void ClientEnvironment::step(float dtime)
                        {
                                // Gravity
                                v3f speed = lplayer->getSpeed();
-                               if(lplayer->swimming_up == false)
-                                       speed.Y -= 9.81 * BS * dtime_part * 2;
+                               if(lplayer->in_liquid == false)
+                                       speed.Y -= lplayer->movement_gravity * dtime_part * 2;
 
-                               // Water resistance
-                               if(lplayer->in_water_stable || lplayer->in_water)
-                               {
-                                       f32 max_down = 2.0*BS;
-                                       if(speed.Y < -max_down) speed.Y = -max_down;
+                               // Liquid floating / sinking
+                               if(lplayer->in_liquid && !lplayer->swimming_vertical)
+                                       speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
 
-                                       f32 max = 2.5*BS;
-                                       if(speed.getLength() > max)
-                                       {
-                                               speed = speed / speed.getLength() * max;
-                                       }
+                               // Liquid resistance
+                               if(lplayer->in_liquid_stable || lplayer->in_liquid)
+                               {
+                                       // How much the node's viscosity blocks movement, ranges between 0 and 1
+                                       // Should match the scale at which viscosity increase affects other liquid attributes
+                                       const f32 viscosity_factor = 0.3;
+
+                                       v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
+                                       f32 dl = d_wanted.getLength();
+                                       if(dl > lplayer->movement_liquid_fluidity_smooth)
+                                               dl = lplayer->movement_liquid_fluidity_smooth;
+                                       dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
+                                       
+                                       v3f d = d_wanted.normalize() * dl;
+                                       speed += d;
+                                       
+#if 0 // old code
+                                       if(speed.X > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.X -= lplayer->movement_liquid_fluidity_smooth;
+                                       if(speed.X < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.X += lplayer->movement_liquid_fluidity_smooth;
+                                       if(speed.Y > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Y -= lplayer->movement_liquid_fluidity_smooth;
+                                       if(speed.Y < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Y += lplayer->movement_liquid_fluidity_smooth;
+                                       if(speed.Z > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Z -= lplayer->movement_liquid_fluidity_smooth;
+                                       if(speed.Z < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Z += lplayer->movement_liquid_fluidity_smooth;
+#endif
                                }
 
                                lplayer->setSpeed(speed);
index 2d0d77140bdb781365ed4c6aa4e37a2a60a0a977..8b6d7e2f6c679052bf462be926c6f201bd7960a3 100644 (file)
@@ -90,37 +90,39 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        */
        
        /*
-               Check if player is in water (the oscillating value)
+               Check if player is in liquid (the oscillating value)
        */
        try{
-               // If in water, the threshold of coming out is at higher y
-               if(in_water)
+               // If in liquid, the threshold of coming out is at higher y
+               if(in_liquid)
                {
                        v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
-                       in_water = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
+                       in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
+                       liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity;
                }
-               // If not in water, the threshold of going in is at lower y
+               // If not in liquid, the threshold of going in is at lower y
                else
                {
                        v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
-                       in_water = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
+                       in_liquid = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
+                       liquid_viscosity = nodemgr->get(map.getNode(pp).getContent()).liquid_viscosity;
                }
        }
        catch(InvalidPositionException &e)
        {
-               in_water = false;
+               in_liquid = false;
        }
 
        /*
-               Check if player is in water (the stable value)
+               Check if player is in liquid (the stable value)
        */
        try{
                v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
-               in_water_stable = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
+               in_liquid_stable = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
        }
        catch(InvalidPositionException &e)
        {
-               in_water_stable = false;
+               in_liquid_stable = false;
        }
 
        /*
@@ -159,7 +161,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                If sneaking, keep in range from the last walked node and don't
                fall off from it
        */
-       if(control.sneak && m_sneak_node_exists && !(fly_allowed && g_settings->getBool("free_move")))
+       if(control.sneak && m_sneak_node_exists && !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid)
        {
                f32 maxd = 0.5*BS + sneak_max;
                v3f lwn_f = intToFloat(m_sneak_node, BS);
@@ -315,7 +317,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        }
 
        if(bouncy_jump && control.jump){
-               m_speed.Y += 6.5*BS;
+               m_speed.Y += movement_speed_jump*BS;
                touching_ground = false;
                MtEvent *e = new SimpleTriggerEvent("PlayerJump");
                m_gamedef->event()->put(e);
@@ -348,7 +350,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        */
        const ContentFeatures &f = nodemgr->get(map.getNodeNoEx(getStandingNodePos()));
        // Determine if jumping is possible
-       m_can_jump = touching_ground;
+       m_can_jump = touching_ground && !in_liquid;
        if(itemgroup_get(f.groups, "disable_jump"))
                m_can_jump = false;
 }
@@ -361,12 +363,8 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
 void LocalPlayer::applyControl(float dtime)
 {
        // Clear stuff
-       swimming_up = false;
+       swimming_vertical = false;
 
-       // Random constants
-       f32 walk_acceleration = 4.0 * BS;
-       f32 walkspeed_max = 4.0 * BS;
-       
        setPitch(control.pitch);
        setYaw(control.yaw);
 
@@ -380,22 +378,17 @@ void LocalPlayer::applyControl(float dtime)
        v3f move_direction = v3f(0,0,1);
        move_direction.rotateXZBy(getYaw());
        
-       v3f speed = v3f(0,0,0);
+       v3f speedH = v3f(0,0,0); // Horizontal (X, Z)
+       v3f speedV = v3f(0,0,0); // Vertical (Y)
        
        bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
        bool fast_allowed = m_gamedef->checkLocalPrivilege("fast");
 
        bool free_move = fly_allowed && g_settings->getBool("free_move");
        bool fast_move = fast_allowed && g_settings->getBool("fast_move");
+       bool fast_or_aux1_descends = (fast_move && control.aux1) || (fast_move && g_settings->getBool("aux1_descends"));
        bool continuous_forward = g_settings->getBool("continuous_forward");
 
-       if(free_move || is_climbing)
-       {
-               v3f speed = getSpeed();
-               speed.Y = 0;
-               setSpeed(speed);
-       }
-
        // Whether superspeed mode is used or not
        bool superspeed = false;
        
@@ -415,18 +408,21 @@ void LocalPlayer::applyControl(float dtime)
                        if(free_move)
                        {
                                // In free movement mode, aux1 descends
-                               v3f speed = getSpeed();
                                if(fast_move)
-                                       speed.Y = -20*BS;
+                                       speedV.Y = -movement_speed_fast;
                                else
-                                       speed.Y = -walkspeed_max;
-                               setSpeed(speed);
+                                       speedV.Y = -movement_speed_walk;
+                       }
+                       else if(in_liquid || in_liquid_stable)
+                       {
+                               // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+                               speedV.Y = -movement_speed_fast;
+                               swimming_vertical = true;
                        }
                        else if(is_climbing)
                        {
-                                       v3f speed = getSpeed();
-                               speed.Y = -3*BS;
-                               setSpeed(speed);
+                               // Always use fast when aux1_descends & fast_move are enabled when climbing, since the aux1 button would mean both turbo and "descend" causing a conflict
+                               speedV.Y = -movement_speed_fast;
                        }
                        else
                        {
@@ -456,66 +452,69 @@ void LocalPlayer::applyControl(float dtime)
                        if(free_move)
                        {
                                // In free movement mode, sneak descends
-                               v3f speed = getSpeed();
-                               if(fast_move && (control.aux1 ||
-                                               g_settings->getBool("always_fly_fast")))
-                                       speed.Y = -20*BS;
+                               if(fast_move && (control.aux1 || g_settings->getBool("always_fly_fast")))
+                                       speedV.Y = -movement_speed_fast;
                                else
-                                       speed.Y = -walkspeed_max;
-                                       setSpeed(speed);
+                                       speedV.Y = -movement_speed_walk;
+                       }
+                       else if(in_liquid || in_liquid_stable)
+                       {
+                               if(fast_or_aux1_descends)
+                                       // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+                                       speedV.Y = -movement_speed_fast;
+                               else
+                                       speedV.Y = -movement_speed_walk;
+                               swimming_vertical = true;
                        }
                        else if(is_climbing)
                        {
-                               v3f speed = getSpeed();
-                               speed.Y = -3*BS;
-                               setSpeed(speed);
+                               if(fast_or_aux1_descends)
+                                       // Always use fast when aux1_descends & fast_move are enabled when climbing, since the aux1 button would mean both turbo and "descend" causing a conflict
+                                       speedV.Y = -movement_speed_fast;
+                               else
+                                       speedV.Y = -movement_speed_climb;
                        }
                }
        }
 
        if(continuous_forward)
-               speed += move_direction;
+               speedH += move_direction;
 
        if(control.up)
        {
                if(continuous_forward)
                        superspeed = true;
                else
-                       speed += move_direction;
+                       speedH += move_direction;
        }
        if(control.down)
        {
-               speed -= move_direction;
+               speedH -= move_direction;
        }
        if(control.left)
        {
-               speed += move_direction.crossProduct(v3f(0,1,0));
+               speedH += move_direction.crossProduct(v3f(0,1,0));
        }
        if(control.right)
        {
-               speed += move_direction.crossProduct(v3f(0,-1,0));
+               speedH += move_direction.crossProduct(v3f(0,-1,0));
        }
        if(control.jump)
        {
                if(free_move)
-               {
-                       v3f speed = getSpeed();
-                       
-                       if(g_settings->getBool("aux1_descends") ||
-                                       g_settings->getBool("always_fly_fast"))
+               {                       
+                       if(g_settings->getBool("aux1_descends") || g_settings->getBool("always_fly_fast"))
                        {
                                if(fast_move)
-                                       speed.Y = 20*BS;
+                                       speedV.Y = movement_speed_fast;
                                else
-                                       speed.Y = walkspeed_max;
+                                       speedV.Y = movement_speed_walk;
                        } else {
                                if(fast_move && control.aux1)
-                                       speed.Y = 20*BS;
+                                       speedV.Y = movement_speed_fast;
                                else
-                                       speed.Y = walkspeed_max;
+                                       speedV.Y = movement_speed_walk;
                        }
-                       
-                       setSpeed(speed);
                }
                else if(m_can_jump)
                {
@@ -524,49 +523,66 @@ void LocalPlayer::applyControl(float dtime)
                                raising the height at which the jump speed is kept
                                at its starting value
                        */
-                       v3f speed = getSpeed();
-                       if(speed.Y >= -0.5*BS)
+                       v3f speedJ = getSpeed();
+                       if(speedJ.Y >= -0.5 * BS)
                        {
-                               speed.Y = 6.5*BS;
-                               setSpeed(speed);
+                               speedJ.Y = movement_speed_jump;
+                               setSpeed(speedJ);
                                
                                MtEvent *e = new SimpleTriggerEvent("PlayerJump");
                                m_gamedef->event()->put(e);
                        }
                }
-               // Use the oscillating value for getting out of water
-               // (so that the player doesn't fly on the surface)
-               else if(in_water)
+               else if(in_liquid)
                {
-                       v3f speed = getSpeed();
-                       speed.Y = 1.5*BS;
-                       setSpeed(speed);
-                       swimming_up = true;
+                       if(fast_or_aux1_descends)
+                               // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+                               speedV.Y = movement_speed_fast;
+                       else
+                               speedV.Y = movement_speed_walk;
+                       swimming_vertical = true;
                }
                else if(is_climbing)
                {
-                       v3f speed = getSpeed();
-                       speed.Y = 3*BS;
-                       setSpeed(speed);
+                       if(fast_or_aux1_descends)
+                               // Always use fast when aux1_descends & fast_move are enabled when climbing, since the aux1 button would mean both turbo and "descend" causing a conflict
+                               speedV.Y = movement_speed_fast;
+                       else
+                               speedV.Y = movement_speed_climb;
                }
        }
 
        // The speed of the player (Y is ignored)
-       if(superspeed)
-               speed = speed.normalize() * walkspeed_max * 5.0;
-       else if(control.sneak && !free_move)
-               speed = speed.normalize() * walkspeed_max / 3.0;
+       if(superspeed || (is_climbing && fast_or_aux1_descends) || ((in_liquid || in_liquid_stable) && fast_or_aux1_descends))
+               speedH = speedH.normalize() * movement_speed_fast;
+       else if(control.sneak && !free_move && !in_liquid && !in_liquid_stable)
+               speedH = speedH.normalize() * movement_speed_crouch;
        else
-               speed = speed.normalize() * walkspeed_max;
-       
-       f32 inc = walk_acceleration * BS * dtime;
-       
-       // Faster acceleration if fast and free movement
-       if(free_move && fast_move && superspeed)
-               inc = walk_acceleration * BS * dtime * 10;
-       
+               speedH = speedH.normalize() * movement_speed_walk;
+
+       // Acceleration increase
+       f32 incH = 0; // Horizontal (X, Z)
+       f32 incV = 0; // Vertical (Y)
+       if((!touching_ground && !free_move && !is_climbing && !in_liquid) || (!free_move && m_can_jump && control.jump))
+       {
+               // Jumping and falling
+               if(superspeed || (fast_move && control.aux1))
+                       incH = movement_acceleration_fast * BS * dtime;
+               else
+                       incH = movement_acceleration_air * BS * dtime;
+               incV = 0; // No vertical acceleration in air
+       }
+       else if(superspeed || (fast_move && control.aux1))
+               incH = incV = movement_acceleration_fast * BS * dtime;
+       else if ((in_liquid || in_liquid_stable) && fast_or_aux1_descends)
+               // Always use fast when aux1_descends & fast_move are enabled in liquid, since the aux1 button would mean both turbo and "swim down" causing a conflict
+               incH = incV = movement_acceleration_fast * BS * dtime;
+       else
+               incH = incV = movement_acceleration_default * BS * dtime;
+
        // Accelerate to target speed with maximum increment
-       accelerate(speed, inc);
+       accelerateHorizontal(speedH, incH);
+       accelerateVertical(speedV, incV);
 }
 
 v3s16 LocalPlayer::getStandingNodePos()
index 36f12c77b5053728d2e3cec221184603958ac108..0c34c4cdfcf2dbb98f0715b607b8f095b0c22ace 100644 (file)
@@ -27,10 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 Player::Player(IGameDef *gamedef):
        touching_ground(false),
-       in_water(false),
-       in_water_stable(false),
+       in_liquid(false),
+       in_liquid_stable(false),
+       liquid_viscosity(0),
        is_climbing(false),
-       swimming_up(false),
+       swimming_vertical(false),
        camera_barely_in_ceiling(false),
        inventory(gamedef->idef()),
        hp(PLAYER_MAX_HP),
@@ -56,19 +57,35 @@ Player::Player(IGameDef *gamedef):
                "list[current_player;main;0,3.5;8,4;]"
                "list[current_player;craft;3,0;3,3;]"
                "list[current_player;craftpreview;7,1;1,1;]";
+
+       // Initialize movement settings at default values, so movement can work if the server fails to send them
+       movement_acceleration_default = 2 * BS;
+       movement_acceleration_air = 0.5 * BS;
+       movement_acceleration_fast = 8 * BS;
+       movement_speed_walk = 4 * BS;
+       movement_speed_crouch = 1.35 * BS;
+       movement_speed_fast = 20 * BS;
+       movement_speed_climb = 2 * BS;
+       movement_speed_jump = 6.5 * BS;
+       movement_liquid_fluidity = 1 * BS;
+       movement_liquid_fluidity_smooth = 0.5 * BS;
+       movement_liquid_sink = 10 * BS;
+       movement_gravity = 9.81 * BS;
 }
 
 Player::~Player()
 {
 }
 
-// Y direction is ignored
-void Player::accelerate(v3f target_speed, f32 max_increase)
+// Horizontal acceleration (X and Z), Y direction is ignored
+void Player::accelerateHorizontal(v3f target_speed, f32 max_increase)
 {
+       if(max_increase == 0)
+               return;
+
        v3f d_wanted = target_speed - m_speed;
        d_wanted.Y = 0;
-       f32 dl_wanted = d_wanted.getLength();
-       f32 dl = dl_wanted;
+       f32 dl = d_wanted.getLength();
        if(dl > max_increase)
                dl = max_increase;
        
@@ -76,7 +93,6 @@ void Player::accelerate(v3f target_speed, f32 max_increase)
 
        m_speed.X += d.X;
        m_speed.Z += d.Z;
-       //m_speed += d;
 
 #if 0 // old code
        if(m_speed.X < target_speed.X - max_increase)
@@ -99,6 +115,32 @@ void Player::accelerate(v3f target_speed, f32 max_increase)
 #endif
 }
 
+// Vertical acceleration (Y), X and Z directions are ignored
+void Player::accelerateVertical(v3f target_speed, f32 max_increase)
+{
+       if(max_increase == 0)
+               return;
+
+       f32 d_wanted = target_speed.Y - m_speed.Y;
+       if(d_wanted > max_increase)
+               d_wanted = max_increase;
+       else if(d_wanted < -max_increase)
+               d_wanted = -max_increase;
+
+       m_speed.Y += d_wanted;
+
+#if 0 // old code
+       if(m_speed.Y < target_speed.Y - max_increase)
+               m_speed.Y += max_increase;
+       else if(m_speed.Y > target_speed.Y + max_increase)
+               m_speed.Y -= max_increase;
+       else if(m_speed.Y < target_speed.Y)
+               m_speed.Y = target_speed.Y;
+       else if(m_speed.Y > target_speed.Y)
+               m_speed.Y = target_speed.Y;
+#endif
+}
+
 v3s16 Player::getLightPosition() const
 {
        return floatToInt(m_position + v3f(0,BS+BS/2,0), BS);
index 67b02c3445d15b7cac634ce8b6917063f3bfce78..770afdb37eab0aa27e7051a4cefc6a944e391dcc 100644 (file)
@@ -108,8 +108,8 @@ public:
                m_speed = speed;
        }
        
-       // Y direction is ignored
-       void accelerate(v3f target_speed, f32 max_increase);
+       void accelerateHorizontal(v3f target_speed, f32 max_increase);
+       void accelerateVertical(v3f target_speed, f32 max_increase);
 
        v3f getPosition()
        {
@@ -196,17 +196,32 @@ public:
 
        bool touching_ground;
        // This oscillates so that the player jumps a bit above the surface
-       bool in_water;
+       bool in_liquid;
        // This is more stable and defines the maximum speed of the player
-       bool in_water_stable;
+       bool in_liquid_stable;
+       // Gets the viscosity of water to calculate friction
+       u8 liquid_viscosity;
        bool is_climbing;
-       bool swimming_up;
+       bool swimming_vertical;
        bool camera_barely_in_ceiling;
        
        u8 light;
 
        Inventory inventory;
 
+       f32 movement_acceleration_default;
+       f32 movement_acceleration_air;
+       f32 movement_acceleration_fast;
+       f32 movement_speed_walk;
+       f32 movement_speed_crouch;
+       f32 movement_speed_fast;
+       f32 movement_speed_climb;
+       f32 movement_speed_jump;
+       f32 movement_liquid_fluidity;
+       f32 movement_liquid_fluidity_smooth;
+       f32 movement_liquid_sink;
+       f32 movement_gravity;
+
        u16 hp;
 
        float hurt_tilt_timer;
index a8640ad101c08e521fd6acd55ded55b0a36dfedd..572ef4d827b6063b2cbe2fecfb3ddaf1d783c167 100644 (file)
@@ -2344,6 +2344,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                infostream<<"Server: Sending content to "
                                <<getPlayerName(peer_id)<<std::endl;
 
+               // Send player movement settings
+               SendMovement(m_con, peer_id);
+
                // Send item definitions
                SendItemDef(m_con, peer_id, m_itemdef);
 
@@ -3534,6 +3537,32 @@ void Server::deletingPeer(con::Peer *peer, bool timeout)
        Static send methods
 */
 
+void Server::SendMovement(con::Connection &con, u16 peer_id)
+{
+       DSTACK(__FUNCTION_NAME);
+       std::ostringstream os(std::ios_base::binary);
+
+       writeU16(os, TOCLIENT_MOVEMENT);
+       writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
+       writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
+       writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
+       writeF1000(os, g_settings->getFloat("movement_speed_walk"));
+       writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
+       writeF1000(os, g_settings->getFloat("movement_speed_fast"));
+       writeF1000(os, g_settings->getFloat("movement_speed_climb"));
+       writeF1000(os, g_settings->getFloat("movement_speed_jump"));
+       writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
+       writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
+       writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
+       writeF1000(os, g_settings->getFloat("movement_gravity"));
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       con.Send(peer_id, 0, data, true);
+}
+
 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
 {
        DSTACK(__FUNCTION_NAME);
index 86d5513d8b2b68fe6ba64c714380d194d562d7c0..29d47337db4eb8e9c724273d065714b83f59ad8a 100644 (file)
@@ -602,6 +602,7 @@ private:
                Static send methods
        */
 
+       static void SendMovement(con::Connection &con, u16 peer_id);
        static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
        static void SendAccessDenied(con::Connection &con, u16 peer_id,
                        const std::wstring &reason);