Update attachments at the ending of the addToScene function for parents. And with this... *drum roll* Client-side attachments are at last functional and stick visibly.

Fix the last segmentation fault (apparently). So far attachments seem to be fully functional, although removing the parent causes children to go to origin 0,0,0 and possibly still cause such a fault (though this should already be addressed)

Fix a bug in falling code where entities get stuck

Also check if the parent has been removed server-side, and detach the child if so. Fixes children going to origin 0,0,0 when their parent is removed.

Unset all attachment properties when permanently detaching (on both the client and server). Also store less data we don't need

Create a separate function for detaching, and also update lua api documentation

When a child is detached, update its position from the server to clients. This WILL cause it to get positioned slightly differently client side, as the server attachment system only copies parent origin and knows not about mesh / bone transformation. This prevents different clients seeing the object detached in different spots which is most correct

Update the position of attached players to clients. An attached player will see himself move, but this is currently VERY ugly and laggy as it is done by the server (it probably must stay this way too)

Use a different approach for locally attached players. This allows for smooth positio transitions to work, as well at the player turning around freely. Still buggy however
This commit is contained in:
MirceaKitsune 2012-11-07 18:42:38 +02:00 committed by Perttu Ahola
parent 52fcb0b4b9
commit 9259d028ac
10 changed files with 173 additions and 108 deletions

@ -1104,6 +1104,8 @@ methods:
- set_wielded_item(item): replaces the wielded item, returns true if successful - set_wielded_item(item): replaces the wielded item, returns true if successful
- set_armor_groups({group1=rating, group2=rating, ...}) - set_armor_groups({group1=rating, group2=rating, ...})
- set_animations({x=1,y=1}, frame_speed=15, frame_blend=0) - set_animations({x=1,y=1}, frame_speed=15, frame_blend=0)
- set_attachment(parent, "", {x=0,y=0,z=0}, {x=0,y=0,z=0})
- set_detachment()
- set_bone_posrot("", {x=0,y=0,z=0}, {x=0,y=0,z=0}) - set_bone_posrot("", {x=0,y=0,z=0}, {x=0,y=0,z=0})
- set_properties(object property table) - set_properties(object property table)
LuaEntitySAO-only: (no-op for other objects) LuaEntitySAO-only: (no-op for other objects)

@ -768,14 +768,23 @@ public:
void removeFromScene(bool permanent) void removeFromScene(bool permanent)
{ {
// bool permanent should be true when removing the object permanently and false when it's only refreshed (and comes back in a few frames) if(permanent) // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
// If this object is being permanently removed, delete it from the attachments list
if(permanent)
{ {
// Detach this object's children
for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++) for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++)
{ {
if(ii->X == this->getId()) // This is the ID of our object if(ii->Y == this->getId()) // Is a child of our object
{
ii->Y = 0;
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
obj->updateParent();
}
}
// Delete this object from the attachments list
for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++)
{
if(ii->X == this->getId()) // Is our object
{ {
attachment_list.erase(ii); attachment_list.erase(ii);
break; break;
@ -783,39 +792,6 @@ public:
} }
} }
// If this object is being removed, either permanently or just to refresh it, then all
// objects attached to it must be unparented else Irrlicht causes a segmentation fault.
for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++)
{
if(ii->Y == this->getId()) // This is a child of our parent
{
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
{
if(permanent)
{
// The parent is being permanently removed, so the child stays detached
ii->Y = 0;
obj->updateParent();
}
else
{
// The parent is being refreshed, detach our child enough to avoid bad memory reads
// This only stays into effect for a few frames, as addToScene will parent its children back
scene::IMeshSceneNode *m_child_meshnode = obj->getMeshSceneNode();
scene::IAnimatedMeshSceneNode *m_child_animated_meshnode = obj->getAnimatedMeshSceneNode();
scene::IBillboardSceneNode *m_child_spritenode = obj->getSpriteSceneNode();
if(m_child_meshnode)
m_child_meshnode->setParent(m_smgr->getRootSceneNode());
if(m_child_animated_meshnode)
m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode());
if(m_child_spritenode)
m_child_spritenode->setParent(m_smgr->getRootSceneNode());
}
}
}
}
if(m_meshnode){ if(m_meshnode){
m_meshnode->remove(); m_meshnode->remove();
m_meshnode = NULL; m_meshnode = NULL;
@ -836,18 +812,6 @@ public:
m_smgr = smgr; m_smgr = smgr;
m_irr = irr; m_irr = irr;
// If this object has attachments and is being re-added after having been refreshed, parent its children back.
// The parent ID for this child hasn't been changed in attachment_list, so just update its attachments.
for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++)
{
if(ii->Y == this->getId()) // This is a child of our parent
{
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
obj->updateParent();
}
}
if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL) if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL)
return; return;
@ -1074,14 +1038,45 @@ public:
if(m_visuals_expired && m_smgr && m_irr){ if(m_visuals_expired && m_smgr && m_irr){
m_visuals_expired = false; m_visuals_expired = false;
// Attachments, part 1: All attached objects must be unparented first, or Irrlicht causes a segmentation fault
for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++)
{
if(ii->Y == this->getId()) // This is a child of our parent
{
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
{
scene::IMeshSceneNode *m_child_meshnode = obj->getMeshSceneNode();
scene::IAnimatedMeshSceneNode *m_child_animated_meshnode = obj->getAnimatedMeshSceneNode();
scene::IBillboardSceneNode *m_child_spritenode = obj->getSpriteSceneNode();
if(m_child_meshnode)
m_child_meshnode->setParent(m_smgr->getRootSceneNode());
if(m_child_animated_meshnode)
m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode());
if(m_child_spritenode)
m_child_spritenode->setParent(m_smgr->getRootSceneNode());
}
}
}
removeFromScene(false); removeFromScene(false);
addToScene(m_smgr, m_gamedef->tsrc(), m_irr); addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
updateAnimations(); updateAnimations();
updateBonePosRot(); updateBonePosRot();
updateAttachments(); updateAttachments();
return;
}
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
for(std::vector<core::vector2d<int> >::iterator ii = attachment_list.begin(); ii != attachment_list.end(); ii++)
{
if(ii->Y == this->getId()) // This is a child of our parent
{
ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child
if(obj)
obj->updateParent();
}
}
}
if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
{ {
// Set these for later // Set these for later
@ -1093,6 +1088,12 @@ public:
m_position = m_spritenode->getAbsolutePosition(); m_position = m_spritenode->getAbsolutePosition();
m_velocity = v3f(0,0,0); m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0); m_acceleration = v3f(0,0,0);
if(m_is_local_player) // Update local player attachment position
{
LocalPlayer *player = m_env->getLocalPlayer();
player->overridePosition = getParent()->getPosition();
}
} }
else else
{ {
@ -1422,6 +1423,11 @@ public:
m_spritenode->setRotation(old_rotation); m_spritenode->setRotation(old_rotation);
m_spritenode->updateAbsolutePosition(); m_spritenode->updateAbsolutePosition();
} }
if(m_is_local_player)
{
LocalPlayer *player = m_env->getLocalPlayer();
player->isAttached = false;
}
} }
else // Attach else // Attach
{ {
@ -1528,6 +1534,12 @@ public:
} }
} }
} }
if(m_is_local_player)
{
LocalPlayer *player = m_env->getLocalPlayer();
player->isAttached = true;
player->overridePosition = m_attachment_position;
}
} }
} }
@ -1557,7 +1569,8 @@ public:
} }
else if(cmd == GENERIC_CMD_UPDATE_POSITION) else if(cmd == GENERIC_CMD_UPDATE_POSITION)
{ {
// Not sent by the server if the object is an attachment // Not sent by the server if this object is an attachment.
// We might however get here if the server notices the object being detached before the client.
m_position = readV3F1000(is); m_position = readV3F1000(is);
m_velocity = readV3F1000(is); m_velocity = readV3F1000(is);
m_acceleration = readV3F1000(is); m_acceleration = readV3F1000(is);
@ -1567,14 +1580,14 @@ public:
bool is_end_position = readU8(is); bool is_end_position = readU8(is);
float update_interval = readF1000(is); float update_interval = readF1000(is);
if(getParent() != NULL) // Just in case
return;
// Place us a bit higher if we're physical, to not sink into // Place us a bit higher if we're physical, to not sink into
// the ground due to sucky collision detection... // the ground due to sucky collision detection...
if(m_prop.physical) if(m_prop.physical)
m_position += v3f(0,0.002,0); m_position += v3f(0,0.002,0);
if(getParent() != NULL) // Just in case
return;
if(do_interpolate){ if(do_interpolate){
if(!m_prop.physical) if(!m_prop.physical)
pos_translator.update(m_position, is_end_position, update_interval); pos_translator.update(m_position, is_end_position, update_interval);

@ -218,7 +218,6 @@ public:
if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS) if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
{ {
// TODO: We shouldn't be sending this when the object is attached, but we can't check m_parent here
setBasePosition(pos_f); setBasePosition(pos_f);
m_last_sent_position = pos_f; m_last_sent_position = pos_f;
@ -387,7 +386,6 @@ void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
// Create entity from name // Create entity from name
lua_State *L = m_env->getLua(); lua_State *L = m_env->getLua();
m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str()); m_registered = scriptapi_luaentity_add(L, m_id, m_init_name.c_str());
m_parent = NULL;
if(m_registered){ if(m_registered){
// Get properties // Get properties
@ -434,6 +432,17 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
return sao; 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) void LuaEntitySAO::step(float dtime, bool send_recommended)
{ {
if(!m_properties_sent) if(!m_properties_sent)
@ -445,13 +454,23 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
m_messages_out.push_back(aom); 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; m_last_sent_position_timer += dtime;
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // 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 the object gets detached this comes into effect automatically from the last known origin
if(m_parent != NULL) if(isAttached())
{ {
v3f pos = m_parent->getBasePosition(); v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
m_base_position = pos; m_base_position = pos;
m_velocity = v3f(0,0,0); m_velocity = v3f(0,0,0);
m_acceleration = v3f(0,0,0); m_acceleration = v3f(0,0,0);
@ -491,7 +510,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
if(send_recommended == false) if(send_recommended == false)
return; return;
if(m_parent != NULL) if(!isAttached())
{ {
// TODO: force send when acceleration changes enough? // TODO: force send when acceleration changes enough?
float minchange = 0.2*BS; float minchange = 0.2*BS;
@ -608,7 +627,7 @@ int LuaEntitySAO::punch(v3f dir,
} }
// It's best that attachments cannot be punched // It's best that attachments cannot be punched
if(m_parent != NULL) if(isAttached())
return 0; return 0;
ItemStack *punchitem = NULL; ItemStack *punchitem = NULL;
@ -660,7 +679,7 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
void LuaEntitySAO::setPos(v3f pos) void LuaEntitySAO::setPos(v3f pos)
{ {
if(m_parent != NULL) if(isAttached())
return; return;
m_base_position = pos; m_base_position = pos;
sendPosition(false, true); sendPosition(false, true);
@ -668,7 +687,7 @@ void LuaEntitySAO::setPos(v3f pos)
void LuaEntitySAO::moveTo(v3f pos, bool continuous) void LuaEntitySAO::moveTo(v3f pos, bool continuous)
{ {
if(m_parent != NULL) if(isAttached())
return; return;
m_base_position = pos; m_base_position = pos;
if(!continuous) if(!continuous)
@ -722,7 +741,7 @@ void LuaEntitySAO::setBonePosRot(std::string bone, v3f position, v3f rotation)
m_animations_bone_sent = false; m_animations_bone_sent = false;
} }
void LuaEntitySAO::setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation) void LuaEntitySAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
{ {
// Attachments need to be handled on both the server and client. // 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 // If we just attach on the server, we can only copy the position of the parent. Attachments
@ -732,11 +751,7 @@ void LuaEntitySAO::setAttachment(ServerActiveObject *parent, std::string bone, v
// This breaks some things so we also give the server the most accurate representation // This breaks some things so we also give the server the most accurate representation
// even if players only see the client changes. // even if players only see the client changes.
// Server attachment: m_attachment_parent_id = parent_id;
m_parent = parent;
// Client attachment:
m_attachment_parent_id = parent->getId();
m_attachment_bone = bone; m_attachment_bone = bone;
m_attachment_position = position; m_attachment_position = position;
m_attachment_rotation = rotation; m_attachment_rotation = rotation;
@ -818,7 +833,7 @@ std::string LuaEntitySAO::getPropertyPacket()
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) 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 the object is attached client-side, don't waste bandwidth sending its position to clients
if(m_parent != NULL) if(isAttached())
return; return;
m_last_sent_move_precision = m_base_position.getDistanceFrom( m_last_sent_move_precision = m_base_position.getDistanceFrom(
@ -872,7 +887,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
m_animations_bone_sent(false), m_animations_bone_sent(false),
m_attachment_sent(false), m_attachment_sent(false),
// public // public
m_teleported(false), m_moved(false),
m_inventory_not_sent(false), m_inventory_not_sent(false),
m_hp_not_sent(false), m_hp_not_sent(false),
m_wielded_item_not_sent(false) m_wielded_item_not_sent(false)
@ -919,7 +934,6 @@ void PlayerSAO::addedToEnvironment(u32 dtime_s)
{ {
ServerActiveObject::addedToEnvironment(dtime_s); ServerActiveObject::addedToEnvironment(dtime_s);
ServerActiveObject::setBasePosition(m_player->getPosition()); ServerActiveObject::setBasePosition(m_player->getPosition());
m_parent = NULL;
m_player->setPlayerSAO(this); m_player->setPlayerSAO(this);
m_player->peer_id = m_peer_id; m_player->peer_id = m_peer_id;
m_last_good_position = m_player->getPosition(); m_last_good_position = m_player->getPosition();
@ -979,6 +993,17 @@ std::string PlayerSAO::getStaticData()
return ""; return "";
} }
bool PlayerSAO::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 PlayerSAO::step(float dtime, bool send_recommended) void PlayerSAO::step(float dtime, bool send_recommended)
{ {
if(!m_properties_sent) if(!m_properties_sent)
@ -990,14 +1015,25 @@ void PlayerSAO::step(float dtime, bool send_recommended)
m_messages_out.push_back(aom); 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_time_from_last_punch += dtime;
m_nocheat_dig_time += dtime; m_nocheat_dig_time += dtime;
// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // 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 the object gets detached this comes into effect automatically from the last known origin
if(m_parent != NULL) if(isAttached())
{ {
v3f pos = m_parent->getBasePosition(); v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
m_last_good_position = pos; m_last_good_position = pos;
m_last_good_position_age = 0; m_last_good_position_age = 0;
m_player->setPosition(pos); m_player->setPosition(pos);
@ -1053,7 +1089,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
<<" moved too fast; resetting position" <<" moved too fast; resetting position"
<<std::endl; <<std::endl;
m_player->setPosition(m_last_good_position); m_player->setPosition(m_last_good_position);
m_teleported = true; m_moved = true;
} }
m_last_good_position_age = 0; m_last_good_position_age = 0;
} }
@ -1064,13 +1100,13 @@ void PlayerSAO::step(float dtime, bool send_recommended)
return; return;
// If the object is attached client-side, don't waste bandwidth sending its position to clients // If the object is attached client-side, don't waste bandwidth sending its position to clients
if(m_position_not_sent && m_parent == NULL) if(m_position_not_sent && !isAttached())
{ {
m_position_not_sent = false; m_position_not_sent = false;
float update_interval = m_env->getSendRecommendedInterval(); float update_interval = m_env->getSendRecommendedInterval();
v3f pos; v3f pos;
if(m_parent != NULL) // Just in case we ever do send attachment position too if(isAttached()) // Just in case we ever do send attachment position too
pos = m_parent->getBasePosition(); pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
else else
pos = m_player->getPosition() + v3f(0,BS*1,0); pos = m_player->getPosition() + v3f(0,BS*1,0);
std::string str = gob_cmd_update_position( std::string str = gob_cmd_update_position(
@ -1138,26 +1174,26 @@ void PlayerSAO::setBasePosition(const v3f &position)
void PlayerSAO::setPos(v3f pos) void PlayerSAO::setPos(v3f pos)
{ {
if(m_parent != NULL) if(isAttached())
return; return;
m_player->setPosition(pos); m_player->setPosition(pos);
// Movement caused by this command is always valid // Movement caused by this command is always valid
m_last_good_position = pos; m_last_good_position = pos;
m_last_good_position_age = 0; m_last_good_position_age = 0;
// Force position change on client // Force position change on client
m_teleported = true; m_moved = true;
} }
void PlayerSAO::moveTo(v3f pos, bool continuous) void PlayerSAO::moveTo(v3f pos, bool continuous)
{ {
if(m_parent != NULL) if(isAttached())
return; return;
m_player->setPosition(pos); m_player->setPosition(pos);
// Movement caused by this command is always valid // Movement caused by this command is always valid
m_last_good_position = pos; m_last_good_position = pos;
m_last_good_position_age = 0; m_last_good_position_age = 0;
// Force position change on client // Force position change on client
m_teleported = true; m_moved = true;
} }
int PlayerSAO::punch(v3f dir, int PlayerSAO::punch(v3f dir,
@ -1166,7 +1202,7 @@ int PlayerSAO::punch(v3f dir,
float time_from_last_punch) float time_from_last_punch)
{ {
// It's best that attachments cannot be punched // It's best that attachments cannot be punched
if(m_parent != NULL) if(isAttached())
return 0; return 0;
if(!toolcap) if(!toolcap)
@ -1266,7 +1302,7 @@ void PlayerSAO::setBonePosRot(std::string bone, v3f position, v3f rotation)
m_animations_bone_sent = false; m_animations_bone_sent = false;
} }
void PlayerSAO::setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation) void PlayerSAO::setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
{ {
// Attachments need to be handled on both the server and client. // 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 // If we just attach on the server, we can only copy the position of the parent. Attachments
@ -1276,11 +1312,7 @@ void PlayerSAO::setAttachment(ServerActiveObject *parent, std::string bone, v3f
// This breaks some things so we also give the server the most accurate representation // This breaks some things so we also give the server the most accurate representation
// even if players only see the client changes. // even if players only see the client changes.
// Server attachment: m_attachment_parent_id = parent_id;
m_parent = parent;
// Client attachment:
m_attachment_parent_id = parent->getId();
m_attachment_bone = bone; m_attachment_bone = bone;
m_attachment_position = position; m_attachment_position = position;
m_attachment_rotation = rotation; m_attachment_rotation = rotation;

@ -46,6 +46,7 @@ public:
virtual void addedToEnvironment(u32 dtime_s); virtual void addedToEnvironment(u32 dtime_s);
static ServerActiveObject* create(ServerEnvironment *env, v3f pos, static ServerActiveObject* create(ServerEnvironment *env, v3f pos,
const std::string &data); const std::string &data);
bool isAttached();
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
@ -63,7 +64,7 @@ public:
void setArmorGroups(const ItemGroupList &armor_groups); void setArmorGroups(const ItemGroupList &armor_groups);
void setAnimations(v2f frames, float frame_speed, float frame_blend); void setAnimations(v2f frames, float frame_speed, float frame_blend);
void setBonePosRot(std::string bone, v3f position, v3f rotation); void setBonePosRot(std::string bone, v3f position, v3f rotation);
void setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation); void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
ObjectProperties* accessObjectProperties(); ObjectProperties* accessObjectProperties();
void notifyObjectPropertiesModified(); void notifyObjectPropertiesModified();
/* LuaEntitySAO-specific */ /* LuaEntitySAO-specific */
@ -108,7 +109,6 @@ private:
std::map<std::string, core::vector2d<v3f> > m_animation_bone; std::map<std::string, core::vector2d<v3f> > m_animation_bone;
bool m_animations_bone_sent; bool m_animations_bone_sent;
ServerActiveObject *m_parent;
int m_attachment_parent_id; int m_attachment_parent_id;
std::string m_attachment_bone; std::string m_attachment_bone;
v3f m_attachment_position; v3f m_attachment_position;
@ -142,6 +142,7 @@ public:
bool unlimitedTransferDistance() const; bool unlimitedTransferDistance() const;
std::string getClientInitializationData(); std::string getClientInitializationData();
std::string getStaticData(); std::string getStaticData();
bool isAttached();
void step(float dtime, bool send_recommended); void step(float dtime, bool send_recommended);
void setBasePosition(const v3f &position); void setBasePosition(const v3f &position);
void setPos(v3f pos); void setPos(v3f pos);
@ -162,7 +163,7 @@ public:
void setArmorGroups(const ItemGroupList &armor_groups); void setArmorGroups(const ItemGroupList &armor_groups);
void setAnimations(v2f frames, float frame_speed, float frame_blend); void setAnimations(v2f frames, float frame_speed, float frame_blend);
void setBonePosRot(std::string bone, v3f position, v3f rotation); void setBonePosRot(std::string bone, v3f position, v3f rotation);
void setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation); void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation);
ObjectProperties* accessObjectProperties(); ObjectProperties* accessObjectProperties();
void notifyObjectPropertiesModified(); void notifyObjectPropertiesModified();
@ -267,7 +268,6 @@ private:
std::map<std::string, core::vector2d<v3f> > m_animation_bone; // stores position and rotation for each bone name std::map<std::string, core::vector2d<v3f> > m_animation_bone; // stores position and rotation for each bone name
bool m_animations_bone_sent; bool m_animations_bone_sent;
ServerActiveObject *m_parent;
int m_attachment_parent_id; int m_attachment_parent_id;
std::string m_attachment_bone; std::string m_attachment_bone;
v3f m_attachment_position; v3f m_attachment_position;
@ -276,7 +276,7 @@ private:
public: public:
// Some flags used by Server // Some flags used by Server
bool m_teleported; bool m_moved;
bool m_inventory_not_sent; bool m_inventory_not_sent;
bool m_hp_not_sent; bool m_hp_not_sent;
bool m_wielded_item_not_sent; bool m_wielded_item_not_sent;

@ -714,7 +714,6 @@ void GUIFormSpecMenu::drawMenu()
Draw backgrounds Draw backgrounds
*/ */
for(u32 i=0; i<m_backgrounds.size(); i++) for(u32 i=0; i<m_backgrounds.size(); i++)
{
const ImageDrawSpec &spec = m_backgrounds[i]; const ImageDrawSpec &spec = m_backgrounds[i];
video::ITexture *texture = video::ITexture *texture =
m_gamedef->tsrc()->getTextureRaw(spec.name); m_gamedef->tsrc()->getTextureRaw(spec.name);
@ -728,7 +727,6 @@ void GUIFormSpecMenu::drawMenu()
core::rect<s32>(core::position2d<s32>(0,0), core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())), core::dimension2di(texture->getOriginalSize())),
NULL/*&AbsoluteClippingRect*/, colors, true); NULL/*&AbsoluteClippingRect*/, colors, true);
}
/* /*
Draw images Draw images

@ -53,6 +53,13 @@ LocalPlayer::~LocalPlayer()
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d, void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
core::list<CollisionInfo> *collision_info) core::list<CollisionInfo> *collision_info)
{ {
// Copy parent position if local player is attached
if(isAttached)
{
setPosition(overridePosition);
return;
}
INodeDefManager *nodemgr = m_gamedef->ndef(); INodeDefManager *nodemgr = m_gamedef->ndef();
v3f position = getPosition(); v3f position = getPosition();

@ -80,6 +80,10 @@ public:
return true; return true;
} }
bool isAttached;
v3f overridePosition;
void move(f32 dtime, Map &map, f32 pos_max_d, void move(f32 dtime, Map &map, f32 pos_max_d,
core::list<CollisionInfo> *collision_info); core::list<CollisionInfo> *collision_info);
void move(f32 dtime, Map &map, f32 pos_max_d); void move(f32 dtime, Map &map, f32 pos_max_d);

@ -2723,7 +2723,6 @@ private:
ServerActiveObject *co = getobject(ref); ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0; if(co == NULL) return 0;
// Do it // Do it
v2f frames = v2f(1, 1); v2f frames = v2f(1, 1);
if(!lua_isnil(L, 2)) if(!lua_isnil(L, 2))
frames = read_v2f(L, 2); frames = read_v2f(L, 2);
@ -2744,7 +2743,6 @@ private:
ServerActiveObject *co = getobject(ref); ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0; if(co == NULL) return 0;
// Do it // Do it
std::string bone = ""; std::string bone = "";
if(!lua_isnil(L, 2)) if(!lua_isnil(L, 2))
bone = lua_tostring(L, 2); bone = lua_tostring(L, 2);
@ -2767,6 +2765,7 @@ private:
ServerActiveObject *parent = getobject(parent_ref); ServerActiveObject *parent = getobject(parent_ref);
if(co == NULL) return 0; if(co == NULL) return 0;
if(parent == NULL) return 0; if(parent == NULL) return 0;
// Do it
std::string bone = ""; std::string bone = "";
if(!lua_isnil(L, 3)) if(!lua_isnil(L, 3))
bone = lua_tostring(L, 3); bone = lua_tostring(L, 3);
@ -2776,9 +2775,18 @@ private:
v3f rotation = v3f(0, 0, 0); v3f rotation = v3f(0, 0, 0);
if(!lua_isnil(L, 5)) if(!lua_isnil(L, 5))
rotation = read_v3f(L, 5); rotation = read_v3f(L, 5);
// Do it co->setAttachment(parent->getId(), bone, position, rotation);
return 0;
}
co->setAttachment(parent, bone, position, rotation); // set_detachment(self)
static int l_set_detachment(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
if(co == NULL) return 0;
// Do it
co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
return 0; return 0;
} }
@ -3099,6 +3107,7 @@ const luaL_reg ObjectRef::methods[] = {
method(ObjectRef, set_animations), method(ObjectRef, set_animations),
method(ObjectRef, set_bone_posrot), method(ObjectRef, set_bone_posrot),
method(ObjectRef, set_attachment), method(ObjectRef, set_attachment),
method(ObjectRef, set_detachment),
method(ObjectRef, set_properties), method(ObjectRef, set_properties),
// LuaEntitySAO-only // LuaEntitySAO-only
method(ObjectRef, setvelocity), method(ObjectRef, setvelocity),

@ -1371,9 +1371,9 @@ void Server::AsyncRunStep()
/* /*
Send player inventories and HPs if necessary Send player inventories and HPs if necessary
*/ */
if(playersao->m_teleported){ if(playersao->m_moved){
SendMovePlayer(client->peer_id); SendMovePlayer(client->peer_id);
playersao->m_teleported = false; playersao->m_moved = false;
} }
if(playersao->m_inventory_not_sent){ if(playersao->m_inventory_not_sent){
UpdateCrafting(client->peer_id); UpdateCrafting(client->peer_id);

@ -156,7 +156,7 @@ public:
{} {}
virtual void setBonePosRot(std::string bone, v3f position, v3f rotation) virtual void setBonePosRot(std::string bone, v3f position, v3f rotation)
{} {}
virtual void setAttachment(ServerActiveObject *parent, std::string bone, v3f position, v3f rotation) virtual void setAttachment(int parent_id, std::string bone, v3f position, v3f rotation)
{} {}
virtual ObjectProperties* accessObjectProperties() virtual ObjectProperties* accessObjectProperties()
{ return NULL; } { return NULL; }