Implement spawning particles with node texture appearance
parent
15ba75e4cf
commit
9d6e7e48d6
|
@ -164,6 +164,7 @@ LOCAL_SRC_FILES := \
|
|||
../../../src/noise.cpp \
|
||||
../../../src/objdef.cpp \
|
||||
../../../src/object_properties.cpp \
|
||||
../../../src/particles.cpp \
|
||||
../../../src/pathfinder.cpp \
|
||||
../../../src/player.cpp \
|
||||
../../../src/porting.cpp \
|
||||
|
|
|
@ -7835,6 +7835,8 @@ Used by `minetest.add_particle`.
|
|||
|
||||
size = 1,
|
||||
-- Scales the visual size of the particle texture.
|
||||
-- If `node` is set, size can be set to 0 to spawn a randomly-sized
|
||||
-- particle (just like actual node dig particles).
|
||||
|
||||
collisiondetection = false,
|
||||
-- If true collides with `walkable` nodes and, depending on the
|
||||
|
@ -7853,6 +7855,7 @@ Used by `minetest.add_particle`.
|
|||
-- If true faces player using y axis only
|
||||
|
||||
texture = "image.png",
|
||||
-- The texture of the particle
|
||||
|
||||
playername = "singleplayer",
|
||||
-- Optional, if specified spawns particle only on the player's client
|
||||
|
@ -7863,6 +7866,17 @@ Used by `minetest.add_particle`.
|
|||
glow = 0
|
||||
-- Optional, specify particle self-luminescence in darkness.
|
||||
-- Values 0-14.
|
||||
|
||||
node = {name = "ignore", param2 = 0},
|
||||
-- Optional, if specified the particle will have the same appearance as
|
||||
-- node dig particles for the given node.
|
||||
-- `texture` and `animation` will be ignored if this is set.
|
||||
|
||||
node_tile = 0,
|
||||
-- Optional, only valid in combination with `node`
|
||||
-- If set to a valid number 1-6, specifies the tile from which the
|
||||
-- particle texture is picked.
|
||||
-- Otherwise, the default behavior is used. (currently: any random tile)
|
||||
}
|
||||
|
||||
|
||||
|
@ -7892,7 +7906,9 @@ Used by `minetest.add_particlespawner`.
|
|||
maxsize = 1,
|
||||
-- The particles' properties are random values between the min and max
|
||||
-- values.
|
||||
-- pos, velocity, acceleration, expirationtime, size
|
||||
-- applies to: pos, velocity, acceleration, expirationtime, size
|
||||
-- If `node` is set, min and maxsize can be set to 0 to spawn
|
||||
-- randomly-sized particles (just like actual node dig particles).
|
||||
|
||||
collisiondetection = false,
|
||||
-- If true collide with `walkable` nodes and, depending on the
|
||||
|
@ -7915,6 +7931,7 @@ Used by `minetest.add_particlespawner`.
|
|||
-- If true face player using y axis only
|
||||
|
||||
texture = "image.png",
|
||||
-- The texture of the particle
|
||||
|
||||
playername = "singleplayer",
|
||||
-- Optional, if specified spawns particles only on the player's client
|
||||
|
@ -7925,6 +7942,17 @@ Used by `minetest.add_particlespawner`.
|
|||
glow = 0
|
||||
-- Optional, specify particle self-luminescence in darkness.
|
||||
-- Values 0-14.
|
||||
|
||||
node = {name = "ignore", param2 = 0},
|
||||
-- Optional, if specified the particles will have the same appearance as
|
||||
-- node dig particles for the given node.
|
||||
-- `texture` and `animation` will be ignored if this is set.
|
||||
|
||||
node_tile = 0,
|
||||
-- Optional, only valid in combination with `node`
|
||||
-- If set to a valid number 1-6, specifies the tile from which the
|
||||
-- particle texture is picked.
|
||||
-- Otherwise, the default behavior is used. (currently: any random tile)
|
||||
}
|
||||
|
||||
`HTTPRequest` definition
|
||||
|
|
|
@ -304,18 +304,37 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius,
|
|||
}
|
||||
|
||||
pp.expirationtime = random_f32(p.minexptime, p.maxexptime);
|
||||
pp.size = random_f32(p.minsize, p.maxsize);
|
||||
|
||||
p.copyCommon(pp);
|
||||
|
||||
video::ITexture *texture;
|
||||
v2f texpos, texsize;
|
||||
video::SColor color(0xFFFFFFFF);
|
||||
|
||||
if (p.node.getContent() != CONTENT_IGNORE) {
|
||||
const ContentFeatures &f =
|
||||
m_particlemanager->m_env->getGameDef()->ndef()->get(p.node);
|
||||
if (!ParticleManager::getNodeParticleParams(p.node, f, pp, &texture,
|
||||
texpos, texsize, &color, p.node_tile))
|
||||
return;
|
||||
} else {
|
||||
texture = m_texture;
|
||||
texpos = v2f(0.0f, 0.0f);
|
||||
texsize = v2f(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
// Allow keeping default random size
|
||||
if (p.maxsize > 0.0f)
|
||||
pp.size = random_f32(p.minsize, p.maxsize);
|
||||
|
||||
m_particlemanager->addParticle(new Particle(
|
||||
m_gamedef,
|
||||
m_player,
|
||||
env,
|
||||
pp,
|
||||
m_texture,
|
||||
v2f(0.0, 0.0),
|
||||
v2f(1.0, 1.0)
|
||||
texture,
|
||||
texpos,
|
||||
texsize,
|
||||
color
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -460,17 +479,35 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
|
|||
break;
|
||||
}
|
||||
case CE_SPAWN_PARTICLE: {
|
||||
const ParticleParameters &p = *event->spawn_particle;
|
||||
video::ITexture *texture =
|
||||
client->tsrc()->getTextureForMesh(p.texture);
|
||||
ParticleParameters &p = *event->spawn_particle;
|
||||
|
||||
Particle *toadd = new Particle(client, player, m_env,
|
||||
p,
|
||||
texture,
|
||||
v2f(0.0, 0.0),
|
||||
v2f(1.0, 1.0));
|
||||
video::ITexture *texture;
|
||||
v2f texpos, texsize;
|
||||
video::SColor color(0xFFFFFFFF);
|
||||
|
||||
addParticle(toadd);
|
||||
f32 oldsize = p.size;
|
||||
|
||||
if (p.node.getContent() != CONTENT_IGNORE) {
|
||||
const ContentFeatures &f = m_env->getGameDef()->ndef()->get(p.node);
|
||||
if (!getNodeParticleParams(p.node, f, p, &texture, texpos,
|
||||
texsize, &color, p.node_tile))
|
||||
texture = nullptr;
|
||||
} else {
|
||||
texture = client->tsrc()->getTextureForMesh(p.texture);
|
||||
texpos = v2f(0.0f, 0.0f);
|
||||
texsize = v2f(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
// Allow keeping default random size
|
||||
if (oldsize > 0.0f)
|
||||
p.size = oldsize;
|
||||
|
||||
if (texture) {
|
||||
Particle *toadd = new Particle(client, player, m_env,
|
||||
p, texture, texpos, texsize, color);
|
||||
|
||||
addParticle(toadd);
|
||||
}
|
||||
|
||||
delete event->spawn_particle;
|
||||
break;
|
||||
|
@ -480,15 +517,19 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
|
|||
}
|
||||
|
||||
bool ParticleManager::getNodeParticleParams(const MapNode &n,
|
||||
const ContentFeatures &f, ParticleParameters &p,
|
||||
video::ITexture **texture, v2f &texpos, v2f &texsize, video::SColor *color)
|
||||
const ContentFeatures &f, ParticleParameters &p, video::ITexture **texture,
|
||||
v2f &texpos, v2f &texsize, video::SColor *color, u8 tilenum)
|
||||
{
|
||||
// No particles for "airlike" nodes
|
||||
if (f.drawtype == NDT_AIRLIKE)
|
||||
return false;
|
||||
|
||||
// Texture
|
||||
u8 texid = rand() % 6;
|
||||
u8 texid;
|
||||
if (tilenum > 0 && tilenum <= 6)
|
||||
texid = tilenum - 1;
|
||||
else
|
||||
texid = rand() % 6;
|
||||
const TileLayer &tile = f.tiles[texid].layers[0];
|
||||
p.animation.type = TAT_NONE;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class Particle : public scene::ISceneNode
|
|||
video::ITexture *texture,
|
||||
v2f texpos,
|
||||
v2f texsize,
|
||||
video::SColor color = video::SColor(0xFFFFFFFF)
|
||||
video::SColor color
|
||||
);
|
||||
~Particle() = default;
|
||||
|
||||
|
@ -171,7 +171,7 @@ public:
|
|||
protected:
|
||||
static bool getNodeParticleParams(const MapNode &n, const ContentFeatures &f,
|
||||
ParticleParameters &p, video::ITexture **texture, v2f &texpos,
|
||||
v2f &texsize, video::SColor *color);
|
||||
v2f &texsize, video::SColor *color, u8 tilenum = 0);
|
||||
|
||||
void addParticle(Particle* toadd);
|
||||
|
||||
|
|
|
@ -1003,6 +1003,16 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
|
|||
p.glow = readU8(is);
|
||||
p.object_collision = readU8(is);
|
||||
|
||||
// This is kinda awful
|
||||
do {
|
||||
u16 tmp_param0 = readU16(is);
|
||||
if (is.eof())
|
||||
break;
|
||||
p.node.param0 = tmp_param0;
|
||||
p.node.param2 = readU8(is);
|
||||
p.node_tile = readU8(is);
|
||||
} while (0);
|
||||
|
||||
auto event = new ClientEvent();
|
||||
event->type = CE_ADD_PARTICLESPAWNER;
|
||||
event->add_particlespawner.p = new ParticleSpawnerParameters(p);
|
||||
|
|
|
@ -34,6 +34,9 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const
|
|||
animation.serialize(os, 6); /* NOT the protocol ver */
|
||||
writeU8(os, glow);
|
||||
writeU8(os, object_collision);
|
||||
writeU16(os, node.param0);
|
||||
writeU8(os, node.param2);
|
||||
writeU8(os, node_tile);
|
||||
}
|
||||
|
||||
void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver)
|
||||
|
@ -50,4 +53,11 @@ void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver)
|
|||
animation.deSerialize(is, 6); /* NOT the protocol ver */
|
||||
glow = readU8(is);
|
||||
object_collision = readU8(is);
|
||||
// This is kinda awful
|
||||
u16 tmp_param0 = readU16(is);
|
||||
if (is.eof())
|
||||
return;
|
||||
node.param0 = tmp_param0;
|
||||
node.param2 = readU8(is);
|
||||
node_tile = readU8(is);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <string>
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "tileanimation.h"
|
||||
#include "mapnode.h"
|
||||
|
||||
// This file defines the particle-related structures that both the server and
|
||||
// client need. The ParticleManager and rendering is in client/particles.h
|
||||
|
@ -34,9 +35,12 @@ struct CommonParticleParams {
|
|||
std::string texture;
|
||||
struct TileAnimationParams animation;
|
||||
u8 glow = 0;
|
||||
MapNode node;
|
||||
u8 node_tile = 0;
|
||||
|
||||
CommonParticleParams() {
|
||||
animation.type = TAT_NONE;
|
||||
node.setContent(CONTENT_IGNORE);
|
||||
}
|
||||
|
||||
/* This helper is useful for copying params from
|
||||
|
@ -49,6 +53,8 @@ struct CommonParticleParams {
|
|||
to.texture = texture;
|
||||
to.animation = animation;
|
||||
to.glow = glow;
|
||||
to.node = node;
|
||||
to.node_tile = node_tile;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -111,6 +111,13 @@ int ModApiParticles::l_add_particle(lua_State *L)
|
|||
p.texture = getstringfield_default(L, 1, "texture", p.texture);
|
||||
p.glow = getintfield_default(L, 1, "glow", p.glow);
|
||||
|
||||
lua_getfield(L, 1, "node");
|
||||
if (lua_istable(L, -1))
|
||||
p.node = readnode(L, -1, getGameDef(L)->ndef());
|
||||
lua_pop(L, 1);
|
||||
|
||||
p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
|
||||
|
||||
playername = getstringfield_default(L, 1, "playername", "");
|
||||
}
|
||||
|
||||
|
@ -231,6 +238,13 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
|
|||
p.texture = getstringfield_default(L, 1, "texture", p.texture);
|
||||
playername = getstringfield_default(L, 1, "playername", "");
|
||||
p.glow = getintfield_default(L, 1, "glow", p.glow);
|
||||
|
||||
lua_getfield(L, 1, "node");
|
||||
if (lua_istable(L, -1))
|
||||
p.node = readnode(L, -1, getGameDef(L)->ndef());
|
||||
lua_pop(L, 1);
|
||||
|
||||
p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
|
||||
}
|
||||
|
||||
u32 id = getServer(L)->addParticleSpawner(p, attached, playername);
|
||||
|
|
|
@ -67,6 +67,13 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L)
|
|||
p.texture = getstringfield_default(L, 1, "texture", p.texture);
|
||||
p.glow = getintfield_default(L, 1, "glow", p.glow);
|
||||
|
||||
lua_getfield(L, 1, "node");
|
||||
if (lua_istable(L, -1))
|
||||
p.node = readnode(L, -1, getGameDef(L)->ndef());
|
||||
lua_pop(L, 1);
|
||||
|
||||
p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
|
||||
|
||||
ClientEvent *event = new ClientEvent();
|
||||
event->type = CE_SPAWN_PARTICLE;
|
||||
event->spawn_particle = new ParticleParameters(p);
|
||||
|
@ -134,6 +141,13 @@ int ModApiParticlesLocal::l_add_particlespawner(lua_State *L)
|
|||
p.texture = getstringfield_default(L, 1, "texture", p.texture);
|
||||
p.glow = getintfield_default(L, 1, "glow", p.glow);
|
||||
|
||||
lua_getfield(L, 1, "node");
|
||||
if (lua_istable(L, -1))
|
||||
p.node = readnode(L, -1, getGameDef(L)->ndef());
|
||||
lua_pop(L, 1);
|
||||
|
||||
p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
|
||||
|
||||
u64 id = getClient(L)->getParticleManager()->generateSpawnerId();
|
||||
|
||||
auto event = new ClientEvent();
|
||||
|
|
|
@ -1577,6 +1577,7 @@ void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
|
|||
pkt.putRawString(os.str());
|
||||
}
|
||||
pkt << p.glow << p.object_collision;
|
||||
pkt << p.node.param0 << p.node.param2 << p.node_tile;
|
||||
|
||||
Send(&pkt);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue