Particles
Particles are one of the few effects within the game that are used as polish to better improve immersion. Their usefulness also requires great caution due to how they are created and referenced in the game.
Sided Issues
Particles are problematic due to their presence only on the physical client. They have no existence on a server whatsoever. This means that if specific data from a server is needed, it needs to be synced from the server to create the particle on the client.
Creating a Particle
A particle can be broken up into four distinct classes. On the server, a ParticleType<?>
holds an IParticleData
to sync the information. On the client, an IParticleFactory
is used to generate a Particle
from the synced IParticleData
. To be more specific, a ParticleType<?>
holds the registry reference of the particle itself. An IParticleData
hooks into a ParticleType<?>
to send information to the IParticleFactory
. An IParticleFactory
creates the specified particle in some place within the world. Then, the Particle
goes and handles the rendering logic to make it appear in game.
ParticleType
s
While there are a lot of different particles in vanilla, in almost all cases vanilla uses BasicParticleType
, a basic implementation of ParticleType
and IParticleData
. This is used whenever server data is not necessary to spawn the particle. The only vanilla particles that do not use BasicParticleType
are redstone dust and block/item texture dependent particles. When requiring server data, a direct implementation of IParticleData
is needed. A good way is to extend ParticleType<?>
and implement IParticleData
on the same class. In the case of a more generic solution, an implementation of IParticleData
can be referenced while the standard ParticleType<?>
class is used.
ParticleType
s must be registered.
IParticleData
Beside the standard reference to a ParticleType<?>
, an IParticleData
is made up of two main methods and two accessory methods for compatibility across Minecraft usage.
First there are the sync methods:
IParticleData#write(PacketBuffer) IParticleData$IDeserializer#read(ParticleType, PacketBuffer)
These two are used to sync information across the network. All information from the server should be synced in this fashion.
The other two are for compatibility with other Minecraft systems:
IParticleData#getParameters IParticleData$IDeserializer#deserialize(ParticleType, StringReader)
These two are used to read/write data to NBT as well as get information to spawn the particle in the world using a command.
Particle
s
Particle
s will be left as an exercise to the reader as it is mainly about deciding what the reader wants to render to the screen. One of the most common classes to subclass, however, is SpriteTexturedParticle
. This abstract class renders a texture specified by the user as the particle to go according to the logic rendered.
IParticleFactory
s
Finally, a particle must be created using an IParticleFactory
. This simply just decides where the particle should be placed in the world at some speed in most cases. Since a Particle
is not beholden to any particular ParticleType<?>
, it can be reused over and over again in different factories if necessary.
An IParticleFactory
must be attached to a ParticleType
using ParticleManager#registerFactory
. This should be called during ParticleFactoryRegisterEvent
on the mod event bus.
Important
IParticleFactory
is only present on the client, so the event needs to be isolated via DistExecutor
or some other method.
Spawning Particles
Particles can be spawned from a world instance. Each side, however, has a specific way of calling them. The ClientWorld
can call either addParticle
or addOptionalParticle
. The ServerWorld
must call spawnParticle
as it sends a packet to the client world to call one of the other two methods. Calling the two ClientWorld
methods on the server will result in nothing happening.