Add particle animation, glow

This is implemented by reusing and extending the
TileAnimation code for the methods used by particles.
This commit is contained in:
sfan5 2017-01-14 16:48:49 +01:00
parent c5967f75f0
commit 7279f0b373
16 changed files with 311 additions and 78 deletions

@ -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`)
{

@ -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]"..

@ -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;

@ -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);
}

@ -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);

@ -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);

@ -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;
}

@ -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);
}

@ -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;
};
/**

@ -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)

@ -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,

@ -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;

@ -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;
}

@ -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);

@ -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);
}

@ -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