Skip to content

Commit

Permalink
Attachments: Fix attachments to temporary removed objects (#8989)
Browse files Browse the repository at this point in the history
Does not clear the parent's attachment information when the child is deleted locally.
Either it was removed permanently, or just temporary - we don't know, but it's up to the server to send a *detach from child" packet for the parent.
  • Loading branch information
SmallJoker authored Oct 2, 2019
1 parent 251038e commit 81c2370
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 31 deletions.
17 changes: 17 additions & 0 deletions src/client/clientenvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,23 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
}
}


void ClientEnvironment::removeActiveObject(u16 id)
{
// Get current attachment childs to detach them visually
std::unordered_set<int> attachment_childs;
if (auto *obj = getActiveObject(id))
attachment_childs = obj->getAttachmentChildIds();

m_ao_manager.removeObject(id);

// Perform a proper detach in Irrlicht
for (auto c_id : attachment_childs) {
if (ClientActiveObject *child = getActiveObject(c_id))
child->updateAttachments();
}
}

void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
{
ClientActiveObject *obj = getActiveObject(id);
Expand Down
5 changes: 1 addition & 4 deletions src/client/clientenvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,7 @@ class ClientEnvironment : public Environment
u16 addActiveObject(ClientActiveObject *object);

void addActiveObject(u16 id, u8 type, const std::string &init_data);
void removeActiveObject(u16 id)
{
m_ao_manager.removeObject(id);
}
void removeActiveObject(u16 id);

void processActiveObjectMessage(u16 id, const std::string &data);

Expand Down
19 changes: 14 additions & 5 deletions src/client/content_cao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,9 @@ void GenericCAO::removeFromScene(bool permanent)
// Should be true when removing the object permanently
// and false when refreshing (eg: updating visuals)
if (m_env && permanent) {
clearChildAttachments();
// The client does not know whether this object does re-appear to
// a later time, thus do not clear child attachments.

clearParentAttachment();
}

Expand Down Expand Up @@ -1330,10 +1332,17 @@ void GenericCAO::updateAttachments()

m_attached_to_local = parent && parent->isLocalPlayer();

if (!parent && m_attachment_parent_id) {
//m_is_visible = false; maybe later. needs better handling
return;
}
/*
Following cases exist:
m_attachment_parent_id == 0 && !parent
This object is not attached
m_attachment_parent_id != 0 && parent
This object is attached
m_attachment_parent_id != 0 && !parent
This object will be attached as soon the parent is known
m_attachment_parent_id == 0 && parent
Impossible case
*/

if (!parent) { // Detach or don't attach
if (m_matrixnode) {
Expand Down
5 changes: 5 additions & 0 deletions src/client/content_cao.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ class GenericCAO : public ClientActiveObject

const v3f getPosition() const;

void setPosition(const v3f &pos)
{
pos_translator.val_current = pos;
}

inline const v3f &getRotation() const { return m_rotation; }

const bool isImmortal();
Expand Down
10 changes: 5 additions & 5 deletions src/content_sao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1107,14 +1107,14 @@ void PlayerSAO::step(float dtime, bool send_recommended)
if (!send_recommended)
return;

// If the object is attached client-side, don't waste bandwidth sending its
// position or rotation to clients.
if (m_position_not_sent && !isAttached()) {
if (m_position_not_sent) {
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();
// When attached, the position is only sent to clients where the
// parent isn't known
if (isAttached())
pos = m_last_good_position;
else
pos = m_base_position;

Expand Down
45 changes: 28 additions & 17 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,19 +694,33 @@ void Server::AsyncRunStep(bool initial_step)
// Route data to every client
for (const auto &client_it : clients) {
RemoteClient *client = client_it.second;
PlayerSAO *player = getPlayerSAO(client->peer_id);
std::string reliable_data;
std::string unreliable_data;
// Go through all objects in message buffer
for (const auto &buffered_message : buffered_messages) {
// If object is not known by client, skip it
// If object does not exist or is not known by client, skip it
u16 id = buffered_message.first;
if (client->m_known_objects.find(id) == client->m_known_objects.end())
ServerActiveObject *sao = m_env->getActiveObject(id);
if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
continue;

// Get message list of object
std::vector<ActiveObjectMessage>* list = buffered_message.second;
// Go through every message
for (const ActiveObjectMessage &aom : *list) {
// Send position updates to players who do not see the attachment
if (aom.datastring[0] == GENERIC_CMD_UPDATE_POSITION) {
if (sao->getId() == player->getId())
continue;

// Do not send position updates for attached players
// as long the parent is known to the client
ServerActiveObject *parent = sao->getParent();
if (parent && client->m_known_objects.find(parent->getId()) !=
client->m_known_objects.end())
continue;
}
// Compose the full new data with header
std::string new_data;
// Add object id
Expand Down Expand Up @@ -1907,34 +1921,31 @@ void Server::SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersa
while (!added_objects.empty()) {
// Get object
u16 id = added_objects.front();
ServerActiveObject* obj = m_env->getActiveObject(id);
ServerActiveObject *obj = m_env->getActiveObject(id);
added_objects.pop();

if (!obj) {
warningstream << FUNCTION_NAME << ": NULL object id="
<< (int)id << std::endl;
continue;
}

// Get object type
u8 type = ACTIVEOBJECT_TYPE_INVALID;
if (!obj)
warningstream << FUNCTION_NAME << ": NULL object" << std::endl;
else
type = obj->getSendType();
u8 type = obj->getSendType();

// Add to data buffer for sending
writeU16((u8*)buf, id);
data.append(buf, 2);
writeU8((u8*)buf, type);
data.append(buf, 1);

if (obj)
data.append(serializeLongString(
obj->getClientInitializationData(client->net_proto_version)));
else
data.append(serializeLongString(""));
data.append(serializeLongString(
obj->getClientInitializationData(client->net_proto_version)));

// Add to known objects
client->m_known_objects.insert(id);

if (obj)
obj->m_known_by_count++;

added_objects.pop();
obj->m_known_by_count++;
}

NetworkPacket pkt(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, data.size(), client->peer_id);
Expand Down

0 comments on commit 81c2370

Please sign in to comment.