mirror of
https://github.com/minetest/minetest.git
synced 2024-11-30 03:23:45 +01:00
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:
parent
c5967f75f0
commit
7279f0b373
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
18
src/server.h
18
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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user