aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client.h1
-rw-r--r--src/content_sao.cpp10
-rw-r--r--src/environment.cpp24
-rw-r--r--src/environment.h4
-rw-r--r--src/network/clientpackethandler.cpp3
-rw-r--r--src/particles.cpp81
-rw-r--r--src/particles.h3
-rw-r--r--src/script/lua_api/l_particles.cpp11
-rw-r--r--src/server.cpp17
-rw-r--r--src/server.h2
-rw-r--r--src/serverobject.cpp1
-rw-r--r--src/serverobject.h10
12 files changed, 130 insertions, 37 deletions
diff --git a/src/client.h b/src/client.h
index 6d24c0b1d..9f5bda059 100644
--- a/src/client.h
+++ b/src/client.h
@@ -201,6 +201,7 @@ struct ClientEvent
f32 maxsize;
bool collisiondetection;
bool collision_removal;
+ u16 attached_id;
bool vertical;
std::string *texture;
u32 id;
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 5d3ed38bc..375a43c90 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -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);
+ }
}
}
diff --git a/src/environment.cpp b/src/environment.cpp
index ceaa01d7a..ceaf40d89 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -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);
diff --git a/src/environment.h b/src/environment.h
index 83ad69562..3f3c1cf2c 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -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
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index b39356e92..090741f9f 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -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;
diff --git a/src/particles.cpp b/src/particles.cpp
index ccca691d1..2efee6ada 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -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,
diff --git a/src/particles.h b/src/particles.h
index bc3ca53b7..eb8c6665d 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -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;
};
/**
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index 263e35407..667ac7272 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -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);
diff --git a/src/server.cpp b/src/server.cpp
index a93c143c7..e67f37d56 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -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;
}
diff --git a/src/server.h b/src/server.h
index 6ee61a0eb..5fc2a9133 100644
--- a/src/server.h
+++ b/src/server.h
@@ -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);
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
index 236d7e8dc..191247829 100644
--- a/src/serverobject.cpp
+++ b/src/serverobject.cpp
@@ -98,4 +98,3 @@ bool ServerActiveObject::setWieldedItem(const ItemStack &item)
}
return false;
}
-
diff --git a/src/serverobject.h b/src/serverobject.h
index cfe2b6bcc..63650e3be 100644
--- a/src/serverobject.h
+++ b/src/serverobject.h
@@ -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