Skip to content

Commit ba91624

Browse files
authoredApr 30, 2018
Allow damage for attached objects, add attach/detach callbacks (#6786)
* Allow right-clicking on attached LuaEntities
1 parent 0b5b32b commit ba91624

9 files changed

+133
-75
lines changed
 

‎doc/lua_api.txt

+7
Original file line numberDiff line numberDiff line change
@@ -4868,6 +4868,13 @@ Registered entities
48684868
* Called when the object dies.
48694869
* `killer`: an `ObjectRef` (can be `nil`)
48704870
* `on_rightclick(self, clicker)`
4871+
* `on_attach_child(self, child)`
4872+
* `child`: an `ObjectRef` (can be `nil`) of the child that attaches
4873+
* `on_detach_child(self, child)`
4874+
* `child`: an `ObjectRef` (can be `nil`) of the child that detaches
4875+
* `on_detach(self, parent)`
4876+
* `parent`: an `ObjectRef` (can be `nil`) from where it got detached
4877+
* This happens before the parent object is removed from the world
48714878
* `get_staticdata(self)`
48724879
* Should return a string that will be passed to `on_activate` when
48734880
the object is instantiated the next time.

‎src/content_cao.cpp

+13-11
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ GenericCAO::~GenericCAO()
343343
bool GenericCAO::getSelectionBox(aabb3f *toset) const
344344
{
345345
if (!m_prop.is_visible || !m_is_visible || m_is_local_player
346-
|| !m_prop.pointable || getParent() != NULL) {
346+
|| !m_prop.pointable) {
347347
return false;
348348
}
349349
*toset = m_selection_box;
@@ -430,6 +430,7 @@ void GenericCAO::removeFromScene(bool permanent)
430430
m_env->attachement_parent_ids[ci] = 0;
431431
}
432432
}
433+
m_children.clear();
433434

434435
m_env->attachement_parent_ids[getId()] = 0;
435436

@@ -1409,17 +1410,18 @@ void GenericCAO::processMessage(const std::string &data)
14091410

14101411
updateBonePosition();
14111412
} else if (cmd == GENERIC_CMD_ATTACH_TO) {
1412-
u16 parentID = readS16(is);
1413-
u16 oldparent = m_env->attachement_parent_ids[getId()];
1414-
if (oldparent) {
1415-
m_children.erase(std::remove(m_children.begin(), m_children.end(),
1416-
getId()), m_children.end());
1417-
}
1418-
m_env->attachement_parent_ids[getId()] = parentID;
1419-
GenericCAO *parentobj = m_env->getGenericCAO(parentID);
1413+
u16 parent_id = readS16(is);
1414+
u16 &old_parent_id = m_env->attachement_parent_ids[getId()];
1415+
if (parent_id != old_parent_id) {
1416+
if (GenericCAO *old_parent = m_env->getGenericCAO(old_parent_id)) {
1417+
old_parent->m_children.erase(std::remove(
1418+
m_children.begin(), m_children.end(),
1419+
getId()), m_children.end());
1420+
}
1421+
if (GenericCAO *new_parent = m_env->getGenericCAO(parent_id))
1422+
new_parent->m_children.push_back(getId());
14201423

1421-
if (parentobj) {
1422-
parentobj->m_children.push_back(getId());
1424+
old_parent_id = parent_id;
14231425
}
14241426

14251427
m_attachment_bone = deSerializeString(is);

‎src/content_sao.cpp

+66-12
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,17 @@ void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position
187187
// This breaks some things so we also give the server the most accurate representation
188188
// even if players only see the client changes.
189189

190+
int old_parent = m_attachment_parent_id;
190191
m_attachment_parent_id = parent_id;
191192
m_attachment_bone = bone;
192193
m_attachment_position = position;
193194
m_attachment_rotation = rotation;
194195
m_attachment_sent = false;
196+
197+
if (parent_id != old_parent) {
198+
onDetach(old_parent);
199+
onAttach(parent_id);
200+
}
195201
}
196202

197203
void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
@@ -203,6 +209,30 @@ void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
203209
*rotation = m_attachment_rotation;
204210
}
205211

212+
void UnitSAO::clearChildAttachments()
213+
{
214+
for (int child_id : m_attachment_child_ids) {
215+
// Child can be NULL if it was deleted earlier
216+
if (ServerActiveObject *child = m_env->getActiveObject(child_id))
217+
child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
218+
}
219+
m_attachment_child_ids.clear();
220+
}
221+
222+
void UnitSAO::clearParentAttachment()
223+
{
224+
ServerActiveObject *parent = nullptr;
225+
if (m_attachment_parent_id) {
226+
parent = m_env->getActiveObject(m_attachment_parent_id);
227+
setAttachment(0, "", m_attachment_position, m_attachment_rotation);
228+
} else {
229+
setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
230+
}
231+
// Do it
232+
if (parent)
233+
parent->removeAttachmentChild(m_id);
234+
}
235+
206236
void UnitSAO::addAttachmentChild(int child_id)
207237
{
208238
m_attachment_child_ids.insert(child_id);
@@ -218,6 +248,38 @@ const std::unordered_set<int> &UnitSAO::getAttachmentChildIds()
218248
return m_attachment_child_ids;
219249
}
220250

251+
void UnitSAO::onAttach(int parent_id)
252+
{
253+
if (!parent_id)
254+
return;
255+
256+
ServerActiveObject *parent = m_env->getActiveObject(parent_id);
257+
258+
if (!parent || parent->isGone())
259+
return; // Do not try to notify soon gone parent
260+
261+
if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY) {
262+
// Call parent's on_attach field
263+
m_env->getScriptIface()->luaentity_on_attach_child(parent_id, this);
264+
}
265+
}
266+
267+
void UnitSAO::onDetach(int parent_id)
268+
{
269+
if (!parent_id)
270+
return;
271+
272+
ServerActiveObject *parent = m_env->getActiveObject(parent_id);
273+
if (getType() == ACTIVEOBJECT_TYPE_LUAENTITY)
274+
m_env->getScriptIface()->luaentity_on_detach(m_id, parent);
275+
276+
if (!parent || parent->isGone())
277+
return; // Do not try to notify soon gone parent
278+
279+
if (parent->getType() == ACTIVEOBJECT_TYPE_LUAENTITY)
280+
m_env->getScriptIface()->luaentity_on_detach_child(parent_id, this);
281+
}
282+
221283
ObjectProperties* UnitSAO::accessObjectProperties()
222284
{
223285
return &m_prop;
@@ -548,10 +610,6 @@ int LuaEntitySAO::punch(v3f dir,
548610
return 0;
549611
}
550612

551-
// It's best that attachments cannot be punched
552-
if (isAttached())
553-
return 0;
554-
555613
ItemStack *punchitem = NULL;
556614
ItemStack punchitem_static;
557615
if (puncher) {
@@ -588,8 +646,10 @@ int LuaEntitySAO::punch(v3f dir,
588646
}
589647
}
590648

591-
if (getHP() == 0) {
649+
if (getHP() == 0 && !isGone()) {
592650
m_pending_removal = true;
651+
clearParentAttachment();
652+
clearChildAttachments();
593653
m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
594654
}
595655

@@ -600,9 +660,7 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
600660
{
601661
if (!m_registered)
602662
return;
603-
// It's best that attachments cannot be clicked
604-
if (isAttached())
605-
return;
663+
606664
m_env->getScriptIface()->luaentity_Rightclick(m_id, clicker);
607665
}
608666

@@ -1187,10 +1245,6 @@ int PlayerSAO::punch(v3f dir,
11871245
ServerActiveObject *puncher,
11881246
float time_from_last_punch)
11891247
{
1190-
// It's best that attachments cannot be punched
1191-
if (isAttached())
1192-
return 0;
1193-
11941248
if (!toolcap)
11951249
return 0;
11961250

‎src/content_sao.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class UnitSAO: public ServerActiveObject
5252
void getBonePosition(const std::string &bone, v3f *position, v3f *rotation);
5353
void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
5454
void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation);
55+
void clearChildAttachments();
56+
void clearParentAttachment();
5557
void addAttachmentChild(int child_id);
5658
void removeAttachmentChild(int child_id);
5759
const std::unordered_set<int> &getAttachmentChildIds();
@@ -72,7 +74,7 @@ class UnitSAO: public ServerActiveObject
7274
float m_animation_blend = 0.0f;
7375
bool m_animation_loop = true;
7476
bool m_animation_sent = false;
75-
bool m_animation_speed_sent = false;
77+
bool m_animation_speed_sent = false;
7678

7779
// Stores position and rotation for each bone name
7880
std::unordered_map<std::string, core::vector2d<v3f>> m_bone_position;
@@ -84,6 +86,9 @@ class UnitSAO: public ServerActiveObject
8486
v3f m_attachment_position;
8587
v3f m_attachment_rotation;
8688
bool m_attachment_sent = false;
89+
private:
90+
void onAttach(int parent_id);
91+
void onDetach(int parent_id);
8792
};
8893

8994
/*

‎src/script/cpp_api/s_entity.cpp

+25-28
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,9 @@ bool ScriptApiEntity::luaentity_Punch(u16 id,
262262
return retval;
263263
}
264264

265-
bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
265+
// Calls entity[field](ObjectRef self, ObjectRef sao)
266+
bool ScriptApiEntity::luaentity_run_simple_callback(u16 id,
267+
ServerActiveObject *sao, const char *field)
266268
{
267269
SCRIPTAPI_PRECHECKHEADER
268270

@@ -273,14 +275,14 @@ bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
273275
int object = lua_gettop(L);
274276
// State: object is at top of stack
275277
// Get function
276-
lua_getfield(L, -1, "on_death");
278+
lua_getfield(L, -1, field);
277279
if (lua_isnil(L, -1)) {
278-
lua_pop(L, 2); // Pop on_death and entity
280+
lua_pop(L, 2); // Pop callback field and entity
279281
return false;
280282
}
281283
luaL_checktype(L, -1, LUA_TFUNCTION);
282284
lua_pushvalue(L, object); // self
283-
objectrefGetOrCreate(L, killer); // killer reference
285+
objectrefGetOrCreate(L, sao); // killer reference
284286

285287
setOriginFromTable(object);
286288
PCALL_RES(lua_pcall(L, 2, 1, error_handler));
@@ -290,33 +292,28 @@ bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
290292
return retval;
291293
}
292294

293-
// Calls entity:on_rightclick(ObjectRef clicker)
294-
void ScriptApiEntity::luaentity_Rightclick(u16 id,
295-
ServerActiveObject *clicker)
295+
bool ScriptApiEntity::luaentity_on_death(u16 id, ServerActiveObject *killer)
296296
{
297-
SCRIPTAPI_PRECHECKHEADER
298-
299-
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
300-
301-
int error_handler = PUSH_ERROR_HANDLER(L);
297+
return luaentity_run_simple_callback(id, killer, "on_death");
298+
}
302299

303-
// Get core.luaentities[id]
304-
luaentity_get(L, id);
305-
int object = lua_gettop(L);
306-
// State: object is at top of stack
307-
// Get function
308-
lua_getfield(L, -1, "on_rightclick");
309-
if (lua_isnil(L, -1)) {
310-
lua_pop(L, 2); // Pop on_rightclick and entity
311-
return;
312-
}
313-
luaL_checktype(L, -1, LUA_TFUNCTION);
314-
lua_pushvalue(L, object); // self
315-
objectrefGetOrCreate(L, clicker); // Clicker reference
300+
// Calls entity:on_rightclick(ObjectRef clicker)
301+
void ScriptApiEntity::luaentity_Rightclick(u16 id, ServerActiveObject *clicker)
302+
{
303+
luaentity_run_simple_callback(id, clicker, "on_rightclick");
304+
}
316305

317-
setOriginFromTable(object);
318-
PCALL_RES(lua_pcall(L, 2, 0, error_handler));
306+
void ScriptApiEntity::luaentity_on_attach_child(u16 id, ServerActiveObject *child)
307+
{
308+
luaentity_run_simple_callback(id, child, "on_attach_child");
309+
}
319310

320-
lua_pop(L, 2); // Pop object and error handler
311+
void ScriptApiEntity::luaentity_on_detach_child(u16 id, ServerActiveObject *child)
312+
{
313+
luaentity_run_simple_callback(id, child, "on_detach_child");
321314
}
322315

316+
void ScriptApiEntity::luaentity_on_detach(u16 id, ServerActiveObject *parent)
317+
{
318+
luaentity_run_simple_callback(id, parent, "on_detach");
319+
}

‎src/script/cpp_api/s_entity.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ class ScriptApiEntity
4141
ServerActiveObject *puncher, float time_from_last_punch,
4242
const ToolCapabilities *toolcap, v3f dir, s16 damage);
4343
bool luaentity_on_death(u16 id, ServerActiveObject *killer);
44-
void luaentity_Rightclick(u16 id,
45-
ServerActiveObject *clicker);
44+
void luaentity_Rightclick(u16 id, ServerActiveObject *clicker);
45+
void luaentity_on_attach_child(u16 id, ServerActiveObject *child);
46+
void luaentity_on_detach_child(u16 id, ServerActiveObject *child);
47+
void luaentity_on_detach(u16 id, ServerActiveObject *parent);
48+
private:
49+
bool luaentity_run_simple_callback(u16 id, ServerActiveObject *sao,
50+
const char *field);
4651
};

‎src/script/lua_api/l_object.cpp

+3-21
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,8 @@ int ObjectRef::l_remove(lua_State *L)
103103
if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
104104
return 0;
105105

106-
const std::unordered_set<int> &child_ids = co->getAttachmentChildIds();
107-
for (int child_id : child_ids) {
108-
// Child can be NULL if it was deleted earlier
109-
if (ServerActiveObject *child = env->getActiveObject(child_id))
110-
child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
111-
}
106+
co->clearChildAttachments();
107+
co->clearParentAttachment();
112108

113109
verbosestream << "ObjectRef::l_remove(): id=" << co->getId() << std::endl;
114110
co->m_pending_removal = true;
@@ -721,21 +717,7 @@ int ObjectRef::l_set_detach(lua_State *L)
721717
if (co == NULL)
722718
return 0;
723719

724-
int parent_id = 0;
725-
std::string bone;
726-
v3f position;
727-
v3f rotation;
728-
co->getAttachment(&parent_id, &bone, &position, &rotation);
729-
ServerActiveObject *parent = NULL;
730-
if (parent_id) {
731-
parent = env->getActiveObject(parent_id);
732-
co->setAttachment(0, "", position, rotation);
733-
} else {
734-
co->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
735-
}
736-
// Do it
737-
if (parent != NULL)
738-
parent->removeAttachmentChild(co->getId());
720+
co->clearParentAttachment();
739721
return 0;
740722
}
741723

‎src/server.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -2504,6 +2504,7 @@ void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
25042504
<< " dies" << std::endl;
25052505

25062506
playersao->setHP(0, reason);
2507+
playersao->clearParentAttachment();
25072508

25082509
// Trigger scripted stuff
25092510
m_script->on_dieplayer(playersao, reason);

‎src/serverobject.h

+5
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ class ServerActiveObject : public ActiveObject
165165
{}
166166
virtual void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation)
167167
{}
168+
virtual void clearChildAttachments() {}
169+
virtual void clearParentAttachment() {}
168170
virtual void addAttachmentChild(int child_id)
169171
{}
170172
virtual void removeAttachmentChild(int child_id)
@@ -250,6 +252,9 @@ class ServerActiveObject : public ActiveObject
250252
std::queue<ActiveObjectMessage> m_messages_out;
251253

252254
protected:
255+
virtual void onAttach(int parent_id) {}
256+
virtual void onDetach(int parent_id) {}
257+
253258
// Used for creating objects based on type
254259
typedef ServerActiveObject* (*Factory)
255260
(ServerEnvironment *env, v3f pos,

0 commit comments

Comments
 (0)
Please sign in to comment.