1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00
This commit is contained in:
TheBusyBiscuit 2020-11-30 17:03:17 +01:00
parent c4619ecbaa
commit 1d4cb85cb1
12 changed files with 94 additions and 37 deletions

View File

@ -80,6 +80,8 @@
* Fixed #2518 * Fixed #2518
* Fixed #2421 * Fixed #2421
* Fixed #2574 * Fixed #2574
* Fixed color in android script downloading screen
* Fixed #2576
## Release Candidate 17 (17 Oct 2020) ## Release Candidate 17 (17 Oct 2020)

View File

@ -241,7 +241,7 @@ public class EnergyNet extends Network {
if (!explodedBlocks.isEmpty()) { if (!explodedBlocks.isEmpty()) {
generators.keySet().removeAll(explodedBlocks); generators.keySet().removeAll(explodedBlocks);
} }
return supply; return supply;
} }

View File

@ -77,8 +77,9 @@ public class AutoSavingService {
Set<BlockStorage> worlds = new HashSet<>(); Set<BlockStorage> worlds = new HashSet<>();
for (World world : Bukkit.getWorlds()) { 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(); storage.computeChanges();
if (storage.getChanges() > 0) { if (storage.getChanges() > 0) {

View File

@ -20,6 +20,7 @@ import org.bukkit.Location;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.scheduler.BukkitScheduler;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -48,10 +49,21 @@ public class SlimefunProfiler {
*/ */
private static final int MAX_TICK_DURATION = 100; 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 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 final AtomicInteger queued = new AtomicInteger(0);
private long totalElapsedTime; private long totalElapsedTime;
@ -59,11 +71,20 @@ public class SlimefunProfiler {
private final Map<ProfiledBlock, Long> timings = new ConcurrentHashMap<>(); private final Map<ProfiledBlock, Long> timings = new ConcurrentHashMap<>();
private final Queue<CommandSender> requests = new ConcurrentLinkedQueue<>(); private final Queue<CommandSender> 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. * This method starts the profiling, data from previous runs will be cleared.
*/ */
public void start() { public void start() {
running.set(true); isProfiling.set(true);
queued.set(0); queued.set(0);
timings.clear(); timings.clear();
} }
@ -74,7 +95,7 @@ public class SlimefunProfiler {
* @return A timestamp, best fed back into {@link #closeEntry(Location, SlimefunItem, long)} * @return A timestamp, best fed back into {@link #closeEntry(Location, SlimefunItem, long)}
*/ */
public long newEntry() { public long newEntry() {
if (!running.get()) { if (!isProfiling.get()) {
return 0; return 0;
} }
@ -93,7 +114,7 @@ public class SlimefunProfiler {
* The amount of entries that should be scheduled. Can be negative * The amount of entries that should be scheduled. Can be negative
*/ */
public void scheduleEntries(int amount) { public void scheduleEntries(int amount) {
if (running.get()) { if (isProfiling.get()) {
queued.getAndAdd(amount); queued.getAndAdd(amount);
} }
} }
@ -136,7 +157,7 @@ public class SlimefunProfiler {
* This stops the profiling. * This stops the profiling.
*/ */
public void stop() { public void stop() {
running.set(false); isProfiling.set(false);
if (SlimefunPlugin.instance() == null || !SlimefunPlugin.instance().isEnabled()) { if (SlimefunPlugin.instance() == null || !SlimefunPlugin.instance().isEnabled()) {
// Slimefun has been disabled // Slimefun has been disabled
@ -151,7 +172,7 @@ public class SlimefunProfiler {
int iterations = 4000; int iterations = 4000;
// Wait for all timing results to come in // Wait for all timing results to come in
while (!running.get() && queued.get() > 0) { while (!isProfiling.get() && queued.get() > 0) {
try { try {
/** /**
* Since we got more than one Thread in our pool, * 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! // Looks like the next profiling has already started, abort!
return; return;
} }

View File

@ -356,6 +356,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
ticker.halt(); ticker.halt();
ticker.run(); ticker.run();
// Kill our Profiler Threads
profiler.kill();
// Save all Player Profiles that are still in memory // Save all Player Profiles that are still in memory
PlayerProfile.iterator().forEachRemaining(profile -> { PlayerProfile.iterator().forEachRemaining(profile -> {
if (profile.isDirty()) { if (profile.isDirty()) {

View File

@ -151,7 +151,7 @@ public final class Script {
@Nonnull @Nonnull
private String getScriptRatingPercentage() { private String getScriptRatingPercentage() {
float percentage = getRating(); float percentage = getRating();
return NumberUtils.getColorFromPercentage(percentage) + String.valueOf(percentage) + ChatColor.RESET + "% "; return NumberUtils.getColorFromPercentage(percentage) + String.valueOf(percentage) + ChatColor.WHITE + "% ";
} }
/** /**

View File

@ -61,10 +61,15 @@ public class SolarGenerator extends SlimefunItem implements EnergyNetProvider {
} }
@Override @Override
public int getCapacity() { public final int getCapacity() {
return 0; return 0;
} }
@Override
public final boolean isChargeable() {
return false;
}
@Override @Override
public int getGeneratedOutput(Location l, Config data) { public int getGeneratedOutput(Location l, Config data) {
World world = l.getWorld(); World world = l.getWorld();

View File

@ -53,7 +53,7 @@ public class BlockPhysicsListener implements Listener {
} }
} }
@EventHandler @EventHandler(ignoreCancelled = true)
public void onPistonExtend(BlockPistonExtendEvent e) { public void onPistonExtend(BlockPistonExtendEvent e) {
if (BlockStorage.hasBlockInfo(e.getBlock())) { if (BlockStorage.hasBlockInfo(e.getBlock())) {
e.setCancelled(true); e.setCancelled(true);
@ -67,7 +67,7 @@ public class BlockPhysicsListener implements Listener {
} }
} }
@EventHandler @EventHandler(ignoreCancelled = true)
public void onPistonRetract(BlockPistonRetractEvent e) { public void onPistonRetract(BlockPistonRetractEvent e) {
if (BlockStorage.hasBlockInfo(e.getBlock())) { if (BlockStorage.hasBlockInfo(e.getBlock())) {
e.setCancelled(true); e.setCancelled(true);

View File

@ -22,7 +22,7 @@ public class WorldListener implements Listener {
@EventHandler @EventHandler
public void onWorldLoad(WorldLoadEvent e) { public void onWorldLoad(WorldLoadEvent e) {
SlimefunPlugin.getWorldSettingsService().load(e.getWorld()); SlimefunPlugin.getWorldSettingsService().load(e.getWorld());
BlockStorage.getForcedStorage(e.getWorld()); BlockStorage.getOrCreate(e.getWorld());
} }
@EventHandler @EventHandler

View File

@ -30,8 +30,8 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.Slimefun;
/** /**
* The {@link TickerTask} is responsible for ticking every {@link BlockTicker}, synchronous * The {@link TickerTask} is responsible for ticking every {@link BlockTicker},
* or not. * synchronous or not.
* *
* @author TheBusyBiscuit * @author TheBusyBiscuit
* *
@ -75,7 +75,7 @@ public class TickerTask implements Runnable {
/** /**
* This method resets this {@link TickerTask} to run again. * This method resets this {@link TickerTask} to run again.
*/ */
public void reset() { private void reset() {
running = false; running = false;
} }
@ -91,6 +91,7 @@ public class TickerTask implements Runnable {
SlimefunPlugin.getProfiler().start(); SlimefunPlugin.getProfiler().start();
Set<BlockTicker> tickers = new HashSet<>(); Set<BlockTicker> tickers = new HashSet<>();
// Remove any deleted blocks
Iterator<Map.Entry<Location, Boolean>> removals = deletionQueue.entrySet().iterator(); Iterator<Map.Entry<Location, Boolean>> removals = deletionQueue.entrySet().iterator();
while (removals.hasNext()) { while (removals.hasNext()) {
Map.Entry<Location, Boolean> entry = removals.next(); Map.Entry<Location, Boolean> entry = removals.next();
@ -98,12 +99,24 @@ public class TickerTask implements Runnable {
removals.remove(); removals.remove();
} }
// Fixes #2576 - Remove any deleted instances of BlockStorage
Iterator<BlockStorage> worlds = SlimefunPlugin.getRegistry().getWorlds().values().iterator();
while (worlds.hasNext()) {
BlockStorage storage = worlds.next();
if (storage.isMarkedForRemoval()) {
worlds.remove();
}
}
// Run our ticker code
if (!halted) { if (!halted) {
for (Map.Entry<ChunkPosition, Set<Location>> entry : tickingLocations.entrySet()) { for (Map.Entry<ChunkPosition, Set<Location>> entry : tickingLocations.entrySet()) {
tickChunk(entry.getKey(), tickers, entry.getValue()); tickChunk(entry.getKey(), tickers, entry.getValue());
} }
} }
// Move any moved block data
Iterator<Map.Entry<Location, Location>> moves = movingQueue.entrySet().iterator(); Iterator<Map.Entry<Location, Location>> moves = movingQueue.entrySet().iterator();
while (moves.hasNext()) { while (moves.hasNext()) {
Map.Entry<Location, Location> entry = moves.next(); Map.Entry<Location, Location> entry = moves.next();

View File

@ -10,6 +10,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -55,14 +56,24 @@ public class BlockStorage {
private final Map<String, Config> blocksCache = new ConcurrentHashMap<>(); private final Map<String, Config> blocksCache = new ConcurrentHashMap<>();
private static int chunkChanges = 0; 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) { public static BlockStorage getStorage(@Nonnull World world) {
return SlimefunPlugin.getRegistry().getWorlds().get(world.getName()); return SlimefunPlugin.getRegistry().getWorlds().get(world.getName());
} }
public static BlockStorage getForcedStorage(@Nonnull World world) { @Nonnull
return isWorldRegistered(world.getName()) ? SlimefunPlugin.getRegistry().getWorlds().get(world.getName()) : new BlockStorage(world); 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) { private static String serializeLocation(Location l) {
@ -321,7 +332,11 @@ public class BlockStorage {
public void saveAndRemove() { public void saveAndRemove() {
save(); save();
SlimefunPlugin.getRegistry().getWorlds().remove(world.getName()); isMarkedForRemoval.set(true);
}
public boolean isMarkedForRemoval() {
return isMarkedForRemoval.get();
} }
public static void saveChunks() { public static void saveChunks() {
@ -496,15 +511,13 @@ public class BlockStorage {
storage.storage.put(l, cfg); storage.storage.put(l, cfg);
String id = cfg.getString("id"); String id = cfg.getString("id");
BlockMenuPreset preset = BlockMenuPreset.getPreset(id);
if (BlockMenuPreset.isInventory(id)) { if (preset != null) {
if (BlockMenuPreset.isUniversalInventory(id)) { if (BlockMenuPreset.isUniversalInventory(id)) {
if (!SlimefunPlugin.getRegistry().getUniversalInventories().containsKey(id)) { SlimefunPlugin.getRegistry().getUniversalInventories().computeIfAbsent(id, key -> new UniversalBlockMenu(preset));
storage.loadUniversalInventory(BlockMenuPreset.getPreset(id));
}
} else if (!storage.hasInventory(l)) { } else if (!storage.hasInventory(l)) {
File file = new File(PATH_INVENTORIES + serializeLocation(l) + ".sfi"); File file = new File(PATH_INVENTORIES + serializeLocation(l) + ".sfi");
BlockMenuPreset preset = BlockMenuPreset.getPreset(id);
if (file.exists()) { if (file.exists()) {
BlockMenu inventory = new BlockMenu(preset, l, new io.github.thebusybiscuit.cscorelib2.config.Config(file)); 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) { public static void deleteLocationInfoUnsafely(Location l, boolean destroy) {
BlockStorage storage = getStorage(l.getWorld()); 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)) { if (hasBlockInfo(l)) {
refreshCache(storage, l, getLocationInfo(l).getString("id"), null, destroy); refreshCache(storage, l, getLocationInfo(l).getString("id"), null, destroy);
storage.storage.remove(l); storage.storage.remove(l);
@ -686,8 +703,8 @@ public class BlockStorage {
return id != null && id.equals(slimefunItem); return id != null && id.equals(slimefunItem);
} }
public static boolean isWorldRegistered(String name) { public static boolean isWorldLoaded(World world) {
return SlimefunPlugin.getRegistry().getWorlds().containsKey(name); return SlimefunPlugin.getRegistry().getWorlds().containsKey(world.getName());
} }
public BlockMenu loadInventory(Location l, BlockMenuPreset preset) { 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) { public void clearInventory(Location l) {
BlockMenu menu = getInventory(l); BlockMenu menu = getInventory(l);
@ -788,7 +800,7 @@ public class BlockStorage {
public static Config getChunkInfo(World world, int x, int z) { public static Config getChunkInfo(World world, int x, int z) {
try { try {
if (!isWorldRegistered(world.getName())) { if (!isWorldLoaded(world)) {
return emptyBlockData; return emptyBlockData;
} }

View File

@ -300,7 +300,7 @@ public abstract class BlockMenuPreset extends ChestMenu {
} }
@Nullable @Nullable
public static BlockMenuPreset getPreset(String id) { public static BlockMenuPreset getPreset(@Nullable String id) {
return id == null ? null : SlimefunPlugin.getRegistry().getMenuPresets().get(id); return id == null ? null : SlimefunPlugin.getRegistry().getMenuPresets().get(id);
} }