Add particle animation, glow
authorsfan5 <sfan5@live.de>
Sat, 14 Jan 2017 15:48:49 +0000 (16:48 +0100)
committersfan5 <sfan5@live.de>
Wed, 18 Jan 2017 22:21:01 +0000 (23:21 +0100)
This is implemented by reusing and extending the
TileAnimation code for the methods used by particles.

16 files changed:
doc/lua_api.txt
games/minimal/mods/experimental/init.lua
src/client.h
src/network/clientpackethandler.cpp
src/network/networkpacket.cpp
src/network/networkpacket.h
src/nodedef.cpp
src/particles.cpp
src/particles.h
src/script/common/c_content.cpp
src/script/common/c_content.h
src/script/lua_api/l_particles.cpp
src/server.cpp
src/server.h
src/tileanimation.cpp
src/tileanimation.h

index c96131455f5e68b64f939a8af405964dd544d248..9bdc01c0795464632c2937ddd37da0454af472bb 100644 (file)
@@ -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`)
 
     {
index 142734cda3668d4d52191dee32fedfdb5926aee0..5e98e1a80154a353de0d5afc113a8576637031af 100644 (file)
@@ -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]"..
index f84246deb49c07dc25b2f91d29a5078fedcb7fc7..b33358d94c5570e519ea28c4f416def3243c62e1 100644 (file)
@@ -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;
index 411982f69109d72b81aa4ac3c45f743ee53782fd..b11f73e869d452677dec5607a8a383874394542a 100644 (file)
@@ -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);
 }
index 388afc18e7c5f628e1f0bc3a50590e6327ed776f..91e6c58e2ad370d43ea008ee2d0fc2b7d8bdc5e7 100644 (file)
@@ -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);
 
index 524470999bf55e75cc9e7a1e428208b05cba858e..3e436aba9e72f8595503bc7b0a216ceef1b776bc 100644 (file)
@@ -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);
index b7d023897ad58e1bb1cec6c63c65ed7828befd9e..a4af26e87ade414818d20e3f14dd7127fa3092cb 100644 (file)
@@ -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;
        }
index d9eb3cfa56cc5e9c8013a98bd33f13d1e920ce19..5f17763e013373cf2ef4423facbb1122635496fe 100644 (file)
@@ -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);
 }
index 00cb2c08e71fc3813254f9a19191abb55342f1f2..5464e66722c9a41dded0e62af1aa472958041fe4 100644 (file)
@@ -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;
 };
 
 /**
index b9bcfef691c1e49c9e640a33457b2b5c76290a86..84af4583b9de7d2962d1b2d18eccfc88f18a6302 100644 (file)
@@ -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);
        }
 
@@ -925,6 +904,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)
index 2a2228b6dd2fb3922666768dab41b5aa6ab0c7f6..9641f5c9eec8a534cebd6e62a9b61dbbd854fedf 100644 (file)
@@ -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,
index 667ac727210b0d80fe36bb7dffd7e82031c5f5d5..7f415844a4b9ac99e4ebe12d0f14aaa2841295a4 100644 (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,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;
index 74d9541c9fd745f337760c724fae980b087390ae..d3d5fd3d18986f7031bcef3d0985e82805ebb5ed 100644 (file)
@@ -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;
 }
index a86f75f1d4d95c7a79797a719ae253683d917bf4..e5121bdc30c2a0f7dd0f432f45c5daed0e043351 100644 (file)
@@ -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);
index a23eecc2ea7d6d9287db7eff77c05725988c793c..67d27d3963bda15dd95201b3cd305df35f63365d 100644 (file)
@@ -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);
+}
index 289ce515b1aa8bcf0bf3f0c50632240ad6c1c21a..eecd3eb96c851f9ba6eb82b52021e7c6552a5d47 100644 (file)
@@ -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