X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcontent_sao.cpp;h=1664f59931068b794d4d3068c4c84526708ef6ec;hb=ad163ee5c3f7d6ca31e0add052fb76466a9bfcc8;hp=e6c8c725c25ff82cd74ef514301ea1917d43d201;hpb=c5a8448c41e4ea9d33a43cebef61425d4568a46d;p=dragonfireclient.git diff --git a/src/content_sao.cpp b/src/content_sao.cpp index e6c8c725c..1664f5993 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -18,65 +18,22 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "content_sao.h" +#include "util/serialize.h" +#include "util/mathconstants.h" #include "collision.h" #include "environment.h" #include "settings.h" -#include "main.h" // For g_profiler -#include "profiler.h" #include "serialization.h" // For compressZlib #include "tool.h" // For ToolCapabilities #include "gamedef.h" #include "player.h" -#include "scriptapi.h" +#include "server.h" +#include "scripting_game.h" #include "genericobject.h" -#include "util/serialize.h" +#include "log.h" std::map ServerActiveObject::m_types; -/* - DummyLoadSAO -*/ - -class DummyLoadSAO : public ServerActiveObject -{ -public: - DummyLoadSAO(ServerEnvironment *env, v3f pos, u8 type): - ServerActiveObject(env, pos) - { - ServerActiveObject::registerType(type, create); - } - // Pretend to be the test object (to fool the client) - u8 getType() const - { return ACTIVEOBJECT_TYPE_TEST; } - // And never save to disk - bool isStaticAllowed() const - { return false; } - - static ServerActiveObject* create(ServerEnvironment *env, v3f pos, - const std::string &data) - { - return new DummyLoadSAO(env, pos, 0); - } - - void step(float dtime, bool send_recommended) - { - m_removed = true; - infostream<<"DummyLoadSAO step"< 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; - moveresult = collisionMoveSimple(m_env,m_env->getGameDef(), - 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<getGameDef()->idef(); - ItemStack item; - item.deSerialize(m_itemstring, idef); - infostream<<__FUNCTION_NAME<<": m_itemstring=\""< item=\""<getInventory(); - if(inv != NULL) - { - std::string wieldlist = puncher->getWieldList(); - ItemStack leftover = inv->addItem(wieldlist, item); - puncher->setInventoryModified(); - if(leftover.empty()) - { - m_removed = true; - } - else - { - m_itemstring = leftover.getItemString(); - m_itemstring_changed = true; - } - } - - return 0; - } - - bool getCollisionBox(aabb3f *toset) { + bool collideWithObjects() { return false; } - private: - std::string m_itemstring; - bool m_itemstring_changed; - v3f m_speed_f; - v3f m_last_sent_position; - IntervalLimiter m_move_interval; + float m_timer1; + float m_age; }; // Prototype (registers item for deserialization) -ItemSAO proto_ItemSAO(NULL, v3f(0,0,0), ""); - -ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos, - const std::string itemstring) -{ - return new ItemSAO(env, pos, itemstring); -} +TestSAO proto_TestSAO(NULL, v3f(0,0,0)); /* LuaEntitySAO @@ -369,6 +135,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, m_armor_groups_sent(false), m_animation_speed(0), m_animation_blend(0), + m_animation_loop(true), m_animation_sent(false), m_bone_position_sent(false), m_attachment_parent_id(0), @@ -379,7 +146,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, ServerActiveObject::registerType(getType(), create); return; } - + // Initialize something to armor groups m_armor_groups["fleshy"] = 100; } @@ -387,26 +154,29 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, LuaEntitySAO::~LuaEntitySAO() { if(m_registered){ - lua_State *L = m_env->getLua(); - scriptapi_luaentity_rm(L, m_id); + m_env->getScriptIface()->luaentity_Remove(m_id); } } void LuaEntitySAO::addedToEnvironment(u32 dtime_s) { ServerActiveObject::addedToEnvironment(dtime_s); - + // Create entity from name - lua_State *L = m_env->getLua(); - m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str()); - + m_registered = m_env->getScriptIface()-> + luaentity_Add(m_id, m_init_name.c_str()); + if(m_registered){ // Get properties - scriptapi_luaentity_get_properties(L, m_id, &m_prop); + m_env->getScriptIface()-> + luaentity_GetProperties(m_id, &m_prop); // Initialize HP from properties m_hp = m_prop.hp_max; // Activate entity, supplying serialized state - scriptapi_luaentity_activate(L, m_id, m_init_state.c_str(), dtime_s); + m_env->getScriptIface()-> + luaentity_Activate(m_id, m_init_state.c_str(), dtime_s); + } else { + m_prop.infotext = m_init_name; } } @@ -464,7 +234,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push_back(aom); + m_messages_out.push(aom); } // If attached, check that our parent is still there. If it isn't, detach. @@ -491,18 +261,19 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) else { if(m_prop.physical){ - core::aabbox3d box = m_prop.collisionbox; + aabb3f 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; moveresult = collisionMoveSimple(m_env,m_env->getGameDef(), - pos_max_d, box, stepheight, dtime, - p_pos, p_velocity, p_acceleration); + 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; @@ -512,11 +283,27 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) * 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)) + { + 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){ - lua_State *L = m_env->getLua(); - scriptapi_luaentity_step(L, m_id, dtime); + m_env->getScriptIface()->luaentity_Step(m_id, dtime); } if(send_recommended == false) @@ -546,24 +333,27 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push_back(aom); + 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); + 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_back(aom); + m_messages_out.push(aom); } if(m_bone_position_sent == false){ m_bone_position_sent = true; - for(std::map >::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); + for (UNORDERED_MAP >::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); + m_messages_out.push(aom); } } @@ -572,7 +362,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) 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); + m_messages_out.push(aom); } } @@ -590,14 +380,23 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) writeF1000(os, m_yaw); writeS16(os, m_hp); - writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here + writeU8(os, 4 + m_bone_position.size() + m_attachment_child_ids.size()); // number of messages stuffed in here os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ - os< >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + os << serializeLongString(gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } os<::const_iterator ii = m_attachment_child_ids.begin(); + (ii != m_attachment_child_ids.end()); ++ii) { + if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { + os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), obj->getClientInitializationData(protocol_version))); + } + } } else { @@ -618,7 +417,7 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) std::string LuaEntitySAO::getStaticData() { - verbosestream<<__FUNCTION_NAME<getLua(); - std::string state = scriptapi_luaentity_get_staticdata(L, m_id); + std::string state = m_env->getScriptIface()-> + luaentity_GetStaticdata(m_id); os<getWieldedItem(); punchitem = &punchitem_static; } @@ -668,28 +467,28 @@ int LuaEntitySAO::punch(v3f dir, toolcap, punchitem, time_from_last_punch); - - if(result.did_punch) - { + + if (result.did_punch) { setHP(getHP() - result.damage); - - actionstream<getDescription()<<", damage "< 0) { + std::string punchername = puncher ? puncher->getDescription() : "nil"; + + actionstream << getDescription() << " punched by " + << punchername << ", damage " << result.damage + << " hp, health now " << getHP() << " hp" << std::endl; } - if(getHP() == 0) - m_removed = true; + 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); } - lua_State *L = m_env->getLua(); - scriptapi_luaentity_punch(L, m_id, puncher, + if (getHP() == 0) + m_removed = true; + + m_env->getScriptIface()->luaentity_Punch(m_id, puncher, time_from_last_punch, toolcap, dir); return result.wear; @@ -697,13 +496,12 @@ int LuaEntitySAO::punch(v3f dir, void LuaEntitySAO::rightClick(ServerActiveObject *clicker) { - if(!m_registered) + if (!m_registered) return; // It's best that attachments cannot be clicked - if(isAttached()) + if (isAttached()) return; - lua_State *L = m_env->getLua(); - scriptapi_luaentity_rightclick(L, m_id, clicker); + m_env->getScriptIface()->luaentity_Rightclick(m_id, clicker); } void LuaEntitySAO::setPos(v3f pos) @@ -756,21 +554,41 @@ void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups) m_armor_groups_sent = false; } -void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend) +ItemGroupList LuaEntitySAO::getArmorGroups() +{ + return m_armor_groups; +} + +void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop) { m_animation_range = frame_range; m_animation_speed = frame_speed; m_animation_blend = frame_blend; + m_animation_loop = frame_loop; m_animation_sent = false; } -void LuaEntitySAO::setBonePosition(std::string bone, v3f position, v3f rotation) +void LuaEntitySAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop) +{ + *frame_range = m_animation_range; + *frame_speed = m_animation_speed; + *frame_blend = m_animation_blend; + *frame_loop = m_animation_loop; +} + +void LuaEntitySAO::setBonePosition(const std::string &bone, v3f position, v3f rotation) { m_bone_position[bone] = core::vector2d(position, rotation); m_bone_position_sent = false; } -void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation) +void LuaEntitySAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation) +{ + *position = m_bone_position[bone].X; + *rotation = m_bone_position[bone].Y; +} + +void LuaEntitySAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) { // Attachments need to be handled on both the server and client. // If we just attach on the server, we can only copy the position of the parent. Attachments @@ -787,6 +605,30 @@ void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, m_attachment_sent = false; } +void LuaEntitySAO::getAttachment(int *parent_id, std::string *bone, v3f *position, + v3f *rotation) +{ + *parent_id = m_attachment_parent_id; + *bone = m_attachment_bone; + *position = m_attachment_position; + *rotation = m_attachment_rotation; +} + +void LuaEntitySAO::addAttachmentChild(int child_id) +{ + m_attachment_child_ids.insert(child_id); +} + +void LuaEntitySAO::removeAttachmentChild(int child_id) +{ + m_attachment_child_ids.erase(child_id); +} + +UNORDERED_SET LuaEntitySAO::getAttachmentChildIds() +{ + return m_attachment_child_ids; +} + ObjectProperties* LuaEntitySAO::accessObjectProperties() { return &m_prop; @@ -832,7 +674,7 @@ 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_back(aom); + m_messages_out.push(aom); } void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, @@ -846,7 +688,7 @@ void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength, ); // create message and add to list ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push_back(aom); + m_messages_out.push(aom); } std::string LuaEntitySAO::getName() @@ -864,7 +706,7 @@ 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; @@ -886,7 +728,7 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); - m_messages_out.push_back(aom); + m_messages_out.push(aom); } bool LuaEntitySAO::getCollisionBox(aabb3f *toset) { @@ -905,20 +747,24 @@ bool LuaEntitySAO::getCollisionBox(aabb3f *toset) { return false; } +bool LuaEntitySAO::collideWithObjects(){ + return m_prop.collideWithObjects; +} + /* PlayerSAO */ // No prototype, PlayerSAO does not need to be deserialized -PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, +PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_, const std::set &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_last_good_position_age(0), m_time_from_last_punch(0), m_nocheat_dig_pos(32767, 32767, 32767), m_nocheat_dig_time(0), @@ -928,21 +774,23 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, m_properties_sent(true), m_privs(privs), m_is_singleplayer(is_singleplayer), + m_animation_speed(0), + m_animation_blend(0), + m_animation_loop(true), 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_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); + assert(m_player); // pre-condition + assert(m_peer_id != 0); // pre-condition setBasePosition(m_player->getPosition()); m_inventory = &m_player->inventory; m_armor_groups["fleshy"] = 100; @@ -950,7 +798,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, m_prop.hp_max = PLAYER_MAX_HP; m_prop.physical = false; m_prop.weight = 75; - m_prop.collisionbox = core::aabbox3d(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.); + m_prop.collisionbox = aabb3f(-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); @@ -985,17 +833,17 @@ void PlayerSAO::addedToEnvironment(u32 dtime_s) m_player->setPlayerSAO(this); m_player->peer_id = m_peer_id; m_last_good_position = m_player->getPosition(); - m_last_good_position_age = 0.0; } // Called before removing from environment void PlayerSAO::removingFromEnvironment() { ServerActiveObject::removingFromEnvironment(); - if(m_player->getPlayerSAO() == this) - { + if (m_player->getPlayerSAO() == this) { m_player->setPlayerSAO(NULL); m_player->peer_id = 0; + m_env->savePlayer(m_player); + m_env->removePlayer(m_player); } } @@ -1004,11 +852,6 @@ bool PlayerSAO::isStaticAllowed() const return false; } -bool PlayerSAO::unlimitedTransferDistance() const -{ - return g_settings->getBool("unlimited_player_transfer_distance"); -} - std::string PlayerSAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); @@ -1023,15 +866,26 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version) writeF1000(os, m_player->getYaw()); writeS16(os, getHP()); - writeU8(os, 5 + m_bone_position.size()); // number of messages stuffed in here + writeU8(os, 6 + m_bone_position.size() + m_attachment_child_ids.size()); // number of messages stuffed in here os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + os< >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { os<::const_iterator ii = m_attachment_child_ids.begin(); + ii != m_attachment_child_ids.end(); ++ii) { + if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { + os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), obj->getClientInitializationData(protocol_version))); + } + } } else { @@ -1052,7 +906,7 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version) std::string PlayerSAO::getStaticData() { - assert(0); + FATAL_ERROR("Deprecated function (?)"); return ""; } @@ -1075,7 +929,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); - m_messages_out.push_back(aom); + m_messages_out.push(aom); } // If attached, check that our parent is still there. If it isn't, detach. @@ -1086,9 +940,22 @@ void PlayerSAO::step(float dtime, bool send_recommended) m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); m_player->setPosition(m_last_good_position); - m_moved = true; + ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } + //dstream<<"PlayerSAO::step: dtime: "<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; @@ -1098,66 +965,8 @@ void PlayerSAO::step(float dtime, bool send_recommended) { 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<getName()<<"'s horizontal speed is " - <<(d_horiz/age)<getPosition(); - } else { - actionstream<<"Player "<getName() - <<" moved too fast; resetting position" - <setPosition(m_last_good_position); - m_moved = true; - } - m_last_good_position_age = 0; - } - } - } if(send_recommended == false) return; @@ -1183,56 +992,56 @@ void PlayerSAO::step(float dtime, bool send_recommended) ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); - m_messages_out.push_back(aom); + m_messages_out.push(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){ + 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); + 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); + 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_back(aom); + 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); + 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_back(aom); + m_messages_out.push(aom); } - if(m_bone_position_sent == false){ + if (!m_bone_position_sent) { m_bone_position_sent = true; - for(std::map >::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); + for (UNORDERED_MAP >::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); + m_messages_out.push(aom); } } - if(m_attachment_sent == false){ + 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); + 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); + m_messages_out.push(aom); } } @@ -1250,9 +1059,7 @@ void PlayerSAO::setPos(v3f pos) m_player->setPosition(pos); // Movement caused by this command is always valid m_last_good_position = pos; - m_last_good_position_age = 0; - // Force position change on client - m_moved = true; + ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } void PlayerSAO::moveTo(v3f pos, bool continuous) @@ -1262,23 +1069,19 @@ void PlayerSAO::moveTo(v3f pos, bool continuous) m_player->setPosition(pos); // Movement caused by this command is always valid m_last_good_position = pos; - m_last_good_position_age = 0; - // Force position change on client - m_moved = true; + ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } void PlayerSAO::setYaw(float yaw) { m_player->setYaw(yaw); - // Force change on client - m_moved = true; + ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } void PlayerSAO::setPitch(float pitch) { m_player->setPitch(pitch); - // Force change on client - m_moved = true; + ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } int PlayerSAO::punch(v3f dir, @@ -1286,20 +1089,20 @@ int PlayerSAO::punch(v3f dir, ServerActiveObject *puncher, float time_from_last_punch) { - // It's best that attachments cannot be punched - if(isAttached()) + // It's best that attachments cannot be punched + if (isAttached()) return 0; - if(!toolcap) + if (!toolcap) return 0; // No effect if PvP disabled - if(g_settings->getBool("enable_pvp") == false){ - if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){ + 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); + m_messages_out.push(aom); return 0; } } @@ -1307,20 +1110,38 @@ int PlayerSAO::punch(v3f dir, HitParams hitparams = getHitParams(m_armor_groups, toolcap, time_from_last_punch); - actionstream<<"Player "<getName()<<" punched by " - <getDescription()<<", damage "<getDescription(); - 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); + 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; } @@ -1333,36 +1154,50 @@ s16 PlayerSAO::getHP() const return m_player->hp; } +s16 PlayerSAO::readDamage() +{ + s16 damage = m_damage; + m_damage = 0; + return damage; +} + void PlayerSAO::setHP(s16 hp) { s16 oldhp = m_player->hp; - if(hp < 0) + s16 hp_change = m_env->getScriptIface()->on_player_hpchange(this, + hp - oldhp); + if (hp_change == 0) + return; + hp = oldhp + hp_change; + + if (hp < 0) hp = 0; - else if(hp > PLAYER_MAX_HP) + 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 + if(hp < oldhp && g_settings->getBool("enable_damage") == false) { return; } m_player->hp = hp; - if(hp != oldhp) - m_hp_not_sent = true; + if (oldhp > hp) + m_damage += (oldhp - hp); - // On death or reincarnation send an active object message - if((hp == 0) != (oldhp == 0)) - { - // Will send new is_visible value based on (getHP()!=0) + // Update properties on death + if ((hp == 0) != (oldhp == 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); - } +} + +u16 PlayerSAO::getBreath() const +{ + return m_player->getBreath(); +} + +void PlayerSAO::setBreath(u16 breath) +{ + m_player->setBreath(breath); } void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) @@ -1371,23 +1206,43 @@ void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) m_armor_groups_sent = false; } -void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend) +ItemGroupList PlayerSAO::getArmorGroups() +{ + return m_armor_groups; +} + +void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop) { // store these so they can be updated to clients m_animation_range = frame_range; m_animation_speed = frame_speed; m_animation_blend = frame_blend; + m_animation_loop = frame_loop; m_animation_sent = false; } -void PlayerSAO::setBonePosition(std::string bone, v3f position, v3f rotation) +void PlayerSAO::getAnimation(v2f *frame_range, float *frame_speed, float *frame_blend, bool *frame_loop) +{ + *frame_range = m_animation_range; + *frame_speed = m_animation_speed; + *frame_blend = m_animation_blend; + *frame_loop = m_animation_loop; +} + +void PlayerSAO::setBonePosition(const std::string &bone, v3f position, v3f rotation) { // store these so they can be updated to clients m_bone_position[bone] = core::vector2d(position, rotation); m_bone_position_sent = false; } -void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation) +void PlayerSAO::getBonePosition(const std::string &bone, v3f *position, v3f *rotation) +{ + *position = m_bone_position[bone].X; + *rotation = m_bone_position[bone].Y; +} + +void PlayerSAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation) { // Attachments need to be handled on both the server and client. // If we just attach on the server, we can only copy the position of the parent. Attachments @@ -1404,6 +1259,30 @@ void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f m_attachment_sent = false; } +void PlayerSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, + v3f *rotation) +{ + *parent_id = m_attachment_parent_id; + *bone = m_attachment_bone; + *position = m_attachment_position; + *rotation = m_attachment_rotation; +} + +void PlayerSAO::addAttachmentChild(int child_id) +{ + m_attachment_child_ids.insert(child_id); +} + +void PlayerSAO::removeAttachmentChild(int child_id) +{ + m_attachment_child_ids.erase(child_id); +} + +UNORDERED_SET PlayerSAO::getAttachmentChildIds() +{ + return m_attachment_child_ids; +} + ObjectProperties* PlayerSAO::accessObjectProperties() { return &m_prop; @@ -1430,11 +1309,6 @@ InventoryLocation PlayerSAO::getInventoryLocation() const return loc; } -void PlayerSAO::setInventoryModified() -{ - m_inventory_not_sent = true; -} - std::string PlayerSAO::getWieldList() const { return "main"; @@ -1447,10 +1321,8 @@ int PlayerSAO::getWieldIndex() const void PlayerSAO::setWieldIndex(int i) { - if(i != m_wield_index) - { + if(i != m_wield_index) { m_wield_index = i; - m_wielded_item_not_sent = true; } } @@ -1471,7 +1343,68 @@ std::string PlayerSAO::getPropertyPacket() return gob_cmd_set_properties(m_prop); } +bool PlayerSAO::checkMovementCheat() +{ + if (isAttached() || m_is_singleplayer || + g_settings->getBool("disable_anticheat")) { + m_last_good_position = m_player->getPosition(); + 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_player->getPosition() - 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_player->getPosition(); + } else { + actionstream << "Player " << m_player->getName() + << " moved too fast; resetting position" + << std::endl; + m_player->setPosition(m_last_good_position); + cheated = true; + } + return cheated; +} + bool PlayerSAO::getCollisionBox(aabb3f *toset) { - //player collision handling is already done clientside no need to do it twice - return false; + //update collision box + *toset = m_player->getCollisionbox(); + + toset->MinEdge += m_base_position; + toset->MaxEdge += m_base_position; + + return true; +} + +bool PlayerSAO::collideWithObjects(){ + return true; }