Attached particle spawners

master
raymoo 2016-08-04 13:09:21 -07:00 committed by Ner'zhul
parent 0b27a70b29
commit c9e7a27eeb
13 changed files with 131 additions and 36 deletions

View File

@ -4120,6 +4120,8 @@ The Biome API is still in an experimental phase and subject to change.
collision_removal = false, collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides, -- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect -- ^ requires collisiondetection = true to have any effect
attached = ObjectRef,
-- ^ attached: if defined, makes particle positions relative to this object.
vertical = false, vertical = false,
-- ^ vertical: if true faces player using y axis only -- ^ vertical: if true faces player using y axis only
texture = "image.png", texture = "image.png",

View File

@ -201,6 +201,7 @@ struct ClientEvent
f32 maxsize; f32 maxsize;
bool collisiondetection; bool collisiondetection;
bool collision_removal; bool collision_removal;
u16 attached_id;
bool vertical; bool vertical;
std::string *texture; std::string *texture;
u32 id; u32 id;

View File

@ -156,6 +156,11 @@ LuaEntitySAO::~LuaEntitySAO()
if(m_registered){ if(m_registered){
m_env->getScriptIface()->luaentity_Remove(m_id); 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) void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
@ -817,7 +822,6 @@ PlayerSAO::~PlayerSAO()
{ {
if(m_inventory != &m_player->inventory) if(m_inventory != &m_player->inventory)
delete m_inventory; delete m_inventory;
} }
std::string PlayerSAO::getDescription() std::string PlayerSAO::getDescription()
@ -844,6 +848,10 @@ void PlayerSAO::removingFromEnvironment()
m_player->peer_id = 0; m_player->peer_id = 0;
m_env->savePlayer(m_player); m_env->savePlayer(m_player);
m_env->removePlayer(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);
}
} }
} }

View File

@ -1518,6 +1518,30 @@ u32 ServerEnvironment::addParticleSpawner(float exptime)
return id; 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) ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
{ {
ActiveObjectMap::iterator n = m_active_objects.find(id); ActiveObjectMap::iterator n = m_active_objects.find(id);

View File

@ -329,7 +329,8 @@ public:
void loadDefaultMeta(); void loadDefaultMeta();
u32 addParticleSpawner(float exptime); 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 External ActiveObject interface
@ -519,6 +520,7 @@ private:
// Particles // Particles
IntervalLimiter m_particle_management_interval; IntervalLimiter m_particle_management_interval;
UNORDERED_MAP<u32, float> m_particle_spawners; UNORDERED_MAP<u32, float> m_particle_spawners;
UNORDERED_MAP<u32, u16> m_particle_spawner_attachments;
}; };
#ifndef SERVER #ifndef SERVER

View File

@ -944,9 +944,11 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
bool vertical = false; bool vertical = false;
bool collision_removal = false; bool collision_removal = false;
u16 attached_id = 0;
try { try {
*pkt >> vertical; *pkt >> vertical;
*pkt >> collision_removal; *pkt >> collision_removal;
*pkt >> attached_id;
} catch (...) {} } catch (...) {}
@ -966,6 +968,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
event.add_particlespawner.maxsize = maxsize; event.add_particlespawner.maxsize = maxsize;
event.add_particlespawner.collisiondetection = collisiondetection; event.add_particlespawner.collisiondetection = collisiondetection;
event.add_particlespawner.collision_removal = collision_removal; event.add_particlespawner.collision_removal = collision_removal;
event.add_particlespawner.attached_id = attached_id;
event.add_particlespawner.vertical = vertical; event.add_particlespawner.vertical = vertical;
event.add_particlespawner.texture = new std::string(texture); event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id; event.add_particlespawner.id = id;

View File

@ -213,7 +213,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
u16 amount, float time, u16 amount, float time,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize, 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) : video::ITexture *texture, u32 id, ParticleManager *p_manager) :
m_particlemanager(p_manager) m_particlemanager(p_manager)
{ {
@ -234,6 +234,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
m_maxsize = maxsize; m_maxsize = maxsize;
m_collisiondetection = collisiondetection; m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal; m_collision_removal = collision_removal;
m_attached_id = attached_id;
m_vertical = vertical; m_vertical = vertical;
m_texture = texture; m_texture = texture;
m_time = 0; m_time = 0;
@ -251,6 +252,15 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
{ {
m_time += dtime; 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 if (m_spawntime != 0) // Spawner exists for a predefined timespan
{ {
for(std::vector<float>::iterator i = m_spawntimes.begin(); for(std::vector<float>::iterator i = m_spawntimes.begin();
@ -260,33 +270,41 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
{ {
m_amount--; m_amount--;
v3f pos = random_v3f(m_minpos, m_maxpos); // Pretend to, but don't actually spawn a
v3f vel = random_v3f(m_minvel, m_maxvel); // particle if it is attached to an unloaded
v3f acc = random_v3f(m_minacc, m_maxacc); // object.
float exptime = rand()/(float)RAND_MAX if (!unloaded) {
*(m_maxexptime-m_minexptime) v3f pos = random_v3f(m_minpos, m_maxpos)
+m_minexptime; + attached_offset;
float size = rand()/(float)RAND_MAX v3f vel = random_v3f(m_minvel, m_maxvel);
*(m_maxsize-m_minsize) v3f acc = random_v3f(m_minacc, m_maxacc);
+m_minsize; // 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( Particle* toadd = new Particle(
m_gamedef, m_gamedef,
m_smgr, m_smgr,
m_player, m_player,
env, env,
pos, pos,
vel, vel,
acc, acc,
exptime, exptime,
size, size,
m_collisiondetection, m_collisiondetection,
m_collision_removal, m_collision_removal,
m_vertical, m_vertical,
m_texture, m_texture,
v2f(0.0, 0.0), v2f(0.0, 0.0),
v2f(1.0, 1.0)); v2f(1.0, 1.0));
m_particlemanager->addParticle(toadd); m_particlemanager->addParticle(toadd);
}
i = m_spawntimes.erase(i); i = m_spawntimes.erase(i);
} }
else 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 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++) for (int i = 0; i <= m_amount; i++)
{ {
if (rand()/(float)RAND_MAX < dtime) 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 vel = random_v3f(m_minvel, m_maxvel);
v3f acc = random_v3f(m_minacc, m_maxacc); v3f acc = random_v3f(m_minacc, m_maxacc);
float exptime = rand()/(float)RAND_MAX float exptime = rand()/(float)RAND_MAX
@ -453,6 +475,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->add_particlespawner.maxsize, event->add_particlespawner.maxsize,
event->add_particlespawner.collisiondetection, event->add_particlespawner.collisiondetection,
event->add_particlespawner.collision_removal, event->add_particlespawner.collision_removal,
event->add_particlespawner.attached_id,
event->add_particlespawner.vertical, event->add_particlespawner.vertical,
texture, texture,
event->add_particlespawner.id, event->add_particlespawner.id,

View File

@ -119,6 +119,7 @@ class ParticleSpawner
float minsize, float maxsize, float minsize, float maxsize,
bool collisiondetection, bool collisiondetection,
bool collision_removal, bool collision_removal,
u16 attached_id,
bool vertical, bool vertical,
video::ITexture *texture, video::ITexture *texture,
u32 id, u32 id,
@ -154,7 +155,7 @@ class ParticleSpawner
bool m_collisiondetection; bool m_collisiondetection;
bool m_collision_removal; bool m_collision_removal;
bool m_vertical; bool m_vertical;
u16 m_attached_id;
}; };
/** /**

View 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_particles.h"
#include "lua_api/l_object.h"
#include "lua_api/l_internal.h" #include "lua_api/l_internal.h"
#include "common/c_converter.h" #include "common/c_converter.h"
#include "server.h" #include "server.h"
@ -138,6 +139,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
time= minexptime= maxexptime= minsize= maxsize= 1; time= minexptime= maxexptime= minsize= maxsize= 1;
bool collisiondetection, vertical, collision_removal; bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false; collisiondetection = vertical = collision_removal = false;
ServerActiveObject *attached = NULL;
std::string texture = ""; std::string texture = "";
std::string playername = ""; std::string playername = "";
@ -198,6 +200,14 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
"collisiondetection", collisiondetection); "collisiondetection", collisiondetection);
collision_removal = getboolfield_default(L, 1, collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal); "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); vertical = getboolfield_default(L, 1, "vertical", vertical);
texture = getstringfield_default(L, 1, "texture", ""); texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", ""); playername = getstringfield_default(L, 1, "playername", "");
@ -211,6 +221,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
minsize, maxsize, minsize, maxsize,
collisiondetection, collisiondetection,
collision_removal, collision_removal,
attached,
vertical, vertical,
texture, playername); texture, playername);
lua_pushnumber(L, id); lua_pushnumber(L, id);

View 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, 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, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
float minsize, float maxsize, bool collisiondetection, bool collision_removal, 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); DSTACK(FUNCTION_NAME);
@ -1692,6 +1692,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
pkt << id << vertical; pkt << id << vertical;
pkt << collision_removal; pkt << collision_removal;
pkt << attached_id;
if (peer_id != PEER_ID_INEXISTENT) { if (peer_id != PEER_ID_INEXISTENT) {
Send(&pkt); 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, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize, float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool collision_removal, bool collisiondetection, bool collision_removal,
bool vertical, const std::string &texture, ServerActiveObject *attached, bool vertical, const std::string &texture,
const std::string &playername) const std::string &playername)
{ {
// m_env will be NULL if the server is initializing // 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; 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, SendAddParticleSpawner(peer_id, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc, minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize, minexptime, maxexptime, minsize, maxsize,
collisiondetection, collision_removal, vertical, texture, id); collisiondetection, collision_removal, attached_id, vertical,
texture, id);
return id; return id;
} }

View File

@ -258,6 +258,7 @@ public:
float minexptime, float maxexptime, float minexptime, float maxexptime,
float minsize, float maxsize, float minsize, float maxsize,
bool collisiondetection, bool collision_removal, bool collisiondetection, bool collision_removal,
ServerActiveObject *attached,
bool vertical, const std::string &texture, bool vertical, const std::string &texture,
const std::string &playername); const std::string &playername);
@ -434,6 +435,7 @@ private:
float minexptime, float maxexptime, float minexptime, float maxexptime,
float minsize, float maxsize, float minsize, float maxsize,
bool collisiondetection, bool collision_removal, bool collisiondetection, bool collision_removal,
u16 attached_id,
bool vertical, const std::string &texture, u32 id); bool vertical, const std::string &texture, u32 id);
void SendDeleteParticleSpawner(u16 peer_id, u32 id); void SendDeleteParticleSpawner(u16 peer_id, u32 id);

View File

@ -98,4 +98,3 @@ bool ServerActiveObject::setWieldedItem(const ItemStack &item)
} }
return false; return false;
} }

View File

@ -188,6 +188,15 @@ public:
{ return 0; } { return 0; }
virtual ItemStack getWieldedItem() const; virtual ItemStack getWieldedItem() const;
virtual bool setWieldedItem(const ItemStack &item); 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 Number of players which know about this object. Object won't be
@ -242,6 +251,7 @@ protected:
ServerEnvironment *m_env; ServerEnvironment *m_env;
v3f m_base_position; v3f m_base_position;
UNORDERED_SET<u32> m_attached_particle_spawners;
private: private:
// Used for creating objects based on type // Used for creating objects based on type