void LuaEntitySAO::setPos(const v3f &pos) { if(isAttached()) return; setBasePosition(pos); sendPosition(false, true); }
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); } }
PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, const std::set<std::string> &privs, bool is_singleplayer): ServerActiveObject(env_, v3f(0,0,0)), m_player(player_), m_peer_id(peer_id_), m_inventory(NULL), m_damage(0), m_last_good_position(0,0,0), m_time_from_last_punch(0), m_nocheat_dig_pos(32767, 32767, 32767), m_nocheat_dig_time(0), m_wield_index(0), m_position_not_sent(false), m_armor_groups_sent(false), m_properties_sent(true), m_privs(privs), m_is_singleplayer(is_singleplayer), m_animation_speed(0), m_animation_blend(0), m_animation_sent(false), m_bone_position_sent(false), m_attachment_parent_id(0), m_attachment_sent(false), // public m_moved(false), m_inventory_not_sent(false), m_hp_not_sent(false), m_breath_not_sent(false), m_wielded_item_not_sent(false), m_physics_override_speed(1), m_physics_override_jump(1), m_physics_override_gravity(1), m_physics_override_sneak(true), m_physics_override_sneak_glitch(true), m_physics_override_sent(false) { assert(m_player); assert(m_peer_id != 0); setBasePosition(m_player->getPosition()); m_inventory = &m_player->inventory; m_armor_groups["fleshy"] = 100; m_prop.hp_max = PLAYER_MAX_HP; m_prop.physical = false; m_prop.weight = 75; m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.); // start of default appearance, this should be overwritten by LUA m_prop.visual = "upright_sprite"; m_prop.visual_size = v2f(1, 2); m_prop.textures.clear(); m_prop.textures.push_back("player.png"); m_prop.textures.push_back("player_back.png"); m_prop.colors.clear(); m_prop.colors.push_back(video::SColor(255, 255, 255, 255)); m_prop.spritediv = v2s16(1,1); // end of default appearance m_prop.is_visible = true; m_prop.makes_footstep_sound = true; }
void LuaEntitySAO::moveTo(v3f pos, bool continuous) { if(isAttached()) return; setBasePosition(pos); if(!continuous) sendPosition(true, true); }
bool PlayerSAO::checkMovementCheat() { if (isAttached() || m_is_singleplayer || g_settings->getBool("disable_anticheat")) { m_last_good_position = m_base_position; return false; } bool cheated = false; /* 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; if (m_privs.count("fast") != 0) { // Fast speed player_max_speed = m_player->movement_speed_fast * m_physics_override_speed; } else { // Normal speed player_max_speed = m_player->movement_speed_walk * m_physics_override_speed; } // Tolerance. The lag pool does this a bit. //player_max_speed *= 2.5; v3f diff = (m_base_position - m_last_good_position); float d_vert = diff.Y; diff.Y = 0; float d_horiz = diff.getLength(); float required_time = d_horiz / player_max_speed; if (d_vert > 0 && d_vert / player_max_speed > required_time) required_time = d_vert / player_max_speed; // Moving upwards if (m_move_pool.grab(required_time)) { m_last_good_position = m_base_position; } else { const float LAG_POOL_MIN = 5.0; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0; lag_pool_max = MYMAX(lag_pool_max, LAG_POOL_MIN); if (m_time_from_last_teleport > lag_pool_max) { actionstream << "Player " << m_player->getName() << " moved too fast; resetting position" << std::endl; cheated = true; } setBasePosition(m_last_good_position); } return cheated; }
void PlayerSAO::moveTo(v3f pos, bool continuous) { if(isAttached()) return; setBasePosition(pos); // Movement caused by this command is always valid m_last_good_position = pos; ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); }
void PlayerSAO::moveTo(v3f pos, bool continuous) { if(isAttached()) return; setBasePosition(pos); // Movement caused by this command is always valid m_last_good_position = pos; m_move_pool.empty(); m_time_from_last_teleport = 0.0; m_env->getGameDef()->SendMovePlayer(m_peer_id); }
void PlayerSAO::setPos(const v3f &pos) { if(isAttached()) return; setBasePosition(pos); { auto lock = lock_unique_rec(); // Movement caused by this command is always valid m_last_good_position = pos; } ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); }
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 LuaEntitySAO::step(float dtime, bool send_recommended) { 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 v3f p_pos = getBasePosition(); v3f p_velocity = m_velocity; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMovePrecise(&m_env->getMap(), gamedef, pos_max_d, box, dtime, p_pos, p_velocity); // Apply results setBasePosition(p_pos); m_velocity = p_velocity; m_velocity += dtime * m_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); } }
PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, const std::set<std::string> &privs, bool is_singleplayer): ServerActiveObject(env_, v3f(0,0,0)), m_player(player_), m_peer_id(peer_id_), m_inventory(NULL), m_last_good_position(0,0,0), m_last_good_position_age(0), m_time_from_last_punch(0), m_nocheat_dig_pos(32767, 32767, 32767), m_nocheat_dig_time(0), m_wield_index(0), m_position_not_sent(false), m_armor_groups_sent(false), m_properties_sent(true), m_privs(privs), m_is_singleplayer(is_singleplayer), // public m_teleported(false), m_inventory_not_sent(false), m_hp_not_sent(false), m_wielded_item_not_sent(false) { assert(m_player); assert(m_peer_id != 0); setBasePosition(m_player->getPosition()); m_inventory = &m_player->inventory; m_armor_groups["choppy"] = 2; m_armor_groups["fleshy"] = 3; m_prop.hp_max = PLAYER_MAX_HP; m_prop.physical = false; m_prop.weight = 75; m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.); m_prop.visual = "upright_sprite"; m_prop.visual_size = v2f(1, 2); m_prop.textures.clear(); m_prop.textures.push_back("player.png"); m_prop.textures.push_back("player_back.png"); m_prop.spritediv = v2s16(1,1); m_prop.is_visible = (getHP() != 0); m_prop.makes_footstep_sound = true; }
void step(float dtime, bool send_recommended) { m_age += dtime; if(m_age > 10) { m_removed = true; return; } auto m_base_position = getBasePosition(); m_base_position.Y += dtime * BS * 2; if(m_base_position.Y > 8*BS) m_base_position.Y = 2*BS; setBasePosition(m_base_position); 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 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 v3f p_pos = getBasePosition(); v3f p_velocity = m_velocity; IGameDef *gamedef = m_env->getGameDef(); moveresult = collisionMovePrecise(&m_env->getMap(), gamedef, pos_max_d, box, dtime, p_pos, p_velocity); // Apply results setBasePosition(p_pos); m_velocity = p_velocity; m_velocity += dtime * m_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); } }
bool ModelContainer::readFile(const char *filename) { bool result = false; unsigned int flags; unsigned int size; char ident[8]; char chunk[4]; unsigned int ival; FILE *rf = fopen(filename, "rb"); if(rf) { free(); result = true; char magic[8]; // Ignore the added magic header fread(magic,1,8,rf); if(strncmp(VMAP_MAGIC,magic,8)) result = false; if(result && fread(ident,8,1,rf) != 1) result = false; if(result && fread(&flags,sizeof(unsigned int),1,rf) != 1) result = false; //POS if(result && fread(chunk,4,1,rf) != 1) result = false; if(result && fread(&size,4,1,rf) != 1) result = false; Vector3 basePos; if(result && fread(&basePos,sizeof(float),3,rf) != 3) result = false; setBasePosition(basePos); //---- Box if(result && fread(chunk,4,1,rf) != 1) result = false; if(result && fread(&size,4,1,rf) != 1) result = false; Vector3 low,high; if(result && fread(&low,sizeof(float),3,rf) != 3) result = false; if(result && fread(&high,sizeof(float),3,rf) != 3) result = false; setBounds(low, high); //---- TreeNodes if(result && fread(chunk,4,1,rf) != 1) result = false; if(result && fread(&size,4,1,rf) != 1) result = false; if(result && fread(&ival,sizeof(unsigned int),1,rf) != 1) result = false; if(result) setNNodes(ival); if(result) setTreeNodeArray(new TreeNode[getNNodes()]); if(result && fread(getTreeNodes(),sizeof(TreeNode),getNNodes(),rf) != getNNodes()) result = false; //---- TriangleBoxes if(result && fread(chunk,4,1,rf) != 1) result = false; if(result && fread(&size,4,1,rf) != 1) result = false; if(result && fread(&ival,sizeof(unsigned int),1,rf) != 1) result = false; setNTriangles(ival); if(result) setTriangleArray(new TriangleBox[getNTriangles()]); if(result && fread(getTriangles(),sizeof(TriangleBox),getNTriangles(),rf) != getNTriangles()) result = false; //---- SubModel if(result && fread(chunk,4,1,rf) != 1) result = false; if(result && fread(&size,4,1,rf) != 1) result = false; if(result && fread(&iNSubModel,sizeof(unsigned int),1,rf) != 1) result = false; if(result) iSubModel = new SubModel[iNSubModel]; if(result) { for (unsigned int i=0; i<iNSubModel && result; ++i) { unsigned char readBuffer[52]; // this is the size of SubModel on 32 bit systems if(fread(readBuffer,sizeof(readBuffer),1,rf) != 1) result = false; iSubModel[i].initFromBinBlock(readBuffer); iSubModel[i].setTriangleArray(getTriangles()); iSubModel[i].setTreeNodeArray(getTreeNodes()); } } fclose(rf); } return result; }
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 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 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 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); } }
bool PlayerSAO::checkMovementCheat() { if (isAttached() || m_is_singleplayer || g_settings->getBool("disable_anticheat")) { m_last_good_position = m_base_position; return false; } bool cheated = false; /* 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_walk = 0; // horizontal movement float player_max_jump = 0; // vertical upwards movement if (m_privs.count("fast") != 0) player_max_walk = m_player->movement_speed_fast; // Fast speed else player_max_walk = m_player->movement_speed_walk; // Normal speed player_max_walk *= m_physics_override_speed; player_max_jump = m_player->movement_speed_jump * m_physics_override_jump; // FIXME: Bouncy nodes cause practically unbound increase in Y speed, // until this can be verified correctly, tolerate higher jumping speeds player_max_jump *= 2.0; // Don't divide by zero! if (player_max_walk < 0.0001f) player_max_walk = 0.0001f; if (player_max_jump < 0.0001f) player_max_jump = 0.0001f; v3f diff = (m_base_position - m_last_good_position); float d_vert = diff.Y; diff.Y = 0; float d_horiz = diff.getLength(); float required_time = d_horiz / player_max_walk; // FIXME: Checking downwards movement is not easily possible currently, // the server could calculate speed differences to examine the gravity if (d_vert > 0) { // In certain cases (water, ladders) walking speed is applied vertically float s = MYMAX(player_max_jump, player_max_walk); required_time = MYMAX(required_time, d_vert / s); } if (m_move_pool.grab(required_time)) { m_last_good_position = m_base_position; } else { const float LAG_POOL_MIN = 5.0; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0; lag_pool_max = MYMAX(lag_pool_max, LAG_POOL_MIN); if (m_time_from_last_teleport > lag_pool_max) { actionstream << "Player " << m_player->getName() << " moved too fast; resetting position" << std::endl; cheated = true; } setBasePosition(m_last_good_position); } return cheated; }
void PlayerSAO::step(float dtime, bool send_recommended) { if (!m_player) return; if(!m_properties_sent) { std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); m_properties_sent = true; } // If attached, check that our parent is still there. If it isn't, detach. if(m_attachment_parent_id && !isAttached()) { { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK1; 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); ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } NOLOCK1:; //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); { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK2; m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; m_ms_from_last_respawn += dtime*1000; } NOLOCK2:; // 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, vel, acc; 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); vel = m_player->getSpeed(); } std::string str = gob_cmd_update_position( pos, vel, acc, 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) { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK3; 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); } NOLOCK3:; if (!m_animation_sent) { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK4; 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); } NOLOCK4:; 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) { std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); m_properties_sent = true; } // 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(); setBasePosition(pos); m_velocity = v3f(0,0,0); m_acceleration = v3f(0,0,0); } else { if(m_prop.physical){ aabb3f 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 = getBasePosition(); 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 setBasePosition(p_pos); m_velocity = p_velocity; m_acceleration = p_acceleration; } else { v3f p_pos = getBasePosition(); p_pos += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; setBasePosition(p_pos); m_velocity += dtime * m_acceleration; } if((m_prop.automatic_face_movement_dir) && (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) { float optimal_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI + m_prop.automatic_face_movement_dir_offset; float max_rotation_delta = dtime * m_prop.automatic_face_movement_max_rotation_per_sec; if ((m_prop.automatic_face_movement_max_rotation_per_sec > 0) && (fabs(m_yaw - optimal_yaw) > max_rotation_delta)) { m_yaw = optimal_yaw < m_yaw ? m_yaw - max_rotation_delta : m_yaw + max_rotation_delta; } else { m_yaw = optimal_yaw; } } } if(m_registered && (getType() < ACTIVEOBJECT_TYPE_LUACREATURE || getType() > ACTIVEOBJECT_TYPE_LUAFALLING)) { 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 = getBasePosition().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 (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 == 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); } }