Skip to content

Commit

Permalink
Allow spawning particles from the server, from lua
Browse files Browse the repository at this point in the history
Spawn single particles or make use of ParticleSpawner for many randomly spawned particles.
Accessible in Lua using minetest.spawn_particle and minetest.add_particlespawner.
Increase Protocol Version to 17.

Conflicts:
	src/clientserver.h
  • Loading branch information
Jeija authored and PilzAdam committed Mar 23, 2013
1 parent ab57fda commit e1ff5b1
Show file tree
Hide file tree
Showing 13 changed files with 1,059 additions and 55 deletions.
31 changes: 31 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -1028,6 +1028,37 @@ minetest.get_ban_description(ip_or_name) -> ban description (string)
minetest.ban_player(name) -> ban a player
minetest.unban_player_or_ip(name) -> unban player or IP address

Particles:
minetest.add_particle(pos, velocity, acceleration, expirationtime,
size, collisiondetection, texture, playername)
^ Spawn particle at pos with velocity and acceleration
^ Disappears after expirationtime seconds
^ collisiondetection: if true collides with physical objects
^ Uses texture (string)
^ Playername is optional, if specified spawns particle only on the player's client

minetest.add_particlespawner(amount, time,
minpos, maxpos,
minvel, maxvel,
minacc, maxacc,
minexptime, maxexptime,
minsize, maxsize,
collisiondetection, texture, playername)
^ Add a particlespawner, an object that spawns an amount of particles over time seconds
^ The particle's properties are random values in between the boundings:
^ minpos/maxpos, minvel/maxvel (velocity), minacc/maxacc (acceleration),
^ minsize/maxsize, minexptime/maxexptime (expirationtime)
^ collisiondetection: if true uses collisiondetection
^ Uses texture (string)
^ Playername is optional, if specified spawns particle only on the player's client
^ If time is 0 has infinite lifespan and spawns the amount on a per-second base
^ Returns and id

minetest.delete_particlespawner(id, player)
^ Delete ParticleSpawner with id (return value from add_particlespawner)
^ If playername is specified, only deletes on the player's client,
^ otherwise on all clients

Random:
minetest.get_connected_players() -> list of ObjectRefs
minetest.hash_node_position({x=,y=,z=}) -> 48-bit integer
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -219,6 +219,7 @@ set(common_SRCS
scriptapi_object.cpp
scriptapi_nodemeta.cpp
scriptapi_inventory.cpp
scriptapi_particles.cpp
scriptapi.cpp
script.cpp
log.cpp
Expand Down
83 changes: 83 additions & 0 deletions src/client.cpp
Expand Up @@ -1936,6 +1936,89 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
event.show_formspec.formname = new std::string(formname);
m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_SPAWN_PARTICLE)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);

v3f pos = readV3F1000(is);
v3f vel = readV3F1000(is);
v3f acc = readV3F1000(is);
float expirationtime = readF1000(is);
float size = readF1000(is);
bool collisiondetection = readU8(is);
std::string texture = deSerializeLongString(is);

ClientEvent event;
event.type = CE_SPAWN_PARTICLE;
event.spawn_particle.pos = new v3f (pos);
event.spawn_particle.vel = new v3f (vel);
event.spawn_particle.acc = new v3f (acc);

event.spawn_particle.expirationtime = expirationtime;
event.spawn_particle.size = size;
event.add_particlespawner.collisiondetection =
collisiondetection;
event.spawn_particle.texture = new std::string(texture);

m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);

u16 amount = readU16(is);
float spawntime = readF1000(is);
v3f minpos = readV3F1000(is);
v3f maxpos = readV3F1000(is);
v3f minvel = readV3F1000(is);
v3f maxvel = readV3F1000(is);
v3f minacc = readV3F1000(is);
v3f maxacc = readV3F1000(is);
float minexptime = readF1000(is);
float maxexptime = readF1000(is);
float minsize = readF1000(is);
float maxsize = readF1000(is);
bool collisiondetection = readU8(is);
std::string texture = deSerializeLongString(is);
u32 id = readU32(is);

ClientEvent event;
event.type = CE_ADD_PARTICLESPAWNER;
event.add_particlespawner.amount = amount;
event.add_particlespawner.spawntime = spawntime;

event.add_particlespawner.minpos = new v3f (minpos);
event.add_particlespawner.maxpos = new v3f (maxpos);
event.add_particlespawner.minvel = new v3f (minvel);
event.add_particlespawner.maxvel = new v3f (maxvel);
event.add_particlespawner.minacc = new v3f (minacc);
event.add_particlespawner.maxacc = new v3f (maxacc);

event.add_particlespawner.minexptime = minexptime;
event.add_particlespawner.maxexptime = maxexptime;
event.add_particlespawner.minsize = minsize;
event.add_particlespawner.maxsize = maxsize;
event.add_particlespawner.collisiondetection = collisiondetection;
event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id;

m_client_event_queue.push_back(event);
}
else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);

u32 id = readU16(is);

ClientEvent event;
event.type = CE_DELETE_PARTICLESPAWNER;
event.delete_particlespawner.id = id;

m_client_event_queue.push_back(event);
}
else
{
infostream<<"Client: Ignoring unknown command "
Expand Down
34 changes: 33 additions & 1 deletion src/client.h
Expand Up @@ -157,7 +157,10 @@ enum ClientEventType
CE_PLAYER_FORCE_MOVE,
CE_DEATHSCREEN,
CE_TEXTURES_UPDATED,
CE_SHOW_FORMSPEC
CE_SHOW_FORMSPEC,
CE_SPAWN_PARTICLE,
CE_ADD_PARTICLESPAWNER,
CE_DELETE_PARTICLESPAWNER
};

struct ClientEvent
Expand Down Expand Up @@ -185,6 +188,35 @@ struct ClientEvent
} show_formspec;
struct{
} textures_updated;
struct{
v3f *pos;
v3f *vel;
v3f *acc;
f32 expirationtime;
f32 size;
bool collisiondetection;
std::string *texture;
} spawn_particle;
struct{
u16 amount;
f32 spawntime;
v3f *minpos;
v3f *maxpos;
v3f *minvel;
v3f *maxvel;
v3f *minacc;
v3f *maxacc;
f32 minexptime;
f32 maxexptime;
f32 minsize;
f32 maxsize;
bool collisiondetection;
std::string *texture;
u32 id;
} add_particlespawner;
struct{
u32 id;
} delete_particlespawner;
};
};

Expand Down
44 changes: 44 additions & 0 deletions src/clientserver.h
Expand Up @@ -82,6 +82,9 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
PROTOCOL_VERSION 17:
Serialization format change: include backface_culling flag in TileDef
Added rightclickable field in nodedef
TOCLIENT_SPAWN_PARTICLE
TOCLIENT_ADD_PARTICLESPAWNER
TOCLIENT_DELETE_PARTICLESPAWNER
*/

#define LATEST_PROTOCOL_VERSION 17
Expand Down Expand Up @@ -359,6 +362,7 @@ enum ToClientCommand
u8[len] name
[2] serialized inventory
*/

TOCLIENT_SHOW_FORMSPEC = 0x44,
/*
[0] u16 command
Expand All @@ -384,6 +388,46 @@ enum ToClientCommand
f1000 movement_liquid_sink
f1000 movement_gravity
*/

TOCLIENT_SPAWN_PARTICLE = 0x46,
/*
u16 command
v3f1000 pos
v3f1000 velocity
v3f1000 acceleration
f1000 expirationtime
f1000 size
u8 bool collisiondetection
u32 len
u8[len] texture
*/

TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
/*
u16 command
u16 amount
f1000 spawntime
v3f1000 minpos
v3f1000 maxpos
v3f1000 minvel
v3f1000 maxvel
v3f1000 minacc
v3f1000 maxacc
f1000 minexptime
f1000 maxexptime
f1000 minsize
f1000 maxsize
u8 bool collisiondetection
u32 len
u8[len] texture
u32 id
*/

TOCLIENT_DELETE_PARTICLESPAWNER = 0x48,
/*
u16 command
u32 id
*/
};

enum ToServerCommand
Expand Down
49 changes: 47 additions & 2 deletions src/game.cpp
Expand Up @@ -2186,6 +2186,47 @@ void the_game(
{
update_wielded_item_trigger = true;
}
else if(event.type == CE_SPAWN_PARTICLE)
{
LocalPlayer* player = client.getEnv().getLocalPlayer();
AtlasPointer ap =
gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));

new Particle(gamedef, smgr, player, client.getEnv(),
*event.spawn_particle.pos,
*event.spawn_particle.vel,
*event.spawn_particle.acc,
event.spawn_particle.expirationtime,
event.spawn_particle.size,
event.spawn_particle.collisiondetection, ap);
}
else if(event.type == CE_ADD_PARTICLESPAWNER)
{
LocalPlayer* player = client.getEnv().getLocalPlayer();
AtlasPointer ap =
gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));

new ParticleSpawner(gamedef, smgr, player,
event.add_particlespawner.amount,
event.add_particlespawner.spawntime,
*event.add_particlespawner.minpos,
*event.add_particlespawner.maxpos,
*event.add_particlespawner.minvel,
*event.add_particlespawner.maxvel,
*event.add_particlespawner.minacc,
*event.add_particlespawner.maxacc,
event.add_particlespawner.minexptime,
event.add_particlespawner.maxexptime,
event.add_particlespawner.minsize,
event.add_particlespawner.maxsize,
event.add_particlespawner.collisiondetection,
ap,
event.add_particlespawner.id);
}
else if(event.type == CE_DELETE_PARTICLESPAWNER)
{
delete_particlespawner (event.delete_particlespawner.id);
}
}
}

Expand Down Expand Up @@ -2415,7 +2456,8 @@ void the_game(
const ContentFeatures &features =
client.getNodeDefManager()->get(n);
addPunchingParticles
(gamedef, smgr, player, nodepos, features.tiles);
(gamedef, smgr, player, client.getEnv(),
nodepos, features.tiles);
}
}

Expand Down Expand Up @@ -2453,7 +2495,8 @@ void the_game(
const ContentFeatures &features =
client.getNodeDefManager()->get(wasnode);
addDiggingParticles
(gamedef, smgr, player, nodepos, features.tiles);
(gamedef, smgr, player, client.getEnv(),
nodepos, features.tiles);
}

dig_time = 0;
Expand Down Expand Up @@ -2734,6 +2777,7 @@ void the_game(
*/

allparticles_step(dtime, client.getEnv());
allparticlespawners_step(dtime, client.getEnv());

/*
Fog
Expand Down Expand Up @@ -3220,6 +3264,7 @@ void the_game(
clouds->drop();
if(gui_chat_console)
gui_chat_console->drop();
clear_particles ();

/*
Draw a "shutting down" screen, which will be shown while the map
Expand Down

0 comments on commit e1ff5b1

Please sign in to comment.