Cleanup of particle & particlespawner structures and code (#9893)

This commit is contained in:
sfan5 2020-05-22 13:23:25 +02:00 committed by GitHub
parent 1bcdc2d7e9
commit 1357ea1da2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 497 additions and 675 deletions

@ -427,6 +427,7 @@ set(common_SRCS
noise.cpp noise.cpp
objdef.cpp objdef.cpp
object_properties.cpp object_properties.cpp
particles.cpp
pathfinder.cpp pathfinder.cpp
player.cpp player.cpp
porting.cpp porting.cpp

@ -21,8 +21,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string> #include <string>
#include "irrlichttypes_bloated.h" #include "irrlichttypes_bloated.h"
#include "hud.h"
#include "skyparams.h" struct ParticleParameters;
struct ParticleSpawnerParameters;
struct SkyboxParams;
struct SunParams;
struct MoonParams;
struct StarParams;
enum ClientEventType : u8 enum ClientEventType : u8
{ {
@ -77,44 +82,12 @@ struct ClientEvent
} show_formspec; } show_formspec;
// struct{ // struct{
//} textures_updated; //} textures_updated;
ParticleParameters *spawn_particle;
struct struct
{ {
v3f *pos; ParticleSpawnerParameters *p;
v3f *vel;
v3f *acc;
f32 expirationtime;
f32 size;
bool collisiondetection;
bool collision_removal;
bool object_collision;
bool vertical;
std::string *texture;
struct TileAnimationParams animation;
u8 glow;
} spawn_particle;
struct
{
u16 amount;
f32 spawntime;
v3f *minpos;
v3f *maxpos;
v3f *minvel;
v3f *maxvel;
v3f *minacc;
v3f *maxacc;
f32 minexptime;
f32 maxexptime;
f32 minsize;
f32 maxsize;
bool collisiondetection;
bool collision_removal;
bool object_collision;
u16 attached_id; u16 attached_id;
bool vertical;
std::string *texture;
u64 id; u64 id;
struct TileAnimationParams animation;
u8 glow;
} add_particlespawner; } add_particlespawner;
struct struct
{ {

@ -37,32 +37,31 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Utility Utility
*/ */
v3f random_v3f(v3f min, v3f max) static f32 random_f32(f32 min, f32 max)
{
return rand() / (float)RAND_MAX * (max - min) + min;
}
static v3f random_v3f(v3f min, v3f max)
{ {
return v3f( return v3f(
rand() / (float)RAND_MAX * (max.X - min.X) + min.X, random_f32(min.X, max.X),
rand() / (float)RAND_MAX * (max.Y - min.Y) + min.Y, random_f32(min.Y, max.Y),
rand() / (float)RAND_MAX * (max.Z - min.Z) + min.Z); random_f32(min.Z, max.Z));
} }
/*
Particle
*/
Particle::Particle( Particle::Particle(
IGameDef *gamedef, IGameDef *gamedef,
LocalPlayer *player, LocalPlayer *player,
ClientEnvironment *env, ClientEnvironment *env,
v3f pos, const ParticleParameters &p,
v3f velocity,
v3f acceleration,
float expirationtime,
float size,
bool collisiondetection,
bool collision_removal,
bool object_collision,
bool vertical,
video::ITexture *texture, video::ITexture *texture,
v2f texpos, v2f texpos,
v2f texsize, v2f texsize,
const struct TileAnimationParams &anim,
u8 glow,
video::SColor color video::SColor color
): ):
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
@ -81,33 +80,28 @@ Particle::Particle(
m_material.setTexture(0, texture); m_material.setTexture(0, texture);
m_texpos = texpos; m_texpos = texpos;
m_texsize = texsize; m_texsize = texsize;
m_animation = anim; m_animation = p.animation;
// Color // Color
m_base_color = color; m_base_color = color;
m_color = color; m_color = color;
// Particle related // Particle related
m_pos = pos; m_pos = p.pos;
m_velocity = velocity; m_velocity = p.vel;
m_acceleration = acceleration; m_acceleration = p.acc;
m_expiration = expirationtime; m_expiration = p.expirationtime;
m_player = player; m_player = player;
m_size = size; m_size = p.size;
m_collisiondetection = collisiondetection; m_collisiondetection = p.collisiondetection;
m_collision_removal = collision_removal; m_collision_removal = p.collision_removal;
m_object_collision = object_collision; m_object_collision = p.object_collision;
m_vertical = vertical; m_vertical = p.vertical;
m_glow = glow; m_glow = p.glow;
// Irrlicht stuff // Irrlicht stuff
m_collisionbox = aabb3f( const float c = p.size / 2;
-size / 2, m_collisionbox = aabb3f(-c, -c, -c, c, c, c);
-size / 2,
-size / 2,
size / 2,
size / 2,
size / 2);
this->setAutomaticCulling(scene::EAC_OFF); this->setAutomaticCulling(scene::EAC_OFF);
// Init lighting // Init lighting
@ -255,52 +249,22 @@ void Particle::updateVertices()
ParticleSpawner::ParticleSpawner( ParticleSpawner::ParticleSpawner(
IGameDef *gamedef, IGameDef *gamedef,
LocalPlayer *player, LocalPlayer *player,
u16 amount, const ParticleSpawnerParameters &p,
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 object_collision,
u16 attached_id, u16 attached_id,
bool vertical,
video::ITexture *texture, video::ITexture *texture,
const struct TileAnimationParams &anim,
u8 glow,
ParticleManager *p_manager ParticleManager *p_manager
): ):
m_particlemanager(p_manager) m_particlemanager(p_manager), p(p)
{ {
m_gamedef = gamedef; m_gamedef = gamedef;
m_player = player; m_player = player;
m_amount = amount;
m_spawntime = time;
m_minpos = minpos;
m_maxpos = maxpos;
m_minvel = minvel;
m_maxvel = maxvel;
m_minacc = minacc;
m_maxacc = maxacc;
m_minexptime = minexptime;
m_maxexptime = maxexptime;
m_minsize = minsize;
m_maxsize = maxsize;
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_object_collision = object_collision;
m_attached_id = attached_id; m_attached_id = attached_id;
m_vertical = vertical;
m_texture = texture; m_texture = texture;
m_time = 0; m_time = 0;
m_animation = anim;
m_glow = glow;
for (u16 i = 0; i <= m_amount; i++) m_spawntimes.reserve(p.amount + 1);
{ for (u16 i = 0; i <= p.amount; i++) {
float spawntime = (float)rand() / (float)RAND_MAX * m_spawntime; float spawntime = rand() / (float)RAND_MAX * p.time;
m_spawntimes.push_back(spawntime); m_spawntimes.push_back(spawntime);
} }
} }
@ -309,7 +273,7 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
const core::matrix4 *attached_absolute_pos_rot_matrix) const core::matrix4 *attached_absolute_pos_rot_matrix)
{ {
v3f ppos = m_player->getPosition() / BS; v3f ppos = m_player->getPosition() / BS;
v3f pos = random_v3f(m_minpos, m_maxpos); v3f pos = random_v3f(p.minpos, p.maxpos);
// Need to apply this first or the following check // Need to apply this first or the following check
// will be wrong for attached spawners // will be wrong for attached spawners
@ -326,41 +290,32 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
if (pos.getDistanceFrom(ppos) > radius) if (pos.getDistanceFrom(ppos) > radius)
return; return;
v3f vel = random_v3f(m_minvel, m_maxvel); // Parameters for the single particle we're about to spawn
v3f acc = random_v3f(m_minacc, m_maxacc); ParticleParameters pp;
pp.pos = pos;
pp.vel = random_v3f(p.minvel, p.maxvel);
pp.acc = random_v3f(p.minacc, p.maxacc);
if (attached_absolute_pos_rot_matrix) { if (attached_absolute_pos_rot_matrix) {
// Apply attachment rotation // Apply attachment rotation
attached_absolute_pos_rot_matrix->rotateVect(vel); attached_absolute_pos_rot_matrix->rotateVect(pp.vel);
attached_absolute_pos_rot_matrix->rotateVect(acc); attached_absolute_pos_rot_matrix->rotateVect(pp.acc);
} }
float exptime = rand() / (float)RAND_MAX pp.expirationtime = random_f32(p.minexptime, p.maxexptime);
* (m_maxexptime - m_minexptime) pp.size = random_f32(p.minsize, p.maxsize);
+ m_minexptime;
float size = rand() / (float)RAND_MAX p.copyCommon(pp);
* (m_maxsize - m_minsize)
+ m_minsize;
m_particlemanager->addParticle(new Particle( m_particlemanager->addParticle(new Particle(
m_gamedef, m_gamedef,
m_player, m_player,
env, env,
pos, pp,
vel,
acc,
exptime,
size,
m_collisiondetection,
m_collision_removal,
m_object_collision,
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_animation,
m_glow
)); ));
} }
@ -381,12 +336,11 @@ void ParticleSpawner::step(float dtime, ClientEnvironment *env)
} }
} }
if (m_spawntime != 0) { if (p.time != 0) {
// Spawner exists for a predefined timespan // Spawner exists for a predefined timespan
for (std::vector<float>::iterator i = m_spawntimes.begin(); for (auto i = m_spawntimes.begin(); i != m_spawntimes.end(); ) {
i != m_spawntimes.end();) { if ((*i) <= m_time && p.amount > 0) {
if ((*i) <= m_time && m_amount > 0) { --p.amount;
--m_amount;
// Pretend to, but don't actually spawn a particle if it is // Pretend to, but don't actually spawn a particle if it is
// attached to an unloaded object or distant from player. // attached to an unloaded object or distant from player.
@ -405,13 +359,16 @@ void ParticleSpawner::step(float dtime, ClientEnvironment *env)
if (unloaded) if (unloaded)
return; return;
for (int i = 0; i <= m_amount; i++) { for (int i = 0; i <= p.amount; i++) {
if (rand() / (float)RAND_MAX < dtime) if (rand() / (float)RAND_MAX < dtime)
spawnParticle(env, radius, attached_absolute_pos_rot_matrix); spawnParticle(env, radius, attached_absolute_pos_rot_matrix);
} }
} }
} }
/*
ParticleManager
*/
ParticleManager::ParticleManager(ClientEnvironment *env) : ParticleManager::ParticleManager(ClientEnvironment *env) :
m_env(env) m_env(env)
@ -479,99 +436,84 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
{ {
switch (event->type) { switch (event->type) {
case CE_DELETE_PARTICLESPAWNER: { case CE_DELETE_PARTICLESPAWNER: {
MutexAutoLock lock(m_spawner_list_lock); deleteParticleSpawner(event->delete_particlespawner.id);
if (m_particle_spawners.find(event->delete_particlespawner.id) !=
m_particle_spawners.end()) {
delete m_particle_spawners.find(event->delete_particlespawner.id)->second;
m_particle_spawners.erase(event->delete_particlespawner.id);
}
// no allocated memory in delete event // no allocated memory in delete event
break; break;
} }
case CE_ADD_PARTICLESPAWNER: { case CE_ADD_PARTICLESPAWNER: {
{ deleteParticleSpawner(event->add_particlespawner.id);
MutexAutoLock lock(m_spawner_list_lock);
if (m_particle_spawners.find(event->add_particlespawner.id) != const ParticleSpawnerParameters &p = *event->add_particlespawner.p;
m_particle_spawners.end()) {
delete m_particle_spawners.find(event->add_particlespawner.id)->second;
m_particle_spawners.erase(event->add_particlespawner.id);
}
}
video::ITexture *texture = video::ITexture *texture =
client->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture)); client->tsrc()->getTextureForMesh(p.texture);
auto toadd = new ParticleSpawner(client, player, auto toadd = new ParticleSpawner(client, player,
event->add_particlespawner.amount, p,
event->add_particlespawner.spawntime,
*event->add_particlespawner.minpos,
*event->add_particlespawner.maxpos,
*event->add_particlespawner.minvel,
*event->add_particlespawner.maxvel,
*event->add_particlespawner.minacc,
*event->add_particlespawner.maxacc,
event->add_particlespawner.minexptime,
event->add_particlespawner.maxexptime,
event->add_particlespawner.minsize,
event->add_particlespawner.maxsize,
event->add_particlespawner.collisiondetection,
event->add_particlespawner.collision_removal,
event->add_particlespawner.object_collision,
event->add_particlespawner.attached_id, event->add_particlespawner.attached_id,
event->add_particlespawner.vertical,
texture, texture,
event->add_particlespawner.animation,
event->add_particlespawner.glow,
this); this);
/* delete allocated content of event */ addParticleSpawner(event->add_particlespawner.id, toadd);
delete event->add_particlespawner.minpos;
delete event->add_particlespawner.maxpos;
delete event->add_particlespawner.minvel;
delete event->add_particlespawner.maxvel;
delete event->add_particlespawner.minacc;
delete event->add_particlespawner.texture;
delete event->add_particlespawner.maxacc;
{ delete event->add_particlespawner.p;
MutexAutoLock lock(m_spawner_list_lock);
m_particle_spawners[event->add_particlespawner.id] = toadd;
}
break; break;
} }
case CE_SPAWN_PARTICLE: { case CE_SPAWN_PARTICLE: {
const ParticleParameters &p = *event->spawn_particle;
video::ITexture *texture = video::ITexture *texture =
client->tsrc()->getTextureForMesh(*(event->spawn_particle.texture)); client->tsrc()->getTextureForMesh(p.texture);
Particle *toadd = new Particle(client, player, m_env, Particle *toadd = new Particle(client, player, m_env,
*event->spawn_particle.pos, p,
*event->spawn_particle.vel,
*event->spawn_particle.acc,
event->spawn_particle.expirationtime,
event->spawn_particle.size,
event->spawn_particle.collisiondetection,
event->spawn_particle.collision_removal,
event->spawn_particle.object_collision,
event->spawn_particle.vertical,
texture, texture,
v2f(0.0, 0.0), v2f(0.0, 0.0),
v2f(1.0, 1.0), v2f(1.0, 1.0));
event->spawn_particle.animation,
event->spawn_particle.glow);
addParticle(toadd); addParticle(toadd);
delete event->spawn_particle.pos; delete event->spawn_particle;
delete event->spawn_particle.vel;
delete event->spawn_particle.acc;
delete event->spawn_particle.texture;
break; break;
} }
default: break; default: break;
} }
} }
bool ParticleManager::getNodeParticleParams(const MapNode &n,
const ContentFeatures &f, ParticleParameters &p,
video::ITexture **texture, v2f &texpos, v2f &texsize, video::SColor *color)
{
// No particles for "airlike" nodes
if (f.drawtype == NDT_AIRLIKE)
return false;
// Texture
u8 texid = rand() % 6;
const TileLayer &tile = f.tiles[texid].layers[0];
p.animation.type = TAT_NONE;
// Only use first frame of animated texture
if (tile.material_flags & MATERIAL_FLAG_ANIMATION)
*texture = (*tile.frames)[0].texture;
else
*texture = tile.texture;
float size = (rand() % 8) / 64.0f;
p.size = BS * size;
if (tile.scale)
size /= tile.scale;
texsize = v2f(size * 2.0f, size * 2.0f);
texpos.X = (rand() % 64) / 64.0f - texsize.X;
texpos.Y = (rand() % 64) / 64.0f - texsize.Y;
if (tile.has_color)
*color = tile.color;
else
n.getColor(f, color);
return true;
}
// The final burst of particles when a node is finally dug, *not* particles // The final burst of particles when a node is finally dug, *not* particles
// spawned during the digging of a node. // spawned during the digging of a node.
@ -593,73 +535,41 @@ void ParticleManager::addDiggingParticles(IGameDef *gamedef,
void ParticleManager::addNodeParticle(IGameDef *gamedef, void ParticleManager::addNodeParticle(IGameDef *gamedef,
LocalPlayer *player, v3s16 pos, const MapNode &n, const ContentFeatures &f) LocalPlayer *player, v3s16 pos, const MapNode &n, const ContentFeatures &f)
{ {
// No particles for "airlike" nodes ParticleParameters p;
if (f.drawtype == NDT_AIRLIKE) video::ITexture *texture;
v2f texpos, texsize;
video::SColor color;
if (!getNodeParticleParams(n, f, p, &texture, texpos, texsize, &color))
return; return;
// Texture p.expirationtime = (rand() % 100) / 100.0f;
u8 texid = myrand_range(0, 5);
const TileLayer &tile = f.tiles[texid].layers[0];
video::ITexture *texture;
struct TileAnimationParams anim;
anim.type = TAT_NONE;
// Only use first frame of animated texture
if (tile.material_flags & MATERIAL_FLAG_ANIMATION)
texture = (*tile.frames)[0].texture;
else
texture = tile.texture;
float size = (rand() % 8) / 64.0f;
float visual_size = BS * size;
if (tile.scale)
size /= tile.scale;
v2f texsize(size * 2.0f, size * 2.0f);
v2f texpos;
texpos.X = (rand() % 64) / 64.0f - texsize.X;
texpos.Y = (rand() % 64) / 64.0f - texsize.Y;
// Physics // Physics
v3f velocity( p.vel = v3f(
(rand() % 150) / 50.0f - 1.5f, (rand() % 150) / 50.0f - 1.5f,
(rand() % 150) / 50.0f, (rand() % 150) / 50.0f,
(rand() % 150) / 50.0f - 1.5f (rand() % 150) / 50.0f - 1.5f
); );
v3f acceleration( p.acc = v3f(
0.0f, 0.0f,
-player->movement_gravity * player->physics_override_gravity / BS, -player->movement_gravity * player->physics_override_gravity / BS,
0.0f 0.0f
); );
v3f particlepos = v3f( p.pos = v3f(
(f32)pos.X + (rand() % 100) / 200.0f - 0.25f, (f32)pos.X + (rand() % 100) / 200.0f - 0.25f,
(f32)pos.Y + (rand() % 100) / 200.0f - 0.25f, (f32)pos.Y + (rand() % 100) / 200.0f - 0.25f,
(f32)pos.Z + (rand() % 100) / 200.0f - 0.25f (f32)pos.Z + (rand() % 100) / 200.0f - 0.25f
); );
video::SColor color;
if (tile.has_color)
color = tile.color;
else
n.getColor(f, &color);
Particle *toadd = new Particle( Particle *toadd = new Particle(
gamedef, gamedef,
player, player,
m_env, m_env,
particlepos, p,
velocity,
acceleration,
(rand() % 100) / 100.0f, // expiration time
visual_size,
true,
false,
false,
false,
texture, texture,
texpos, texpos,
texsize, texsize,
anim,
0,
color); color);
addParticle(toadd); addParticle(toadd);
@ -670,3 +580,20 @@ void ParticleManager::addParticle(Particle *toadd)
MutexAutoLock lock(m_particle_list_lock); MutexAutoLock lock(m_particle_list_lock);
m_particles.push_back(toadd); m_particles.push_back(toadd);
} }
void ParticleManager::addParticleSpawner(u64 id, ParticleSpawner *toadd)
{
MutexAutoLock lock(m_spawner_list_lock);
m_particle_spawners[id] = toadd;
}
void ParticleManager::deleteParticleSpawner(u64 id)
{
MutexAutoLock lock(m_spawner_list_lock);
auto it = m_particle_spawners.find(id);
if (it != m_particle_spawners.end()) {
delete it->second;
m_particle_spawners.erase(it);
}
}

@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "client/tile.h" #include "client/tile.h"
#include "localplayer.h" #include "localplayer.h"
#include "tileanimation.h" #include "../particles.h"
struct ClientEvent; struct ClientEvent;
class ParticleManager; class ParticleManager;
@ -38,20 +38,10 @@ class Particle : public scene::ISceneNode
IGameDef* gamedef, IGameDef* gamedef,
LocalPlayer *player, LocalPlayer *player,
ClientEnvironment *env, ClientEnvironment *env,
v3f pos, const ParticleParameters &p,
v3f velocity,
v3f acceleration,
float expirationtime,
float size,
bool collisiondetection,
bool collision_removal,
bool object_collision,
bool vertical,
video::ITexture *texture, video::ITexture *texture,
v2f texpos, v2f texpos,
v2f texsize, v2f texsize,
const struct TileAnimationParams &anim,
u8 glow,
video::SColor color = video::SColor(0xFFFFFFFF) video::SColor color = video::SColor(0xFFFFFFFF)
); );
~Particle() = default; ~Particle() = default;
@ -119,20 +109,9 @@ class ParticleSpawner
public: public:
ParticleSpawner(IGameDef* gamedef, ParticleSpawner(IGameDef* gamedef,
LocalPlayer *player, LocalPlayer *player,
u16 amount, const ParticleSpawnerParameters &p,
float time,
v3f minp, v3f maxp,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection,
bool collision_removal,
bool object_collision,
u16 attached_id, u16 attached_id,
bool vertical,
video::ITexture *texture, video::ITexture *texture,
const struct TileAnimationParams &anim, u8 glow,
ParticleManager* p_manager); ParticleManager* p_manager);
~ParticleSpawner() = default; ~ParticleSpawner() = default;
@ -140,7 +119,7 @@ public:
void step(float dtime, ClientEnvironment *env); void step(float dtime, ClientEnvironment *env);
bool get_expired () bool get_expired ()
{ return (m_amount <= 0) && m_spawntime != 0; } { return p.amount <= 0 && p.time != 0; }
private: private:
void spawnParticle(ClientEnvironment *env, float radius, void spawnParticle(ClientEnvironment *env, float radius,
@ -150,27 +129,10 @@ private:
float m_time; float m_time;
IGameDef *m_gamedef; IGameDef *m_gamedef;
LocalPlayer *m_player; LocalPlayer *m_player;
u16 m_amount; ParticleSpawnerParameters p;
float m_spawntime;
v3f m_minpos;
v3f m_maxpos;
v3f m_minvel;
v3f m_maxvel;
v3f m_minacc;
v3f m_maxacc;
float m_minexptime;
float m_maxexptime;
float m_minsize;
float m_maxsize;
video::ITexture *m_texture; video::ITexture *m_texture;
std::vector<float> m_spawntimes; std::vector<float> m_spawntimes;
bool m_collisiondetection;
bool m_collision_removal;
bool m_object_collision;
bool m_vertical;
u16 m_attached_id; u16 m_attached_id;
struct TileAnimationParams m_animation;
u8 m_glow;
}; };
/** /**
@ -197,8 +159,8 @@ public:
/** /**
* This function is only used by client particle spawners * This function is only used by client particle spawners
* *
* We don't need to check the particle spawner list because client ID will n * We don't need to check the particle spawner list because client ID will
* ever overlap (u64) * never overlap (u64)
* @return new id * @return new id
*/ */
u64 generateSpawnerId() u64 generateSpawnerId()
@ -207,9 +169,15 @@ public:
} }
protected: protected:
static bool getNodeParticleParams(const MapNode &n, const ContentFeatures &f,
ParticleParameters &p, video::ITexture **texture, v2f &texpos,
v2f &texsize, video::SColor *color);
void addParticle(Particle* toadd); void addParticle(Particle* toadd);
private: private:
void addParticleSpawner(u64 id, ParticleSpawner *toadd);
void deleteParticleSpawner(u64 id);
void stepParticles(float dtime); void stepParticles(float dtime);
void stepSpawners(float dtime); void stepSpawners(float dtime);

@ -958,114 +958,56 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
std::string datastring(pkt->getString(0), pkt->getSize()); std::string datastring(pkt->getString(0), pkt->getSize());
std::istringstream is(datastring, std::ios_base::binary); std::istringstream is(datastring, std::ios_base::binary);
v3f pos = readV3F32(is); ParticleParameters p;
v3f vel = readV3F32(is); p.deSerialize(is, m_proto_ver);
v3f acc = readV3F32(is);
float expirationtime = readF32(is);
float size = readF32(is);
bool collisiondetection = readU8(is);
std::string texture = deSerializeLongString(is);
bool vertical = false;
bool collision_removal = false;
TileAnimationParams animation;
animation.type = TAT_NONE;
u8 glow = 0;
bool object_collision = false;
try {
vertical = readU8(is);
collision_removal = readU8(is);
animation.deSerialize(is, m_proto_ver);
glow = readU8(is);
object_collision = readU8(is);
} catch (...) {}
ClientEvent *event = new ClientEvent(); ClientEvent *event = new ClientEvent();
event->type = CE_SPAWN_PARTICLE; event->type = CE_SPAWN_PARTICLE;
event->spawn_particle.pos = new v3f (pos); event->spawn_particle = new ParticleParameters(p);
event->spawn_particle.vel = new v3f (vel);
event->spawn_particle.acc = new v3f (acc);
event->spawn_particle.expirationtime = expirationtime;
event->spawn_particle.size = size;
event->spawn_particle.collisiondetection = collisiondetection;
event->spawn_particle.collision_removal = collision_removal;
event->spawn_particle.object_collision = object_collision;
event->spawn_particle.vertical = vertical;
event->spawn_particle.texture = new std::string(texture);
event->spawn_particle.animation = animation;
event->spawn_particle.glow = glow;
m_client_event_queue.push(event); m_client_event_queue.push(event);
} }
void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
{ {
u16 amount; std::string datastring(pkt->getString(0), pkt->getSize());
float spawntime; std::istringstream is(datastring, std::ios_base::binary);
v3f minpos;
v3f maxpos; ParticleSpawnerParameters p;
v3f minvel;
v3f maxvel;
v3f minacc;
v3f maxacc;
float minexptime;
float maxexptime;
float minsize;
float maxsize;
bool collisiondetection;
u32 server_id; u32 server_id;
u16 attached_id = 0;
*pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel p.amount = readU16(is);
>> minacc >> maxacc >> minexptime >> maxexptime >> minsize p.time = readF32(is);
>> maxsize >> collisiondetection; p.minpos = readV3F32(is);
p.maxpos = readV3F32(is);
p.minvel = readV3F32(is);
p.maxvel = readV3F32(is);
p.minacc = readV3F32(is);
p.maxacc = readV3F32(is);
p.minexptime = readF32(is);
p.maxexptime = readF32(is);
p.minsize = readF32(is);
p.maxsize = readF32(is);
p.collisiondetection = readU8(is);
p.texture = deSerializeLongString(is);
std::string texture = pkt->readLongString(); server_id = readU32(is);
*pkt >> server_id; p.vertical = readU8(is);
p.collision_removal = readU8(is);
bool vertical = false; attached_id = readU16(is);
bool collision_removal = false;
u16 attached_id = 0;
TileAnimationParams animation;
animation.type = TAT_NONE;
u8 glow = 0;
bool object_collision = false;
try {
*pkt >> vertical;
*pkt >> collision_removal;
*pkt >> attached_id;
// This is horrible but required (why are there two ways to deserialize pkts?) p.animation.deSerialize(is, m_proto_ver);
std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes()); p.glow = readU8(is);
std::istringstream is(datastring, std::ios_base::binary); p.object_collision = readU8(is);
animation.deSerialize(is, m_proto_ver);
glow = readU8(is);
object_collision = readU8(is);
} catch (...) {}
auto event = new ClientEvent(); auto event = new ClientEvent();
event->type = CE_ADD_PARTICLESPAWNER; event->type = CE_ADD_PARTICLESPAWNER;
event->add_particlespawner.amount = amount; event->add_particlespawner.p = new ParticleSpawnerParameters(p);
event->add_particlespawner.spawntime = spawntime; event->add_particlespawner.attached_id = attached_id;
event->add_particlespawner.minpos = new v3f (minpos); event->add_particlespawner.id = server_id;
event->add_particlespawner.maxpos = new v3f (maxpos);
event->add_particlespawner.minvel = new v3f (minvel);
event->add_particlespawner.maxvel = new v3f (maxvel);
event->add_particlespawner.minacc = new v3f (minacc);
event->add_particlespawner.maxacc = new v3f (maxacc);
event->add_particlespawner.minexptime = minexptime;
event->add_particlespawner.maxexptime = maxexptime;
event->add_particlespawner.minsize = minsize;
event->add_particlespawner.maxsize = maxsize;
event->add_particlespawner.collisiondetection = collisiondetection;
event->add_particlespawner.collision_removal = collision_removal;
event->add_particlespawner.object_collision = object_collision;
event->add_particlespawner.attached_id = attached_id;
event->add_particlespawner.vertical = vertical;
event->add_particlespawner.texture = new std::string(texture);
event->add_particlespawner.id = server_id;
event->add_particlespawner.animation = animation;
event->add_particlespawner.glow = glow;
m_client_event_queue.push(event); m_client_event_queue.push(event);
} }

53
src/particles.cpp Normal file

@ -0,0 +1,53 @@
/*
Minetest
Copyright (C) 2020 sfan5 <sfan5@live.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "particles.h"
#include "util/serialize.h"
void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const
{
writeV3F32(os, pos);
writeV3F32(os, vel);
writeV3F32(os, acc);
writeF32(os, expirationtime);
writeF32(os, size);
writeU8(os, collisiondetection);
os << serializeLongString(texture);
writeU8(os, vertical);
writeU8(os, collision_removal);
animation.serialize(os, 6); /* NOT the protocol ver */
writeU8(os, glow);
writeU8(os, object_collision);
}
void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver)
{
pos = readV3F32(is);
vel = readV3F32(is);
acc = readV3F32(is);
expirationtime = readF32(is);
size = readF32(is);
collisiondetection = readU8(is);
texture = deSerializeLongString(is);
vertical = readU8(is);
collision_removal = readU8(is);
animation.deSerialize(is, 6); /* NOT the protocol ver */
glow = readU8(is);
object_collision = readU8(is);
}

73
src/particles.h Normal file

@ -0,0 +1,73 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <string>
#include "irrlichttypes_bloated.h"
#include "tileanimation.h"
// This file defines the particle-related structures that both the server and
// client need. The ParticleManager and rendering is in client/particles.h
struct CommonParticleParams {
bool collisiondetection = false;
bool collision_removal = false;
bool object_collision = false;
bool vertical = false;
std::string texture;
struct TileAnimationParams animation;
u8 glow = 0;
CommonParticleParams() {
animation.type = TAT_NONE;
}
/* This helper is useful for copying params from
* ParticleSpawnerParameters to ParticleParameters */
inline void copyCommon(CommonParticleParams &to) const {
to.collisiondetection = collisiondetection;
to.collision_removal = collision_removal;
to.object_collision = object_collision;
to.vertical = vertical;
to.texture = texture;
to.animation = animation;
to.glow = glow;
}
};
struct ParticleParameters : CommonParticleParams {
v3f pos;
v3f vel;
v3f acc;
f32 expirationtime = 1;
f32 size = 1;
void serialize(std::ostream &os, u16 protocol_ver) const;
void deSerialize(std::istream &is, u16 protocol_ver);
};
struct ParticleSpawnerParameters : CommonParticleParams {
u16 amount = 1;
v3f minpos, maxpos, minvel, maxvel, minacc, maxacc;
f32 time = 1;
f32 minexptime = 1, maxexptime = 1, minsize = 1, maxsize = 1;
// For historical reasons no (de-)serialization methods here
};

@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h" #include "common/c_converter.h"
#include "common/c_content.h" #include "common/c_content.h"
#include "server.h" #include "server.h"
#include "client/particles.h" #include "particles.h"
// add_particle({pos=, velocity=, acceleration=, expirationtime=, // add_particle({pos=, velocity=, acceleration=, expirationtime=,
// size=, collisiondetection=, collision_removal=, object_collision=, // size=, collisiondetection=, collision_removal=, object_collision=,
@ -40,85 +40,81 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// glow = num // glow = num
int ModApiParticles::l_add_particle(lua_State *L) int ModApiParticles::l_add_particle(lua_State *L)
{ {
MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
// Get parameters // Get parameters
v3f pos, vel, acc; struct ParticleParameters p;
float expirationtime, size;
expirationtime = size = 1;
bool collisiondetection, vertical, collision_removal, object_collision;
collisiondetection = vertical = collision_removal = object_collision = false;
struct TileAnimationParams animation;
animation.type = TAT_NONE;
std::string texture;
std::string playername; std::string playername;
u8 glow = 0;
if (lua_gettop(L) > 1) // deprecated if (lua_gettop(L) > 1) // deprecated
{ {
log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition"); log_deprecated(L, "Deprecated add_particle call with "
pos = check_v3f(L, 1); "individual parameters instead of definition");
vel = check_v3f(L, 2); p.pos = check_v3f(L, 1);
acc = check_v3f(L, 3); p.vel = check_v3f(L, 2);
expirationtime = luaL_checknumber(L, 4); p.acc = check_v3f(L, 3);
size = luaL_checknumber(L, 5); p.expirationtime = luaL_checknumber(L, 4);
collisiondetection = readParam<bool>(L, 6); p.size = luaL_checknumber(L, 5);
texture = luaL_checkstring(L, 7); p.collisiondetection = readParam<bool>(L, 6);
p.texture = luaL_checkstring(L, 7);
if (lua_gettop(L) == 8) // only spawn for a single player if (lua_gettop(L) == 8) // only spawn for a single player
playername = luaL_checkstring(L, 8); playername = luaL_checkstring(L, 8);
} }
else if (lua_istable(L, 1)) else if (lua_istable(L, 1))
{ {
lua_getfield(L, 1, "pos"); lua_getfield(L, 1, "pos");
pos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(); if (lua_istable(L, -1))
p.pos = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "vel"); lua_getfield(L, 1, "vel");
if (lua_istable(L, -1)) { if (lua_istable(L, -1)) {
vel = check_v3f(L, -1); p.vel = check_v3f(L, -1);
log_deprecated(L, "The use of vel is deprecated. " log_deprecated(L, "The use of vel is deprecated. "
"Use velocity instead"); "Use velocity instead");
} }
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "velocity"); lua_getfield(L, 1, "velocity");
vel = lua_istable(L, -1) ? check_v3f(L, -1) : vel; if (lua_istable(L, -1))
p.vel = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "acc"); lua_getfield(L, 1, "acc");
if (lua_istable(L, -1)) { if (lua_istable(L, -1)) {
acc = check_v3f(L, -1); p.acc = check_v3f(L, -1);
log_deprecated(L, "The use of acc is deprecated. " log_deprecated(L, "The use of acc is deprecated. "
"Use acceleration instead"); "Use acceleration instead");
} }
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "acceleration"); lua_getfield(L, 1, "acceleration");
acc = lua_istable(L, -1) ? check_v3f(L, -1) : acc; if (lua_istable(L, -1))
p.acc = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
expirationtime = getfloatfield_default(L, 1, "expirationtime", 1); p.expirationtime = getfloatfield_default(L, 1, "expirationtime",
size = getfloatfield_default(L, 1, "size", 1); p.expirationtime);
collisiondetection = getboolfield_default(L, 1, p.size = getfloatfield_default(L, 1, "size", p.size);
"collisiondetection", collisiondetection); p.collisiondetection = getboolfield_default(L, 1,
collision_removal = getboolfield_default(L, 1, "collisiondetection", p.collisiondetection);
"collision_removal", collision_removal); p.collision_removal = getboolfield_default(L, 1,
object_collision = getboolfield_default(L, 1, "collision_removal", p.collision_removal);
"object_collision", object_collision); p.object_collision = getboolfield_default(L, 1,
vertical = getboolfield_default(L, 1, "vertical", vertical); "object_collision", p.object_collision);
p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
lua_getfield(L, 1, "animation"); lua_getfield(L, 1, "animation");
animation = read_animation_definition(L, -1); p.animation = read_animation_definition(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
texture = getstringfield_default(L, 1, "texture", ""); p.texture = getstringfield_default(L, 1, "texture", p.texture);
playername = getstringfield_default(L, 1, "playername", ""); p.glow = getintfield_default(L, 1, "glow", p.glow);
glow = getintfield_default(L, 1, "glow", 0); playername = getstringfield_default(L, 1, "playername", "");
} }
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
collisiondetection, collision_removal, object_collision, vertical, getServer(L)->spawnParticle(playername, p);
texture, animation, glow);
return 1; return 1;
} }
@ -146,84 +142,82 @@ int ModApiParticles::l_add_particle(lua_State *L)
// glow = num // glow = num
int ModApiParticles::l_add_particlespawner(lua_State *L) int ModApiParticles::l_add_particlespawner(lua_State *L)
{ {
MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
// Get parameters // Get parameters
u16 amount = 1; ParticleSpawnerParameters p;
v3f minpos, maxpos, minvel, maxvel, minacc, maxacc;
float time, minexptime, maxexptime, minsize, maxsize;
time = minexptime = maxexptime = minsize = maxsize = 1;
bool collisiondetection, vertical, collision_removal, object_collision;
collisiondetection = vertical = collision_removal = object_collision = false;
struct TileAnimationParams animation;
animation.type = TAT_NONE;
ServerActiveObject *attached = NULL; ServerActiveObject *attached = NULL;
std::string texture;
std::string playername; std::string playername;
u8 glow = 0;
if (lua_gettop(L) > 1) //deprecated if (lua_gettop(L) > 1) //deprecated
{ {
log_deprecated(L,"Deprecated add_particlespawner call with individual parameters instead of definition"); log_deprecated(L, "Deprecated add_particlespawner call with "
amount = luaL_checknumber(L, 1); "individual parameters instead of definition");
time = luaL_checknumber(L, 2); p.amount = luaL_checknumber(L, 1);
minpos = check_v3f(L, 3); p.time = luaL_checknumber(L, 2);
maxpos = check_v3f(L, 4); p.minpos = check_v3f(L, 3);
minvel = check_v3f(L, 5); p.maxpos = check_v3f(L, 4);
maxvel = check_v3f(L, 6); p.minvel = check_v3f(L, 5);
minacc = check_v3f(L, 7); p.maxvel = check_v3f(L, 6);
maxacc = check_v3f(L, 8); p.minacc = check_v3f(L, 7);
minexptime = luaL_checknumber(L, 9); p.maxacc = check_v3f(L, 8);
maxexptime = luaL_checknumber(L, 10); p.minexptime = luaL_checknumber(L, 9);
minsize = luaL_checknumber(L, 11); p.maxexptime = luaL_checknumber(L, 10);
maxsize = luaL_checknumber(L, 12); p.minsize = luaL_checknumber(L, 11);
collisiondetection = readParam<bool>(L, 13); p.maxsize = luaL_checknumber(L, 12);
texture = luaL_checkstring(L, 14); p.collisiondetection = readParam<bool>(L, 13);
p.texture = luaL_checkstring(L, 14);
if (lua_gettop(L) == 15) // only spawn for a single player if (lua_gettop(L) == 15) // only spawn for a single player
playername = luaL_checkstring(L, 15); playername = luaL_checkstring(L, 15);
} }
else if (lua_istable(L, 1)) else if (lua_istable(L, 1))
{ {
amount = getintfield_default(L, 1, "amount", amount); p.amount = getintfield_default(L, 1, "amount", p.amount);
time = getfloatfield_default(L, 1, "time", time); p.time = getfloatfield_default(L, 1, "time", p.time);
lua_getfield(L, 1, "minpos"); lua_getfield(L, 1, "minpos");
minpos = lua_istable(L, -1) ? check_v3f(L, -1) : minpos; if (lua_istable(L, -1))
p.minpos = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "maxpos"); lua_getfield(L, 1, "maxpos");
maxpos = lua_istable(L, -1) ? check_v3f(L, -1) : maxpos; if (lua_istable(L, -1))
p.maxpos = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "minvel"); lua_getfield(L, 1, "minvel");
minvel = lua_istable(L, -1) ? check_v3f(L, -1) : minvel; if (lua_istable(L, -1))
p.minvel = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "maxvel"); lua_getfield(L, 1, "maxvel");
maxvel = lua_istable(L, -1) ? check_v3f(L, -1) : maxvel; if (lua_istable(L, -1))
p.maxvel = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "minacc"); lua_getfield(L, 1, "minacc");
minacc = lua_istable(L, -1) ? check_v3f(L, -1) : minacc; if (lua_istable(L, -1))
p.minacc = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "maxacc"); lua_getfield(L, 1, "maxacc");
maxacc = lua_istable(L, -1) ? check_v3f(L, -1) : maxacc; if (lua_istable(L, -1))
p.maxacc = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
minexptime = getfloatfield_default(L, 1, "minexptime", minexptime); p.minexptime = getfloatfield_default(L, 1, "minexptime", p.minexptime);
maxexptime = getfloatfield_default(L, 1, "maxexptime", maxexptime); p.maxexptime = getfloatfield_default(L, 1, "maxexptime", p.maxexptime);
minsize = getfloatfield_default(L, 1, "minsize", minsize); p.minsize = getfloatfield_default(L, 1, "minsize", p.minsize);
maxsize = getfloatfield_default(L, 1, "maxsize", maxsize); p.maxsize = getfloatfield_default(L, 1, "maxsize", p.maxsize);
collisiondetection = getboolfield_default(L, 1, p.collisiondetection = getboolfield_default(L, 1,
"collisiondetection", collisiondetection); "collisiondetection", p.collisiondetection);
collision_removal = getboolfield_default(L, 1, p.collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal); "collision_removal", p.collision_removal);
object_collision = getboolfield_default(L, 1, p.object_collision = getboolfield_default(L, 1,
"object_collision", object_collision); "object_collision", p.object_collision);
lua_getfield(L, 1, "animation"); lua_getfield(L, 1, "animation");
animation = read_animation_definition(L, -1); p.animation = read_animation_definition(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "attached"); lua_getfield(L, 1, "attached");
@ -233,25 +227,13 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
attached = ObjectRef::getobject(ref); attached = ObjectRef::getobject(ref);
} }
vertical = getboolfield_default(L, 1, "vertical", vertical); p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
texture = getstringfield_default(L, 1, "texture", ""); p.texture = getstringfield_default(L, 1, "texture", p.texture);
playername = getstringfield_default(L, 1, "playername", ""); playername = getstringfield_default(L, 1, "playername", "");
glow = getintfield_default(L, 1, "glow", 0); p.glow = getintfield_default(L, 1, "glow", p.glow);
} }
u32 id = getServer(L)->addParticleSpawner(amount, time, u32 id = getServer(L)->addParticleSpawner(p, attached, playername);
minpos, maxpos,
minvel, maxvel,
minacc, maxacc,
minexptime, maxexptime,
minsize, maxsize,
collisiondetection,
collision_removal,
object_collision,
attached,
vertical,
texture, playername,
animation, glow);
lua_pushnumber(L, id); lua_pushnumber(L, id);
return 1; return 1;
@ -261,7 +243,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
// player (string) is optional // player (string) is optional
int ModApiParticles::l_delete_particlespawner(lua_State *L) int ModApiParticles::l_delete_particlespawner(lua_State *L)
{ {
MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
// Get parameters // Get parameters
u32 id = luaL_checknumber(L, 1); u32 id = luaL_checknumber(L, 1);

@ -32,56 +32,44 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L)
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
// Get parameters // Get parameters
v3f pos, vel, acc; ParticleParameters p;
float expirationtime, size;
bool collisiondetection, vertical, collision_removal;
struct TileAnimationParams animation;
animation.type = TAT_NONE;
std::string texture;
u8 glow;
lua_getfield(L, 1, "pos"); lua_getfield(L, 1, "pos");
pos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.pos = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "velocity"); lua_getfield(L, 1, "velocity");
vel = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.vel = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "acceleration"); lua_getfield(L, 1, "acceleration");
acc = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.acc = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
expirationtime = getfloatfield_default(L, 1, "expirationtime", 1); p.expirationtime = getfloatfield_default(L, 1, "expirationtime",
size = getfloatfield_default(L, 1, "size", 1); p.expirationtime);
collisiondetection = getboolfield_default(L, 1, "collisiondetection", false); p.size = getfloatfield_default(L, 1, "size", p.size);
collision_removal = getboolfield_default(L, 1, "collision_removal", false); p.collisiondetection = getboolfield_default(L, 1,
vertical = getboolfield_default(L, 1, "vertical", false); "collisiondetection", p.collisiondetection);
p.collision_removal = getboolfield_default(L, 1,
"collision_removal", p.collision_removal);
p.object_collision = getboolfield_default(L, 1,
"object_collision", p.object_collision);
p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
lua_getfield(L, 1, "animation"); lua_getfield(L, 1, "animation");
animation = read_animation_definition(L, -1); p.animation = read_animation_definition(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
texture = getstringfield_default(L, 1, "texture", ""); p.texture = getstringfield_default(L, 1, "texture", p.texture);
p.glow = getintfield_default(L, 1, "glow", p.glow);
glow = getintfield_default(L, 1, "glow", 0);
ClientEvent *event = new ClientEvent(); ClientEvent *event = new ClientEvent();
event->type = CE_SPAWN_PARTICLE; event->type = CE_SPAWN_PARTICLE;
event->spawn_particle.pos = new v3f (pos); event->spawn_particle = new ParticleParameters(p);
event->spawn_particle.vel = new v3f (vel);
event->spawn_particle.acc = new v3f (acc);
event->spawn_particle.expirationtime = expirationtime;
event->spawn_particle.size = size;
event->spawn_particle.collisiondetection = collisiondetection;
event->spawn_particle.collision_removal = collision_removal;
event->spawn_particle.vertical = vertical;
event->spawn_particle.texture = new std::string(texture);
event->spawn_particle.animation = animation;
event->spawn_particle.glow = glow;
getClient(L)->pushToEventQueue(event); getClient(L)->pushToEventQueue(event);
return 0; return 0;
@ -90,94 +78,69 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L)
int ModApiParticlesLocal::l_add_particlespawner(lua_State *L) int ModApiParticlesLocal::l_add_particlespawner(lua_State *L)
{ {
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
// Get parameters // Get parameters
u16 amount; ParticleSpawnerParameters p;
v3f minpos, maxpos, minvel, maxvel, minacc, maxacc;
float time, minexptime, maxexptime, minsize, maxsize;
bool collisiondetection, vertical, collision_removal;
struct TileAnimationParams animation; p.amount = getintfield_default(L, 1, "amount", p.amount);
animation.type = TAT_NONE; p.time = getfloatfield_default(L, 1, "time", p.time);
// TODO: Implement this when there is a way to get an objectref.
// ServerActiveObject *attached = NULL;
std::string texture;
u8 glow;
amount = getintfield_default(L, 1, "amount", 1);
time = getfloatfield_default(L, 1, "time", 1);
lua_getfield(L, 1, "minpos"); lua_getfield(L, 1, "minpos");
minpos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.minpos = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "maxpos"); lua_getfield(L, 1, "maxpos");
maxpos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.maxpos = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "minvel"); lua_getfield(L, 1, "minvel");
minvel = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.minvel = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "maxvel"); lua_getfield(L, 1, "maxvel");
maxvel = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.maxvel = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "minacc"); lua_getfield(L, 1, "minacc");
minacc = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.minacc = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, 1, "maxacc"); lua_getfield(L, 1, "maxacc");
maxacc = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); if (lua_istable(L, -1))
p.maxacc = check_v3f(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
minexptime = getfloatfield_default(L, 1, "minexptime", 1); p.minexptime = getfloatfield_default(L, 1, "minexptime", p.minexptime);
maxexptime = getfloatfield_default(L, 1, "maxexptime", 1); p.maxexptime = getfloatfield_default(L, 1, "maxexptime", p.maxexptime);
minsize = getfloatfield_default(L, 1, "minsize", 1); p.minsize = getfloatfield_default(L, 1, "minsize", p.minsize);
maxsize = getfloatfield_default(L, 1, "maxsize", 1); p.maxsize = getfloatfield_default(L, 1, "maxsize", p.maxsize);
p.collisiondetection = getboolfield_default(L, 1,
collisiondetection = getboolfield_default(L, 1, "collisiondetection", false); "collisiondetection", p.collisiondetection);
collision_removal = getboolfield_default(L, 1, "collision_removal", false); p.collision_removal = getboolfield_default(L, 1,
vertical = getboolfield_default(L, 1, "vertical", false); "collision_removal", p.collision_removal);
p.object_collision = getboolfield_default(L, 1,
"object_collision", p.object_collision);
lua_getfield(L, 1, "animation"); lua_getfield(L, 1, "animation");
animation = read_animation_definition(L, -1); p.animation = read_animation_definition(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
// TODO: Implement this when a way to get an objectref on the client is added p.vertical = getboolfield_default(L, 1, "vertical", p.vertical);
// lua_getfield(L, 1, "attached"); p.texture = getstringfield_default(L, 1, "texture", p.texture);
// if (!lua_isnil(L, -1)) { p.glow = getintfield_default(L, 1, "glow", p.glow);
// ObjectRef *ref = ObjectRef::checkobject(L, -1);
// lua_pop(L, 1);
// attached = ObjectRef::getobject(ref);
// }
texture = getstringfield_default(L, 1, "texture", "");
glow = getintfield_default(L, 1, "glow", 0);
u64 id = getClient(L)->getParticleManager()->generateSpawnerId(); u64 id = getClient(L)->getParticleManager()->generateSpawnerId();
auto event = new ClientEvent(); auto event = new ClientEvent();
event->type = CE_ADD_PARTICLESPAWNER; event->type = CE_ADD_PARTICLESPAWNER;
event->add_particlespawner.amount = amount; event->add_particlespawner.p = new ParticleSpawnerParameters(p);
event->add_particlespawner.spawntime = time; event->add_particlespawner.attached_id = 0;
event->add_particlespawner.minpos = new v3f (minpos); event->add_particlespawner.id = id;
event->add_particlespawner.maxpos = new v3f (maxpos);
event->add_particlespawner.minvel = new v3f (minvel);
event->add_particlespawner.maxvel = new v3f (maxvel);
event->add_particlespawner.minacc = new v3f (minacc);
event->add_particlespawner.maxacc = new v3f (maxacc);
event->add_particlespawner.minexptime = minexptime;
event->add_particlespawner.maxexptime = maxexptime;
event->add_particlespawner.minsize = minsize;
event->add_particlespawner.maxsize = maxsize;
event->add_particlespawner.collisiondetection = collisiondetection;
event->add_particlespawner.collision_removal = collision_removal;
event->add_particlespawner.attached_id = 0;
event->add_particlespawner.vertical = vertical;
event->add_particlespawner.texture = new std::string(texture);
event->add_particlespawner.id = id;
event->add_particlespawner.animation = animation;
event->add_particlespawner.glow = glow;
getClient(L)->pushToEventQueue(event); getClient(L)->pushToEventQueue(event);
lua_pushnumber(L, id); lua_pushnumber(L, id);

@ -1504,17 +1504,15 @@ void Server::SendShowFormspecMessage(session_t peer_id, const std::string &forms
// Spawns a particle on peer with peer_id // Spawns a particle on peer with peer_id
void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version, void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
v3f pos, v3f velocity, v3f acceleration, const ParticleParameters &p)
float expirationtime, float size, bool collisiondetection,
bool collision_removal, bool object_collision,
bool vertical, const std::string &texture,
const struct TileAnimationParams &animation, u8 glow)
{ {
static thread_local const float radius = static thread_local const float radius =
g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS; g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS;
if (peer_id == PEER_ID_INEXISTENT) { if (peer_id == PEER_ID_INEXISTENT) {
std::vector<session_t> clients = m_clients.getClientIDs(); std::vector<session_t> clients = m_clients.getClientIDs();
const v3f pos = p.pos * BS;
const float radius_sq = radius * radius;
for (const session_t client_id : clients) { for (const session_t client_id : clients) {
RemotePlayer *player = m_env->getPlayer(client_id); RemotePlayer *player = m_env->getPlayer(client_id);
@ -1526,76 +1524,59 @@ void Server::SendSpawnParticle(session_t peer_id, u16 protocol_version,
continue; continue;
// Do not send to distant clients // Do not send to distant clients
if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius) if (sao->getBasePosition().getDistanceFromSQ(pos) > radius_sq)
continue; continue;
SendSpawnParticle(client_id, player->protocol_version, SendSpawnParticle(client_id, player->protocol_version, p);
pos, velocity, acceleration,
expirationtime, size, collisiondetection, collision_removal,
object_collision, vertical, texture, animation, glow);
} }
return; return;
} }
assert(protocol_version != 0);
NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id); NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
pkt << pos << velocity << acceleration << expirationtime {
<< size << collisiondetection; // NetworkPacket and iostreams are incompatible...
pkt.putLongString(texture); std::ostringstream oss(std::ios_base::binary);
pkt << vertical; p.serialize(oss, protocol_version);
pkt << collision_removal; pkt.putRawString(oss.str());
// This is horrible but required (why are there two ways to serialize pkts?) }
std::ostringstream os(std::ios_base::binary);
animation.serialize(os, protocol_version);
pkt.putRawString(os.str());
pkt << glow;
pkt << object_collision;
Send(&pkt); Send(&pkt);
} }
// Adds a ParticleSpawner on peer with peer_id // Adds a ParticleSpawner on peer with peer_id
void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version, void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
u16 amount, float spawntime, v3f minpos, v3f maxpos, const ParticleSpawnerParameters &p, u16 attached_id, u32 id)
v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
float minsize, float maxsize, bool collisiondetection, bool collision_removal,
bool object_collision, u16 attached_id, bool vertical, const std::string &texture, u32 id,
const struct TileAnimationParams &animation, u8 glow)
{ {
if (peer_id == PEER_ID_INEXISTENT) { if (peer_id == PEER_ID_INEXISTENT) {
// This sucks and should be replaced:
std::vector<session_t> clients = m_clients.getClientIDs(); std::vector<session_t> clients = m_clients.getClientIDs();
for (const session_t client_id : clients) { for (const session_t client_id : clients) {
RemotePlayer *player = m_env->getPlayer(client_id); RemotePlayer *player = m_env->getPlayer(client_id);
if (!player) if (!player)
continue; continue;
SendAddParticleSpawner(client_id, player->protocol_version, SendAddParticleSpawner(client_id, player->protocol_version,
amount, spawntime, minpos, maxpos, p, attached_id, id);
minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
minsize, maxsize, collisiondetection, collision_removal,
object_collision, attached_id, vertical, texture, id,
animation, glow);
} }
return; return;
} }
assert(protocol_version != 0);
NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id); NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 100, peer_id);
pkt << amount << spawntime << minpos << maxpos << minvel << maxvel pkt << p.amount << p.time << p.minpos << p.maxpos << p.minvel
<< minacc << maxacc << minexptime << maxexptime << minsize << p.maxvel << p.minacc << p.maxacc << p.minexptime << p.maxexptime
<< maxsize << collisiondetection; << p.minsize << p.maxsize << p.collisiondetection;
pkt.putLongString(texture); pkt.putLongString(p.texture);
pkt << id << vertical; pkt << id << p.vertical << p.collision_removal << attached_id;
pkt << collision_removal; {
pkt << attached_id; std::ostringstream os(std::ios_base::binary);
// This is horrible but required p.animation.serialize(os, protocol_version);
std::ostringstream os(std::ios_base::binary); pkt.putRawString(os.str());
animation.serialize(os, protocol_version); }
pkt.putRawString(os.str()); pkt << p.glow << p.object_collision;
pkt << glow;
pkt << object_collision;
Send(&pkt); Send(&pkt);
} }
@ -1604,7 +1585,6 @@ void Server::SendDeleteParticleSpawner(session_t peer_id, u32 id)
{ {
NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id); NetworkPacket pkt(TOCLIENT_DELETE_PARTICLESPAWNER, 4, peer_id);
// Ugly error in this packet
pkt << id; pkt << id;
if (peer_id != PEER_ID_INEXISTENT) if (peer_id != PEER_ID_INEXISTENT)
@ -3365,12 +3345,8 @@ void Server::notifyPlayers(const std::wstring &msg)
SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg)); SendChatMessage(PEER_ID_INEXISTENT, ChatMessage(msg));
} }
void Server::spawnParticle(const std::string &playername, v3f pos, void Server::spawnParticle(const std::string &playername,
v3f velocity, v3f acceleration, const ParticleParameters &p)
float expirationtime, float size, bool
collisiondetection, bool collision_removal, bool object_collision,
bool vertical, const std::string &texture,
const struct TileAnimationParams &animation, u8 glow)
{ {
// m_env will be NULL if the server is initializing // m_env will be NULL if the server is initializing
if (!m_env) if (!m_env)
@ -3386,18 +3362,11 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
proto_ver = player->protocol_version; proto_ver = player->protocol_version;
} }
SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration, SendSpawnParticle(peer_id, proto_ver, p);
expirationtime, size, collisiondetection, collision_removal,
object_collision, vertical, texture, animation, glow);
} }
u32 Server::addParticleSpawner(u16 amount, float spawntime, u32 Server::addParticleSpawner(const ParticleSpawnerParameters &p,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, ServerActiveObject *attached, const std::string &playername)
float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool collision_removal, bool object_collision,
ServerActiveObject *attached, bool vertical, const std::string &texture,
const std::string &playername, const struct TileAnimationParams &animation,
u8 glow)
{ {
// m_env will be NULL if the server is initializing // m_env will be NULL if the server is initializing
if (!m_env) if (!m_env)
@ -3417,16 +3386,11 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
u32 id; u32 id;
if (attached_id == 0) if (attached_id == 0)
id = m_env->addParticleSpawner(spawntime); id = m_env->addParticleSpawner(p.time);
else else
id = m_env->addParticleSpawner(spawntime, attached_id); id = m_env->addParticleSpawner(p.time, attached_id);
SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize, collisiondetection,
collision_removal, object_collision, attached_id, vertical,
texture, id, animation, glow);
SendAddParticleSpawner(peer_id, proto_ver, p, attached_id, id);
return id; return id;
} }

@ -27,7 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content/mods.h" #include "content/mods.h"
#include "inventorymanager.h" #include "inventorymanager.h"
#include "content/subgames.h" #include "content/subgames.h"
#include "tileanimation.h" // struct TileAnimationParams #include "tileanimation.h" // TileAnimationParams
#include "particles.h" // ParticleParams
#include "network/peerhandler.h" #include "network/peerhandler.h"
#include "network/address.h" #include "network/address.h"
#include "util/numeric.h" #include "util/numeric.h"
@ -226,24 +227,12 @@ public:
void notifyPlayer(const char *name, const std::wstring &msg); void notifyPlayer(const char *name, const std::wstring &msg);
void notifyPlayers(const std::wstring &msg); void notifyPlayers(const std::wstring &msg);
void spawnParticle(const std::string &playername,
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, bool collision_removal, bool object_collision,
bool vertical, const std::string &texture,
const struct TileAnimationParams &animation, u8 glow);
u32 addParticleSpawner(u16 amount, float spawntime, void spawnParticle(const std::string &playername,
v3f minpos, v3f maxpos, const ParticleParameters &p);
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc, u32 addParticleSpawner(const ParticleSpawnerParameters &p,
float minexptime, float maxexptime, ServerActiveObject *attached, const std::string &playername);
float minsize, float maxsize,
bool collisiondetection, bool collision_removal, bool object_collision,
ServerActiveObject *attached,
bool vertical, const std::string &texture,
const std::string &playername, const struct TileAnimationParams &animation,
u8 glow);
void deleteParticleSpawner(const std::string &playername, u32 id); void deleteParticleSpawner(const std::string &playername, u32 id);
@ -453,26 +442,13 @@ private:
// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all) // Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
void SendAddParticleSpawner(session_t peer_id, u16 protocol_version, void SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
u16 amount, float spawntime, const ParticleSpawnerParameters &p, u16 attached_id, u32 id);
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 object_collision,
u16 attached_id,
bool vertical, const std::string &texture, u32 id,
const struct TileAnimationParams &animation, u8 glow);
void SendDeleteParticleSpawner(session_t peer_id, u32 id); void SendDeleteParticleSpawner(session_t peer_id, u32 id);
// Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all) // Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all)
void SendSpawnParticle(session_t peer_id, u16 protocol_version, void SendSpawnParticle(session_t peer_id, u16 protocol_version,
v3f pos, v3f velocity, v3f acceleration, const ParticleParameters &p);
float expirationtime, float size,
bool collisiondetection, bool collision_removal, bool object_collision,
bool vertical, const std::string &texture,
const struct TileAnimationParams &animation, u8 glow);
void SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao); void SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao);
void SendActiveObjectMessages(session_t peer_id, const std::string &datas, void SendActiveObjectMessages(session_t peer_id, const std::string &datas,