diff --git a/src/client.cpp b/src/client.cpp index 0463aa81c..bc303bc4b 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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) { diff --git a/src/content_cao.cpp b/src/content_cao.cpp index a2708674b..3c30a0819 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -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) diff --git a/src/environment.cpp b/src/environment.cpp index 7c2aef272..6f1d8ff55 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -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); } } diff --git a/src/player.cpp b/src/player.cpp index 6506c43c3..068b51790 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -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) diff --git a/src/server.cpp b/src/server.cpp index a0c8a0092..bf90b2aa7 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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 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(player); + if(g_settings->getBool("enable_damage")) { actionstream<getName()<<" damaged by " <<(int)damage<<" hp at "<getPosition()/BS) <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<getName()<<" respawns at " @@ -2811,6 +2818,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<getName() + <<" tried to interact, but is dead!"<m_last_good_position; // Update wielded item @@ -3968,26 +3982,14 @@ void Server::SendTexturesRequested(u16 peer_id,core::list tosend Something random */ -void Server::HandlePlayerHP(Player *player, s16 damage) +void Server::DiePlayer(Player *player) { ServerRemotePlayer *srp = static_cast(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 " <getName()<<" dies"<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(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(player); /* Add player to environment */ m_env->addPlayer(player); + m_env->addActiveObject(srp); /* Run scripts */ - ServerRemotePlayer *srp = static_cast(player); scriptapi_on_newplayer(m_lua, srp); /* Add stuff to inventory */ diff --git a/src/server.h b/src/server.h index 4fdb60065..40f0fe582 100644 --- a/src/server.h +++ b/src/server.h @@ -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); diff --git a/src/serverremoteplayer.cpp b/src/serverremoteplayer.cpp index b4dbbdb1b..728ffe026 100644 --- a/src/serverremoteplayer.cpp +++ b/src/serverremoteplayer.cpp @@ -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() { diff --git a/src/serverremoteplayer.h b/src/serverremoteplayer.h index 9d9437646..94926c824 100644 --- a/src/serverremoteplayer.h +++ b/src/serverremoteplayer.h @@ -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;