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)
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)
{
bool m_is_local_player;
LocalPlayer *m_local_player;
float m_damage_visual_timer;
+ bool m_dead;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
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);
m_position = readV3F1000(is);
// yaw
m_yaw = readF1000(is);
+ // dead
+ m_dead = readU8(is);
pos_translator.init(m_position);
{
if(m_is_local_player)
return NULL;
+ if(m_dead)
+ return NULL;
return &m_selection_box;
}
v3f getPosition()
m_text->setPosition(v3f(0, (f32)BS*2.1, 0));
updateTextures("");
+ updateVisibility();
updateNodePos();
}
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()
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)
void step(float dtime, ClientEnvironment *env)
{
pos_translator.translate(dtime);
+ updateVisibility();
updateNodePos();
if(m_damage_visual_timer > 0){
{
// 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)
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
{
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);
}
}
}
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);
}
}
}
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)
/*
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
}
/*
- 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);
// 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(
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
*/
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);
}
}
if(player->hp != 0)
return;
- srp->m_respawn_active = false;
-
RespawnPlayer(player);
actionstream<<player->getName()<<" respawns at "
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
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);
}
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());
// 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"))
{
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 */
Something random
*/
- void HandlePlayerHP(Player *player, s16 damage);
+ void DiePlayer(Player *player);
void RespawnPlayer(Player *player);
void UpdateCrafting(u16 peer_id);
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)
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
+ // dead
+ writeU8(os, getHP() == 0);
return os.str();
}
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()
{
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;