Players stay in environment even when dead, damage flash and fall damage fixes
authorKahrl <kahrl@gmx.net>
Mon, 23 Jan 2012 23:00:26 +0000 (00:00 +0100)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 5 Feb 2012 10:06:55 +0000 (12:06 +0200)
Don't set m_removed on dead players (dead players are indicated by hp == 0). Local
damage flash is shown whatever the cause was (even from Lua set_hp). PlayerCAO
damage flash matches duration of local damage flash. Fall damage is dealt much more consistently (this is done by disallowing jumping when speed.Y is very negative, up to now jumping could sometimes negate fall damage)

src/client.cpp
src/content_cao.cpp
src/environment.cpp
src/player.cpp
src/server.cpp
src/server.h
src/serverremoteplayer.cpp
src/serverremoteplayer.h

index 0463aa81c9cf5f47f56bdeefb469267465829d01..bc303bc4b225adad7d19cff51c543f376e153c1b 100644 (file)
@@ -1171,8 +1171,18 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                std::istringstream is(datastring, std::ios_base::binary);
                Player *player = m_env.getLocalPlayer();
                assert(player != NULL);
+               u8 oldhp = player->hp;
                u8 hp = readU8(is);
                player->hp = hp;
+
+               if(hp < oldhp)
+               {
+                       // Add to ClientEvent queue
+                       ClientEvent event;
+                       event.type = CE_PLAYER_DAMAGE;
+                       event.player_damage.amount = oldhp - hp;
+                       m_client_event_queue.push_back(event);
+               }
        }
        else if(command == TOCLIENT_MOVE_PLAYER)
        {
index a2708674b7295d86ba775a640a725b0a4bfca997..3c30a08195feeb974ebd8dc0fc215f1ee35ff570 100644 (file)
@@ -2067,6 +2067,7 @@ private:
        bool m_is_local_player;
        LocalPlayer *m_local_player;
        float m_damage_visual_timer;
+       bool m_dead;
 
 public:
        PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
@@ -2078,7 +2079,8 @@ public:
                m_yaw(0),
                m_is_local_player(false),
                m_local_player(NULL),
-               m_damage_visual_timer(0)
+               m_damage_visual_timer(0),
+               m_dead(false)
        {
                if(gamedef == NULL)
                        ClientActiveObject::registerType(getType(), create);
@@ -2100,6 +2102,8 @@ public:
                m_position = readV3F1000(is);
                // yaw
                m_yaw = readF1000(is);
+               // dead
+               m_dead = readU8(is);
 
                pos_translator.init(m_position);
 
@@ -2129,6 +2133,8 @@ public:
        {
                if(m_is_local_player)
                        return NULL;
+               if(m_dead)
+                       return NULL;
                return &m_selection_box;
        }
        v3f getPosition()
@@ -2204,6 +2210,7 @@ public:
                m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
                
                updateTextures("");
+               updateVisibility();
                updateNodePos();
        }
 
@@ -2221,11 +2228,11 @@ public:
                if(m_node == NULL)
                        return;
                
-               m_node->setVisible(true);
-
                u8 li = decode_light(light_at_pos);
                video::SColor color(255,li,li,li);
                setMeshColor(m_node->getMesh(), color);
+
+               updateVisibility();
        }
 
        v3s16 getLightPosition()
@@ -2233,6 +2240,14 @@ public:
                return floatToInt(m_position+v3f(0,BS*1.5,0), BS);
        }
 
+       void updateVisibility()
+       {
+               if(m_node == NULL)
+                       return;
+
+               m_node->setVisible(!m_dead);
+       }
+
        void updateNodePos()
        {
                if(m_node == NULL)
@@ -2248,6 +2263,7 @@ public:
        void step(float dtime, ClientEnvironment *env)
        {
                pos_translator.translate(dtime);
+               updateVisibility();
                updateNodePos();
 
                if(m_damage_visual_timer > 0){
@@ -2279,13 +2295,16 @@ public:
                {
                        // damage
                        s16 damage = readS16(is);
-                       
-                       if(m_is_local_player)
-                               m_env->damageLocalPlayer(damage, false);
-                       
-                       m_damage_visual_timer = 0.5;
+                       m_damage_visual_timer = 0.05;
+                       if(damage >= 2)
+                               m_damage_visual_timer += 0.05 * damage;
                        updateTextures("^[brighten");
                }
+               else if(cmd == 2) // died or respawned
+               {
+                       m_dead = readU8(is);
+                       updateVisibility();
+               }
        }
 
        void updateTextures(const std::string &mod)
index 7c2aef27208df1d1b439b7c366b23bfcbd0e0a5f..6f1d8ff551ee6bbdd11fb013deda75eed6f0fb01 100644 (file)
@@ -797,6 +797,8 @@ void ServerEnvironment::clearAllObjects()
                        i.atEnd()==false; i++)
        {
                ServerActiveObject* obj = i.getNode()->getValue();
+               if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+                       continue;
                u16 id = i.getNode()->getKey();         
                v3f objectpos = obj->getBasePosition(); 
                // Delete static object if block is loaded
@@ -1983,16 +1985,7 @@ void ClientEnvironment::step(float dtime)
                        {
                                f32 damage_f = (info.speed - tolerance)/BS*factor;
                                u16 damage = (u16)(damage_f+0.5);
-                               if(lplayer->hp > damage)
-                                       lplayer->hp -= damage;
-                               else
-                                       lplayer->hp = 0;
-
-                               ClientEnvEvent event;
-                               event.type = CEE_PLAYER_DAMAGE;
-                               event.player_damage.amount = damage;
-                               event.player_damage.send_to_server = true;
-                               m_client_event_queue.push_back(event);
+                               damageLocalPlayer(damage, true);
                        }
                }
        }
@@ -2022,11 +2015,7 @@ void ClientEnvironment::step(float dtime)
                
                if(damage_per_second != 0)
                {
-                       ClientEnvEvent event;
-                       event.type = CEE_PLAYER_DAMAGE;
-                       event.player_damage.amount = damage_per_second;
-                       event.player_damage.send_to_server = true;
-                       m_client_event_queue.push_back(event);
+                       damageLocalPlayer(damage_per_second, true);
                }
        }
        
index 6506c43c37293ef9234b6242003ade5cfd054f42..068b51790117aea0bca74c699dd4710dd030dcdd 100644 (file)
@@ -713,14 +713,17 @@ void LocalPlayer::applyControl(float dtime)
                }
                else if(touching_ground)
                {
-                       v3f speed = getSpeed();
                        /*
                                NOTE: The d value in move() affects jump height by
                                raising the height at which the jump speed is kept
                                at its starting value
                        */
-                       speed.Y = 6.5*BS;
-                       setSpeed(speed);
+                       v3f speed = getSpeed();
+                       if(speed.Y >= -0.5*BS)
+                       {
+                               speed.Y = 6.5*BS;
+                               setSpeed(speed);
+                       }
                }
                // Use the oscillating value for getting out of water
                // (so that the player doesn't fly on the surface)
index a0c8a00928011740af8f9e862f7c03b6d3556871..bf90b2aa7289b03b7d455913e9937857bdf3f219 100644 (file)
@@ -1270,7 +1270,8 @@ void Server::AsyncRunStep()
                        /*
                                Handle player HPs (die if hp=0)
                        */
-                       HandlePlayerHP(player, 0);
+                       if(player->hp == 0 && player->m_hp_not_sent)
+                               DiePlayer(player);
 
                        /*
                                Send player inventories and HPs if necessary
@@ -1284,9 +1285,9 @@ void Server::AsyncRunStep()
                        }
 
                        /*
-                               Add to environment if is not in respawn screen
+                               Add to environment
                        */
-                       if(!player->m_is_in_environment && !player->m_respawn_active){
+                       if(!player->m_is_in_environment){
                                player->m_removed = false;
                                player->setId(0);
                                m_env->addActiveObject(player);
@@ -2129,6 +2130,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // Send HP
                SendPlayerHP(player);
                
+               // Show death screen if necessary
+               if(player->hp == 0)
+                       SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
+
                // Send time of day
                {
                        SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
@@ -2159,11 +2164,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
                }
 
-               /*
-                       Check HP, respawn if necessary
-               */
-               HandlePlayerHP(player, 0);
-
                /*
                        Print out action
                */
@@ -2662,16 +2662,25 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                std::istringstream is(datastring, std::ios_base::binary);
                u8 damage = readU8(is);
 
+               ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
+
                if(g_settings->getBool("enable_damage"))
                {
                        actionstream<<player->getName()<<" damaged by "
                                        <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
                                        <<std::endl;
-                               
-                       HandlePlayerHP(player, damage);
+
+                       srp->setHP(srp->getHP() - damage);
+
+                       if(srp->getHP() == 0 && srp->m_hp_not_sent)
+                               DiePlayer(srp);
+
+                       if(srp->m_hp_not_sent)
+                               SendPlayerHP(player);
                }
                else
                {
+                       // Force send (to correct the client's predicted HP)
                        SendPlayerHP(player);
                }
        }
@@ -2751,8 +2760,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                if(player->hp != 0)
                        return;
                
-               srp->m_respawn_active = false;
-
                RespawnPlayer(player);
                
                actionstream<<player->getName()<<" respawns at "
@@ -2811,6 +2818,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
 
+               if(player->hp == 0)
+               {
+                       infostream<<"TOSERVER_INTERACT: "<<srp->getName()
+                               <<" tried to interact, but is dead!"<<std::endl;
+                       return;
+               }
+
                v3f player_pos = srp->m_last_good_position;
 
                // Update wielded item
@@ -3968,26 +3982,14 @@ void Server::SendTexturesRequested(u16 peer_id,core::list<TextureRequest> tosend
        Something random
 */
 
-void Server::HandlePlayerHP(Player *player, s16 damage)
+void Server::DiePlayer(Player *player)
 {
        ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
 
-       if(srp->m_respawn_active)
-               return;
-       
-       if(player->hp > damage)
-       {
-               if(damage != 0){
-                       player->hp -= damage;
-                       SendPlayerHP(player);
-               }
-               return;
-       }
-
-       infostream<<"Server::HandlePlayerHP(): Player "
+       infostream<<"Server::DiePlayer(): Player "
                        <<player->getName()<<" dies"<<std::endl;
        
-       player->hp = 0;
+       srp->setHP(0);
        
        // Trigger scripted stuff
        scriptapi_on_dieplayer(m_lua, srp);
@@ -3999,24 +4001,13 @@ void Server::HandlePlayerHP(Player *player, s16 damage)
        }
 
        SendPlayerHP(player);
-       
-       RemoteClient *client = getClient(player->peer_id);
-       if(client->net_proto_version >= 3)
-       {
-               SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
-               srp->m_removed = true;
-               srp->m_respawn_active = true;
-       }
-       else
-       {
-               RespawnPlayer(player);
-       }
+       SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
 }
 
 void Server::RespawnPlayer(Player *player)
 {
-       player->hp = 20;
        ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
+       srp->setHP(20);
        bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
        if(!repositioned){
                v3f pos = findSpawnPos(m_env->getServerMap());
@@ -4268,6 +4259,14 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
                // Got one.
                player->peer_id = peer_id;
                
+               // Re-add player to environment
+               if(player->m_removed)
+               {
+                       player->m_removed = false;
+                       player->setId(0);
+                       m_env->addActiveObject(player);
+               }
+
                // Reset inventory to creative if in creative mode
                if(g_settings->getBool("creative_mode"))
                {
@@ -4305,12 +4304,13 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
                v3f pos = findSpawnPos(m_env->getServerMap());
 
                player = new ServerRemotePlayer(m_env, pos, peer_id, name);
+               ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
 
                /* Add player to environment */
                m_env->addPlayer(player);
+               m_env->addActiveObject(srp);
 
                /* Run scripts */
-               ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
                scriptapi_on_newplayer(m_lua, srp);
 
                /* Add stuff to inventory */
index 4fdb600657b69746d4a74e678d1e0edcfb0cd96b..40f0fe582a49a1b525a507d10ed990d3146dea50 100644 (file)
@@ -592,7 +592,7 @@ private:
                Something random
        */
        
-       void HandlePlayerHP(Player *player, s16 damage);
+       void DiePlayer(Player *player);
        void RespawnPlayer(Player *player);
        
        void UpdateCrafting(u16 peer_id);
index b4dbbdb1b0663f7d9abd45b972079c247e8252ce..728ffe0262451d1d2c482d9443c7863131d10c3a 100644 (file)
@@ -34,7 +34,6 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
        m_wield_index(0),
        m_inventory_not_sent(false),
        m_hp_not_sent(false),
-       m_respawn_active(false),
        m_is_in_environment(false),
        m_time_from_last_punch(0),
        m_position_not_sent(false)
@@ -159,6 +158,8 @@ std::string ServerRemotePlayer::getClientInitializationData()
        writeV3F1000(os, getPosition());
        // yaw
        writeF1000(os, getYaw());
+       // dead
+       writeU8(os, getHP() == 0);
        return os.str();
 }
 
@@ -247,6 +248,19 @@ void ServerRemotePlayer::setHP(s16 hp_)
 
        if(hp != oldhp)
                m_hp_not_sent = true;
+
+       // On death or reincarnation send an active object message
+       if((hp == 0) != (oldhp == 0))
+       {
+               std::ostringstream os(std::ios::binary);
+               // command (2 = update death state)
+               writeU8(os, 2);
+               // dead?
+               writeU8(os, hp == 0);
+               // create message and add to list
+               ActiveObjectMessage aom(getId(), false, os.str());
+               m_messages_out.push_back(aom);
+       }
 }
 s16 ServerRemotePlayer::getHP()
 {
index 9d943764619db4a4e8f56948ea216469ee1a8b41..94926c824c4479c4a7fdcc62c0093b149e9674fc 100644 (file)
@@ -90,7 +90,6 @@ public:
        int m_wield_index;
        bool m_inventory_not_sent;
        bool m_hp_not_sent;
-       bool m_respawn_active;
        bool m_is_in_environment;
        // Incremented by step(), read and reset by Server
        float m_time_from_last_punch;