5757import java .util .ArrayList ;
5858import java .util .List ;
5959import java .util .Map ;
60+ import java .util .Objects ;
6061import java .util .UUID ;
6162import java .util .concurrent .CompletableFuture ;
63+ import java .util .concurrent .ConcurrentHashMap ;
6264
6365/**
6466 * A Multi Block Barrel with Inventory
6769@ Setter
6870public class Barrel extends BarrelBody implements InventoryHolder {
6971
70- @ Getter
71- public static final List <Barrel > barrels = new ArrayList <>();
72+ private static final Map <UUID , List <Barrel >> barrels = new ConcurrentHashMap <>();
7273 private static final Config config = ConfigManager .getConfig (Config .class );
7374 private static final Lang lang = ConfigManager .getConfig (Lang .class );
74- private static int check = 0 ; // Which Barrel was last checked
75+ private static Map < UUID , Integer > checkCounters = new ConcurrentHashMap <>() ; // Which Barrel was last checked
7576 /**
7677 * -- GETTER --
7778 * Is this a small barrel?
@@ -136,28 +137,30 @@ public Barrel(Block spigot, byte sign, BoundingBox bounds, ItemStack[] items, fl
136137 }
137138
138139 public static void onUpdate () {
139- for (Barrel barrel : barrels ) {
140- // A Minecraft day is 20 min, so add 1/20 to the time every minute
141- if (barrel != null ) {
142- barrel .time += (float ) (1.0 / config .getAgingYearDuration ());
143- }
144- }
145- int numBarrels = barrels .size ();
146- if (check == 0 && numBarrels > 0 ) {
147- Barrel random = barrels .get ((int ) Math .floor (Math .random () * numBarrels ));
148- if (random != null ) {
149- // You have been selected for a random search
150- // We want to check at least one barrel every time
151- random .checked = false ;
152- }
153- if (numBarrels > 50 ) {
154- Barrel randomInTheBack = barrels .get (numBarrels - 1 - (int ) (Math .random () * (numBarrels >>> 2 )));
155- if (randomInTheBack != null ) {
156- // Prioritize checking one of the less recently used barrels as well
157- randomInTheBack .checked = false ;
140+ barrels .values ()
141+ .stream ()
142+ .flatMap (List ::stream )
143+ .filter (Objects ::nonNull )
144+ .forEach (barrel -> barrel .time += (float ) (1.0 / config .getAgingYearDuration ()));
145+ for (UUID worldUuid : barrels .keySet ()) {
146+ List <Barrel > worldBarrels = barrels .get (worldUuid );
147+ int numBarrels = worldBarrels .size ();
148+ if (checkCounters .getOrDefault (worldUuid , 0 ) == 0 && numBarrels > 0 ) {
149+ Barrel random = worldBarrels .get ((int ) Math .floor (Math .random () * numBarrels ));
150+ if (random != null ) {
151+ // You have been selected for a random search
152+ // We want to check at least one barrel every time
153+ random .checked = false ;
158154 }
155+ if (numBarrels > 50 ) {
156+ Barrel randomInTheBack = worldBarrels .get (numBarrels - 1 - (int ) (Math .random () * (numBarrels >>> 2 )));
157+ if (randomInTheBack != null ) {
158+ // Prioritize checking one of the less recently used barrels as well
159+ randomInTheBack .checked = false ;
160+ }
161+ }
162+ new BarrelCheck ().runTaskTimer (BreweryPlugin .getInstance (), 1 , 1 );
159163 }
160- new BarrelCheck ().runTaskTimer (BreweryPlugin .getInstance (), 1 , 1 );
161164 }
162165 }
163166
@@ -309,16 +312,19 @@ public static Barrel getBySpigot(Block sign) {
309312 if (!spigot .equals (sign )) {
310313 signoffset = (byte ) (sign .getY () - spigot .getY ());
311314 }
312-
315+ List <Barrel > worldBarrels = barrels .get (sign .getWorld ().getUID ());
316+ if (worldBarrels == null ) {
317+ return null ;
318+ }
313319 int i = 0 ;
314- for (Barrel barrel : barrels ) {
320+ for (Barrel barrel : worldBarrels ) {
315321 if (barrel != null && barrel .isSignOfBarrel (signoffset )) {
316322 if (barrel .spigot .equals (spigot )) {
317323 if (barrel .getSignoffset () == 0 && signoffset != 0 ) {
318324 // Barrel has no signOffset even though we clicked a sign, may be old
319325 barrel .setSignoffset (signoffset );
320326 }
321- moveMRU (i );
327+ moveMRU (sign . getWorld (). getUID (), i );
322328 return barrel ;
323329 }
324330 }
@@ -332,26 +338,34 @@ public static Barrel getBySpigot(Block sign) {
332338 */
333339 @ Nullable
334340 public static Barrel getByWood (Block wood ) {
335- if (BarrelAsset .isBarrelAsset (BarrelAsset .PLANKS , wood .getType ()) || BarrelAsset .isBarrelAsset (BarrelAsset .STAIRS , wood .getType ())) {
336- int i = 0 ;
337- for (Barrel barrel : barrels ) {
338- if (barrel .getSpigot ().getWorld ().equals (wood .getWorld ()) && barrel .getBounds ().contains (wood )) {
339- moveMRU (i );
340- return barrel ;
341- }
342- i ++;
341+ if (!BarrelAsset .isBarrelAsset (BarrelAsset .PLANKS , wood .getType ()) && !BarrelAsset .isBarrelAsset (BarrelAsset .STAIRS , wood .getType ())) {
342+ return null ;
343+ }
344+ List <Barrel > worldBarrels = barrels .get (wood .getWorld ().getUID ());
345+ if (worldBarrels == null ) {
346+ return null ;
347+ }
348+ for (int i = 0 ; i < worldBarrels .size (); i ++) {
349+ Barrel barrel = worldBarrels .get (i );
350+ if (barrel .getSpigot ().getWorld ().equals (wood .getWorld ()) && barrel .getBounds ().contains (wood )) {
351+ moveMRU (wood .getWorld ().getUID (), i );
352+ return barrel ;
343353 }
344354 }
345355 return null ;
346356 }
347357
348358 // Move Barrel that was recently used more towards the front of the List
349359 // Optimizes retrieve by Block over time
350- private static void moveMRU (int index ) {
351- if (index > 0 ) {
352- // Swap entry at the index with the one next to it
353- barrels .set (index - 1 , barrels .set (index , barrels .get (index - 1 )));
360+ private static void moveMRU (UUID worldUuid , int index ) {
361+ if (index < 0 ) {
362+ return ;
363+ }
364+ List <Barrel > worldBarrels = barrels .get (worldUuid );
365+ if (index >= worldBarrels .size ()) {
366+ return ;
354367 }
368+ worldBarrels .set (index - 1 , worldBarrels .set (index , worldBarrels .get (index - 1 )));
355369 }
356370
357371 /**
@@ -386,7 +400,7 @@ public static boolean create(Block sign, Player player) {
386400 BarrelCreateEvent createEvent = new BarrelCreateEvent (barrel , player );
387401 BreweryPlugin .getInstance ().getServer ().getPluginManager ().callEvent (createEvent );
388402 if (!createEvent .isCancelled ()) {
389- barrels .add ( 0 , barrel );
403+ barrels .computeIfAbsent ( sign . getWorld (). getUID (), ignored -> new ArrayList <>()). addFirst ( barrel );
390404 return true ;
391405 }
392406 }
@@ -430,7 +444,7 @@ public void remove(@Nullable Block broken, @Nullable Player breaker, boolean dro
430444 if (event .willDropItems ()) {
431445 if (getBounds () == null ) {
432446 Logging .debugLog ("Barrel Body is null, can't drop items: " + this .id );
433- barrels .remove (this );
447+ barrels .getOrDefault ( spigot . getWorld (). getUID (), new ArrayList <>()). remove (this );
434448 return ;
435449 }
436450
@@ -466,7 +480,7 @@ public void remove(@Nullable Block broken, @Nullable Player breaker, boolean dro
466480 }
467481 }
468482
469- barrels .remove (this );
483+ barrels .getOrDefault ( spigot . getWorld (). getUID (), new ArrayList <>()). remove (this );
470484 }
471485
472486 @ Override
@@ -521,32 +535,41 @@ public static Block getSpigotOfSign(Block block) {
521535 * Are any Barrels in that World
522536 */
523537 public static boolean hasDataInWorld (World world ) {
524- return barrels .stream (). anyMatch ( barrel -> barrel . spigot . getWorld (). equals ( world ) );
538+ return barrels .containsKey ( world . getUID ()) && ! barrels . get ( world . getUID ()). isEmpty ( );
525539 }
526540
527541 /**
528542 * unloads barrels that are in a unloading world
529543 */
530544 public static void onUnload (World world ) {
531- barrels .removeIf ( barrel -> barrel . spigot . getWorld (). equals ( world ));
545+ barrels .remove ( world . getUID ( ));
532546 }
533547
534- /**
535- * Unload all Barrels that have a Block in a unloaded World
536- */
537- public static void unloadWorlds () {
538- List <World > worlds = BreweryPlugin .getInstance ().getServer ().getWorlds ();
539- barrels .removeIf (barrel -> !worlds .contains (barrel .spigot .getWorld ()));
548+ public static void registerBarrel (Barrel barrel ) {
549+ barrels .computeIfAbsent (barrel .spigot .getWorld ().getUID (), ignored -> new ArrayList <>())
550+ .add (barrel );
551+ }
552+
553+ public static List <Barrel > getAllBarrels () {
554+ return barrels .values ().stream ()
555+ .flatMap (List ::stream )
556+ .filter (Objects ::nonNull )
557+ .toList ();
540558 }
541559
542560 public static class BarrelCheck extends UniversalRunnable {
543561 @ Override
544562 public void run () {
545- boolean repeat = true ;
546- while (repeat ) {
547- if (check < barrels .size ()) {
548- Barrel barrel = barrels .get (check );
549- if (!barrel .checked ) {
563+ barrels .keySet ()
564+ .forEach (worldUuid -> {
565+ int counter = checkCounters .computeIfAbsent (worldUuid , ignored -> -1 );
566+ List <Barrel > worldBarrels = barrels .get (worldUuid );
567+ counter = counter + 1 % worldBarrels .size ();
568+ while (counter < worldBarrels .size ()) {
569+ Barrel barrel = worldBarrels .get (counter ++);
570+ if (barrel .checked ) {
571+ continue ;
572+ }
550573 BreweryPlugin .getScheduler ().runTask (barrel .getSpigot ().getLocation (), () -> {
551574 Block broken = barrel .getBrokenBlock (false );
552575 if (broken != null ) {
@@ -562,15 +585,10 @@ public void run() {
562585 barrel .checked = true ;
563586 }
564587 });
565- repeat = false ;
588+ return ;
566589 }
567- check ++;
568- } else {
569- check = 0 ;
570- repeat = false ;
571590 cancel ();
572- }
573- }
591+ });
574592 }
575593
576594 }
0 commit comments