int PlayerSAO::punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, float time_from_last_punch) { // It's best that attachments cannot be punched if (isAttached()) return 0; if (!toolcap) return 0; // No effect if PvP disabled if (g_settings->getBool("enable_pvp") == false) { if (puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { std::string str = gob_cmd_punched(0, getHP()); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); return 0; } } HitParams hitparams = getHitParams(m_armor_groups, toolcap, time_from_last_punch); std::string punchername = "nil"; if (puncher != 0) punchername = puncher->getDescription(); PlayerSAO *playersao = m_player->getPlayerSAO(); bool damage_handled = m_env->getScriptIface()->on_punchplayer(playersao, puncher, time_from_last_punch, toolcap, dir, hitparams.hp); if (!damage_handled) { setHP(getHP() - hitparams.hp); } else { // override client prediction if (puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { std::string str = gob_cmd_punched(0, getHP()); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } actionstream << "Player " << m_player->getName() << " punched by " << punchername; if (!damage_handled) { actionstream << ", damage " << hitparams.hp << " HP"; } else { actionstream << ", damage handled by lua"; } actionstream << std::endl; return hitparams.wear; }
void step(float dtime, bool send_recommended) { ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG); assert(m_env); const float interval = 0.2; if(m_move_interval.step(dtime, interval)==false) return; dtime = interval; core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.); collisionMoveResult moveresult; // Apply gravity m_speed_f += v3f(0, -dtime*9.81*BS, 0); // Maximum movement without glitches f32 pos_max_d = BS*0.25; // Limit speed if(m_speed_f.getLength()*dtime > pos_max_d) m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime); v3f pos_f = getBasePosition(); v3f pos_f_old = pos_f; v3f accel_f = v3f(0,0,0); f32 stepheight = 0; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMoveSimple(&m_env->getMap(), gamedef, pos_max_d, box, stepheight, dtime, pos_f, m_speed_f, accel_f); if(send_recommended == false) return; if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS) { setBasePosition(pos_f); m_last_sent_position = pos_f; std::ostringstream os(std::ios::binary); // command (0 = update position) writeU8(os, 0); // pos writeV3F1000(os, m_base_position); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } if(m_itemstring_changed) { m_itemstring_changed = false; std::ostringstream os(std::ios::binary); // command (1 = update itemstring) writeU8(os, 1); // itemstring os<<serializeString(m_itemstring); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } }
void step(float dtime, bool send_recommended) { m_age += dtime; if(m_age > 10) { m_removed = true; return; } m_base_position.Y += dtime * BS * 2; if(m_base_position.Y > 8*BS) m_base_position.Y = 2*BS; if(send_recommended == false) return; m_timer1 -= dtime; if(m_timer1 < 0.0) { m_timer1 += 0.125; std::string data; data += itos(0); // 0 = position data += " "; data += itos(m_base_position.X); data += " "; data += itos(m_base_position.Y); data += " "; data += itos(m_base_position.Z); ActiveObjectMessage aom(getId(), false, data); m_messages_out.push(aom); } }
void Oerkki1SAO::doDamage(u16 d) { infostream<<"oerkki damage: "<<d<<std::endl; if(d < m_hp) { m_hp -= d; } else { // Die m_hp = 0; m_removed = true; } { std::ostringstream os(std::ios::binary); // command (1 = damage) writeU8(os, 1); // amount writeU8(os, d); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } }
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { m_last_sent_move_precision = m_base_position.getDistanceFrom( m_last_sent_position); m_last_sent_position_timer = 0; m_last_sent_yaw = m_yaw; m_last_sent_position = m_base_position; m_last_sent_velocity = m_velocity; //m_last_sent_acceleration = m_acceleration; float update_interval = m_env->getSendRecommendedInterval(); std::ostringstream os(std::ios::binary); // command (0 = update position) writeU8(os, 0); // do_interpolate writeU8(os, do_interpolate); // pos writeV3F1000(os, m_base_position); // velocity writeV3F1000(os, m_velocity); // acceleration writeV3F1000(os, m_acceleration); // yaw writeF1000(os, m_yaw); // is_end_position (for interpolation) writeU8(os, is_movement_end); // update_interval (for interpolation) writeF1000(os, update_interval); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); }
void PlayerSAO::setHP(s16 hp) { s16 oldhp = m_player->hp; if(hp < 0) hp = 0; else if(hp > PLAYER_MAX_HP) hp = PLAYER_MAX_HP; if(hp < oldhp && g_settings->getBool("enable_damage") == false) { m_hp_not_sent = true; // fix wrong prediction on client return; } m_player->hp = hp; if(hp != oldhp) m_hp_not_sent = true; // On death or reincarnation send an active object message if((hp == 0) != (oldhp == 0)) { // Will send new is_visible value based on (getHP()!=0) m_properties_sent = false; // Send new HP std::string str = gob_cmd_punched(0, getHP()); ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } }
void MobV2SAO::doDamage(u16 d) { infostream<<"MobV2 hp="<<m_hp<<" damage="<<d<<std::endl; if(d < m_hp) { m_hp -= d; } else { actionstream<<"A "<<(isPeaceful()?"peaceful":"non-peaceful") <<" mob id="<<m_id<<" dies at "<<PP(m_base_position)<<std::endl; // Die m_hp = 0; m_removed = true; } { std::ostringstream os(std::ios::binary); // command (1 = damage) writeU8(os, 1); // amount writeU16(os, d); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } }
void LuaEntitySAO::setTextureMod(const std::string &mod) { std::string str = gob_cmd_set_texture_mod(mod); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); }
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { m_last_sent_move_precision = m_base_position.getDistanceFrom( m_last_sent_position); m_last_sent_position_timer = 0; m_last_sent_yaw = m_yaw; m_last_sent_position = m_base_position; m_last_sent_velocity = m_velocity; //m_last_sent_acceleration = m_acceleration; float update_interval = m_env->getSendRecommendedInterval(); std::string str = gob_cmd_update_position( m_base_position, m_velocity, m_acceleration, m_yaw, do_interpolate, is_movement_end, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push_back(aom); }
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { // If the object is attached client-side, don't waste bandwidth sending its position to clients if(isAttached()) return; m_last_sent_move_precision = m_base_position.getDistanceFrom( m_last_sent_position); m_last_sent_position_timer = 0; m_last_sent_yaw = m_yaw; m_last_sent_position = m_base_position; m_last_sent_velocity = m_velocity; //m_last_sent_acceleration = m_acceleration; float update_interval = m_env->getSendRecommendedInterval(); std::string str = gob_cmd_update_position( m_base_position, m_velocity, m_acceleration, m_yaw, do_interpolate, is_movement_end, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push(aom); }
int PlayerSAO::punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, float time_from_last_punch) { // It's best that attachments cannot be punched if(isAttached()) return 0; if(!toolcap) return 0; // No effect if PvP disabled if(g_settings->getBool("enable_pvp") == false){ if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){ std::string str = gob_cmd_punched(0, getHP()); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); return 0; } } HitParams hitparams = getHitParams(m_armor_groups, toolcap, time_from_last_punch); std::string punchername = "nil"; if ( puncher != 0 ) punchername = puncher->getDescription(); actionstream<<"Player "<<m_player->getName()<<" punched by " <<punchername<<", damage "<<hitparams.hp <<" HP"<<std::endl; setHP(getHP() - hitparams.hp); if(hitparams.hp != 0) { std::string str = gob_cmd_punched(hitparams.hp, getHP()); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } return hitparams.wear; }
int LuaEntitySAO::punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, float time_from_last_punch) { if(!m_registered){ // Delete unknown LuaEntities when punched m_removed = true; return 0; } // It's best that attachments cannot be punched if(isAttached()) return 0; ItemStack *punchitem = NULL; ItemStack punchitem_static; if(puncher){ punchitem_static = puncher->getWieldedItem(); punchitem = &punchitem_static; } PunchDamageResult result = getPunchDamage( m_armor_groups, toolcap, punchitem, time_from_last_punch); if(result.did_punch) { setHP(getHP() - result.damage); std::string punchername = "nil"; if ( puncher != 0 ) punchername = puncher->getDescription(); actionstream<<getDescription()<<" punched by " <<punchername<<", damage "<<result.damage <<" hp, health now "<<getHP()<<" hp"<<std::endl; { std::string str = gob_cmd_punched(result.damage, getHP()); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } if(getHP() == 0) m_removed = true; } ENV_TO_SA(m_env)->luaentity_Punch(m_id, puncher, time_from_last_punch, toolcap, dir); return result.wear; }
int LuaEntitySAO::punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, float time_from_last_punch) { if (!m_registered) { // Delete unknown LuaEntities when punched m_pending_removal = true; return 0; } ItemStack *punchitem = NULL; ItemStack punchitem_static; if (puncher) { punchitem_static = puncher->getWieldedItem(); punchitem = &punchitem_static; } PunchDamageResult result = getPunchDamage( m_armor_groups, toolcap, punchitem, time_from_last_punch); bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher, time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0); if (!damage_handled) { if (result.did_punch) { setHP(getHP() - result.damage, PlayerHPChangeReason(PlayerHPChangeReason::SET_HP)); if (result.damage > 0) { std::string punchername = puncher ? puncher->getDescription() : "nil"; actionstream << getDescription() << " punched by " << punchername << ", damage " << result.damage << " hp, health now " << getHP() << " hp" << std::endl; } std::string str = gob_cmd_punched(result.damage, getHP()); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } if (getHP() == 0 && !isGone()) { m_pending_removal = true; clearParentAttachment(); clearChildAttachments(); m_env->getScriptIface()->luaentity_on_death(m_id, puncher); } return result.wear; }
void LuaEntitySAO::setTextureMod(const std::string &mod) { std::ostringstream os(std::ios::binary); // command (1 = set texture modification) writeU8(os, 1); // parameters os<<serializeString(mod); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); }
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, bool select_horiz_by_yawpitch) { std::string str = gob_cmd_set_sprite( p, num_frames, framelength, select_horiz_by_yawpitch ); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); }
void ItemSAO::step(float dtime, bool send_recommended) { ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG); assert(m_env); const float interval = 0.2; if(m_move_interval.step(dtime, interval)==false) return; dtime = interval; core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.); collisionMoveResult moveresult; // Apply gravity m_speed_f += v3f(0, -dtime*9.81*BS, 0); // Maximum movement without glitches f32 pos_max_d = BS*0.25; // Limit speed if(m_speed_f.getLength()*dtime > pos_max_d) m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime); v3f pos_f = getBasePosition(); v3f pos_f_old = pos_f; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMoveSimple(&m_env->getMap(), gamedef, pos_max_d, box, dtime, pos_f, m_speed_f); if(send_recommended == false) return; if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS) { setBasePosition(pos_f); m_last_sent_position = pos_f; std::ostringstream os(std::ios::binary); char buf[6]; // command (0 = update position) buf[0] = 0; os.write(buf, 1); // pos writeS32((u8*)buf, m_base_position.X*1000); os.write(buf, 4); writeS32((u8*)buf, m_base_position.Y*1000); os.write(buf, 4); writeS32((u8*)buf, m_base_position.Z*1000); os.write(buf, 4); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } }
void Server::SendPlayerHP(u16 peer_id) { DSTACK(FUNCTION_NAME); PlayerSAO *playersao = getPlayerSAO(peer_id); if (!playersao) return; SendHP(peer_id, playersao->getHP()); m_script->player_event(playersao,"health_changed"); // Send to other clients std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP()); ActiveObjectMessage aom(playersao->getId(), true, str); playersao->m_messages_out.push(aom); }
void MobV2SAO::sendPosition() { m_last_sent_position = m_base_position; std::ostringstream os(std::ios::binary); // command (0 = update position) writeU8(os, 0); // pos writeV3F1000(os, m_base_position); // yaw writeF1000(os, m_yaw); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); }
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, bool select_horiz_by_yawpitch) { std::ostringstream os(std::ios::binary); // command (2 = set sprite) writeU8(os, 2); // parameters writeV2S16(os, p); writeU16(os, num_frames); writeF1000(os, framelength); writeU8(os, select_horiz_by_yawpitch); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); }
void PlayerSAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } // If attached, check that our parent is still there. If it isn't, detach. if(m_attachment_parent_id && !isAttached()) { m_attachment_parent_id = 0; m_attachment_bone = ""; m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); m_player->setPosition(m_last_good_position); ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl; // Set lag pool maximums based on estimated lag const float LAG_POOL_MIN = 5.0; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0; if(lag_pool_max < LAG_POOL_MIN) lag_pool_max = LAG_POOL_MIN; m_dig_pool.setMax(lag_pool_max); m_move_pool.setMax(lag_pool_max); // Increment cheat prevention timers m_dig_pool.add(dtime); m_move_pool.add(dtime); m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // If the object gets detached this comes into effect automatically from the last known origin if(isAttached()) { v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); m_last_good_position = pos; m_player->setPosition(pos); } if(send_recommended == false) return; // If the object is attached client-side, don't waste bandwidth sending its position to clients if(m_position_not_sent && !isAttached()) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); v3f pos; if(isAttached()) // Just in case we ever do send attachment position too pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); else pos = m_player->getPosition() + v3f(0,BS*1,0); std::string str = gob_cmd_update_position( pos, v3f(0,0,0), v3f(0,0,0), m_player->getYaw(), true, false, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push(aom); } if(m_armor_groups_sent == false) { m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if(m_physics_override_sent == false){ m_physics_override_sent = true; std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak, m_physics_override_sneak_glitch); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if(m_animation_sent == false){ m_animation_sent = true; std::string str = gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if(m_bone_position_sent == false){ m_bone_position_sent = true; for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } if(m_attachment_sent == false){ m_attachment_sent = true; std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (m_nametag_sent == false) { m_nametag_sent = true; std::string str = gob_cmd_update_nametag_attributes(m_nametag_color); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } }
void PlayerSAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; if(m_is_singleplayer || g_settings->getBool("disable_anticheat")) { m_last_good_position = m_player->getPosition(); m_last_good_position_age = 0; } else { /* Check player movements NOTE: Actually the server should handle player physics like the client does and compare player's position to what is calculated on our side. This is required when eg. players fly due to an explosion. Altough a node-based alternative might be possible too, and much more lightweight. */ float player_max_speed = 0; float player_max_speed_up = 0; if(m_privs.count("fast") != 0){ // Fast speed player_max_speed = BS * 20; player_max_speed_up = BS * 20; } else { // Normal speed player_max_speed = BS * 4.0; player_max_speed_up = BS * 4.0; } // Tolerance player_max_speed *= 2.5; player_max_speed_up *= 2.5; m_last_good_position_age += dtime; if(m_last_good_position_age >= 1.0){ float age = m_last_good_position_age; v3f diff = (m_player->getPosition() - m_last_good_position); float d_vert = diff.Y; diff.Y = 0; float d_horiz = diff.getLength(); /*infostream<<m_player->getName()<<"'s horizontal speed is " <<(d_horiz/age)<<std::endl;*/ if(d_horiz <= age * player_max_speed && (d_vert < 0 || d_vert < age * player_max_speed_up)){ m_last_good_position = m_player->getPosition(); } else { actionstream<<"Player "<<m_player->getName() <<" moved too fast; resetting position" <<std::endl; m_player->setPosition(m_last_good_position); m_teleported = true; } m_last_good_position_age = 0; } } if(send_recommended == false) return; if(m_position_not_sent) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); std::string str = gob_cmd_update_position( m_player->getPosition() + v3f(0,BS*1,0), v3f(0,0,0), v3f(0,0,0), m_player->getYaw(), true, false, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push_back(aom); } if(m_wielded_item_not_sent) { m_wielded_item_not_sent = false; // GenericCAO has no special way to show this } if(m_armor_groups_sent == false){ m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } }
void LuaEntitySAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } m_last_sent_position_timer += dtime; if(m_prop.physical){ core::aabbox3d<f32> box = m_prop.collisionbox; box.MinEdge *= BS; box.MaxEdge *= BS; collisionMoveResult moveresult; f32 pos_max_d = BS*0.25; // Distance per iteration f32 stepheight = 0; // Maximum climbable step height v3f p_pos = m_base_position; v3f p_velocity = m_velocity; v3f p_acceleration = m_acceleration; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMoveSimple(&m_env->getMap(), gamedef, pos_max_d, box, stepheight, dtime, p_pos, p_velocity, p_acceleration); // Apply results m_base_position = p_pos; m_velocity = p_velocity; m_acceleration = p_acceleration; } else { m_base_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; m_velocity += dtime * m_acceleration; } if(m_registered){ lua_State *L = m_env->getLua(); scriptapi_luaentity_step(L, m_id, dtime); } if(send_recommended == false) return; // TODO: force send when acceleration changes enough? float minchange = 0.2*BS; if(m_last_sent_position_timer > 1.0){ minchange = 0.01*BS; } else if(m_last_sent_position_timer > 0.2){ minchange = 0.05*BS; } float move_d = m_base_position.getDistanceFrom(m_last_sent_position); move_d += m_last_sent_move_precision; float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); if(move_d > minchange || vel_d > minchange || fabs(m_yaw - m_last_sent_yaw) > 1.0){ sendPosition(true, false); } if(m_armor_groups_sent == false){ m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } }
void MobV2SAO::step(float dtime, bool send_recommended) { ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG); assert(m_env); Map *map = &m_env->getMap(); m_age += dtime; if(m_die_age >= 0.0 && m_age >= m_die_age){ m_removed = true; return; } m_random_disturb_timer += dtime; if(m_random_disturb_timer >= 5.0) { m_random_disturb_timer = 0; // Check connected players core::list<Player*> players = m_env->getPlayers(true); core::list<Player*>::Iterator i; for(i = players.begin(); i != players.end(); i++) { Player *player = *i; v3f playerpos = player->getPosition(); f32 dist = m_base_position.getDistanceFrom(playerpos); if(dist < BS*16) { if(myrand_range(0,3) == 0){ actionstream<<"Mob id="<<m_id<<" at " <<PP(m_base_position/BS) <<" got randomly disturbed by " <<player->getName()<<std::endl; m_disturbing_player = player->getName(); m_disturb_timer = 0; break; } } } } Player *disturbing_player = m_env->getPlayer(m_disturbing_player.c_str()); v3f disturbing_player_off = v3f(0,1,0); v3f disturbing_player_norm = v3f(0,1,0); float disturbing_player_distance = 1000000; float disturbing_player_dir = 0; if(disturbing_player){ disturbing_player_off = disturbing_player->getPosition() - m_base_position; disturbing_player_distance = disturbing_player_off.getLength(); disturbing_player_norm = disturbing_player_off; disturbing_player_norm.normalize(); disturbing_player_dir = 180./PI*atan2(disturbing_player_norm.Z, disturbing_player_norm.X); } m_disturb_timer += dtime; if(!m_falling) { m_shooting_timer -= dtime; if(m_shooting_timer <= 0.0 && m_shooting){ m_shooting = false; std::string shoot_type = m_properties->get("shoot_type"); v3f shoot_pos(0,0,0); shoot_pos.Y += m_properties->getFloat("shoot_y") * BS; if(shoot_type == "fireball"){ v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI)); dir.Y = m_shoot_y; dir.normalize(); v3f speed = dir * BS * 10.0; v3f pos = m_base_position + shoot_pos; infostream<<__FUNCTION_NAME<<": Mob id="<<m_id <<" shooting fireball from "<<PP(pos) <<" at speed "<<PP(speed)<<std::endl; Settings properties; properties.set("looks", "fireball"); properties.setV3F("speed", speed); properties.setFloat("die_age", 5.0); properties.set("move_type", "constant_speed"); properties.setFloat("hp", 1000); properties.set("lock_full_brightness", "true"); properties.set("player_hit_damage", "9"); properties.set("player_hit_distance", "2"); properties.set("player_hit_interval", "1"); ServerActiveObject *obj = new MobV2SAO(m_env, pos, &properties); //m_env->addActiveObjectAsStatic(obj); m_env->addActiveObject(obj); } else { infostream<<__FUNCTION_NAME<<": Mob id="<<m_id <<": Unknown shoot_type="<<shoot_type <<std::endl; } } m_shoot_reload_timer += dtime; float reload_time = 15.0; if(m_disturb_timer <= 15.0) reload_time = 3.0; bool shoot_without_player = false; if(m_properties->getBool("mindless_rage")) shoot_without_player = true; if(!m_shooting && m_shoot_reload_timer >= reload_time && !m_next_pos_exists && (m_disturb_timer <= 60.0 || shoot_without_player)) { m_shoot_y = 0; if(m_disturb_timer < 60.0 && disturbing_player && disturbing_player_distance < 16*BS && fabs(disturbing_player_norm.Y) < 0.8){ m_yaw = disturbing_player_dir; sendPosition(); m_shoot_y += disturbing_player_norm.Y; } else { m_shoot_y = 0.01 * myrand_range(-30,10); } m_shoot_reload_timer = 0.0; m_shooting = true; m_shooting_timer = 1.5; { std::ostringstream os(std::ios::binary); // command (2 = shooting) writeU8(os, 2); // time writeF1000(os, m_shooting_timer + 0.1); // bright? writeU8(os, true); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } } } if(m_move_type == "ground_nodes") { if(!m_shooting){ m_walk_around_timer -= dtime; if(m_walk_around_timer <= 0.0){ m_walk_around = !m_walk_around; if(m_walk_around) m_walk_around_timer = 0.1*myrand_range(10,50); else m_walk_around_timer = 0.1*myrand_range(30,70); } } /* Move */ if(m_next_pos_exists){ v3f pos_f = m_base_position; v3f next_pos_f = intToFloat(m_next_pos_i, BS); v3f v = next_pos_f - pos_f; m_yaw = atan2(v.Z, v.X) / PI * 180; v3f diff = next_pos_f - pos_f; v3f dir = diff; dir.normalize(); float speed = BS * 0.5; if(m_falling) speed = BS * 3.0; dir *= dtime * speed; bool arrived = false; if(dir.getLength() > diff.getLength()){ dir = diff; arrived = true; } pos_f += dir; m_base_position = pos_f; if((pos_f - next_pos_f).getLength() < 0.1 || arrived){ m_next_pos_exists = false; } } v3s16 pos_i = floatToInt(m_base_position, BS); v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5); v3s16 pos_size_off(0,0,0); if(m_size.X >= 2.5){ pos_size_off.X = -1; pos_size_off.Y = -1; } if(!m_next_pos_exists){ /* Check whether to drop down */ if(checkFreePosition(map, pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){ m_next_pos_i = pos_i + v3s16(0,-1,0); m_next_pos_exists = true; m_falling = true; } else { m_falling = false; } } if(m_walk_around) { if(!m_next_pos_exists){ /* Find some position where to go next */ v3s16 dps[3*3*3]; int num_dps = 0; for(int dx=-1; dx<=1; dx++) for(int dy=-1; dy<=1; dy++) for(int dz=-1; dz<=1; dz++){ if(dx == 0 && dy == 0) continue; if(dx != 0 && dz != 0 && dy != 0) continue; dps[num_dps++] = v3s16(dx,dy,dz); } u32 order[3*3*3]; get_random_u32_array(order, num_dps); for(int i=0; i<num_dps; i++){ v3s16 p = dps[order[i]] + pos_i; bool is_free = checkFreeAndWalkablePosition(map, p + pos_size_off, size_blocks); if(!is_free) continue; m_next_pos_i = p; m_next_pos_exists = true; break; } } } } else if(m_move_type == "constant_speed") { m_base_position += m_speed * dtime; v3s16 pos_i = floatToInt(m_base_position, BS); v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5); v3s16 pos_size_off(0,0,0); if(m_size.X >= 2.5){ pos_size_off.X = -1; pos_size_off.Y = -1; } bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks); if(!free){ explodeSquare(map, pos_i, v3s16(3,3,3)); m_removed = true; return; } } else { errorstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\"" <<m_move_type<<"\""<<std::endl; } if(send_recommended == false) return; if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS) { sendPosition(); } }
void PlayerSAO::step(float dtime, bool send_recommended) { if (m_drowning_interval.step(dtime, 2.0)) { // get head position v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); MapNode n = m_env->getMap().getNodeNoEx(p); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If node generates drown if (c.drowning > 0 && m_hp > 0) { if (m_breath > 0) setBreath(m_breath - 1); // No more breath, damage player if (m_breath == 0) { setHP(m_hp - c.drowning); m_env->getGameDef()->SendPlayerHPOrDie(this); } } } if (m_breathing_interval.step(dtime, 0.5)) { // get head position v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); MapNode n = m_env->getMap().getNodeNoEx(p); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If player is alive & no drowning, breath if (m_hp > 0 && m_breath < PLAYER_MAX_BREATH && c.drowning == 0) setBreath(m_breath + 1); } if (m_node_hurt_interval.step(dtime, 1.0)) { // Feet, middle and head v3s16 p1 = floatToInt(m_base_position + v3f(0, BS*0.1, 0), BS); MapNode n1 = m_env->getMap().getNodeNoEx(p1); v3s16 p2 = floatToInt(m_base_position + v3f(0, BS*0.8, 0), BS); MapNode n2 = m_env->getMap().getNodeNoEx(p2); v3s16 p3 = floatToInt(m_base_position + v3f(0, BS*1.6, 0), BS); MapNode n3 = m_env->getMap().getNodeNoEx(p3); u32 damage_per_second = 0; damage_per_second = MYMAX(damage_per_second, m_env->getGameDef()->ndef()->get(n1).damage_per_second); damage_per_second = MYMAX(damage_per_second, m_env->getGameDef()->ndef()->get(n2).damage_per_second); damage_per_second = MYMAX(damage_per_second, m_env->getGameDef()->ndef()->get(n3).damage_per_second); if (damage_per_second != 0 && m_hp > 0) { s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second); setHP(newhp); m_env->getGameDef()->SendPlayerHPOrDie(this); } } if (!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } // If attached, check that our parent is still there. If it isn't, detach. if(m_attachment_parent_id && !isAttached()) { m_attachment_parent_id = 0; m_attachment_bone = ""; m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); setBasePosition(m_last_good_position); m_env->getGameDef()->SendMovePlayer(m_peer_id); } //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl; // Set lag pool maximums based on estimated lag const float LAG_POOL_MIN = 5.0; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0; if(lag_pool_max < LAG_POOL_MIN) lag_pool_max = LAG_POOL_MIN; m_dig_pool.setMax(lag_pool_max); m_move_pool.setMax(lag_pool_max); // Increment cheat prevention timers m_dig_pool.add(dtime); m_move_pool.add(dtime); m_time_from_last_teleport += dtime; m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // If the object gets detached this comes into effect automatically from the last known origin if (isAttached()) { v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); m_last_good_position = pos; setBasePosition(pos); } if (!send_recommended) return; // If the object is attached client-side, don't waste bandwidth sending its position to clients if(m_position_not_sent && !isAttached()) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); v3f pos; if(isAttached()) // Just in case we ever do send attachment position too pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); else pos = m_base_position + v3f(0,BS*1,0); std::string str = gob_cmd_update_position( pos, v3f(0,0,0), v3f(0,0,0), m_yaw, true, false, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push(aom); } if (!m_armor_groups_sent) { m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_physics_override_sent) { m_physics_override_sent = true; std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak, m_physics_override_sneak_glitch, m_physics_override_new_move); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_animation_sent) { m_animation_sent = true; std::string str = gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_bone_position_sent) { m_bone_position_sent = true; for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } if (!m_attachment_sent){ m_attachment_sent = true; std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } }
void LuaEntitySAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } // If attached, check that our parent is still there. If it isn't, detach. if(m_attachment_parent_id && !isAttached()) { m_attachment_parent_id = 0; m_attachment_bone = ""; m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); sendPosition(false, true); } m_last_sent_position_timer += dtime; // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // If the object gets detached this comes into effect automatically from the last known origin if(isAttached()) { v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); m_base_position = pos; m_velocity = v3f(0,0,0); m_acceleration = v3f(0,0,0); } else { if(m_prop.physical){ core::aabbox3d<f32> box = m_prop.collisionbox; box.MinEdge *= BS; box.MaxEdge *= BS; collisionMoveResult moveresult; f32 pos_max_d = BS*0.25; // Distance per iteration v3f p_pos = m_base_position; v3f p_velocity = m_velocity; v3f p_acceleration = m_acceleration; moveresult = collisionMoveSimple(m_env,m_env->getGameDef(), pos_max_d, box, m_prop.stepheight, dtime, p_pos, p_velocity, p_acceleration, this, m_prop.collideWithObjects); // Apply results m_base_position = p_pos; m_velocity = p_velocity; m_acceleration = p_acceleration; } else { m_base_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; m_velocity += dtime * m_acceleration; } if((m_prop.automatic_face_movement_dir) && (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)){ m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI + m_prop.automatic_face_movement_dir_offset; } } if(m_registered){ m_env->getScriptIface()->luaentity_Step(m_id, dtime); } if(send_recommended == false) return; if(!isAttached()) { // TODO: force send when acceleration changes enough? float minchange = 0.2*BS; if(m_last_sent_position_timer > 1.0){ minchange = 0.01*BS; } else if(m_last_sent_position_timer > 0.2){ minchange = 0.05*BS; } float move_d = m_base_position.getDistanceFrom(m_last_sent_position); move_d += m_last_sent_move_precision; float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity); if(move_d > minchange || vel_d > minchange || fabs(m_yaw - m_last_sent_yaw) > 1.0){ sendPosition(true, false); } } if(m_armor_groups_sent == false){ m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if(m_animation_sent == false){ m_animation_sent = true; std::string str = gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if(m_bone_position_sent == false){ m_bone_position_sent = true; for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } if(m_attachment_sent == false){ m_attachment_sent = true; std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } }
void PlayerSAO::step(float dtime, bool send_recommended) { if (m_drowning_interval.step(dtime, 2.0f)) { // Get nose/mouth position, approximate with eye position v3s16 p = floatToInt(getEyePosition(), BS); MapNode n = m_env->getMap().getNodeNoEx(p); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If node generates drown if (c.drowning > 0 && m_hp > 0) { if (m_breath > 0) setBreath(m_breath - 1); // No more breath, damage player if (m_breath == 0) { PlayerHPChangeReason reason(PlayerHPChangeReason::DROWNING); setHP(m_hp - c.drowning, reason); m_env->getGameDef()->SendPlayerHPOrDie(this, reason); } } } if (m_breathing_interval.step(dtime, 0.5f)) { // Get nose/mouth position, approximate with eye position v3s16 p = floatToInt(getEyePosition(), BS); MapNode n = m_env->getMap().getNodeNoEx(p); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If player is alive & no drowning, breathe if (m_hp > 0 && m_breath < m_prop.breath_max && c.drowning == 0) setBreath(m_breath + 1); } if (m_node_hurt_interval.step(dtime, 1.0f)) { u32 damage_per_second = 0; // Lowest and highest damage points are 0.1 within collisionbox float dam_top = m_prop.collisionbox.MaxEdge.Y - 0.1f; // Sequence of damage points, starting 0.1 above feet and progressing // upwards in 1 node intervals, stopping below top damage point. for (float dam_height = 0.1f; dam_height < dam_top; dam_height++) { v3s16 p = floatToInt(m_base_position + v3f(0.0f, dam_height * BS, 0.0f), BS); MapNode n = m_env->getMap().getNodeNoEx(p); damage_per_second = std::max(damage_per_second, m_env->getGameDef()->ndef()->get(n).damage_per_second); } // Top damage point v3s16 ptop = floatToInt(m_base_position + v3f(0.0f, dam_top * BS, 0.0f), BS); MapNode ntop = m_env->getMap().getNodeNoEx(ptop); damage_per_second = std::max(damage_per_second, m_env->getGameDef()->ndef()->get(ntop).damage_per_second); if (damage_per_second != 0 && m_hp > 0) { s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second); PlayerHPChangeReason reason(PlayerHPChangeReason::NODE_DAMAGE); setHP(newhp, reason); m_env->getGameDef()->SendPlayerHPOrDie(this, reason); } } if (!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } // If attached, check that our parent is still there. If it isn't, detach. if (m_attachment_parent_id && !isAttached()) { m_attachment_parent_id = 0; m_attachment_bone = ""; m_attachment_position = v3f(0.0f, 0.0f, 0.0f); m_attachment_rotation = v3f(0.0f, 0.0f, 0.0f); setBasePosition(m_last_good_position); m_env->getGameDef()->SendMovePlayer(m_peer_id); } //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl; // Set lag pool maximums based on estimated lag const float LAG_POOL_MIN = 5.0f; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0f; if(lag_pool_max < LAG_POOL_MIN) lag_pool_max = LAG_POOL_MIN; m_dig_pool.setMax(lag_pool_max); m_move_pool.setMax(lag_pool_max); // Increment cheat prevention timers m_dig_pool.add(dtime); m_move_pool.add(dtime); m_time_from_last_teleport += dtime; m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; // Each frame, parent position is copied if the object is attached, // otherwise it's calculated normally. // If the object gets detached this comes into effect automatically from // the last known origin. if (isAttached()) { v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); m_last_good_position = pos; setBasePosition(pos); } if (!send_recommended) return; // If the object is attached client-side, don't waste bandwidth sending its // position to clients. if (m_position_not_sent && !isAttached()) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); v3f pos; if (isAttached()) // Just in case we ever do send attachment position too pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); else pos = m_base_position; std::string str = gob_cmd_update_position( pos, v3f(0.0f, 0.0f, 0.0f), v3f(0.0f, 0.0f, 0.0f), m_yaw, true, false, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push(aom); } if (!m_armor_groups_sent) { m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_physics_override_sent) { m_physics_override_sent = true; std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak, m_physics_override_sneak_glitch, m_physics_override_new_move); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_animation_sent) { m_animation_sent = true; std::string str = gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_bone_position_sent) { m_bone_position_sent = true; for (std::unordered_map<std::string, core::vector2d<v3f>>::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } if (!m_attachment_sent) { m_attachment_sent = true; std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } }
void Oerkki1SAO::step(float dtime, bool send_recommended) { ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG); assert(m_env); if(m_is_active == false) { if(m_inactive_interval.step(dtime, 0.5)==false) return; } /* The AI */ m_age += dtime; if(m_age > 120) { // Die m_removed = true; return; } m_after_jump_timer -= dtime; v3f old_speed = m_speed_f; // Apply gravity m_speed_f.Y -= dtime*9.81*BS; /* Move around if some player is close */ bool player_is_close = false; bool player_is_too_close = false; v3f near_player_pos; // Check connected players core::list<Player*> players = m_env->getPlayers(true); core::list<Player*>::Iterator i; for(i = players.begin(); i != players.end(); i++) { Player *player = *i; v3f playerpos = player->getPosition(); f32 dist = m_base_position.getDistanceFrom(playerpos); if(dist < BS*0.6) { m_removed = true; return; player_is_too_close = true; near_player_pos = playerpos; } else if(dist < BS*15.0 && !player_is_too_close) { player_is_close = true; near_player_pos = playerpos; } } m_is_active = player_is_close; v3f target_speed = m_speed_f; if(!player_is_close) { target_speed = v3f(0,0,0); } else { // Move around v3f ndir = near_player_pos - m_base_position; ndir.Y = 0; ndir.normalize(); f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X); if(nyaw < m_yaw - 180) nyaw += 360; else if(nyaw > m_yaw + 180) nyaw -= 360; m_yaw = 0.95*m_yaw + 0.05*nyaw; m_yaw = wrapDegrees(m_yaw); f32 speed = 2*BS; if((m_touching_ground || m_after_jump_timer > 0.0) && !player_is_too_close) { v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI)); target_speed.X = speed * dir.X; target_speed.Z = speed * dir.Z; } if(m_touching_ground && (m_oldpos - m_base_position).getLength() < dtime*speed/2) { m_counter1 -= dtime; if(m_counter1 < 0.0) { m_counter1 += 0.2; // Jump target_speed.Y = 5.0*BS; m_after_jump_timer = 1.0; } } { m_counter2 -= dtime; if(m_counter2 < 0.0) { m_counter2 += (float)(myrand()%100)/100*3.0; //m_yaw += ((float)(myrand()%200)-100)/100*180; m_yaw += ((float)(myrand()%200)-100)/100*90; m_yaw = wrapDegrees(m_yaw); } } } if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close) accelerate_xz(m_speed_f, target_speed, dtime*BS*8); else accelerate_xz(m_speed_f, target_speed, dtime*BS*4); m_oldpos = m_base_position; /* Move it, with collision detection */ core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.); collisionMoveResult moveresult; // Maximum movement without glitches f32 pos_max_d = BS*0.25; /*// Limit speed if(m_speed_f.getLength()*dtime > pos_max_d) m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/ v3f pos_f = getBasePosition(); v3f pos_f_old = pos_f; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMovePrecise(&m_env->getMap(), gamedef, pos_max_d, box, dtime, pos_f, m_speed_f); m_touching_ground = moveresult.touching_ground; // Do collision damage float tolerance = BS*30; float factor = BS*0.5; v3f speed_diff = old_speed - m_speed_f; // Increase effect in X and Z speed_diff.X *= 2; speed_diff.Z *= 2; float vel = speed_diff.getLength(); if(vel > tolerance) { f32 damage_f = (vel - tolerance)/BS*factor; u16 damage = (u16)(damage_f+0.5); doDamage(damage); } setBasePosition(pos_f); if(send_recommended == false && m_speed_f.getLength() < 3.0*BS) return; if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS) { m_last_sent_position = pos_f; std::ostringstream os(std::ios::binary); // command (0 = update position) writeU8(os, 0); // pos writeV3F1000(os, m_base_position); // yaw writeF1000(os, m_yaw); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } }
void FireflySAO::step(float dtime, bool send_recommended) { ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG); assert(m_env); if(m_is_active == false) { if(m_inactive_interval.step(dtime, 0.5)==false) return; } /* The AI */ // Apply (less) gravity m_speed_f.Y -= dtime*3*BS; /* Move around if some player is close */ bool player_is_close = false; // Check connected players core::list<Player*> players = m_env->getPlayers(true); core::list<Player*>::Iterator i; for(i = players.begin(); i != players.end(); i++) { Player *player = *i; v3f playerpos = player->getPosition(); if(m_base_position.getDistanceFrom(playerpos) < BS*10.0) { player_is_close = true; break; } } m_is_active = player_is_close; if(player_is_close == false) { m_speed_f.X = 0; m_speed_f.Z = 0; } else { // Move around v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI)); f32 speed = BS/2; m_speed_f.X = speed * dir.X; m_speed_f.Z = speed * dir.Z; if(m_touching_ground && (m_oldpos - m_base_position).getLength() < dtime*speed/2) { m_counter1 -= dtime; if(m_counter1 < 0.0) { m_counter1 += 1.0; m_speed_f.Y = 5.0*BS; } } { m_counter2 -= dtime; if(m_counter2 < 0.0) { m_counter2 += (float)(myrand()%100)/100*3.0; m_yaw += ((float)(myrand()%200)-100)/100*180; m_yaw = wrapDegrees(m_yaw); } } } m_oldpos = m_base_position; /* Move it, with collision detection */ core::aabbox3d<f32> box(-BS/3.,-BS*2/3.0,-BS/3., BS/3.,BS*4./3.,BS/3.); collisionMoveResult moveresult; // Maximum movement without glitches f32 pos_max_d = BS*0.25; // Limit speed if(m_speed_f.getLength()*dtime > pos_max_d) m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime); v3f pos_f = getBasePosition(); v3f pos_f_old = pos_f; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMoveSimple(&m_env->getMap(), gamedef, pos_max_d, box, dtime, pos_f, m_speed_f); m_touching_ground = moveresult.touching_ground; setBasePosition(pos_f); if(send_recommended == false) return; if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS) { m_last_sent_position = pos_f; std::ostringstream os(std::ios::binary); // command (0 = update position) writeU8(os, 0); // pos writeV3F1000(os, m_base_position); // yaw writeF1000(os, m_yaw); // create message and add to list ActiveObjectMessage aom(getId(), false, os.str()); m_messages_out.push_back(aom); } }
void PlayerSAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } // If attached, check that our parent is still there. If it isn't, detach. if(m_attachment_parent_id && !isAttached()) { m_attachment_parent_id = 0; m_attachment_bone = ""; m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); m_player->setPosition(m_last_good_position); m_moved = true; } m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // If the object gets detached this comes into effect automatically from the last known origin if(isAttached()) { v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); m_last_good_position = pos; m_last_good_position_age = 0; m_player->setPosition(pos); } else { if(m_is_singleplayer || g_settings->getBool("disable_anticheat")) { m_last_good_position = m_player->getPosition(); m_last_good_position_age = 0; } else { /* Check player movements NOTE: Actually the server should handle player physics like the client does and compare player's position to what is calculated on our side. This is required when eg. players fly due to an explosion. Altough a node-based alternative might be possible too, and much more lightweight. */ float player_max_speed = 0; float player_max_speed_up = 0; if(m_privs.count("fast") != 0){ // Fast speed player_max_speed = BS * 20; player_max_speed_up = BS * 20; } else { // Normal speed player_max_speed = BS * 4.0; player_max_speed_up = BS * 4.0; } // Tolerance player_max_speed *= 2.5; player_max_speed_up *= 2.5; m_last_good_position_age += dtime; if(m_last_good_position_age >= 1.0){ float age = m_last_good_position_age; v3f diff = (m_player->getPosition() - m_last_good_position); float d_vert = diff.Y; diff.Y = 0; float d_horiz = diff.getLength(); /*infostream<<m_player->getName()<<"'s horizontal speed is " <<(d_horiz/age)<<std::endl;*/ if(d_horiz <= age * player_max_speed && (d_vert < 0 || d_vert < age * player_max_speed_up)){ m_last_good_position = m_player->getPosition(); } else { actionstream<<"Player "<<m_player->getName() <<" moved too fast; resetting position" <<std::endl; m_player->setPosition(m_last_good_position); m_moved = true; } m_last_good_position_age = 0; } } } if(send_recommended == false) return; // If the object is attached client-side, don't waste bandwidth sending its position to clients if(m_position_not_sent && !isAttached()) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); v3f pos; if(isAttached()) // Just in case we ever do send attachment position too pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); else pos = m_player->getPosition() + v3f(0,BS*1,0); std::string str = gob_cmd_update_position( pos, v3f(0,0,0), v3f(0,0,0), m_player->getYaw(), true, false, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push_back(aom); } if(m_wielded_item_not_sent) { m_wielded_item_not_sent = false; // GenericCAO has no special way to show this } if(m_armor_groups_sent == false){ m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } if(m_animation_sent == false){ m_animation_sent = true; std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } if(m_bone_position_sent == false){ m_bone_position_sent = true; for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } } if(m_attachment_sent == false){ m_attachment_sent = true; std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } }