Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 79 additions & 61 deletions src/main/java/com/dre/brewery/Barrel.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
* A Multi Block Barrel with Inventory
Expand All @@ -67,11 +69,10 @@
@Setter
public class Barrel extends BarrelBody implements InventoryHolder {

@Getter
public static final List<Barrel> barrels = new ArrayList<>();
private static final Map<UUID, List<Barrel>> barrels = new ConcurrentHashMap<>();
private static final Config config = ConfigManager.getConfig(Config.class);
private static final Lang lang = ConfigManager.getConfig(Lang.class);
private static int check = 0; // Which Barrel was last checked
private static Map<UUID, Integer> checkCounters = new ConcurrentHashMap<>(); // Which Barrel was last checked
/**
* -- GETTER --
* Is this a small barrel?
Expand Down Expand Up @@ -136,28 +137,30 @@ public Barrel(Block spigot, byte sign, BoundingBox bounds, ItemStack[] items, fl
}

public static void onUpdate() {
for (Barrel barrel : barrels) {
// A Minecraft day is 20 min, so add 1/20 to the time every minute
if (barrel != null) {
barrel.time += (float) (1.0 / config.getAgingYearDuration());
}
}
int numBarrels = barrels.size();
if (check == 0 && numBarrels > 0) {
Barrel random = barrels.get((int) Math.floor(Math.random() * numBarrels));
if (random != null) {
// You have been selected for a random search
// We want to check at least one barrel every time
random.checked = false;
}
if (numBarrels > 50) {
Barrel randomInTheBack = barrels.get(numBarrels - 1 - (int) (Math.random() * (numBarrels >>> 2)));
if (randomInTheBack != null) {
// Prioritize checking one of the less recently used barrels as well
randomInTheBack.checked = false;
barrels.values()
.stream()
.flatMap(List::stream)
.filter(Objects::nonNull)
.forEach(barrel -> barrel.time += (float) (1.0 / config.getAgingYearDuration()));
for (UUID worldUuid : barrels.keySet()) {
List<Barrel> worldBarrels = barrels.get(worldUuid);
int numBarrels = worldBarrels.size();
if (checkCounters.getOrDefault(worldUuid, 0) == 0 && numBarrels > 0) {
Barrel random = worldBarrels.get((int) Math.floor(Math.random() * numBarrels));
if (random != null) {
// You have been selected for a random search
// We want to check at least one barrel every time
random.checked = false;
}
if (numBarrels > 50) {
Barrel randomInTheBack = worldBarrels.get(numBarrels - 1 - (int) (Math.random() * (numBarrels >>> 2)));
if (randomInTheBack != null) {
// Prioritize checking one of the less recently used barrels as well
randomInTheBack.checked = false;
}
}
new BarrelCheck().runTaskTimer(BreweryPlugin.getInstance(), 1, 1);
}
new BarrelCheck().runTaskTimer(BreweryPlugin.getInstance(), 1, 1);
}
}

Expand Down Expand Up @@ -309,16 +312,19 @@ public static Barrel getBySpigot(Block sign) {
if (!spigot.equals(sign)) {
signoffset = (byte) (sign.getY() - spigot.getY());
}

List<Barrel> worldBarrels = barrels.get(sign.getWorld().getUID());
if (worldBarrels == null) {
return null;
}
int i = 0;
for (Barrel barrel : barrels) {
for (Barrel barrel : worldBarrels) {
if (barrel != null && barrel.isSignOfBarrel(signoffset)) {
if (barrel.spigot.equals(spigot)) {
if (barrel.getSignoffset() == 0 && signoffset != 0) {
// Barrel has no signOffset even though we clicked a sign, may be old
barrel.setSignoffset(signoffset);
}
moveMRU(i);
moveMRU(sign.getWorld().getUID(), i);
return barrel;
}
}
Expand All @@ -332,26 +338,34 @@ public static Barrel getBySpigot(Block sign) {
*/
@Nullable
public static Barrel getByWood(Block wood) {
if (BarrelAsset.isBarrelAsset(BarrelAsset.PLANKS, wood.getType()) || BarrelAsset.isBarrelAsset(BarrelAsset.STAIRS, wood.getType())) {
int i = 0;
for (Barrel barrel : barrels) {
if (barrel.getSpigot().getWorld().equals(wood.getWorld()) && barrel.getBounds().contains(wood)) {
moveMRU(i);
return barrel;
}
i++;
if (!BarrelAsset.isBarrelAsset(BarrelAsset.PLANKS, wood.getType()) && !BarrelAsset.isBarrelAsset(BarrelAsset.STAIRS, wood.getType())) {
return null;
}
List<Barrel> worldBarrels = barrels.get(wood.getWorld().getUID());
if (worldBarrels == null) {
return null;
}
for (int i = 0; i < worldBarrels.size(); i++) {
Barrel barrel = worldBarrels.get(i);
if (barrel.getSpigot().getWorld().equals(wood.getWorld()) && barrel.getBounds().contains(wood)) {
moveMRU(wood.getWorld().getUID(), i);
return barrel;
}
}
return null;
}

// Move Barrel that was recently used more towards the front of the List
// Optimizes retrieve by Block over time
private static void moveMRU(int index) {
if (index > 0) {
// Swap entry at the index with the one next to it
barrels.set(index - 1, barrels.set(index, barrels.get(index - 1)));
private static void moveMRU(UUID worldUuid, int index) {
if (index < 0) {
return;
}
List<Barrel> worldBarrels = barrels.get(worldUuid);
if (index >= worldBarrels.size()) {
return;
}
worldBarrels.set(index - 1, worldBarrels.set(index, worldBarrels.get(index - 1)));
}

/**
Expand Down Expand Up @@ -386,7 +400,7 @@ public static boolean create(Block sign, Player player) {
BarrelCreateEvent createEvent = new BarrelCreateEvent(barrel, player);
BreweryPlugin.getInstance().getServer().getPluginManager().callEvent(createEvent);
if (!createEvent.isCancelled()) {
barrels.add(0, barrel);
barrels.computeIfAbsent(sign.getWorld().getUID(), ignored -> new ArrayList<>()).addFirst(barrel);
return true;
}
}
Expand Down Expand Up @@ -430,7 +444,7 @@ public void remove(@Nullable Block broken, @Nullable Player breaker, boolean dro
if (event.willDropItems()) {
if (getBounds() == null) {
Logging.debugLog("Barrel Body is null, can't drop items: " + this.id);
barrels.remove(this);
barrels.getOrDefault(spigot.getWorld().getUID(), new ArrayList<>()).remove(this);
return;
}

Expand Down Expand Up @@ -466,7 +480,7 @@ public void remove(@Nullable Block broken, @Nullable Player breaker, boolean dro
}
}

barrels.remove(this);
barrels.getOrDefault(spigot.getWorld().getUID(), new ArrayList<>()).remove(this);
}

@Override
Expand Down Expand Up @@ -521,32 +535,41 @@ public static Block getSpigotOfSign(Block block) {
* Are any Barrels in that World
*/
public static boolean hasDataInWorld(World world) {
return barrels.stream().anyMatch(barrel -> barrel.spigot.getWorld().equals(world));
return barrels.containsKey(world.getUID()) && !barrels.get(world.getUID()).isEmpty();
}

/**
* unloads barrels that are in a unloading world
*/
public static void onUnload(World world) {
barrels.removeIf(barrel -> barrel.spigot.getWorld().equals(world));
barrels.remove(world.getUID());
}

/**
* Unload all Barrels that have a Block in a unloaded World
*/
public static void unloadWorlds() {
List<World> worlds = BreweryPlugin.getInstance().getServer().getWorlds();
barrels.removeIf(barrel -> !worlds.contains(barrel.spigot.getWorld()));
public static void registerBarrel(Barrel barrel) {
barrels.computeIfAbsent(barrel.spigot.getWorld().getUID(), ignored -> new ArrayList<>())
.add(barrel);
}

public static List<Barrel> getAllBarrels() {
return barrels.values().stream()
.flatMap(List::stream)
.filter(Objects::nonNull)
.toList();
}

public static class BarrelCheck extends UniversalRunnable {
@Override
public void run() {
boolean repeat = true;
while (repeat) {
if (check < barrels.size()) {
Barrel barrel = barrels.get(check);
if (!barrel.checked) {
barrels.keySet()
.forEach(worldUuid -> {
int counter = checkCounters.computeIfAbsent(worldUuid, ignored -> -1);
List<Barrel> worldBarrels = barrels.get(worldUuid);
counter = counter + 1 % worldBarrels.size();
Comment thread
Thorinwasher marked this conversation as resolved.
Outdated
while (counter < worldBarrels.size()) {
Barrel barrel = worldBarrels.get(counter++);
if (barrel.checked) {
continue;
}
BreweryPlugin.getScheduler().runTask(barrel.getSpigot().getLocation(), () -> {
Block broken = barrel.getBrokenBlock(false);
if (broken != null) {
Expand All @@ -562,15 +585,10 @@ public void run() {
barrel.checked = true;
}
});
repeat = false;
return;
}
check++;
} else {
check = 0;
repeat = false;
cancel();
}
}
});
}

}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/dre/brewery/BreweryPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ public void onEnable() {

// Load objects
DataManager.loadMiscData(dataManager.getBreweryMiscData());
dataManager.getAllBarrels().thenApplyAsync(barrels -> Barrel.getBarrels().addAll(barrels.stream()
dataManager.getAllBarrels().thenAcceptAsync(barrels -> barrels.stream()
.filter(Objects::nonNull)
.toList()
));
.forEach(Barrel::registerBarrel)
);
BCauldron.getBcauldrons().putAll(dataManager.getAllCauldrons().stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/dre/brewery/listeners/WorldListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* BreweryX Bukkit-Plugin for an alternate brewing process
* Copyright (C) 2024-2025 The Brewery Team
*
* This file is part of BreweryX.
*
* BreweryX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BreweryX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with BreweryX. If not, see <http://www.gnu.org/licenses/gpl-3.0.html>.
*/

package com.dre.brewery.listeners;

import com.dre.brewery.Barrel;
import com.dre.brewery.storage.DataManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;

public record WorldListener(DataManager dataManager) implements Listener {

@EventHandler(priority = EventPriority.MONITOR)
public void onWorldLoad(WorldLoadEvent event) {
dataManager.getAllBarrels()
.thenAcceptAsync(barrels -> barrels.stream()
.filter(barrel -> barrel.getSpigot().getWorld().equals(event.getWorld()))
.forEach(Barrel.getBarrels()::add)
);
}

@EventHandler(priority = EventPriority.MONITOR)
public void onWorldLoad(WorldUnloadEvent event) {
dataManager.getAllBarrels()
.thenAcceptAsync(barrels -> barrels.stream()
.filter(barrel -> barrel.getSpigot().getWorld().equals(event.getWorld()))
.forEach(Barrel.getBarrels()::remove)
);
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/dre/brewery/storage/DataManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public void saveAll(boolean async) {
}

public void saveAll(boolean async, Runnable callback) {
Collection<Barrel> barrels = Barrel.getBarrels();
Collection<Barrel> barrels = Barrel.getAllBarrels();
Collection<BCauldron> cauldrons = BCauldron.getBcauldrons().values();
Collection<BPlayer> bPlayers = BPlayer.getPlayers().values();
Collection<Wakeup> wakeups = Wakeup.getWakeups();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public CompletableFuture<Barrel> getBarrel(UUID id) {

Location spigotLoc = deserializeLocation(dataFile.getString(path + ".spigot"));
if (spigotLoc == null) {
return null;
return CompletableFuture.completedFuture(null);
}

int[] bounds = Arrays.stream(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public CompletableFuture<Barrel> getBarrel(UUID id) {
if (serializableBarrel != null) {
return serializableBarrel.toBarrel();
}
return null;
return CompletableFuture.completedFuture(null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ public CompletableFuture<Barrel> getBarrel(UUID id) {
if (serializableBarrel != null) {
return serializableBarrel.toBarrel();
}
return null;
return CompletableFuture.completedFuture(null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public CompletableFuture<Barrel> getBarrel(UUID id) {
if (serializableBarrel != null) {
return serializableBarrel.toBarrel();
}
return null;
return CompletableFuture.completedFuture(null);
}

@Override
Expand Down
Loading