Skip to content

Commit 33ae38a

Browse files
Chesvin1Thorinwasher
authored andcommitted
feat: Optimize BCauldron particle effects for Folia
1 parent 4071d91 commit 33ae38a

2 files changed

Lines changed: 93 additions & 20 deletions

File tree

src/main/java/com/dre/brewery/BCauldron.java

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.dre.brewery.utility.MaterialUtil;
3232
import com.dre.brewery.utility.MinecraftVersion;
3333
import com.dre.brewery.utility.Tuple;
34+
import com.github.Anon8281.universalScheduler.scheduling.tasks.MyScheduledTask;
3435
import lombok.Getter;
3536
import lombok.Setter;
3637
import org.bukkit.Color;
@@ -56,10 +57,10 @@
5657
import java.util.HashSet;
5758
import java.util.List;
5859
import java.util.Map;
59-
import java.util.Random;
6060
import java.util.Set;
6161
import java.util.UUID;
6262
import java.util.concurrent.ConcurrentHashMap;
63+
import java.util.concurrent.ThreadLocalRandom;
6364

6465
@Getter
6566
@Setter
@@ -69,7 +70,6 @@ public class BCauldron {
6970
private static final Config config = ConfigManager.getConfig(Config.class);
7071
private static final Lang lang = ConfigManager.getConfig(Lang.class);
7172
public static final int PARTICLEPAUSE = 15;
72-
public static Random particleRandom = new Random();
7373
private static final Set<UUID> plInteracted = new HashSet<>(); // Interact Event helper
7474
@Getter
7575
public static Map<Block, BCauldron> bcauldrons = new ConcurrentHashMap<>(); // All active cauldrons. Mapped to their block for fast retrieve
@@ -82,6 +82,7 @@ public class BCauldron {
8282
private Color particleColor;
8383
private final Location particleLocation;
8484
private final UUID id;
85+
private volatile MyScheduledTask foliaParticleTask;
8586

8687
public BCauldron(Block block) {
8788
this.block = block;
@@ -181,6 +182,7 @@ public static boolean ingredientAdd(Block block, ItemStack ingredient, Player pl
181182
if (bcauldron == null) {
182183
bcauldron = new BCauldron(block);
183184
BCauldron.bcauldrons.put(block, bcauldron);
185+
bcauldron.startFoliaParticleTask();
184186
}
185187

186188
IngedientAddEvent event = new IngedientAddEvent(player, block, bcauldron, ingredient.clone(), rItem);
@@ -208,20 +210,20 @@ public boolean fill(Player player, Block block) {
208210
if (VERSION.isOrLater(MinecraftVersion.V1_13)) {
209211
BlockData data = block.getBlockData();
210212
if (!(data instanceof Levelled)) {
211-
bcauldrons.remove(block);
213+
remove(block);
212214
return false;
213215
}
214216
Levelled cauldron = ((Levelled) data);
215217
if (cauldron.getLevel() <= 0) {
216-
bcauldrons.remove(block);
218+
remove(block);
217219
return false;
218220
}
219221

220222
// If the Water_Cauldron type exists and the cauldron is on last level
221223
if (MaterialUtil.WATER_CAULDRON != null && cauldron.getLevel() == 1) {
222224
// Empty Cauldron
223225
block.setType(Material.CAULDRON);
224-
bcauldrons.remove(block);
226+
remove(block);
225227
} else {
226228
cauldron.setLevel(cauldron.getLevel() - 1);
227229

@@ -231,7 +233,7 @@ public boolean fill(Player player, Block block) {
231233
block.setBlockData(data);
232234

233235
if (cauldron.getLevel() <= 0) {
234-
bcauldrons.remove(block);
236+
remove(block);
235237
} else {
236238
changed = true;
237239
}
@@ -243,14 +245,14 @@ public boolean fill(Player player, Block block) {
243245
if (data > 3) {
244246
data = 3;
245247
} else if (data <= 0) {
246-
bcauldrons.remove(block);
248+
remove(block);
247249
return false;
248250
}
249251
data -= 1;
250252
MaterialUtil.setData(block, data);
251253

252254
if (data == 0) {
253-
bcauldrons.remove(block);
255+
remove(block);
254256
} else {
255257
changed = true;
256258
}
@@ -284,6 +286,8 @@ public static void printTime(Player player, Block block) {
284286
}
285287

286288
public void cookEffect() {
289+
assert !VERSION.isFolia() || BreweryPlugin.getScheduler().isRegionThread(block.getLocation())
290+
: "cookEffect must run on owning region thread";
287291
if (BUtil.isChunkLoaded(block) && MaterialUtil.isCauldronHeatSource(block.getRelative(BlockFace.DOWN))) {
288292
Color color = getParticleColor();
289293
// Colorable spirally spell, 0 count enables color instead of the offset variables
@@ -304,17 +308,17 @@ public void cookEffect() {
304308
return;
305309
}
306310

307-
if (particleRandom.nextFloat() > 0.85) {
311+
if (ThreadLocalRandom.current().nextFloat() > 0.85f) {
308312
// Dark pixely smoke cloud at 0.4 random in x and z
309313
// 0 count enables direction, send to y = 1 with speed 0.09
310314
block.getWorld().spawnParticle(BukkitConstants.LARGE_SMOKE, getRandParticleLoc(), 0, 0, 1, 0, 0.09);
311315
}
312-
if (particleRandom.nextFloat() > 0.2) {
316+
if (ThreadLocalRandom.current().nextFloat() > 0.2f) {
313317
// A Water Splash with 0.2 offset in x and z
314318
block.getWorld().spawnParticle(BukkitConstants.SPLASH, particleLocation, 1, 0.2, 0, 0.2);
315319
}
316320

317-
if (VERSION.isOrLater(MinecraftVersion.V1_13) && particleRandom.nextFloat() > 0.4) {
321+
if (VERSION.isOrLater(MinecraftVersion.V1_13) && ThreadLocalRandom.current().nextFloat() > 0.4f) {
318322
// Two hovering pixely dust clouds, a bit of offset and with DustOptions to give some color and size
319323
block.getWorld().spawnParticle(BukkitConstants.DUST, particleLocation, 2, 0.15, 0.2, 0.15, new Particle.DustOptions(color, 1.5f));
320324
}
@@ -323,9 +327,9 @@ public void cookEffect() {
323327

324328
private Location getRandParticleLoc() {
325329
return new Location(particleLocation.getWorld(),
326-
particleLocation.getX() + (particleRandom.nextDouble() * 0.8) - 0.4,
330+
particleLocation.getX() + (ThreadLocalRandom.current().nextDouble() * 0.8) - 0.4,
327331
particleLocation.getY(),
328-
particleLocation.getZ() + (particleRandom.nextDouble() * 0.8) - 0.4);
332+
particleLocation.getZ() + (ThreadLocalRandom.current().nextDouble() * 0.8) - 0.4);
329333
}
330334

331335
/**
@@ -404,19 +408,71 @@ public Color getParticleColor() {
404408
}
405409

406410
public static void processCookEffects() {
411+
if (VERSION.isFolia()) return;
407412
if (!config.isEnableCauldronParticles()) return;
408413
if (bcauldrons.isEmpty()) {
409414
return;
410415
}
411416
final float chance = 1f / PARTICLEPAUSE;
412417

413418
for (BCauldron cauldron : bcauldrons.values()) {
414-
if (particleRandom.nextFloat() < chance) {
419+
if (ThreadLocalRandom.current().nextFloat() < chance) {
415420
BreweryPlugin.getScheduler().runTask(cauldron.block.getLocation(), cauldron::cookEffect);
416421
}
417422
}
418423
}
419424

425+
public void startFoliaParticleTask() {
426+
if (!VERSION.isFolia() || !config.isEnableCauldronParticles()) {
427+
return;
428+
}
429+
synchronized (this) {
430+
if (foliaParticleTask != null && !foliaParticleTask.isCancelled()) {
431+
return;
432+
}
433+
long delay = ThreadLocalRandom.current().nextLong(1, PARTICLEPAUSE + 1L);
434+
foliaParticleTask = BreweryPlugin.getScheduler().runTaskTimer(block.getLocation(), () -> {
435+
if (!config.isEnableCauldronParticles()) {
436+
return;
437+
}
438+
if (config.isMinimalParticles() && ThreadLocalRandom.current().nextFloat() > 0.5f) {
439+
return;
440+
}
441+
cookEffect();
442+
}, delay, PARTICLEPAUSE);
443+
}
444+
}
445+
446+
public void stopFoliaParticleTask() {
447+
if (!VERSION.isFolia()) {
448+
return;
449+
}
450+
synchronized (this) {
451+
if (foliaParticleTask != null) {
452+
foliaParticleTask.cancel();
453+
foliaParticleTask = null;
454+
}
455+
}
456+
}
457+
458+
public static void startAllFoliaParticleTasks() {
459+
if (!VERSION.isFolia() || !config.isEnableCauldronParticles()) {
460+
return;
461+
}
462+
for (BCauldron cauldron : bcauldrons.values()) {
463+
cauldron.startFoliaParticleTask();
464+
}
465+
}
466+
467+
public static void stopAllFoliaParticleTasks() {
468+
if (!VERSION.isFolia()) {
469+
return;
470+
}
471+
for (BCauldron cauldron : bcauldrons.values()) {
472+
cauldron.stopFoliaParticleTask();
473+
}
474+
}
475+
420476
public static void clickCauldron(PlayerInteractEvent event) {
421477
Material materialInHand = event.getMaterial();
422478
ItemStack item = event.getItem();
@@ -529,8 +585,10 @@ public static void clickCauldron(PlayerInteractEvent event) {
529585
*/
530586
public static void reload() {
531587
if (!config.isEnableCauldronParticles()) {
588+
stopAllFoliaParticleTasks();
532589
return;
533590
}
591+
startAllFoliaParticleTasks();
534592

535593
var scheduler = BreweryPlugin.getScheduler();
536594
for (BCauldron cauldron : bcauldrons.values()) {
@@ -549,7 +607,12 @@ public static void reload() {
549607
* reset to normal cauldron
550608
*/
551609
public static boolean remove(Block block) {
552-
return bcauldrons.remove(block) != null;
610+
BCauldron removed = bcauldrons.remove(block);
611+
if (removed != null) {
612+
removed.stopFoliaParticleTask();
613+
return true;
614+
}
615+
return false;
553616
}
554617

555618
/**
@@ -562,15 +625,21 @@ public static boolean hasDataInWorld(World world) {
562625
// unloads cauldrons that are in a unloading world
563626
// as they were written to file just before, this is safe to do
564627
public static void onUnload(World world) {
565-
bcauldrons.keySet().removeIf(block -> block.getWorld().equals(world));
628+
List<Block> blocksToRemove = bcauldrons.keySet().stream()
629+
.filter(block -> block.getWorld().equals(world))
630+
.toList();
631+
blocksToRemove.forEach(BCauldron::remove);
566632
}
567633

568634
/**
569635
* Unload all Cauldrons that have are in a unloaded World
570636
*/
571637
public static void unloadWorlds() {
572638
List<World> worlds = BreweryPlugin.getInstance().getServer().getWorlds();
573-
bcauldrons.keySet().removeIf(block -> !worlds.contains(block.getWorld()));
639+
List<Block> blocksToRemove = bcauldrons.keySet().stream()
640+
.filter(block -> !worlds.contains(block.getWorld()))
641+
.toList();
642+
blocksToRemove.forEach(BCauldron::remove);
574643
}
575644

576645
public static void save(ConfigurationSection config, ConfigurationSection oldData) {

src/main/java/com/dre/brewery/BreweryPlugin.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import java.util.HashMap;
7878
import java.util.Map;
7979
import java.util.Objects;
80+
import java.util.concurrent.ThreadLocalRandom;
8081
import java.util.function.Function;
8182
import java.util.stream.Collectors;
8283

@@ -182,6 +183,7 @@ public void onEnable() {
182183
BCauldron::getBlock, Function.identity(),
183184
(existing, replacement) -> replacement // Issues#68
184185
)));
186+
BCauldron.startAllFoliaParticleTasks();
185187
BPlayer.getPlayers().putAll(dataManager.getAllPlayers()
186188
.stream()
187189
.filter(Objects::nonNull)
@@ -241,7 +243,7 @@ public void onEnable() {
241243
// Heartbeat
242244
BreweryPlugin.getScheduler().runTaskTimer(new BreweryRunnable(), 650, 1200);
243245
BreweryPlugin.getScheduler().runTaskTimer(new DrunkRunnable(), 120, 120);
244-
if (getMCVersion().isOrLater(MinecraftVersion.V1_9))
246+
if (getMCVersion().isOrLater(MinecraftVersion.V1_9) && !MinecraftVersion.isFolia())
245247
BreweryPlugin.getScheduler().runTaskTimer(new CauldronParticles(), 1, 1);
246248

247249

@@ -271,6 +273,8 @@ public void onDisable() {
271273
// Disable listeners
272274
HandlerList.unregisterAll(this);
273275

276+
BCauldron.stopAllFoliaParticleTasks();
277+
274278
// Stop schedulers
275279
BreweryPlugin.getScheduler().cancelTasks(this);
276280

@@ -330,7 +334,7 @@ public void run() {
330334
for (BCauldron bCauldron : BCauldron.bcauldrons.values()) {
331335
BreweryPlugin.getScheduler().runTask(bCauldron.getBlock().getLocation(), () -> {
332336
if (!bCauldron.onUpdate()) {
333-
BCauldron.bcauldrons.remove(bCauldron.getBlock());
337+
BCauldron.remove(bCauldron.getBlock());
334338
}
335339
});
336340
}
@@ -360,7 +364,7 @@ public void run() {
360364
Config config = ConfigManager.getConfig(Config.class);
361365

362366
if (!config.isEnableCauldronParticles()) return;
363-
if (config.isMinimalParticles() && BCauldron.particleRandom.nextFloat() > 0.5f) {
367+
if (config.isMinimalParticles() && ThreadLocalRandom.current().nextFloat() > 0.5f) {
364368
return;
365369
}
366370
BCauldron.processCookEffects();

0 commit comments

Comments
 (0)