1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-02 16:38:41 +00:00

Adding particle blend, glow and animation (#4705)

This commit is contained in:
Foghrye4 2016-11-14 18:09:59 +04:00 committed by Zeno-
parent 649448a2a9
commit 93e3555eae
15 changed files with 800 additions and 81 deletions

View file

@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "particles.h"
#include "network/networkpacket.h"
#include "nodedef.h" // AnimationType
struct MeshMakeData;
class MapBlockMesh;
@ -185,6 +186,14 @@ struct ClientEvent
bool collision_removal;
bool vertical;
std::string *texture;
u32 material_type_param;
AnimationType animation_type;
u16 vertical_frame_num;
u16 horizontal_frame_num;
u16 first_frame;
float frame_length;
bool loop_animation;
u8 glow;
} spawn_particle;
struct{
u16 amount;
@ -205,6 +214,15 @@ struct ClientEvent
bool vertical;
std::string *texture;
u32 id;
u32 material_type_param;
AnimationType animation_type;
u16 vertical_frame_num;
u16 horizontal_frame_num;
u16 min_first_frame;
u16 max_first_frame;
float frame_length;
bool loop_animation;
u8 glow;
} add_particlespawner;
struct{
u32 id;

View file

@ -896,23 +896,46 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
std::string texture = deSerializeLongString(is);
bool vertical = false;
bool collision_removal = false;
u32 material_type_param = 0;
AnimationType animation_type = AT_NONE;
u16 vertical_frame_num = 1;
u16 horizontal_frame_num = 1;
u16 first_frame = 0;
float frame_length = -1;
bool loop_animation = true;
u8 glow = 0;
try {
vertical = readU8(is);
collision_removal = readU8(is);
material_type_param = readU32(is);
animation_type = (AnimationType)readU8(is);
vertical_frame_num = readU16(is);
horizontal_frame_num = readU16(is);
first_frame = readU16(is);
frame_length = readF1000(is);
loop_animation = readU8(is);
glow = readU8(is);
} catch (...) {}
ClientEvent event;
event.type = CE_SPAWN_PARTICLE;
event.spawn_particle.pos = new v3f (pos);
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.type = CE_SPAWN_PARTICLE;
event.spawn_particle.pos = new v3f (pos);
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.material_type_param = material_type_param;
event.spawn_particle.animation_type = animation_type;
event.spawn_particle.vertical_frame_num = vertical_frame_num;
event.spawn_particle.horizontal_frame_num = horizontal_frame_num;
event.spawn_particle.first_frame = first_frame;
event.spawn_particle.frame_length = frame_length;
event.spawn_particle.loop_animation = loop_animation;
event.spawn_particle.glow = glow;
m_client_event_queue.push(event);
}
@ -932,6 +955,15 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
float maxsize;
bool collisiondetection;
u32 id;
u32 material_type_param = 0;
u8 animation_type = (u8)AT_NONE;
u16 vertical_frame_num = 1;
u16 horizontal_frame_num = 1;
u16 min_first_frame = 0;
u16 max_first_frame = 0;
float frame_length = -1;
bool loop_animation = true;
u8 glow = 0;
*pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
>> minacc >> maxacc >> minexptime >> maxexptime >> minsize
@ -948,29 +980,46 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
*pkt >> vertical;
*pkt >> collision_removal;
*pkt >> attached_id;
*pkt >> material_type_param;
*pkt >> animation_type;
*pkt >> vertical_frame_num;
*pkt >> horizontal_frame_num;
*pkt >> min_first_frame;
*pkt >> max_first_frame;
*pkt >> frame_length;
*pkt >> loop_animation;
*pkt >> glow;
} catch (...) {}
ClientEvent event;
event.type = CE_ADD_PARTICLESPAWNER;
event.add_particlespawner.amount = amount;
event.add_particlespawner.spawntime = spawntime;
event.add_particlespawner.minpos = new v3f (minpos);
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 = attached_id;
event.add_particlespawner.vertical = vertical;
event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id;
event.type = CE_ADD_PARTICLESPAWNER;
event.add_particlespawner.amount = amount;
event.add_particlespawner.spawntime = spawntime;
event.add_particlespawner.minpos = new v3f (minpos);
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 = attached_id;
event.add_particlespawner.vertical = vertical;
event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id;
event.add_particlespawner.material_type_param = material_type_param;
event.add_particlespawner.animation_type = (AnimationType)animation_type;
event.add_particlespawner.vertical_frame_num = vertical_frame_num;
event.add_particlespawner.horizontal_frame_num = horizontal_frame_num;
event.add_particlespawner.min_first_frame = min_first_frame;
event.add_particlespawner.max_first_frame = max_first_frame;
event.add_particlespawner.frame_length = frame_length;
event.add_particlespawner.loop_animation = loop_animation;
event.add_particlespawner.glow = glow;
m_client_event_queue.push(event);
}

View file

@ -211,7 +211,7 @@ void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, con
{
int version = readU8(is);
name = deSerializeString(is);
animation.type = (TileAnimationType)readU8(is);
animation.type = (AnimationType)readU8(is);
animation.aspect_w = readU16(is);
animation.aspect_h = readU16(is);
animation.length = readF1000(is);
@ -531,7 +531,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
tile->material_flags = 0;
if (backface_culling)
tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
if (tiledef->animation.type == AT_VERTICAL_FRAMES)
tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
if (tiledef->tileable_horizontal)
tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;

View file

@ -161,9 +161,10 @@ enum NodeDrawType
/*
Stand-alone definition of a TileSpec (basically a server-side TileSpec)
*/
enum TileAnimationType{
TAT_NONE=0,
TAT_VERTICAL_FRAMES=1,
enum AnimationType{
AT_NONE = 0,
AT_VERTICAL_FRAMES = 1,
AT_2D_ANIMATION_SHEET = 2,
};
struct TileDef
{
@ -172,7 +173,7 @@ struct TileDef
bool tileable_horizontal;
bool tileable_vertical;
struct{
enum TileAnimationType type;
enum AnimationType type;
int aspect_w; // width for aspect ratio
int aspect_h; // height for aspect ratio
float length; // seconds
@ -184,7 +185,7 @@ struct TileDef
backface_culling = true;
tileable_horizontal = true;
tileable_vertical = true;
animation.type = TAT_NONE;
animation.type = AT_NONE;
animation.aspect_w = 1;
animation.aspect_h = 1;
animation.length = 1.0;

View file

@ -43,6 +43,22 @@ v3f random_v3f(v3f min, v3f max)
rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
}
u32 check_material_type_param(u32 material_type_param)
{
u32 alphaSource = (material_type_param & 0x0000F000) >> 12;
u32 modulo = (material_type_param & 0x00000F00) >> 8;
u32 srcFact = (material_type_param & 0x000000F0) >> 4;
u32 dstFact = material_type_param & 0x0000000F;
if (alphaSource <= 3 && modulo <= 4 && srcFact <= 10 && dstFact <= 10) {
return material_type_param;
} else {
errorstream << "Server send incorrect ";
errorstream << "material_type_param value for particle.";
errorstream << std::endl;
return 0;
}
}
Particle::Particle(
IGameDef *gamedef,
scene::ISceneManager* smgr,
@ -58,7 +74,14 @@ Particle::Particle(
bool vertical,
video::ITexture *texture,
v2f texpos,
v2f texsize
v2f texsize,
u32 material_type_param,
u16 vertical_frame_num,
u16 horizontal_frame_num,
u16 first_frame,
float frame_length,
bool loop_animation,
u8 glow
):
scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
@ -71,11 +94,26 @@ Particle::Particle(
m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
m_material.setFlag(video::EMF_FOG_ENABLE, true);
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
if (material_type_param != 0) {
m_material.MaterialType = video::EMT_ONETEXTURE_BLEND;
m_material.MaterialTypeParam = irr::core::FR(material_type_param);
// We must disable z-buffer if we want to avoid transparent pixels
// to overlap pixels with lower z-value.
m_material.setFlag(video::EMF_ZWRITE_ENABLE, false);
} else {
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
m_material.setTexture(0, texture);
m_texpos = texpos;
m_texsize = texsize;
m_vertical_frame_num = vertical_frame_num;
m_horizontal_frame_num = horizontal_frame_num;
m_first_frame = first_frame;
m_frame_length = frame_length;
m_loop_animation = loop_animation;
m_texsize.Y /= m_vertical_frame_num;
m_texsize.X /= m_horizontal_frame_num;
// Particle related
m_pos = pos;
@ -88,6 +126,7 @@ Particle::Particle(
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_vertical = vertical;
m_glow = glow;
// Irrlicht stuff
m_collisionbox = aabb3f
@ -170,16 +209,29 @@ void Particle::updateLight()
else
light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
m_light = decode_light(light);
m_light = decode_light(light + m_glow);
}
void Particle::updateVertices()
{
video::SColor c(255, m_light, m_light, m_light);
f32 tx0 = m_texpos.X;
f32 tx1 = m_texpos.X + m_texsize.X;
f32 ty0 = m_texpos.Y;
f32 ty1 = m_texpos.Y + m_texsize.Y;
u16 frame = m_first_frame;
if (m_frame_length > 0) {
if (m_loop_animation)
frame = m_first_frame + (u32)(m_time / m_frame_length)
% (m_vertical_frame_num *
m_horizontal_frame_num - m_first_frame);
else if (m_time >=
(m_vertical_frame_num * m_horizontal_frame_num
- m_first_frame) * m_frame_length)
frame = m_vertical_frame_num * m_horizontal_frame_num - 1;
else
frame = m_first_frame + (u16)(m_time / m_frame_length);
}
f32 tx0 = m_texpos.X + m_texsize.X * (frame % m_horizontal_frame_num);
f32 tx1 = m_texpos.X + m_texsize.X * (frame % m_horizontal_frame_num + 1);
f32 ty0 = m_texpos.Y + m_texsize.Y * (frame / m_horizontal_frame_num);
f32 ty1 = m_texpos.Y + m_texsize.Y * (frame / m_horizontal_frame_num + 1);
m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
c, tx0, ty1);
@ -214,7 +266,16 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
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, u16 attached_id, bool vertical,
video::ITexture *texture, u32 id, ParticleManager *p_manager) :
video::ITexture *texture, u32 id,
u32 material_type_param,
u16 vertical_frame_num,
u16 horizontal_frame_num,
u16 min_first_frame,
u16 max_first_frame,
float frame_length,
bool loop_animation,
u8 glow,
ParticleManager *p_manager) :
m_particlemanager(p_manager)
{
m_gamedef = gamedef;
@ -238,6 +299,14 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
m_vertical = vertical;
m_texture = texture;
m_time = 0;
m_vertical_frame_num = vertical_frame_num;
m_horizontal_frame_num = horizontal_frame_num;
m_min_first_frame = min_first_frame;
m_max_first_frame = max_first_frame;
m_frame_length = frame_length;
m_loop_animation = loop_animation;
m_material_type_param = material_type_param;
m_glow = glow;
for (u16 i = 0; i<=m_amount; i++)
{
@ -251,7 +320,6 @@ ParticleSpawner::~ParticleSpawner() {}
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) {
@ -285,7 +353,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
float size = rand()/(float)RAND_MAX
*(m_maxsize-m_minsize)
+m_minsize;
u16 first_frame = m_min_first_frame +
rand() %
(m_max_first_frame -
m_min_first_frame + 1);
Particle* toadd = new Particle(
m_gamedef,
m_smgr,
@ -301,7 +372,14 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
m_vertical,
m_texture,
v2f(0.0, 0.0),
v2f(1.0, 1.0));
v2f(1.0, 1.0),
m_material_type_param,
m_vertical_frame_num,
m_horizontal_frame_num,
first_frame,
m_frame_length,
m_loop_animation,
m_glow);
m_particlemanager->addParticle(toadd);
}
i = m_spawntimes.erase(i);
@ -331,7 +409,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
float size = rand()/(float)RAND_MAX
*(m_maxsize-m_minsize)
+m_minsize;
u16 first_frame = m_min_first_frame +
rand() %
(m_max_first_frame -
m_min_first_frame + 1);
Particle* toadd = new Particle(
m_gamedef,
m_smgr,
@ -347,7 +428,14 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
m_vertical,
m_texture,
v2f(0.0, 0.0),
v2f(1.0, 1.0));
v2f(1.0, 1.0),
m_material_type_param,
m_vertical_frame_num,
m_horizontal_frame_num,
first_frame,
m_frame_length,
m_loop_animation,
m_glow);
m_particlemanager->addParticle(toadd);
}
}
@ -459,6 +547,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
video::ITexture *texture =
gamedef->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture));
float frame_length = -1;
u16 vertical_frame_num = 1;
u16 horizontal_frame_num = 1;
u32 material_type_param =
check_material_type_param(event->add_particlespawner.material_type_param);
switch (event->add_particlespawner.animation_type) {
case AT_NONE:
break;
case AT_VERTICAL_FRAMES: {
v2u32 size = texture->getOriginalSize();
int frame_height = (float)size.X /
(float)event->add_particlespawner.vertical_frame_num *
(float)event->add_particlespawner.horizontal_frame_num;
vertical_frame_num = size.Y / frame_height;
frame_length =
event->add_particlespawner.frame_length /
vertical_frame_num;
break;
}
case AT_2D_ANIMATION_SHEET: {
vertical_frame_num =
event->add_particlespawner.vertical_frame_num;
horizontal_frame_num =
event->add_particlespawner.horizontal_frame_num;
frame_length =
event->add_particlespawner.frame_length;
break;
}
default:
break;
}
ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player,
event->add_particlespawner.amount,
event->add_particlespawner.spawntime,
@ -478,6 +599,14 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->add_particlespawner.vertical,
texture,
event->add_particlespawner.id,
material_type_param,
vertical_frame_num,
horizontal_frame_num,
event->add_particlespawner.min_first_frame,
event->add_particlespawner.max_first_frame,
frame_length,
event->add_particlespawner.loop_animation,
event->add_particlespawner.glow,
this);
/* delete allocated content of event */
@ -502,6 +631,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
video::ITexture *texture =
gamedef->tsrc()->getTextureForMesh(*(event->spawn_particle.texture));
float frame_length = -1;
u16 vertical_frame_num = 1;
u16 horizontal_frame_num = 1;
u32 material_type_param =
check_material_type_param(event->spawn_particle.material_type_param);
switch (event->spawn_particle.animation_type) {
case AT_NONE:
break;
case AT_VERTICAL_FRAMES: {
v2u32 size = texture->getOriginalSize();
int frame_height = (float)size.X /
(float)event->spawn_particle.vertical_frame_num *
(float)event->spawn_particle.horizontal_frame_num;
vertical_frame_num = size.Y / frame_height;
frame_length =
event->spawn_particle.frame_length /
vertical_frame_num;
break;
}
case AT_2D_ANIMATION_SHEET: {
vertical_frame_num =
event->spawn_particle.vertical_frame_num;
horizontal_frame_num =
event->spawn_particle.horizontal_frame_num;
frame_length =
event->spawn_particle.frame_length;
break;
}
default:
break;
}
Particle* toadd = new Particle(gamedef, smgr, player, m_env,
*event->spawn_particle.pos,
*event->spawn_particle.vel,
@ -513,13 +675,21 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->spawn_particle.vertical,
texture,
v2f(0.0, 0.0),
v2f(1.0, 1.0));
v2f(1.0, 1.0),
material_type_param,
vertical_frame_num,
horizontal_frame_num,
event->spawn_particle.first_frame,
frame_length,
event->spawn_particle.loop_animation,
event->spawn_particle.glow);
addParticle(toadd);
delete event->spawn_particle.pos;
delete event->spawn_particle.vel;
delete event->spawn_particle.acc;
delete event->spawn_particle.texture;
break;
}
@ -588,7 +758,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
false,
texture,
texpos,
texsize);
texsize,
0, 1, 1, 0, -1, true, 0);
addParticle(toadd);
}

View file

@ -50,7 +50,14 @@ class Particle : public scene::ISceneNode
bool vertical,
video::ITexture *texture,
v2f texpos,
v2f texsize
v2f texsize,
u32 material_type_param,
u16 vertical_frame_num,
u16 horizontal_frame_num,
u16 first_frame,
float frame_length,
bool loop_animation,
u8 glow
);
~Particle();
@ -102,6 +109,12 @@ private:
bool m_collision_removal;
bool m_vertical;
v3s16 m_camera_offset;
u16 m_vertical_frame_num;
u16 m_horizontal_frame_num;
u16 m_first_frame;
float m_frame_length;
bool m_loop_animation;
u8 m_glow;
};
class ParticleSpawner
@ -123,8 +136,15 @@ class ParticleSpawner
bool vertical,
video::ITexture *texture,
u32 id,
u32 material_type_param,
u16 vertical_frame_num,
u16 horizontal_frame_num,
u16 min_first_frame,
u16 max_first_frame,
float frame_length,
bool loop_animation,
u8 glow,
ParticleManager* p_manager);
~ParticleSpawner();
void step(float dtime, ClientEnvironment *env);
@ -156,6 +176,14 @@ class ParticleSpawner
bool m_collision_removal;
bool m_vertical;
u16 m_attached_id;
u32 m_material_type_param;
u16 m_vertical_frame_num;
u16 m_horizontal_frame_num;
u16 m_min_first_frame;
u16 m_max_first_frame;
float m_frame_length;
bool m_loop_animation;
u8 m_glow;
};
/**

View file

@ -35,10 +35,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include <json/json.h>
struct EnumString es_TileAnimationType[] =
struct EnumString es_AnimationType[] =
{
{TAT_NONE, "none"},
{TAT_VERTICAL_FRAMES, "vertical_frames"},
{AT_NONE, "none"},
{AT_VERTICAL_FRAMES, "vertical_frames"},
{AT_2D_ANIMATION_SHEET, "2d_animation_sheet"},
{0, NULL},
};
@ -335,9 +336,9 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
lua_getfield(L, index, "animation");
if(lua_istable(L, -1)){
// {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
tiledef.animation.type = (TileAnimationType)
getenumfield(L, -1, "type", es_TileAnimationType,
TAT_NONE);
tiledef.animation.type = (AnimationType)
getenumfield(L, -1, "type", es_AnimationType,
AT_NONE);
tiledef.animation.aspect_w =
getintfield_default(L, -1, "aspect_w", 16);
tiledef.animation.aspect_h =

View file

@ -159,6 +159,6 @@ bool push_json_value (lua_State *L,
void read_json_value (lua_State *L, Json::Value &root,
int index, u8 recursion = 0);
extern struct EnumString es_TileAnimationType[];
extern struct EnumString es_AnimationType[];
#endif /* C_CONTENT_H_ */

View file

@ -513,6 +513,28 @@ int getintfield_default(lua_State *L, int table,
return result;
}
int check_material_type_param(lua_State *L, int table,
const char *fieldname, int default_)
{
int material_type_param =
getintfield_default(L, table, fieldname, default_);
u32 alphaSource = (material_type_param & 0x0000F000) >> 12;
u32 modulo = (material_type_param & 0x00000F00) >> 8;
u32 srcFact = (material_type_param & 0x000000F0) >> 4;
u32 dstFact = material_type_param & 0x0000000F;
if (alphaSource <= 3 && modulo <= 4 && srcFact <= 10 && dstFact <= 10) {
return material_type_param;
} else {
std::ostringstream error_text;
error_text << "Incorrect material_type_param value ";
error_text << "for particle or particle spawner.";
error_text << std::endl;
throw LuaError(error_text.str());
return 0;
}
}
float getfloatfield_default(lua_State *L, int table,
const char *fieldname, float default_)
{

View file

@ -45,6 +45,8 @@ float getfloatfield_default(lua_State *L, int table,
const char *fieldname, float default_);
int getintfield_default (lua_State *L, int table,
const char *fieldname, int default_);
int check_material_type_param(lua_State *L, int table,
const char *fieldname, int default_);
bool getstringfield(lua_State *L, int table,
const char *fieldname, std::string &result);

View file

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_object.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "server.h"
#include "particles.h"
@ -34,6 +35,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
// material_type_param = num
// animation = animation definition
// glow = indexed color or color string
int ModApiParticles::l_add_particle(lua_State *L)
{
MAP_LOCK_REQUIRED;
@ -44,13 +48,24 @@ int ModApiParticles::l_add_particle(lua_State *L)
float expirationtime, size;
expirationtime = size = 1;
float frame_or_loop_length = -1;
AnimationType animation_type = AT_NONE;
u16 vertical_frame_num_or_aspect = 1;
u16 horizontal_frame_num_or_aspect = 1;
u16 first_frame = 0;
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
bool loop_animation = true;
std::string texture = "";
std::string playername = "";
u32 material_type_param = 0;
u8 glow = 0;
if (lua_gettop(L) > 1) // deprecated
{
log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition");
@ -94,8 +109,61 @@ int ModApiParticles::l_add_particle(lua_State *L)
acc = lua_istable(L, -1) ? check_v3f(L, -1) : acc;
lua_pop(L, 1);
expirationtime = getfloatfield_default(L, 1, "expirationtime", 1);
expirationtime = getfloatfield_default(L, 1, "expirationtime", 1);
size = getfloatfield_default(L, 1, "size", 1);
lua_getfield(L, 1, "animation");
if (lua_istable(L, -1)) {
animation_type = (AnimationType)
getenumfield(L, -1, "type", es_AnimationType,
AT_NONE);
}
switch (animation_type) {
case AT_NONE:
break;
case AT_2D_ANIMATION_SHEET:
frame_or_loop_length =
getfloatfield_default(L, -1, "frame_length", -1);
vertical_frame_num_or_aspect =
getintfield_default(L, -1, "vertical_frame_num", 1);
horizontal_frame_num_or_aspect =
getintfield_default(L, -1, "horizontal_frame_num", 1);
first_frame =
getintfield_default(L, -1, "first_frame", 0);
loop_animation =
getboolfield_default(L, -1, "loop_animation", true);
break;
case AT_VERTICAL_FRAMES:
frame_or_loop_length =
getfloatfield_default(L, -1, "length", -1);
vertical_frame_num_or_aspect =
getintfield_default(L, -1, "aspect_w", 1);
horizontal_frame_num_or_aspect =
getintfield_default(L, -1, "aspect_h", 1);
first_frame =
getintfield_default(L, -1, "first_frame", 0);
loop_animation =
getboolfield_default(L, -1, "loop_animation", true);
break;
default:
break;
}
lua_pop(L, 1);
if (animation_type == AT_2D_ANIMATION_SHEET &&
first_frame >= vertical_frame_num_or_aspect *
horizontal_frame_num_or_aspect) {
std::ostringstream error_text;
error_text << "first_frame should be lower, than "
<< "vertical_frame_num * horizontal_frame_num. "
<< "Got first_frame=" << first_frame
<< ", vertical_frame_num="
<< vertical_frame_num_or_aspect
<< " and horizontal_frame_num="
<< horizontal_frame_num_or_aspect << std::endl;
throw LuaError(error_text.str());
}
collisiondetection = getboolfield_default(L, 1,
"collisiondetection", collisiondetection);
collision_removal = getboolfield_default(L, 1,
@ -103,9 +171,16 @@ int ModApiParticles::l_add_particle(lua_State *L)
vertical = getboolfield_default(L, 1, "vertical", vertical);
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
material_type_param = check_material_type_param(L, 1, "material_type_param", 0);
glow = getintfield_default (L, 1, "glow", 0);
}
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
collisiondetection, collision_removal, vertical, texture);
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime,
size, collisiondetection, collision_removal, vertical,
texture, material_type_param,
animation_type,
vertical_frame_num_or_aspect,
horizontal_frame_num_or_aspect,
first_frame, frame_or_loop_length, loop_animation, glow);
return 1;
}
@ -127,21 +202,33 @@ int ModApiParticles::l_add_particle(lua_State *L)
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
// material_type_param = num
// animation = animation definition
// glow = indexed color or color string
int ModApiParticles::l_add_particlespawner(lua_State *L)
{
MAP_LOCK_REQUIRED;
// Get parameters
u16 amount = 1;
u16 vertical_frame_num_or_aspect = 1;
u16 horizontal_frame_num_or_aspect = 1;
u16 min_first_frame = 0;
u16 max_first_frame = 0;
v3f minpos, maxpos, minvel, maxvel, minacc, maxacc;
minpos= maxpos= minvel= maxvel= minacc= maxacc= v3f(0, 0, 0);
float time, minexptime, maxexptime, minsize, maxsize;
time= minexptime= maxexptime= minsize= maxsize= 1;
AnimationType animation_type = AT_NONE;
float frame_or_loop_length = -1;
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
bool loop_animation = true;
ServerActiveObject *attached = NULL;
std::string texture = "";
std::string playername = "";
u32 material_type_param = 0;
u8 glow = 0;
if (lua_gettop(L) > 1) //deprecated
{
@ -196,6 +283,65 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
maxexptime = getfloatfield_default(L, 1, "maxexptime", maxexptime);
minsize = getfloatfield_default(L, 1, "minsize", minsize);
maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
lua_getfield(L, 1, "animation");
if (lua_istable(L, -1)) {
animation_type = (AnimationType)
getenumfield(L, -1, "type", es_AnimationType,
AT_NONE);
}
switch (animation_type) {
case AT_NONE:
break;
case AT_2D_ANIMATION_SHEET:
frame_or_loop_length =
getfloatfield_default(L, -1, "frame_length", -1);
vertical_frame_num_or_aspect =
getintfield_default(L, -1, "vertical_frame_num", 1);
horizontal_frame_num_or_aspect =
getintfield_default(L, -1, "horizontal_frame_num", 1);
min_first_frame =
getintfield_default(L, -1, "min_first_frame", 0);
max_first_frame =
getintfield_default(L, -1, "max_first_frame", 0);
loop_animation =
getboolfield_default(L, -1, "loop_animation", true);
break;
case AT_VERTICAL_FRAMES:
frame_or_loop_length =
getfloatfield_default(L, -1, "length", -1);
vertical_frame_num_or_aspect =
getintfield_default(L, -1, "aspect_w", 1);
horizontal_frame_num_or_aspect =
getintfield_default(L, -1, "aspect_h", 1);
min_first_frame =
getintfield_default(L, -1, "min_first_frame", 0);
max_first_frame =
getintfield_default(L, -1, "max_first_frame", 0);
loop_animation =
getboolfield_default(L, -1, "loop_animation", true);
break;
default:
break;
}
lua_pop(L, 1);
if (animation_type == AT_2D_ANIMATION_SHEET &&
max_first_frame >= vertical_frame_num_or_aspect *
horizontal_frame_num_or_aspect) {
std::ostringstream error_text;
error_text << "max_first_frame should be lower, than "
<< "vertical_frame_num * horizontal_frame_num. "
<< "Got max_first_frame="
<< max_first_frame
<< ", vertical_frame_num="
<< vertical_frame_num_or_aspect
<< " and horizontal_frame_num="
<< horizontal_frame_num_or_aspect << std::endl;
throw LuaError(error_text.str());
}
collisiondetection = getboolfield_default(L, 1,
"collisiondetection", collisiondetection);
collision_removal = getboolfield_default(L, 1,
@ -211,6 +357,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
vertical = getboolfield_default(L, 1, "vertical", vertical);
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
material_type_param = check_material_type_param(L, 1, "material_type_param", 0);
glow = getintfield_default(L, 1, "glow", 0);
}
u32 id = getServer(L)->addParticleSpawner(amount, time,
@ -223,9 +371,17 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
collision_removal,
attached,
vertical,
texture, playername);
texture,
playername,
material_type_param,
animation_type,
vertical_frame_num_or_aspect,
horizontal_frame_num_or_aspect,
min_first_frame, max_first_frame,
frame_or_loop_length,
loop_animation,
glow);
lua_pushnumber(L, id);
return 1;
}

View file

@ -1658,7 +1658,11 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size, bool collisiondetection,
bool collision_removal,
bool vertical, const std::string &texture)
bool vertical, const std::string &texture,
u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
float frame_length, bool loop_animation,
u8 glow)
{
DSTACK(FUNCTION_NAME);
@ -1670,6 +1674,12 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
pkt << vertical;
pkt << collision_removal;
pkt << material_type_param
<< (u8)animation_type
<< vertical_frame_num
<< horizontal_frame_num << first_frame
<< frame_length << loop_animation << glow;
if (peer_id != PEER_ID_INEXISTENT) {
Send(&pkt);
}
@ -1682,7 +1692,10 @@ 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,
u16 attached_id, bool vertical, const std::string &texture, u32 id)
u16 attached_id, bool vertical, const std::string &texture, u32 id,
u32 material_type_param, AnimationType animation_type, u16 vertical_frame_num, u16 horizontal_frame_num,
u16 min_first_frame, u16 max_first_frame, float frame_length,
bool loop_animation, u8 glow)
{
DSTACK(FUNCTION_NAME);
@ -1698,6 +1711,12 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
pkt << collision_removal;
pkt << attached_id;
pkt << material_type_param
<< (u8)animation_type
<< vertical_frame_num << horizontal_frame_num
<< min_first_frame << max_first_frame
<< frame_length << loop_animation << glow;
if (peer_id != PEER_ID_INEXISTENT) {
Send(&pkt);
}
@ -3147,7 +3166,11 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
v3f velocity, v3f acceleration,
float expirationtime, float size, bool
collisiondetection, bool collision_removal,
bool vertical, const std::string &texture)
bool vertical, const std::string &texture,
u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
float frame_length, bool loop_animation,
u8 glow)
{
// m_env will be NULL if the server is initializing
if (!m_env)
@ -3163,7 +3186,11 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
SendSpawnParticle(peer_id, pos, velocity, acceleration,
expirationtime, size, collisiondetection,
collision_removal, vertical, texture);
collision_removal, vertical, texture,
material_type_param, animation_type,
vertical_frame_num, horizontal_frame_num,
first_frame, frame_length, loop_animation,
glow);
}
u32 Server::addParticleSpawner(u16 amount, float spawntime,
@ -3171,7 +3198,9 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
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)
const std::string &playername, u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num, u16 min_first_frame, u16 max_first_frame,
float frame_length, bool loop_animation, u8 glow)
{
// m_env will be NULL if the server is initializing
if (!m_env)
@ -3197,7 +3226,10 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, collision_removal, attached_id, vertical,
texture, id);
texture, id, material_type_param, animation_type,
vertical_frame_num, horizontal_frame_num,
min_first_frame, max_first_frame, frame_length, loop_animation,
glow);
return id;
}

View file

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "gamedef.h"
#include "serialization.h" // For SER_FMT_VER_INVALID
#include "nodedef.h" // AnimationType
#include "mods.h"
#include "inventorymanager.h"
#include "subgame.h"
@ -254,7 +255,11 @@ public:
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, bool collision_removal,
bool vertical, const std::string &texture);
bool vertical, const std::string &texture,
u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
float frame_length, bool loop_animation,
u8 glow);
u32 addParticleSpawner(u16 amount, float spawntime,
v3f minpos, v3f maxpos,
@ -265,7 +270,12 @@ public:
bool collisiondetection, bool collision_removal,
ServerActiveObject *attached,
bool vertical, const std::string &texture,
const std::string &playername);
const std::string &playername,
u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num,
u16 min_first_frame, u16 max_first_frame,
float frame_length, bool loop_animation,
u8 glow);
void deleteParticleSpawner(const std::string &playername, u32 id);
@ -441,7 +451,12 @@ private:
float minsize, float maxsize,
bool collisiondetection, bool collision_removal,
u16 attached_id,
bool vertical, const std::string &texture, u32 id);
bool vertical, const std::string &texture, u32 id,
u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num,
u16 min_first_frame, u16 max_first_frame,
float frame_length, bool loop_animation,
u8 glow);
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
@ -450,7 +465,11 @@ private:
v3f pos, v3f velocity, v3f acceleration,
float expirationtime, float size,
bool collisiondetection, bool collision_removal,
bool vertical, const std::string &texture);
bool vertical, const std::string &texture,
u32 material_type_param, AnimationType animation_type,
u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
float frame_length, bool loop_animation,
u8 glow);
u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);