aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsfan5 <sfan5@live.de>2017-01-14 16:48:49 +0100
committersfan5 <sfan5@live.de>2017-01-18 23:21:01 +0100
commit7279f0b37335396c85f6bdd7dc67ff56e53df0f9 (patch)
treebe0ee716cf8bc6e5379415a663db91b8a358c8ab
parentc5967f75f0a9827d1b65b384edd6ba07c73ffd2f (diff)
downloadminetest-7279f0b37335396c85f6bdd7dc67ff56e53df0f9.tar.gz
minetest-7279f0b37335396c85f6bdd7dc67ff56e53df0f9.tar.bz2
minetest-7279f0b37335396c85f6bdd7dc67ff56e53df0f9.zip
Add particle animation, glow
This is implemented by reusing and extending the TileAnimation code for the methods used by particles.
-rw-r--r--doc/lua_api.txt7
-rw-r--r--games/minimal/mods/experimental/init.lua37
-rw-r--r--src/client.h5
-rw-r--r--src/network/clientpackethandler.cpp18
-rw-r--r--src/network/networkpacket.cpp2
-rw-r--r--src/network/networkpacket.h5
-rw-r--r--src/nodedef.cpp2
-rw-r--r--src/particles.cpp74
-rw-r--r--src/particles.h12
-rw-r--r--src/script/common/c_content.cpp60
-rw-r--r--src/script/common/c_content.h1
-rw-r--r--src/script/lua_api/l_particles.cpp27
-rw-r--r--src/server.cpp85
-rw-r--r--src/server.h18
-rw-r--r--src/tileanimation.cpp32
-rw-r--r--src/tileanimation.h4
16 files changed, 311 insertions, 78 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index c96131455..9bdc01c07 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -4180,10 +4180,15 @@ The Biome API is still in an experimental phase and subject to change.
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
-- ^ Uses texture (string)
- playername = "singleplayer"
+ playername = "singleplayer",
-- ^ optional, if specified spawns particle only on the player's client
+ animation = {Tile Animation definition},
+ -- ^ optional, specifies how to animate the particle texture
+ glow = 0
+ -- ^ optional, specify particle self-luminescence in darkness
}
+
### `ParticleSpawner` definition (`add_particlespawner`)
{
diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua
index 142734cda..5e98e1a80 100644
--- a/games/minimal/mods/experimental/init.lua
+++ b/games/minimal/mods/experimental/init.lua
@@ -523,6 +523,43 @@ minetest.register_craft({
}
})
+minetest.register_craftitem("experimental:tester_tool_2", {
+ description = "Tester Tool 2",
+ inventory_image = "experimental_tester_tool_1.png^[invert:g",
+ on_use = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing, true)
+ if pos == nil then return end
+ pos = vector.add(pos, {x=0, y=0.5, z=0})
+ local tex, anim
+ if math.random(0, 1) == 0 then
+ tex = "default_lava_source_animated.png"
+ anim = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5}
+ else
+ tex = "default_lava_flowing_animated.png"
+ anim = {type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3}
+ end
+
+ minetest.add_particle({
+ pos = pos,
+ velocity = {x=0, y=0, z=0},
+ acceleration = {x=0, y=0.04, z=0},
+ expirationtime = 6,
+ collisiondetection = true,
+ texture = tex,
+ animation = anim,
+ size = 4,
+ glow = math.random(0, 5),
+ })
+ end,
+})
+
+minetest.register_craft({
+ output = 'experimental:tester_tool_2',
+ recipe = {
+ {'group:crumbly','group:crumbly'},
+ }
+})
+
--[[minetest.register_on_joinplayer(function(player)
minetest.after(3, function()
player:set_inventory_formspec("size[8,7.5]"..
diff --git a/src/client.h b/src/client.h
index f84246deb..b33358d94 100644
--- a/src/client.h
+++ b/src/client.h
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "particles.h"
#include "mapnode.h"
+#include "tileanimation.h"
struct MeshMakeData;
class MapBlockMesh;
@@ -186,6 +187,8 @@ struct ClientEvent
bool collision_removal;
bool vertical;
std::string *texture;
+ struct TileAnimationParams animation;
+ u8 glow;
} spawn_particle;
struct{
u16 amount;
@@ -206,6 +209,8 @@ struct ClientEvent
bool vertical;
std::string *texture;
u32 id;
+ struct TileAnimationParams animation;
+ u8 glow;
} add_particlespawner;
struct{
u32 id;
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 411982f69..b11f73e86 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "network/clientopcodes.h"
#include "util/serialize.h"
#include "util/srp.h"
+#include "tileanimation.h"
void Client::handleCommand_Deprecated(NetworkPacket* pkt)
{
@@ -896,9 +897,14 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
std::string texture = deSerializeLongString(is);
bool vertical = false;
bool collision_removal = false;
+ struct TileAnimationParams animation;
+ animation.type = TAT_NONE;
+ u8 glow = 0;
try {
vertical = readU8(is);
collision_removal = readU8(is);
+ animation.deSerialize(is, m_proto_ver);
+ glow = readU8(is);
} catch (...) {}
ClientEvent event;
@@ -912,6 +918,8 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
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;
m_client_event_queue.push(event);
}
@@ -943,12 +951,20 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
bool vertical = false;
bool collision_removal = false;
+ struct TileAnimationParams animation;
+ animation.type = TAT_NONE;
+ u8 glow = 0;
u16 attached_id = 0;
try {
*pkt >> vertical;
*pkt >> collision_removal;
*pkt >> attached_id;
+ // This is horrible but required (why are there two ways to deserialize pkts?)
+ std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes());
+ std::istringstream is(datastring, std::ios_base::binary);
+ animation.deSerialize(is, m_proto_ver);
+ glow = readU8(is);
} catch (...) {}
ClientEvent event;
@@ -971,6 +987,8 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
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;
m_client_event_queue.push(event);
}
diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp
index 388afc18e..91e6c58e2 100644
--- a/src/network/networkpacket.cpp
+++ b/src/network/networkpacket.cpp
@@ -63,7 +63,7 @@ void NetworkPacket::putRawPacket(u8 *data, u32 datasize, u16 peer_id)
m_data = std::vector<u8>(&data[2], &data[2 + m_datasize]);
}
-char* NetworkPacket::getString(u32 from_offset)
+const char* NetworkPacket::getString(u32 from_offset)
{
checkReadOffset(from_offset, 0);
diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h
index 524470999..3e436aba9 100644
--- a/src/network/networkpacket.h
+++ b/src/network/networkpacket.h
@@ -41,12 +41,15 @@ public:
u16 getPeerId() { return m_peer_id; }
u16 getCommand() { return m_command; }
const u32 getRemainingBytes() const { return m_datasize - m_read_offset; }
+ const char* getRemainingString() { return getString(m_read_offset); }
// Returns a c-string without copying.
// A better name for this would be getRawString()
- char* getString(u32 from_offset);
+ const char* getString(u32 from_offset);
// major difference to putCString(): doesn't write len into the buffer
void putRawString(const char* src, u32 len);
+ void putRawString(const std::string &src)
+ { putRawString(src.c_str(), src.size()); }
NetworkPacket& operator>>(std::string& dst);
NetworkPacket& operator<<(std::string src);
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index b7d023897..a4af26e87 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -541,7 +541,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
int frame_length_ms;
tiledef->animation.determineParams(tile->texture->getOriginalSize(),
- &frame_count, &frame_length_ms);
+ &frame_count, &frame_length_ms, NULL);
tile->animation_frame_count = frame_count;
tile->animation_frame_length_ms = frame_length_ms;
}
diff --git a/src/particles.cpp b/src/particles.cpp
index d9eb3cfa5..5f17763e0 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -54,7 +54,9 @@ Particle::Particle(
bool vertical,
video::ITexture *texture,
v2f texpos,
- v2f texsize
+ v2f texsize,
+ const struct TileAnimationParams &anim,
+ u8 glow
):
scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
@@ -71,7 +73,9 @@ Particle::Particle(
m_material.setTexture(0, texture);
m_texpos = texpos;
m_texsize = texsize;
-
+ m_animation = anim;
+ m_animation_frame = 0;
+ m_animation_time = 0.0;
// Particle related
m_pos = pos;
@@ -84,6 +88,7 @@ Particle::Particle(
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_vertical = vertical;
+ m_glow = glow;
// Irrlicht stuff
m_collisionbox = aabb3f
@@ -142,6 +147,18 @@ void Particle::step(float dtime)
m_velocity += m_acceleration * dtime;
m_pos += m_velocity * dtime;
}
+ if (m_animation.type != TAT_NONE) {
+ m_animation_time += dtime;
+ int frame_length_i, frame_count;
+ m_animation.determineParams(
+ m_material.getTexture(0)->getSize(),
+ &frame_count, &frame_length_i, NULL);
+ float frame_length = frame_length_i / 1000.0;
+ while (m_animation_time > frame_length) {
+ m_animation_frame++;
+ m_animation_time -= frame_length;
+ }
+ }
// Update lighting
updateLight();
@@ -166,16 +183,32 @@ 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;
+ f32 tx0, tx1, ty0, ty1;
+
+ if (m_animation.type != TAT_NONE) {
+ const v2u32 texsize = m_material.getTexture(0)->getSize();
+ v2f texcoord, framesize_f;
+ v2u32 framesize;
+ texcoord = m_animation.getTextureCoords(texsize, m_animation_frame);
+ m_animation.determineParams(texsize, NULL, NULL, &framesize);
+ framesize_f = v2f(framesize.X / (float) texsize.X, framesize.Y / (float) texsize.Y);
+
+ tx0 = m_texpos.X + texcoord.X;
+ tx1 = m_texpos.X + texcoord.X + framesize_f.X * m_texsize.X;
+ ty0 = m_texpos.Y + texcoord.Y;
+ ty1 = m_texpos.Y + texcoord.Y + framesize_f.Y * m_texsize.Y;
+ } else {
+ tx0 = m_texpos.X;
+ tx1 = m_texpos.X + m_texsize.X;
+ ty0 = m_texpos.Y;
+ ty1 = m_texpos.Y + m_texsize.Y;
+ }
m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
c, tx0, ty1);
@@ -210,7 +243,9 @@ 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, const struct TileAnimationParams &anim,
+ u8 glow,
+ ParticleManager *p_manager) :
m_particlemanager(p_manager)
{
m_gamedef = gamedef;
@@ -234,6 +269,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
m_vertical = vertical;
m_texture = texture;
m_time = 0;
+ m_animation = anim;
+ m_glow = glow;
for (u16 i = 0; i<=m_amount; i++)
{
@@ -309,7 +346,9 @@ 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_animation,
+ m_glow);
m_particlemanager->addParticle(toadd);
}
i = m_spawntimes.erase(i);
@@ -363,7 +402,9 @@ 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_animation,
+ m_glow);
m_particlemanager->addParticle(toadd);
}
}
@@ -494,6 +535,8 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
event->add_particlespawner.vertical,
texture,
event->add_particlespawner.id,
+ event->add_particlespawner.animation,
+ event->add_particlespawner.glow,
this);
/* delete allocated content of event */
@@ -529,13 +572,16 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
event->spawn_particle.vertical,
texture,
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);
delete event->spawn_particle.pos;
delete event->spawn_particle.vel;
delete event->spawn_particle.acc;
+ delete event->spawn_particle.texture;
break;
}
@@ -564,6 +610,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
// Texture
u8 texid = myrand_range(0, 5);
video::ITexture *texture;
+ struct TileAnimationParams anim;
+ anim.type = TAT_NONE;
// Only use first frame of animated texture
if (tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION)
@@ -605,7 +653,9 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
false,
texture,
texpos,
- texsize);
+ texsize,
+ anim,
+ 0);
addParticle(toadd);
}
diff --git a/src/particles.h b/src/particles.h
index 00cb2c08e..5464e6672 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/tile.h"
#include "localplayer.h"
#include "environment.h"
+#include "tileanimation.h"
struct ClientEvent;
class ParticleManager;
@@ -50,7 +51,9 @@ class Particle : public scene::ISceneNode
bool vertical,
video::ITexture *texture,
v2f texpos,
- v2f texsize
+ v2f texsize,
+ const struct TileAnimationParams &anim,
+ u8 glow
);
~Particle();
@@ -102,6 +105,10 @@ private:
bool m_collision_removal;
bool m_vertical;
v3s16 m_camera_offset;
+ struct TileAnimationParams m_animation;
+ float m_animation_time;
+ int m_animation_frame;
+ u8 m_glow;
};
class ParticleSpawner
@@ -123,6 +130,7 @@ class ParticleSpawner
bool vertical,
video::ITexture *texture,
u32 id,
+ const struct TileAnimationParams &anim, u8 glow,
ParticleManager* p_manager);
~ParticleSpawner();
@@ -156,6 +164,8 @@ class ParticleSpawner
bool m_collision_removal;
bool m_vertical;
u16 m_attached_id;
+ struct TileAnimationParams m_animation;
+ u8 m_glow;
};
/**
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index b9bcfef69..84af4583b 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -322,7 +322,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
}
else if(lua_istable(L, index))
{
- // {name="default_lava.png", animation={}}
+ // name="default_lava.png"
tiledef.name = "";
getstringfield(L, index, "name", tiledef.name);
getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
@@ -334,28 +334,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
L, index, "tileable_vertical", default_tiling);
// animation = {}
lua_getfield(L, index, "animation");
- if(lua_istable(L, -1)){
- tiledef.animation.type = (TileAnimationType)
- getenumfield(L, -1, "type", es_TileAnimationType,
- TAT_NONE);
- if (tiledef.animation.type == TAT_VERTICAL_FRAMES) {
- // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
- tiledef.animation.vertical_frames.aspect_w =
- getintfield_default(L, -1, "aspect_w", 16);
- tiledef.animation.vertical_frames.aspect_h =
- getintfield_default(L, -1, "aspect_h", 16);
- tiledef.animation.vertical_frames.length =
- getfloatfield_default(L, -1, "length", 1.0);
- } else if (tiledef.animation.type == TAT_SHEET_2D) {
- // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
- getintfield(L, -1, "frames_w",
- tiledef.animation.sheet_2d.frames_w);
- getintfield(L, -1, "frames_h",
- tiledef.animation.sheet_2d.frames_h);
- getfloatfield(L, -1, "frame_length",
- tiledef.animation.sheet_2d.frame_length);
- }
- }
+ tiledef.animation = read_animation_definition(L, -1);
lua_pop(L, 1);
}
@@ -926,6 +905,41 @@ void read_inventory_list(lua_State *L, int tableindex,
}
/******************************************************************************/
+struct TileAnimationParams read_animation_definition(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ struct TileAnimationParams anim;
+ anim.type = TAT_NONE;
+ if (!lua_istable(L, index))
+ return anim;
+
+ anim.type = (TileAnimationType)
+ getenumfield(L, index, "type", es_TileAnimationType,
+ TAT_NONE);
+ if (anim.type == TAT_VERTICAL_FRAMES) {
+ // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
+ anim.vertical_frames.aspect_w =
+ getintfield_default(L, index, "aspect_w", 16);
+ anim.vertical_frames.aspect_h =
+ getintfield_default(L, index, "aspect_h", 16);
+ anim.vertical_frames.length =
+ getfloatfield_default(L, index, "length", 1.0);
+ } else if (anim.type == TAT_SHEET_2D) {
+ // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5}
+ getintfield(L, index, "frames_w",
+ anim.sheet_2d.frames_w);
+ getintfield(L, index, "frames_h",
+ anim.sheet_2d.frames_h);
+ getfloatfield(L, index, "frame_length",
+ anim.sheet_2d.frame_length);
+ }
+
+ return anim;
+}
+
+/******************************************************************************/
ToolCapabilities read_tool_capabilities(
lua_State *L, int table)
{
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 2a2228b6d..9641f5c9e 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -79,6 +79,7 @@ void push_hit_params (lua_State *L,
ItemStack read_item (lua_State *L, int index, Server *srv);
+struct TileAnimationParams read_animation_definition(lua_State *L, int index);
ToolCapabilities read_tool_capabilities (lua_State *L, int table);
void push_tool_capabilities (lua_State *L,
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index 667ac7272..7f415844a 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -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,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
+// animation = TileAnimation definition
+// glow = num
int ModApiParticles::l_add_particle(lua_State *L)
{
MAP_LOCK_REQUIRED;
@@ -47,10 +50,13 @@ int ModApiParticles::l_add_particle(lua_State *L)
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
+ struct TileAnimationParams animation;
std::string texture = "";
std::string playername = "";
+ u8 glow = 0;
+
if (lua_gettop(L) > 1) // deprecated
{
log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition");
@@ -101,11 +107,18 @@ int ModApiParticles::l_add_particle(lua_State *L)
collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal);
vertical = getboolfield_default(L, 1, "vertical", vertical);
+
+ lua_getfield(L, 1, "animation");
+ animation = read_animation_definition(L, -1);
+ lua_pop(L, 1);
+
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
+
+ glow = getintfield_default(L, 1, "glow", 0);
}
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
- collisiondetection, collision_removal, vertical, texture);
+ collisiondetection, collision_removal, vertical, texture, animation, glow);
return 1;
}
@@ -127,6 +140,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
+// animation = TileAnimation definition
+// glow = num
int ModApiParticles::l_add_particlespawner(lua_State *L)
{
MAP_LOCK_REQUIRED;
@@ -139,9 +154,11 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
time= minexptime= maxexptime= minsize= maxsize= 1;
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
+ struct TileAnimationParams animation;
ServerActiveObject *attached = NULL;
std::string texture = "";
std::string playername = "";
+ u8 glow = 0;
if (lua_gettop(L) > 1) //deprecated
{
@@ -201,6 +218,10 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal);
+ lua_getfield(L, 1, "animation");
+ animation = read_animation_definition(L, -1);
+ lua_pop(L, 1);
+
lua_getfield(L, 1, "attached");
if (!lua_isnil(L, -1)) {
ObjectRef *ref = ObjectRef::checkobject(L, -1);
@@ -211,6 +232,7 @@ 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", "");
+ glow = getintfield_default(L, 1, "glow", 0);
}
u32 id = getServer(L)->addParticleSpawner(amount, time,
@@ -223,7 +245,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
collision_removal,
attached,
vertical,
- texture, playername);
+ texture, playername,
+ animation, glow);
lua_pushnumber(L, id);
return 1;
diff --git a/src/server.cpp b/src/server.cpp
index 74d9541c9..d3d5fd3d1 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1662,12 +1662,28 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
}
// Spawns a particle on peer with peer_id
-void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
+void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version,
+ 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,
+ const struct TileAnimationParams &animation, u8 glow)
{
DSTACK(FUNCTION_NAME);
+ if (peer_id == PEER_ID_INEXISTENT) {
+ // This sucks and should be replaced by a better solution in a refactor:
+ std::vector<u16> clients = m_clients.getClientIDs();
+ for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
+ RemotePlayer *player = m_env->getPlayer(*i);
+ if (!player)
+ continue;
+ SendSpawnParticle(*i, player->protocol_version,
+ pos, velocity, acceleration,
+ expirationtime, size, collisiondetection,
+ collision_removal, vertical, texture, animation, glow);
+ }
+ return;
+ }
NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id);
@@ -1676,22 +1692,39 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
pkt.putLongString(texture);
pkt << vertical;
pkt << collision_removal;
+ // 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;
- if (peer_id != PEER_ID_INEXISTENT) {
- Send(&pkt);
- }
- else {
- m_clients.sendToAll(0, &pkt, true);
- }
+ Send(&pkt);
}
// Adds a ParticleSpawner on peer with peer_id
-void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
+void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
+ 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,
+ const struct TileAnimationParams &animation, u8 glow)
{
DSTACK(FUNCTION_NAME);
+ if (peer_id == PEER_ID_INEXISTENT) {
+ // This sucks and should be replaced:
+ std::vector<u16> clients = m_clients.getClientIDs();
+ for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
+ RemotePlayer *player = m_env->getPlayer(*i);
+ if (!player)
+ continue;
+ SendAddParticleSpawner(*i, player->protocol_version,
+ amount, spawntime, minpos, maxpos,
+ minvel, maxvel, minacc, maxacc, minexptime, maxexptime,
+ minsize, maxsize, collisiondetection, collision_removal,
+ attached_id, vertical, texture, id, animation, glow);
+ }
+ return;
+ }
NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id);
@@ -1704,13 +1737,13 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
pkt << id << vertical;
pkt << collision_removal;
pkt << attached_id;
+ // This is horrible but required
+ std::ostringstream os(std::ios_base::binary);
+ animation.serialize(os, protocol_version);
+ pkt.putRawString(os.str());
+ pkt << glow;
- if (peer_id != PEER_ID_INEXISTENT) {
- Send(&pkt);
- }
- else {
- m_clients.sendToAll(0, &pkt, true);
- }
+ Send(&pkt);
}
void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
@@ -3165,23 +3198,25 @@ 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,
+ const struct TileAnimationParams &animation, u8 glow)
{
// m_env will be NULL if the server is initializing
if (!m_env)
return;
- u16 peer_id = PEER_ID_INEXISTENT;
+ u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
if (playername != "") {
RemotePlayer *player = m_env->getPlayer(playername.c_str());
if (!player)
return;
peer_id = player->peer_id;
+ proto_ver = player->protocol_version;
}
- SendSpawnParticle(peer_id, pos, velocity, acceleration,
+ SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration,
expirationtime, size, collisiondetection,
- collision_removal, vertical, texture);
+ collision_removal, vertical, texture, animation, glow);
}
u32 Server::addParticleSpawner(u16 amount, float spawntime,
@@ -3189,18 +3224,20 @@ 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, const struct TileAnimationParams &animation,
+ u8 glow)
{
// m_env will be NULL if the server is initializing
if (!m_env)
return -1;
- u16 peer_id = PEER_ID_INEXISTENT;
+ u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0;
if (playername != "") {
RemotePlayer *player = m_env->getPlayer(playername.c_str());
if (!player)
return -1;
peer_id = player->peer_id;
+ proto_ver = player->protocol_version;
}
u16 attached_id = attached ? attached->getId() : 0;
@@ -3211,11 +3248,11 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
else
id = m_env->addParticleSpawner(spawntime, attached_id);
- SendAddParticleSpawner(peer_id, amount, spawntime,
+ SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime,
minpos, maxpos, minvel, maxvel, minacc, maxacc,
minexptime, maxexptime, minsize, maxsize,
collisiondetection, collision_removal, attached_id, vertical,
- texture, id);
+ texture, id, animation, glow);
return id;
}
diff --git a/src/server.h b/src/server.h
index a86f75f1d..e5121bdc3 100644
--- a/src/server.h
+++ b/src/server.h
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mods.h"
#include "inventorymanager.h"
#include "subgame.h"
+#include "tileanimation.h" // struct TileAnimationParams
#include "util/numeric.h"
#include "util/thread.h"
#include "util/basic_macros.h"
@@ -252,7 +253,8 @@ 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,
+ const struct TileAnimationParams &animation, u8 glow);
u32 addParticleSpawner(u16 amount, float spawntime,
v3f minpos, v3f maxpos,
@@ -263,7 +265,8 @@ public:
bool collisiondetection, bool collision_removal,
ServerActiveObject *attached,
bool vertical, const std::string &texture,
- const std::string &playername);
+ const std::string &playername, const struct TileAnimationParams &animation,
+ u8 glow);
void deleteParticleSpawner(const std::string &playername, u32 id);
@@ -428,7 +431,8 @@ private:
void sendDetachedInventories(u16 peer_id);
// Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
- void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime,
+ void SendAddParticleSpawner(u16 peer_id, u16 protocol_version,
+ u16 amount, float spawntime,
v3f minpos, v3f maxpos,
v3f minvel, v3f maxvel,
v3f minacc, v3f maxacc,
@@ -436,16 +440,18 @@ 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,
+ const struct TileAnimationParams &animation, u8 glow);
void SendDeleteParticleSpawner(u16 peer_id, u32 id);
// Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all)
- void SendSpawnParticle(u16 peer_id,
+ void SendSpawnParticle(u16 peer_id, u16 protocol_version,
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,
+ const struct TileAnimationParams &animation, u8 glow);
u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);
diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp
index a23eecc2e..67d27d396 100644
--- a/src/tileanimation.cpp
+++ b/src/tileanimation.cpp
@@ -69,7 +69,8 @@ void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version)
}
}
-void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const
+void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count,
+ int *frame_length_ms, v2u32 *frame_size) const
{
if (type == TAT_VERTICAL_FRAMES) {
int frame_height = (float)texture_size.X /
@@ -80,15 +81,17 @@ void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count,
*frame_count = _frame_count;
if (frame_length_ms)
*frame_length_ms = 1000.0 * vertical_frames.length / _frame_count;
+ if (frame_size)
+ *frame_size = v2u32(texture_size.X, frame_height);
} else if (type == TAT_SHEET_2D) {
if (frame_count)
*frame_count = sheet_2d.frames_w * sheet_2d.frames_h;
if (frame_length_ms)
*frame_length_ms = 1000 * sheet_2d.frame_length;
- } else { // TAT_NONE
- *frame_count = 1;
- *frame_length_ms = 1000;
+ if (frame_size)
+ *frame_size = v2u32(texture_size.X / sheet_2d.frames_w, texture_size.Y / sheet_2d.frames_h);
}
+ // caller should check for TAT_NONE
}
void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const
@@ -97,7 +100,7 @@ void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size
return;
if (type == TAT_VERTICAL_FRAMES) {
int frame_count;
- determineParams(texture_size, &frame_count, NULL);
+ determineParams(texture_size, &frame_count, NULL, NULL);
os << "^[verticalframe:" << frame_count << ":" << frame;
} else if (type == TAT_SHEET_2D) {
int q, r;
@@ -107,3 +110,22 @@ void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size
<< ":" << r << "," << q;
}
}
+
+v2f TileAnimationParams::getTextureCoords(v2u32 texture_size, int frame) const
+{
+ v2u32 ret(0, 0);
+ if (type == TAT_VERTICAL_FRAMES) {
+ int frame_height = (float)texture_size.X /
+ (float)vertical_frames.aspect_w *
+ (float)vertical_frames.aspect_h;
+ ret = v2u32(0, frame_height * frame);
+ } else if (type == TAT_SHEET_2D) {
+ v2u32 frame_size;
+ determineParams(texture_size, NULL, NULL, &frame_size);
+ int q, r;
+ q = frame / sheet_2d.frames_w;
+ r = frame % sheet_2d.frames_w;
+ ret = v2u32(r * frame_size.X, q * frame_size.Y);
+ }
+ return v2f(ret.X / (float) texture_size.X, ret.Y / (float) texture_size.Y);
+}
diff --git a/src/tileanimation.h b/src/tileanimation.h
index 289ce515b..eecd3eb96 100644
--- a/src/tileanimation.h
+++ b/src/tileanimation.h
@@ -48,8 +48,10 @@ struct TileAnimationParams {
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is, u16 protocol_version);
- void determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const;
+ void determineParams(v2u32 texture_size, int *frame_count,
+ int *frame_length_ms, v2u32 *frame_size) const;
void getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const;
+ v2f getTextureCoords(v2u32 texture_size, int frame) const;
};
#endif