-
-
Notifications
You must be signed in to change notification settings - Fork 29
ParticleTasks
ParticleTasks are the most efficient and elegant way to repeatedly display particles. As an example, let's look at a very inefficient method which even lags the server when used excessively:
public void displayCube(World world, Vector start, Vector end) {
for (int x = start.getBlockX(); x <= end.getBlockX(); ++x) {
for (int y = start.getBlockY(); y <= end.getBlockY(); ++y) {
for (int z = start.getBlockZ(); z <= end.getBlockZ(); ++z) {
new ParticleBuilder(ParticleEffect.FLAME, new Location(world, x, y, z)).display();
}
}
}
}
To progressively display this cube, this method has to be called every few ticks. This will lead to high CPU time and lag because the packets are rebuilt for every run. Also, the PlayerConnection has to be retrieved for every particle which also causes delay (Even with the ConnectionCache).
Instead of the above code, we can start a new GlobalTask
. A GlobalTask is a repeating task that sends the given particles to every player.
public void startCubeTask(World world, Vector start, Vector end) {
List<Object> packets = new ArrayList<>();
ParticleBuilder particle = new ParticleBuilder(ParticleEffect.FLAME);
for (int x = start.getBlockX(); x <= end.getBlockX(); ++x) {
for (int y = start.getBlockY(); y <= end.getBlockY(); ++y) {
for (int z = start.getBlockZ(); z <= end.getBlockZ(); ++z) {
packets.add(particle.setLocation(new Location(world, x, y, z)).toPacket());
}
}
}
ParticleTask task = new GlobalTask(packets, 5); // Create a new GlobalTask with a tick delay of 5
return TaskManager.getTaskManager().startTask(task); // Start the new task and return the id
}
This method will start a new ParticleTask that displays a cube of flame particles every 5 ticks. The return value is the id of the task, which can be used to cancel the timer at any time (see TaskManager#stopTask
).
Class name | Short explanation |
---|---|
GlobalTask | Displays the particle to every player that is currently online. |
TargetedTask | Displays the particle to the provided list of players. |
SingularTask | Only displays the particles to one specific player. |
FilteredTask | Only displays the particles to players that match the given filter. |
SuppliedTask | Uses a Supplier to evaluate which players should see particles. |
If you have any suggestions for more task implementations, please open an issue with a detailed explanation.
A GlobalTask is the simplest implementation of the ParticleTask class. It displays the particles to every player that is currently online. The constructor only needs the packets and the tick delay.
TargetedTasks are tasks that only target a predefined list of players. Please note that this implementation currently saves a collection of players, not UUIDS! So if a player rejoins, they won't be able to see the particles. However, because of the JVMs reference implementation, this can be used to directly link to the reference of an object.
A SingularTask only sends the particles to one specific player. But unlike TargetedTasks, the UUID of the player is saved instead of the player object. Because of this, the targeted player will still see the particle, even after rejoining.
A FilteredTask applies a given Filter to all online players and only displays the particle to matches.
As an example, let's create a task that only sends the particles to server operators every 10 ticks: Lambda:
ParticleTask task = new FilteredTask(packets, 10, player -> player.isOp());
or by using a method reference:
ParticleTask task = new FilteredTask(packets, 10, Player::isOp);
SuppliedTasks use a Supplier to retrieve the list of targeted players. The supplier is called every time the task is called.
e.g. with a TeamManager that has getters for each team.
ParticleTask task = new SuppliedTask(packets, 5, () -> teamManager.getRedPlayers());