Attached particle spawners
authorraymoo <uguu@installgentoo.com>
Thu, 4 Aug 2016 20:09:21 +0000 (13:09 -0700)
committerNer'zhul <nerzhul@users.noreply.github.com>
Thu, 13 Oct 2016 15:33:16 +0000 (17:33 +0200)
13 files changed:
doc/lua_api.txt
src/client.h
src/content_sao.cpp
src/environment.cpp
src/environment.h
src/network/clientpackethandler.cpp
src/particles.cpp
src/particles.h
src/script/lua_api/l_particles.cpp
src/server.cpp
src/server.h
src/serverobject.cpp
src/serverobject.h

index 6bdcd4fe443fdffb5f408aac522e060234c9d536..a1d598e7de49fdfa890f0550f7465fcd39ca0280 100644 (file)
@@ -4120,6 +4120,8 @@ The Biome API is still in an experimental phase and subject to change.
         collision_removal = false,
     --  ^ collision_removal: if true then particle is removed when it collides,
     --  ^ requires collisiondetection = true to have any effect
+        attached = ObjectRef,
+    --  ^ attached: if defined, makes particle positions relative to this object.
         vertical = false,
     --  ^ vertical: if true faces player using y axis only
         texture = "image.png",
index 6d24c0b1d27219bc45980dc952717c3c6332fd93..9f5bda059ce3c26058263fae3868ff40a8c7bef7 100644 (file)
@@ -201,6 +201,7 @@ struct ClientEvent
                        f32 maxsize;
                        bool collisiondetection;
                        bool collision_removal;
+                       u16 attached_id;
                        bool vertical;
                        std::string *texture;
                        u32 id;
index 5d3ed38bc28f5b690ac30e116af3f65d62cb0bdf..375a43c906c89fc4cabcd89efc1a0d3639c16fa3 100644 (file)
@@ -156,6 +156,11 @@ LuaEntitySAO::~LuaEntitySAO()
        if(m_registered){
                m_env->getScriptIface()->luaentity_Remove(m_id);
        }
+
+       for (UNORDERED_SET<u32>::iterator it = m_attached_particle_spawners.begin();
+               it != m_attached_particle_spawners.end(); ++it) {
+               m_env->deleteParticleSpawner(*it, false);
+       }
 }
 
 void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
@@ -817,7 +822,6 @@ PlayerSAO::~PlayerSAO()
 {
        if(m_inventory != &m_player->inventory)
                delete m_inventory;
-
 }
 
 std::string PlayerSAO::getDescription()
@@ -844,6 +848,10 @@ void PlayerSAO::removingFromEnvironment()
                m_player->peer_id = 0;
                m_env->savePlayer(m_player);
                m_env->removePlayer(m_player);
+               for (UNORDERED_SET<u32>::iterator it = m_attached_particle_spawners.begin();
+                       it != m_attached_particle_spawners.end(); ++it) {
+                       m_env->deleteParticleSpawner(*it, false);
+               }
        }
 }
 
index ceaa01d7a4d6dfeff723a906d983ae693c4e19a0..ceaf40d8992429849e9ec5b34b174467f814572d 100644 (file)
@@ -1518,6 +1518,30 @@ u32 ServerEnvironment::addParticleSpawner(float exptime)
        return id;
 }
 
+u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
+{
+       u32 id = addParticleSpawner(exptime);
+       m_particle_spawner_attachments[id] = attached_id;
+       if (ServerActiveObject *obj = getActiveObject(attached_id)) {
+               obj->attachParticleSpawner(id);
+       }
+       return id;
+}
+
+void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
+{
+       m_particle_spawners.erase(id);
+       UNORDERED_MAP<u32, u16>::iterator it = m_particle_spawner_attachments.find(id);
+       if (it != m_particle_spawner_attachments.end()) {
+               u16 obj_id = (*it).second;
+               ServerActiveObject *sao = getActiveObject(obj_id);
+               if (sao != NULL && remove_from_object) {
+                       sao->detachParticleSpawner(id);
+               }
+               m_particle_spawner_attachments.erase(id);
+       }
+}
+
 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
 {
        ActiveObjectMap::iterator n = m_active_objects.find(id);
index 83ad69562375a76f00af988cfc8bd2105dee7f14..3f3c1cf2c8911709c8f0774f9edc704f48185b7a 100644 (file)
@@ -329,7 +329,8 @@ public:
        void loadDefaultMeta();
 
        u32 addParticleSpawner(float exptime);
-       void deleteParticleSpawner(u32 id) { m_particle_spawners.erase(id); }
+       u32 addParticleSpawner(float exptime, u16 attached_id);
+       void deleteParticleSpawner(u32 id, bool remove_from_object = true);
 
        /*
                External ActiveObject interface
@@ -519,6 +520,7 @@ private:
        // Particles
        IntervalLimiter m_particle_management_interval;
        UNORDERED_MAP<u32, float> m_particle_spawners;
+       UNORDERED_MAP<u32, u16> m_particle_spawner_attachments;
 };
 
 #ifndef SERVER
index b39356e926e1af2f9c11eb1fd8ac883364d948fe..090741f9fe786ee52df9341d3f6da5539c874e1c 100644 (file)
@@ -944,9 +944,11 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
 
        bool vertical = false;
        bool collision_removal = false;
+       u16 attached_id = 0;
        try {
                *pkt >> vertical;
                *pkt >> collision_removal;
+               *pkt >> attached_id;
 
        } catch (...) {}
 
@@ -966,6 +968,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
        event.add_particlespawner.maxsize            = maxsize;
        event.add_particlespawner.collisiondetection = collisiondetection;
        event.add_particlespawner.collision_removal  = collision_removal;
+       event.add_particlespawner.attached_id        = attached_id;
        event.add_particlespawner.vertical           = vertical;
        event.add_particlespawner.texture            = new std::string(texture);
        event.add_particlespawner.id                 = id;
index ccca691d17d76267f386c7f91b801e1d922dbc74..2efee6adaeb2e9be78b0780460f63635c876b7bf 100644 (file)
@@ -213,7 +213,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
        u16 amount, float time,
        v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
        float minexptime, float maxexptime, float minsize, float maxsize,
-       bool collisiondetection, bool collision_removal, bool vertical,
+       bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical,
        video::ITexture *texture, u32 id, ParticleManager *p_manager) :
        m_particlemanager(p_manager)
 {
@@ -234,6 +234,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
        m_maxsize = maxsize;
        m_collisiondetection = collisiondetection;
        m_collision_removal = collision_removal;
+       m_attached_id = attached_id;
        m_vertical = vertical;
        m_texture = texture;
        m_time = 0;
@@ -251,6 +252,15 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
 {
        m_time += dtime;
 
+       bool unloaded = false;
+       v3f attached_offset = v3f(0,0,0);
+       if (m_attached_id != 0) {
+               if (ClientActiveObject *attached = env->getActiveObject(m_attached_id))
+                       attached_offset = attached->getPosition() / BS;
+               else
+                       unloaded = true;
+       }
+
        if (m_spawntime != 0) // Spawner exists for a predefined timespan
        {
                for(std::vector<float>::iterator i = m_spawntimes.begin();
@@ -260,33 +270,41 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
                        {
                                m_amount--;
 
-                               v3f pos = random_v3f(m_minpos, m_maxpos);
-                               v3f vel = random_v3f(m_minvel, m_maxvel);
-                               v3f acc = random_v3f(m_minacc, m_maxacc);
-                               float exptime = rand()/(float)RAND_MAX
-                                               *(m_maxexptime-m_minexptime)
-                                               +m_minexptime;
-                               float size = rand()/(float)RAND_MAX
-                                               *(m_maxsize-m_minsize)
-                                               +m_minsize;
-
-                               Particle* toadd = new Particle(
-                                       m_gamedef,
-                                       m_smgr,
-                                       m_player,
-                                       env,
-                                       pos,
-                                       vel,
-                                       acc,
-                                       exptime,
-                                       size,
-                                       m_collisiondetection,
-                                       m_collision_removal,
-                                       m_vertical,
-                                       m_texture,
-                                       v2f(0.0, 0.0),
-                                       v2f(1.0, 1.0));
-                               m_particlemanager->addParticle(toadd);
+                               // Pretend to, but don't actually spawn a
+                               // particle if it is attached to an unloaded
+                               // object.
+                               if (!unloaded) {
+                                       v3f pos = random_v3f(m_minpos, m_maxpos)
+                                                       + attached_offset;
+                                       v3f vel = random_v3f(m_minvel, m_maxvel);
+                                       v3f acc = random_v3f(m_minacc, m_maxacc);
+                                       // Make relative to offest
+                                       pos += attached_offset;
+                                       float exptime = rand()/(float)RAND_MAX
+                                                       *(m_maxexptime-m_minexptime)
+                                                       +m_minexptime;
+                                       float size = rand()/(float)RAND_MAX
+                                                       *(m_maxsize-m_minsize)
+                                                       +m_minsize;
+
+                                       Particle* toadd = new Particle(
+                                               m_gamedef,
+                                               m_smgr,
+                                               m_player,
+                                               env,
+                                               pos,
+                                               vel,
+                                               acc,
+                                               exptime,
+                                               size,
+                                               m_collisiondetection,
+                                               m_collision_removal,
+                                               m_vertical,
+                                               m_texture,
+                                               v2f(0.0, 0.0),
+                                               v2f(1.0, 1.0));
+                                       m_particlemanager->addParticle(toadd);
+                               }
                                i = m_spawntimes.erase(i);
                        }
                        else
@@ -297,11 +315,15 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
        }
        else // Spawner exists for an infinity timespan, spawn on a per-second base
        {
+               // Skip this step if attached to an unloaded object
+               if (unloaded)
+                       return;
                for (int i = 0; i <= m_amount; i++)
                {
                        if (rand()/(float)RAND_MAX < dtime)
                        {
-                               v3f pos = random_v3f(m_minpos, m_maxpos);
+                               v3f pos = random_v3f(m_minpos, m_maxpos)
+                                               + attached_offset;
                                v3f vel = random_v3f(m_minvel, m_maxvel);
                                v3f acc = random_v3f(m_minacc, m_maxacc);
                                float exptime = rand()/(float)RAND_MAX
@@ -453,6 +475,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
                                        event->add_particlespawner.maxsize,
                                        event->add_particlespawner.collisiondetection,
                                        event->add_particlespawner.collision_removal,
+                                       event->add_particlespawner.attached_id,
                                        event->add_particlespawner.vertical,
                                        texture,
                                        event->add_particlespawner.id,
index bc3ca53b7ce2e14328fc538f9f594c00b44c59ec..eb8c6665d0e127200e9dd1ddc5655f13e6494a23 100644 (file)
@@ -119,6 +119,7 @@ class ParticleSpawner
                float minsize, float maxsize,
                bool collisiondetection,
                bool collision_removal,
+               u16 attached_id,
                bool vertical,
                video::ITexture *texture,
                u32 id,
@@ -154,7 +155,7 @@ class ParticleSpawner
        bool m_collisiondetection;
        bool m_collision_removal;
        bool m_vertical;
-
+       u16 m_attached_id;
 };
 
 /**
index 263e35407e36d0312988e155daf08c4ef82c51af..667ac727210b0d80fe36bb7dffd7e82031c5f5d5 100644 (file)
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "lua_api/l_particles.h"
+#include "lua_api/l_object.h"
 #include "lua_api/l_internal.h"
 #include "common/c_converter.h"
 #include "server.h"
@@ -138,6 +139,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
              time= minexptime= maxexptime= minsize= maxsize= 1;
        bool collisiondetection, vertical, collision_removal;
             collisiondetection = vertical = collision_removal = false;
+       ServerActiveObject *attached = NULL;
        std::string texture = "";
        std::string playername = "";
 
@@ -198,6 +200,14 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
                        "collisiondetection", collisiondetection);
                collision_removal = getboolfield_default(L, 1,
                        "collision_removal", collision_removal);
+
+               lua_getfield(L, 1, "attached");
+               if (!lua_isnil(L, -1)) {
+                       ObjectRef *ref = ObjectRef::checkobject(L, -1);
+                       lua_pop(L, 1);
+                       attached = ObjectRef::getobject(ref);
+               }
+
                vertical = getboolfield_default(L, 1, "vertical", vertical);
                texture = getstringfield_default(L, 1, "texture", "");
                playername = getstringfield_default(L, 1, "playername", "");
@@ -211,6 +221,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
                        minsize, maxsize,
                        collisiondetection,
                        collision_removal,
+                       attached,
                        vertical,
                        texture, playername);
        lua_pushnumber(L, id);
index a93c143c7d01f5d10e6fcbd23caa407394798f16..e67f37d561fda39bd69e95efcfafdee6871c50da 100644 (file)
@@ -1678,7 +1678,7 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
        v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
        float minsize, float maxsize, bool collisiondetection, bool collision_removal,
-       bool vertical, const std::string &texture, u32 id)
+       u16 attached_id, bool vertical, const std::string &texture, u32 id)
 {
        DSTACK(FUNCTION_NAME);
 
@@ -1692,6 +1692,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
 
        pkt << id << vertical;
        pkt << collision_removal;
+       pkt << attached_id;
 
        if (peer_id != PEER_ID_INEXISTENT) {
                Send(&pkt);
@@ -3156,7 +3157,7 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
        v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
        float minexptime, float maxexptime, float minsize, float maxsize,
        bool collisiondetection, bool collision_removal,
-       bool vertical, const std::string &texture,
+       ServerActiveObject *attached, bool vertical, const std::string &texture,
        const std::string &playername)
 {
        // m_env will be NULL if the server is initializing
@@ -3171,11 +3172,19 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
                peer_id = player->peer_id;
        }
 
-       u32 id = m_env->addParticleSpawner(spawntime);
+       u16 attached_id = attached ? attached->getId() : 0;
+
+       u32 id;
+       if (attached_id == 0)
+               id = m_env->addParticleSpawner(spawntime);
+       else
+               id = m_env->addParticleSpawner(spawntime, attached_id);
+
        SendAddParticleSpawner(peer_id, amount, spawntime,
                minpos, maxpos, minvel, maxvel, minacc, maxacc,
                minexptime, maxexptime, minsize, maxsize,
-               collisiondetection, collision_removal, vertical, texture, id);
+               collisiondetection, collision_removal, attached_id, vertical,
+               texture, id);
 
        return id;
 }
index 6ee61a0eb6e9dab829751beac578f01b1ae631e2..5fc2a913369d607a27101a40dcae9726c5972fc3 100644 (file)
@@ -258,6 +258,7 @@ public:
                float minexptime, float maxexptime,
                float minsize, float maxsize,
                bool collisiondetection, bool collision_removal,
+               ServerActiveObject *attached,
                bool vertical, const std::string &texture,
                const std::string &playername);
 
@@ -434,6 +435,7 @@ private:
                float minexptime, float maxexptime,
                float minsize, float maxsize,
                bool collisiondetection, bool collision_removal,
+               u16 attached_id,
                bool vertical, const std::string &texture, u32 id);
 
        void SendDeleteParticleSpawner(u16 peer_id, u32 id);
index 236d7e8dc06feaaca81fedb4c3479fc87ed3d103..191247829304b48cd0bbb126a61c4d6b74f5902a 100644 (file)
@@ -98,4 +98,3 @@ bool ServerActiveObject::setWieldedItem(const ItemStack &item)
        }
        return false;
 }
-
index cfe2b6bcc20a366c9dc72f8774d3bfac0cb7fc95..63650e3be325c4b7096b0a7de23b616c49c53439 100644 (file)
@@ -188,6 +188,15 @@ public:
        { return 0; }
        virtual ItemStack getWieldedItem() const;
        virtual bool setWieldedItem(const ItemStack &item);
+       inline void attachParticleSpawner(u32 id)
+       {
+               m_attached_particle_spawners.insert(id);
+       }
+       inline void detachParticleSpawner(u32 id)
+       {
+               m_attached_particle_spawners.erase(id);
+       }
+
 
        /*
                Number of players which know about this object. Object won't be
@@ -242,6 +251,7 @@ protected:
 
        ServerEnvironment *m_env;
        v3f m_base_position;
+       UNORDERED_SET<u32> m_attached_particle_spawners;
 
 private:
        // Used for creating objects based on type