From 1d4cb85cb1ccd827c8a3583498128f81182e835d Mon Sep 17 00:00:00 2001 From: TheBusyBiscuit Date: Mon, 30 Nov 2020 17:03:17 +0100 Subject: [PATCH] Fixes #2576 --- CHANGELOG.md | 2 + .../core/networks/energy/EnergyNet.java | 2 +- .../core/services/AutoSavingService.java | 5 +- .../services/profiler/SlimefunProfiler.java | 37 +++++++++++---- .../implementation/SlimefunPlugin.java | 3 ++ .../implementation/items/androids/Script.java | 2 +- .../electric/generators/SolarGenerator.java | 7 ++- .../listeners/BlockPhysicsListener.java | 4 +- .../listeners/WorldListener.java | 2 +- .../implementation/tasks/TickerTask.java | 19 ++++++-- .../Slimefun/api/BlockStorage.java | 46 ++++++++++++------- .../api/inventory/BlockMenuPreset.java | 2 +- 12 files changed, 94 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ed9b71e..c6aab6513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,8 @@ * Fixed #2518 * Fixed #2421 * Fixed #2574 +* Fixed color in android script downloading screen +* Fixed #2576 ## Release Candidate 17 (17 Oct 2020) diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java index 5af82c19e..0e659e474 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/networks/energy/EnergyNet.java @@ -241,7 +241,7 @@ public class EnergyNet extends Network { if (!explodedBlocks.isEmpty()) { generators.keySet().removeAll(explodedBlocks); } - + return supply; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java index d965cefde..b28c6d086 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java @@ -77,8 +77,9 @@ public class AutoSavingService { Set worlds = new HashSet<>(); for (World world : Bukkit.getWorlds()) { - if (BlockStorage.isWorldRegistered(world.getName())) { - BlockStorage storage = BlockStorage.getStorage(world); + BlockStorage storage = BlockStorage.getStorage(world); + + if (storage != null) { storage.computeChanges(); if (storage.getChanges() > 0) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java index 71db3afd1..514b4d32e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/profiler/SlimefunProfiler.java @@ -20,6 +20,7 @@ import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; +import org.bukkit.scheduler.BukkitScheduler; import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; @@ -48,10 +49,21 @@ public class SlimefunProfiler { */ private static final int MAX_TICK_DURATION = 100; - private final SlimefunThreadFactory threadFactory = new SlimefunThreadFactory(8); + /** + * Our internal instance of {@link SlimefunThreadFactory}, it provides the naming + * convention for our {@link Thread} pool and also the count of this pool. + */ + private final SlimefunThreadFactory threadFactory = new SlimefunThreadFactory(2); + + /** + * This is our {@link Thread} pool to evaluate timings data. + * We cannot use the {@link BukkitScheduler} here because we need to evaluate + * this data in split seconds. + * So we cannot simply wait until the next server tick for this. + */ private final ExecutorService executor = Executors.newFixedThreadPool(threadFactory.getThreadCount(), threadFactory); - private final AtomicBoolean running = new AtomicBoolean(false); + private final AtomicBoolean isProfiling = new AtomicBoolean(false); private final AtomicInteger queued = new AtomicInteger(0); private long totalElapsedTime; @@ -59,11 +71,20 @@ public class SlimefunProfiler { private final Map timings = new ConcurrentHashMap<>(); private final Queue requests = new ConcurrentLinkedQueue<>(); + /** + * This method terminates the {@link SlimefunProfiler}. + * We need to call this method when the {@link Server} shuts down to prevent any + * of our {@link Thread Threads} from being kept alive. + */ + public void kill() { + executor.shutdown(); + } + /** * This method starts the profiling, data from previous runs will be cleared. */ public void start() { - running.set(true); + isProfiling.set(true); queued.set(0); timings.clear(); } @@ -74,7 +95,7 @@ public class SlimefunProfiler { * @return A timestamp, best fed back into {@link #closeEntry(Location, SlimefunItem, long)} */ public long newEntry() { - if (!running.get()) { + if (!isProfiling.get()) { return 0; } @@ -93,7 +114,7 @@ public class SlimefunProfiler { * The amount of entries that should be scheduled. Can be negative */ public void scheduleEntries(int amount) { - if (running.get()) { + if (isProfiling.get()) { queued.getAndAdd(amount); } } @@ -136,7 +157,7 @@ public class SlimefunProfiler { * This stops the profiling. */ public void stop() { - running.set(false); + isProfiling.set(false); if (SlimefunPlugin.instance() == null || !SlimefunPlugin.instance().isEnabled()) { // Slimefun has been disabled @@ -151,7 +172,7 @@ public class SlimefunProfiler { int iterations = 4000; // Wait for all timing results to come in - while (!running.get() && queued.get() > 0) { + while (!isProfiling.get() && queued.get() > 0) { try { /** * Since we got more than one Thread in our pool, @@ -177,7 +198,7 @@ public class SlimefunProfiler { } } - if (running.get() && queued.get() > 0) { + if (isProfiling.get() && queued.get() > 0) { // Looks like the next profiling has already started, abort! return; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java index 513e81d5d..0e72fdc84 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunPlugin.java @@ -356,6 +356,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon { ticker.halt(); ticker.run(); + // Kill our Profiler Threads + profiler.kill(); + // Save all Player Profiles that are still in memory PlayerProfile.iterator().forEachRemaining(profile -> { if (profile.isDirty()) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java index 7ee370638..6437e91f6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Script.java @@ -151,7 +151,7 @@ public final class Script { @Nonnull private String getScriptRatingPercentage() { float percentage = getRating(); - return NumberUtils.getColorFromPercentage(percentage) + String.valueOf(percentage) + ChatColor.RESET + "% "; + return NumberUtils.getColorFromPercentage(percentage) + String.valueOf(percentage) + ChatColor.WHITE + "% "; } /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/SolarGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/SolarGenerator.java index 942945155..2b67bcd1f 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/SolarGenerator.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/SolarGenerator.java @@ -61,10 +61,15 @@ public class SolarGenerator extends SlimefunItem implements EnergyNetProvider { } @Override - public int getCapacity() { + public final int getCapacity() { return 0; } + @Override + public final boolean isChargeable() { + return false; + } + @Override public int getGeneratedOutput(Location l, Config data) { World world = l.getWorld(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java index eb4aeaba4..56ffb7423 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java @@ -53,7 +53,7 @@ public class BlockPhysicsListener implements Listener { } } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onPistonExtend(BlockPistonExtendEvent e) { if (BlockStorage.hasBlockInfo(e.getBlock())) { e.setCancelled(true); @@ -67,7 +67,7 @@ public class BlockPhysicsListener implements Listener { } } - @EventHandler + @EventHandler(ignoreCancelled = true) public void onPistonRetract(BlockPistonRetractEvent e) { if (BlockStorage.hasBlockInfo(e.getBlock())) { e.setCancelled(true); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java index a18400451..315bc295d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java @@ -22,7 +22,7 @@ public class WorldListener implements Listener { @EventHandler public void onWorldLoad(WorldLoadEvent e) { SlimefunPlugin.getWorldSettingsService().load(e.getWorld()); - BlockStorage.getForcedStorage(e.getWorld()); + BlockStorage.getOrCreate(e.getWorld()); } @EventHandler diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java index 9057928e5..7c4be4ddc 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java @@ -30,8 +30,8 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.Slimefun; /** - * The {@link TickerTask} is responsible for ticking every {@link BlockTicker}, synchronous - * or not. + * The {@link TickerTask} is responsible for ticking every {@link BlockTicker}, + * synchronous or not. * * @author TheBusyBiscuit * @@ -75,7 +75,7 @@ public class TickerTask implements Runnable { /** * This method resets this {@link TickerTask} to run again. */ - public void reset() { + private void reset() { running = false; } @@ -91,6 +91,7 @@ public class TickerTask implements Runnable { SlimefunPlugin.getProfiler().start(); Set tickers = new HashSet<>(); + // Remove any deleted blocks Iterator> removals = deletionQueue.entrySet().iterator(); while (removals.hasNext()) { Map.Entry entry = removals.next(); @@ -98,12 +99,24 @@ public class TickerTask implements Runnable { removals.remove(); } + // Fixes #2576 - Remove any deleted instances of BlockStorage + Iterator worlds = SlimefunPlugin.getRegistry().getWorlds().values().iterator(); + while (worlds.hasNext()) { + BlockStorage storage = worlds.next(); + + if (storage.isMarkedForRemoval()) { + worlds.remove(); + } + } + + // Run our ticker code if (!halted) { for (Map.Entry> entry : tickingLocations.entrySet()) { tickChunk(entry.getKey(), tickers, entry.getValue()); } } + // Move any moved block data Iterator> moves = movingQueue.entrySet().iterator(); while (moves.hasNext()) { Map.Entry entry = moves.next(); diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java index c7441b3df..c8de41284 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -55,14 +56,24 @@ public class BlockStorage { private final Map blocksCache = new ConcurrentHashMap<>(); private static int chunkChanges = 0; - private int changes = 0; + private int changes = 0; + private AtomicBoolean isMarkedForRemoval = new AtomicBoolean(false); + + @Nullable public static BlockStorage getStorage(@Nonnull World world) { return SlimefunPlugin.getRegistry().getWorlds().get(world.getName()); } - public static BlockStorage getForcedStorage(@Nonnull World world) { - return isWorldRegistered(world.getName()) ? SlimefunPlugin.getRegistry().getWorlds().get(world.getName()) : new BlockStorage(world); + @Nonnull + public static BlockStorage getOrCreate(@Nonnull World world) { + BlockStorage storage = SlimefunPlugin.getRegistry().getWorlds().get(world.getName()); + + if (storage == null) { + return new BlockStorage(world); + } else { + return storage; + } } private static String serializeLocation(Location l) { @@ -321,7 +332,11 @@ public class BlockStorage { public void saveAndRemove() { save(); - SlimefunPlugin.getRegistry().getWorlds().remove(world.getName()); + isMarkedForRemoval.set(true); + } + + public boolean isMarkedForRemoval() { + return isMarkedForRemoval.get(); } public static void saveChunks() { @@ -496,15 +511,13 @@ public class BlockStorage { storage.storage.put(l, cfg); String id = cfg.getString("id"); + BlockMenuPreset preset = BlockMenuPreset.getPreset(id); - if (BlockMenuPreset.isInventory(id)) { + if (preset != null) { if (BlockMenuPreset.isUniversalInventory(id)) { - if (!SlimefunPlugin.getRegistry().getUniversalInventories().containsKey(id)) { - storage.loadUniversalInventory(BlockMenuPreset.getPreset(id)); - } + SlimefunPlugin.getRegistry().getUniversalInventories().computeIfAbsent(id, key -> new UniversalBlockMenu(preset)); } else if (!storage.hasInventory(l)) { File file = new File(PATH_INVENTORIES + serializeLocation(l) + ".sfi"); - BlockMenuPreset preset = BlockMenuPreset.getPreset(id); if (file.exists()) { BlockMenu inventory = new BlockMenu(preset, l, new io.github.thebusybiscuit.cscorelib2.config.Config(file)); @@ -560,6 +573,10 @@ public class BlockStorage { public static void deleteLocationInfoUnsafely(Location l, boolean destroy) { BlockStorage storage = getStorage(l.getWorld()); + if (storage == null) { + throw new IllegalStateException("World \"" + l.getWorld().getName() + "\" seems to have been deleted. Do not call unsafe methods directly!"); + } + if (hasBlockInfo(l)) { refreshCache(storage, l, getLocationInfo(l).getString("id"), null, destroy); storage.storage.remove(l); @@ -686,8 +703,8 @@ public class BlockStorage { return id != null && id.equals(slimefunItem); } - public static boolean isWorldRegistered(String name) { - return SlimefunPlugin.getRegistry().getWorlds().containsKey(name); + public static boolean isWorldLoaded(World world) { + return SlimefunPlugin.getRegistry().getWorlds().containsKey(world.getName()); } public BlockMenu loadInventory(Location l, BlockMenuPreset preset) { @@ -715,11 +732,6 @@ public class BlockStorage { } } - public void loadUniversalInventory(BlockMenuPreset preset) { - UniversalBlockMenu inventory = new UniversalBlockMenu(preset); - SlimefunPlugin.getRegistry().getUniversalInventories().put(preset.getID(), inventory); - } - public void clearInventory(Location l) { BlockMenu menu = getInventory(l); @@ -788,7 +800,7 @@ public class BlockStorage { public static Config getChunkInfo(World world, int x, int z) { try { - if (!isWorldRegistered(world.getName())) { + if (!isWorldLoaded(world)) { return emptyBlockData; } diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java index 4c80fedb2..3239d8f19 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java @@ -300,7 +300,7 @@ public abstract class BlockMenuPreset extends ChestMenu { } @Nullable - public static BlockMenuPreset getPreset(String id) { + public static BlockMenuPreset getPreset(@Nullable String id) { return id == null ? null : SlimefunPlugin.getRegistry().getMenuPresets().get(id); }