X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcontent_sao.cpp;h=718a42dffcff479eea9eb3fa06cd737789a6b85d;hb=5bd50a2d9060f265d4c8d2fff062cac106ccab7c;hp=0488c802394b536802370d6bfb3ff458a0553120;hpb=2795f44f0316c83728bc8059a020869058498f78;p=dragonfireclient.git diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 0488c8023..718a42dff 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1,6 +1,6 @@ /* -Minetest-c55 -Copyright (C) 2010-2011 celeron55, Perttu Ahola +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -245,7 +245,7 @@ class ItemSAO : public ServerActiveObject } } - std::string getClientInitializationData() + std::string getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); // version @@ -292,13 +292,6 @@ class ItemSAO : public ServerActiveObject ServerActiveObject *puncher, float time_from_last_punch) { - // Directly delete item in creative mode - if(g_settings->getBool("creative_mode") == true) - { - m_removed = true; - return 0; - } - // Take item into inventory ItemStack item = createItemStack(); Inventory *inv = puncher->getInventory(); @@ -362,7 +355,13 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, m_last_sent_velocity(0,0,0), m_last_sent_position_timer(0), m_last_sent_move_precision(0), - m_armor_groups_sent(false) + m_armor_groups_sent(false), + 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) { // Only register type if no environment supplied if(env == NULL){ @@ -383,9 +382,9 @@ LuaEntitySAO::~LuaEntitySAO() } } -void LuaEntitySAO::addedToEnvironment() +void LuaEntitySAO::addedToEnvironment(u32 dtime_s) { - ServerActiveObject::addedToEnvironment(); + ServerActiveObject::addedToEnvironment(dtime_s); // Create entity from name lua_State *L = m_env->getLua(); @@ -397,7 +396,7 @@ void LuaEntitySAO::addedToEnvironment() // 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()); + scriptapi_luaentity_activate(L, m_id, m_init_state.c_str(), dtime_s); } } @@ -436,6 +435,17 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos, return sao; } +bool LuaEntitySAO::isAttached() +{ + if(!m_attachment_parent_id) + return false; + // Check if the parent still exists + ServerActiveObject *obj = m_env->getActiveObject(m_attachment_parent_id); + if(obj) + return true; + return false; +} + void LuaEntitySAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) @@ -447,30 +457,52 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) 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); + sendPosition(false, true); + } + m_last_sent_position_timer += dtime; - - if(m_prop.physical){ - core::aabbox3d 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; + + // 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 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){ @@ -480,20 +512,23 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) 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(!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){ @@ -504,20 +539,70 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) 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 >::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); + } } -std::string LuaEntitySAO::getClientInitializationData() +std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); - writeU8(os, 0); // version - os<= 14) + { + writeU8(os, 1); // version + os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + os<getLua(); scriptapi_luaentity_rightclick(L, m_id, clicker); } void LuaEntitySAO::setPos(v3f pos) { + if(isAttached()) + return; m_base_position = pos; sendPosition(false, true); } void LuaEntitySAO::moveTo(v3f pos, bool continuous) { + if(isAttached()) + return; m_base_position = pos; if(!continuous) sendPosition(true, true); @@ -651,6 +747,37 @@ void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups) m_armor_groups_sent = false; } +void LuaEntitySAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend) +{ + m_animation_range = frame_range; + m_animation_speed = frame_speed; + m_animation_blend = frame_blend; + m_animation_sent = false; +} + +void LuaEntitySAO::setBonePosition(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) +{ + // 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 + // are still sent to clients at an interval so players might see them lagging, plus we can't + // read and attach to skeletal bones. + // If we just attach on the client, the server still sees the child at its original location. + // This breaks some things so we also give the server the most accurate representation + // even if players only see the client changes. + + m_attachment_parent_id = parent_id; + m_attachment_bone = bone; + m_attachment_position = position; + m_attachment_rotation = rotation; + m_attachment_sent = false; +} + ObjectProperties* LuaEntitySAO::accessObjectProperties() { return &m_prop; @@ -725,6 +852,10 @@ std::string LuaEntitySAO::getPropertyPacket() 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; @@ -772,8 +903,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, m_properties_sent(true), m_privs(privs), m_is_singleplayer(is_singleplayer), + m_animation_sent(false), + m_bone_position_sent(false), + m_attachment_sent(false), // public - m_teleported(false), + m_moved(false), m_inventory_not_sent(false), m_hp_not_sent(false), m_wielded_item_not_sent(false) @@ -789,13 +923,17 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_, 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.); + // 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); - m_prop.is_visible = (getHP() != 0); + // end of default appearance + m_prop.is_visible = true; m_prop.makes_footstep_sound = true; } @@ -812,9 +950,9 @@ std::string PlayerSAO::getDescription() } // Called after id has been set and has been inserted in environment -void PlayerSAO::addedToEnvironment() +void PlayerSAO::addedToEnvironment(u32 dtime_s) { - ServerActiveObject::addedToEnvironment(); + ServerActiveObject::addedToEnvironment(dtime_s); ServerActiveObject::setBasePosition(m_player->getPosition()); m_player->setPlayerSAO(this); m_player->peer_id = m_peer_id; @@ -843,18 +981,43 @@ bool PlayerSAO::unlimitedTransferDistance() const return g_settings->getBool("unlimited_player_transfer_distance"); } -std::string PlayerSAO::getClientInitializationData() +std::string PlayerSAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); - writeU8(os, 0); // version - os<getName()); // name - writeU8(os, 1); // is_player - writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0)); - writeF1000(os, m_player->getYaw()); - writeS16(os, getHP()); - writeU8(os, 2); // number of messages stuffed in here - os<= 15) + { + writeU8(os, 1); // version + os<getName()); // name + writeU8(os, 1); // is_player + writeS16(os, getId()); //id + writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0)); + writeF1000(os, m_player->getYaw()); + writeS16(os, getHP()); + + writeU8(os, 4 + m_bone_position.size()); // number of messages stuffed in here + os< >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + os<getName()); // name + writeU8(os, 1); // is_player + writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0)); + writeF1000(os, m_player->getYaw()); + writeS16(os, getHP()); + writeU8(os, 2); // number of messages stuffed in here + os<getActiveObject(m_attachment_parent_id); + if(obj) + return true; + return false; +} + void PlayerSAO::step(float dtime, bool send_recommended) { if(!m_properties_sent) @@ -875,73 +1049,102 @@ void PlayerSAO::step(float dtime, bool send_recommended) 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; - - if(m_is_singleplayer || g_settings->getBool("disable_anticheat")) + + // 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()) { - m_last_good_position = m_player->getPosition(); + 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 { - /* - 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; + if(m_is_singleplayer || g_settings->getBool("disable_anticheat")) + { + m_last_good_position = m_player->getPosition(); + m_last_good_position_age = 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 + { + /* + 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 { - actionstream<<"Player "<getName() - <<" moved too fast; resetting position" - <setPosition(m_last_good_position); - m_teleported = true; + // 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; } - m_last_good_position_age = 0; } } if(send_recommended == false) return; - if(m_position_not_sent) + // 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( - m_player->getPosition() + v3f(0,BS*1,0), + pos, v3f(0,0,0), v3f(0,0,0), m_player->getYaw(), @@ -968,32 +1171,63 @@ void PlayerSAO::step(float dtime, bool send_recommended) 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 >::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); + } } void PlayerSAO::setBasePosition(const v3f &position) { + // This needs to be ran for attachments too ServerActiveObject::setBasePosition(position); m_position_not_sent = true; } void PlayerSAO::setPos(v3f pos) { + if(isAttached()) + return; 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_teleported = true; + m_moved = true; } void PlayerSAO::moveTo(v3f pos, bool continuous) { + if(isAttached()) + return; 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_teleported = true; + m_moved = true; } int PlayerSAO::punch(v3f dir, @@ -1001,6 +1235,10 @@ int PlayerSAO::punch(v3f dir, ServerActiveObject *puncher, float time_from_last_punch) { + // It's best that attachments cannot be punched + if(isAttached()) + return 0; + if(!toolcap) return 0; @@ -1082,6 +1320,39 @@ void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) m_armor_groups_sent = false; } +void PlayerSAO::setAnimation(v2f frame_range, float frame_speed, float frame_blend) +{ + // 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_sent = false; +} + +void PlayerSAO::setBonePosition(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) +{ + // 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 + // are still sent to clients at an interval so players might see them lagging, plus we can't + // read and attach to skeletal bones. + // If we just attach on the client, the server still sees the child at its original location. + // This breaks some things so we also give the server the most accurate representation + // even if players only see the client changes. + + m_attachment_parent_id = parent_id; + m_attachment_bone = bone; + m_attachment_position = position; + m_attachment_rotation = rotation; + m_attachment_sent = false; +} + ObjectProperties* PlayerSAO::accessObjectProperties() { return &m_prop; @@ -1143,19 +1414,9 @@ void PlayerSAO::disconnected() } } -void PlayerSAO::createCreativeInventory() -{ - if(m_inventory != &m_player->inventory) - delete m_inventory; - - m_inventory = new Inventory(m_player->inventory); - m_inventory->clearContents(); - scriptapi_get_creative_inventory(m_env->getLua(), this); -} - std::string PlayerSAO::getPropertyPacket() { - m_prop.is_visible = (getHP() != 0); + m_prop.is_visible = (true); return gob_cmd_set_properties(m_prop); }