mirror of
https://github.com/StarWishsama/Slimefun4.git
synced 2024-09-19 19:25:48 +00:00
Performance and memory improvements
This commit is contained in:
parent
d77fd498f8
commit
d0e7e21877
@ -48,6 +48,7 @@
|
|||||||
* Memory/GC improvements for the profiler
|
* Memory/GC improvements for the profiler
|
||||||
* Performance improvements for the Fluid Pump
|
* Performance improvements for the Fluid Pump
|
||||||
* Removed EmeraldEnchants integration
|
* Removed EmeraldEnchants integration
|
||||||
|
* Memory and performance improvements for ticking blocks
|
||||||
|
|
||||||
#### Fixes
|
#### Fixes
|
||||||
* Fixed #2448
|
* Fixed #2448
|
||||||
|
2
pom.xml
2
pom.xml
@ -337,7 +337,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.TheBusyBiscuit</groupId>
|
<groupId>com.github.TheBusyBiscuit</groupId>
|
||||||
<artifactId>CS-CoreLib2</artifactId>
|
<artifactId>CS-CoreLib2</artifactId>
|
||||||
<version>0.27.3</version>
|
<version>0.27.4</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -132,11 +132,16 @@ public abstract class Network {
|
|||||||
*
|
*
|
||||||
* @param l
|
* @param l
|
||||||
* The {@link Location} to check for
|
* The {@link Location} to check for
|
||||||
|
*
|
||||||
* @return Whether the given {@link Location} is part of this {@link Network}
|
* @return Whether the given {@link Location} is part of this {@link Network}
|
||||||
*/
|
*/
|
||||||
public boolean connectsTo(@Nonnull Location l) {
|
public boolean connectsTo(@Nonnull Location l) {
|
||||||
|
if (regulator.equals(l)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
return connectedLocations.contains(l);
|
return connectedLocations.contains(l);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private NetworkComponent getCurrentClassification(@Nonnull Location l) {
|
private NetworkComponent getCurrentClassification(@Nonnull Location l) {
|
||||||
|
@ -75,9 +75,11 @@ public class RainbowTickHandler extends BlockTicker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Material type : materials) {
|
for (Material type : materials) {
|
||||||
// This BlockData is purely virtual and only created on startup, it should have
|
/**
|
||||||
// no impact on performance, in fact it should save performance as it preloads
|
* This BlockData is purely virtual and only created on startup, it should have
|
||||||
// the data but also saves heavy calls for other Materials
|
* no impact on performance, in fact it should save performance as it preloads
|
||||||
|
* the data but also saves heavy calls for other Materials
|
||||||
|
*/
|
||||||
if (type.createBlockData() instanceof GlassPane) {
|
if (type.createBlockData() instanceof GlassPane) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -89,8 +91,10 @@ public class RainbowTickHandler extends BlockTicker {
|
|||||||
@Override
|
@Override
|
||||||
public void tick(Block b, SlimefunItem item, Config data) {
|
public void tick(Block b, SlimefunItem item, Config data) {
|
||||||
if (b.getType() == Material.AIR) {
|
if (b.getType() == Material.AIR) {
|
||||||
// The block was broken, setting the Material now would result in a
|
/**
|
||||||
// duplication glitch
|
* The block was broken, setting the Material now would result in a
|
||||||
|
* duplication glitch
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
|
||||||
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
||||||
import io.github.thebusybiscuit.slimefun4.api.network.Network;
|
import io.github.thebusybiscuit.slimefun4.api.network.Network;
|
||||||
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
|
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
|
||||||
@ -23,6 +22,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
|
|||||||
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
|
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
|
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
|
||||||
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
@ -254,10 +254,10 @@ public class EnergyNet extends Network {
|
|||||||
|
|
||||||
private void updateHologram(@Nonnull Block b, double supply, double demand) {
|
private void updateHologram(@Nonnull Block b, double supply, double demand) {
|
||||||
if (demand > supply) {
|
if (demand > supply) {
|
||||||
String netLoss = DoubleHandler.getFancyDouble(Math.abs(supply - demand));
|
String netLoss = NumberUtils.getCompactDouble(demand - supply);
|
||||||
SimpleHologram.update(b, "&4&l- &c" + netLoss + " &7J &e\u26A1");
|
SimpleHologram.update(b, "&4&l- &c" + netLoss + " &7J &e\u26A1");
|
||||||
} else {
|
} else {
|
||||||
String netGain = DoubleHandler.getFancyDouble(supply - demand);
|
String netGain = NumberUtils.getCompactDouble(supply - demand);
|
||||||
SimpleHologram.update(b, "&2&l+ &a" + netGain + " &7J &e\u26A1");
|
SimpleHologram.update(b, "&2&l+ &a" + netGain + " &7J &e\u26A1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ 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(5);
|
private final SlimefunThreadFactory threadFactory = new SlimefunThreadFactory(8);
|
||||||
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 running = new AtomicBoolean(false);
|
||||||
|
@ -8,12 +8,12 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
|
||||||
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
|
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
|
||||||
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
|
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
|
||||||
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
|
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
|
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||||
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
@ -50,8 +50,8 @@ public class Multimeter extends SimpleSlimefunItem<ItemUseHandler> {
|
|||||||
e.cancel();
|
e.cancel();
|
||||||
|
|
||||||
Location l = e.getClickedBlock().get().getLocation();
|
Location l = e.getClickedBlock().get().getLocation();
|
||||||
String stored = DoubleHandler.getFancyDouble(component.getCharge(l)) + " J";
|
String stored = NumberUtils.getCompactDouble(component.getCharge(l)) + " J";
|
||||||
String capacity = DoubleHandler.getFancyDouble(component.getCapacity()) + " J";
|
String capacity = NumberUtils.getCompactDouble(component.getCapacity()) + " J";
|
||||||
|
|
||||||
Player p = e.getPlayer();
|
Player p = e.getPlayer();
|
||||||
p.sendMessage("");
|
p.sendMessage("");
|
||||||
|
@ -11,6 +11,7 @@ import org.bukkit.block.Block;
|
|||||||
import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock;
|
import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor;
|
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This task is run whenever a {@link Capacitor} needs to update their texture.
|
* This task is run whenever a {@link Capacitor} needs to update their texture.
|
||||||
@ -58,18 +59,23 @@ public class CapacitorTextureUpdateTask implements Runnable {
|
|||||||
if (type == Material.PLAYER_HEAD || type == Material.PLAYER_WALL_HEAD) {
|
if (type == Material.PLAYER_HEAD || type == Material.PLAYER_WALL_HEAD) {
|
||||||
if (filledPercentage <= 0.25) {
|
if (filledPercentage <= 0.25) {
|
||||||
// 0-25% capacity
|
// 0-25% capacity
|
||||||
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_25.getTexture());
|
setTexture(b, HeadTexture.CAPACITOR_25);
|
||||||
} else if (filledPercentage <= 0.5) {
|
} else if (filledPercentage <= 0.5) {
|
||||||
// 25-50% capacity
|
// 25-50% capacity
|
||||||
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_50.getTexture());
|
setTexture(b, HeadTexture.CAPACITOR_50);
|
||||||
} else if (filledPercentage <= 0.75) {
|
} else if (filledPercentage <= 0.75) {
|
||||||
// 50-75% capacity
|
// 50-75% capacity
|
||||||
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_75.getTexture());
|
setTexture(b, HeadTexture.CAPACITOR_75);
|
||||||
} else {
|
} else {
|
||||||
// 75-100% capacity
|
// 75-100% capacity
|
||||||
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_100.getTexture());
|
setTexture(b, HeadTexture.CAPACITOR_100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setTexture(@Nonnull Block b, @Nonnull HeadTexture texture) {
|
||||||
|
SkullBlock.setFromHash(b, texture.getUniqueId(), texture.getTexture(), false);
|
||||||
|
PaperLib.getBlockState(b, false).getState().update(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
|
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -10,17 +11,18 @@ import java.util.logging.Level;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
|
||||||
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
|
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
|
||||||
|
import io.github.thebusybiscuit.cscorelib2.blocks.ChunkPosition;
|
||||||
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
|
|
||||||
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
|
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
|
||||||
@ -41,7 +43,7 @@ public class TickerTask implements Runnable {
|
|||||||
/**
|
/**
|
||||||
* This Map holds all currently actively ticking locations.
|
* This Map holds all currently actively ticking locations.
|
||||||
*/
|
*/
|
||||||
private final Map<String, Set<Location>> activeTickers = new ConcurrentHashMap<>();
|
private final Map<ChunkPosition, Set<Location>> tickingLocations = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// These are "Queues" of blocks that need to be removed or moved
|
// These are "Queues" of blocks that need to be removed or moved
|
||||||
private final Map<Location, Location> movingQueue = new ConcurrentHashMap<>();
|
private final Map<Location, Location> movingQueue = new ConcurrentHashMap<>();
|
||||||
@ -97,8 +99,8 @@ public class TickerTask implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!halted) {
|
if (!halted) {
|
||||||
for (Map.Entry<String, Set<Location>> entry : activeTickers.entrySet()) {
|
for (Map.Entry<ChunkPosition, Set<Location>> entry : tickingLocations.entrySet()) {
|
||||||
tickChunk(tickers, entry.getKey(), entry.getValue());
|
tickChunk(entry.getKey(), tickers, entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,21 +125,16 @@ public class TickerTask implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
private void tickChunk(Set<BlockTicker> tickers, String chunk, Set<Location> locations) {
|
private void tickChunk(ChunkPosition chunk, Set<BlockTicker> tickers, Set<Location> locations) {
|
||||||
try {
|
try {
|
||||||
String[] components = PatternUtils.SEMICOLON.split(chunk);
|
// Only continue if the Chunk is actually loaded
|
||||||
|
if (chunk.isLoaded()) {
|
||||||
World world = Bukkit.getWorld(components[0]);
|
|
||||||
int x = Integer.parseInt(components[components.length - 2]);
|
|
||||||
int z = Integer.parseInt(components[components.length - 1]);
|
|
||||||
|
|
||||||
if (world != null && world.isChunkLoaded(x, z)) {
|
|
||||||
for (Location l : locations) {
|
for (Location l : locations) {
|
||||||
tickLocation(tickers, l);
|
tickLocation(tickers, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ArrayIndexOutOfBoundsException | NumberFormatException x) {
|
} catch (ArrayIndexOutOfBoundsException | NumberFormatException x) {
|
||||||
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Exception has occurred while trying to parse Chunk: " + chunk);
|
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Exception has occurred while trying to resolve Chunk: " + chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,14 +232,82 @@ public class TickerTask implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns the {@link Map} of actively ticking locations according to
|
* This method returns a <strong>read-only</strong> {@link Map}
|
||||||
* their chunk id.
|
* representation of every {@link ChunkPosition} and its corresponding
|
||||||
|
* {@link Set} of ticking {@link Location Locations}.
|
||||||
*
|
*
|
||||||
* @return The {@link Map} of active tickers
|
* This does include any {@link Location} from an unloaded {@link Chunk} too!
|
||||||
|
*
|
||||||
|
* @return A {@link Map} representation of all ticking {@link Location Locations}
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public Map<String, Set<Location>> getActiveTickers() {
|
public Map<ChunkPosition, Set<Location>> getLocations() {
|
||||||
return activeTickers;
|
return Collections.unmodifiableMap(tickingLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a <strong>read-only</strong> {@link Set}
|
||||||
|
* of all ticking {@link Location Locations} in a given {@link Chunk}.
|
||||||
|
* The {@link Chunk} does not have to be loaded.
|
||||||
|
* If no {@link Location} is present, the returned {@link Set} will be empty.
|
||||||
|
*
|
||||||
|
* @param chunk
|
||||||
|
* The {@link Chunk}
|
||||||
|
*
|
||||||
|
* @return A {@link Set} of all ticking {@link Location Locations}
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public Set<Location> getLocations(@Nonnull Chunk chunk) {
|
||||||
|
Validate.notNull(chunk, "The Chunk cannot be null!");
|
||||||
|
|
||||||
|
Set<Location> locations = tickingLocations.getOrDefault(new ChunkPosition(chunk), new HashSet<>());
|
||||||
|
return Collections.unmodifiableSet(locations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enables the ticker at the given {@link Location} and adds it to our "queue".
|
||||||
|
*
|
||||||
|
* @param l
|
||||||
|
* The {@link Location} to activate
|
||||||
|
*/
|
||||||
|
public void enableTicker(@Nonnull Location l) {
|
||||||
|
Validate.notNull(l, "Location cannot be null!");
|
||||||
|
|
||||||
|
ChunkPosition chunk = new ChunkPosition(l.getWorld(), l.getBlockX() >> 4, l.getBlockZ() >> 4);
|
||||||
|
Set<Location> newValue = new HashSet<>();
|
||||||
|
Set<Location> oldValue = tickingLocations.putIfAbsent(chunk, newValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is faster than doing computeIfAbsent(...)
|
||||||
|
* on a ConcurrentHashMap because it won't block the Thread for too long
|
||||||
|
*/
|
||||||
|
if (oldValue != null) {
|
||||||
|
oldValue.add(l);
|
||||||
|
} else {
|
||||||
|
newValue.add(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method disables the ticker at the given {@link Location} and removes it from our internal
|
||||||
|
* "queue".
|
||||||
|
*
|
||||||
|
* @param l
|
||||||
|
* The {@link Location} to remove
|
||||||
|
*/
|
||||||
|
public void disableTicker(@Nonnull Location l) {
|
||||||
|
Validate.notNull(l, "Location cannot be null!");
|
||||||
|
|
||||||
|
ChunkPosition chunk = new ChunkPosition(l.getWorld(), l.getBlockX() >> 4, l.getBlockZ() >> 4);
|
||||||
|
Set<Location> locations = tickingLocations.get(chunk);
|
||||||
|
|
||||||
|
if (locations != null) {
|
||||||
|
locations.remove(l);
|
||||||
|
|
||||||
|
if (locations.isEmpty()) {
|
||||||
|
tickingLocations.remove(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.utils;
|
package io.github.thebusybiscuit.slimefun4.utils;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
@ -114,11 +116,14 @@ public enum HeadTexture {
|
|||||||
public static final HeadTexture[] valuesCache = values();
|
public static final HeadTexture[] valuesCache = values();
|
||||||
|
|
||||||
private final String texture;
|
private final String texture;
|
||||||
|
private final UUID uuid;
|
||||||
|
|
||||||
HeadTexture(@Nonnull String texture) {
|
HeadTexture(@Nonnull String texture) {
|
||||||
Validate.notNull(texture, "Texture cannot be null");
|
Validate.notNull(texture, "Texture cannot be null");
|
||||||
Validate.isTrue(PatternUtils.HEXADECIMAL.matcher(texture).matches(), "Textures must be in hexadecimal.");
|
Validate.isTrue(PatternUtils.HEXADECIMAL.matcher(texture).matches(), "Textures must be in hexadecimal.");
|
||||||
|
|
||||||
this.texture = texture;
|
this.texture = texture;
|
||||||
|
this.uuid = UUID.nameUUIDFromBytes(texture.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,6 +136,18 @@ public enum HeadTexture {
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This returns the {@link UUID} for this {@link HeadTexture}.
|
||||||
|
* The {@link UUID} is generated from the texture and cached for
|
||||||
|
* performance reasons.
|
||||||
|
*
|
||||||
|
* @return The {@link UUID} for this {@link HeadTexture}
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public UUID getUniqueId() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns an {@link ItemStack} with the given texture assigned to it.
|
* This method returns an {@link ItemStack} with the given texture assigned to it.
|
||||||
*
|
*
|
||||||
|
@ -24,6 +24,7 @@ public final class NumberUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This is our {@link DecimalFormat} for decimal values.
|
* This is our {@link DecimalFormat} for decimal values.
|
||||||
|
* This instance is not thread-safe!
|
||||||
*/
|
*/
|
||||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ROOT));
|
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ROOT));
|
||||||
|
|
||||||
@ -48,6 +49,34 @@ public final class NumberUtils {
|
|||||||
return NumberFormat.getNumberInstance(Locale.US).format(number);
|
return NumberFormat.getNumberInstance(Locale.US).format(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static String getCompactDouble(double value) {
|
||||||
|
if (value < 0) {
|
||||||
|
// Negative numbers are a special case
|
||||||
|
return '-' + getCompactDouble(-value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 1000.0) {
|
||||||
|
// Below 1K
|
||||||
|
return DECIMAL_FORMAT.format(value);
|
||||||
|
} else if (value < 1000000.0) {
|
||||||
|
// Thousands
|
||||||
|
return DECIMAL_FORMAT.format(value / 1000.0) + 'K';
|
||||||
|
} else if (value < 1000000000.0) {
|
||||||
|
// Million
|
||||||
|
return DECIMAL_FORMAT.format(value / 1000000.0) + 'M';
|
||||||
|
} else if (value < 1000000000000.0) {
|
||||||
|
// Billion
|
||||||
|
return DECIMAL_FORMAT.format(value / 1000000000.0) + 'B';
|
||||||
|
} else if (value < 1000000000000000.0) {
|
||||||
|
// Trillion
|
||||||
|
return DECIMAL_FORMAT.format(value / 1000000000000.0) + 'T';
|
||||||
|
} else {
|
||||||
|
// Quadrillion
|
||||||
|
return DECIMAL_FORMAT.format(value / 1000000000000000.0) + 'Q';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method transforms a String representation of a {@link LocalDateTime}
|
* This method transforms a String representation of a {@link LocalDateTime}
|
||||||
* from GitHub's API back into a {@link LocalDateTime} object
|
* from GitHub's API back into a {@link LocalDateTime} object
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.utils.holograms;
|
package io.github.thebusybiscuit.slimefun4.utils.holograms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -17,9 +19,10 @@ public final class ReactorHologram {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public static ArmorStand getArmorStand(@Nonnull Location reactor, boolean createIfNoneExists) {
|
public static ArmorStand getArmorStand(@Nonnull Location reactor, boolean createIfNoneExists) {
|
||||||
Location l = new Location(reactor.getWorld(), reactor.getX() + 0.5, reactor.getY() + 0.7, reactor.getZ() + 0.5);
|
Location l = new Location(reactor.getWorld(), reactor.getX() + 0.5, reactor.getY() + 0.7, reactor.getZ() + 0.5);
|
||||||
|
Collection<Entity> holograms = l.getWorld().getNearbyEntities(l, 0.2, 0.2, 0.2, ReactorHologram::isPossibleHologram);
|
||||||
|
|
||||||
for (Entity n : l.getChunk().getEntities()) {
|
for (Entity n : holograms) {
|
||||||
if (n instanceof ArmorStand && l.distanceSquared(n.getLocation()) < 0.4D) {
|
if (n instanceof ArmorStand) {
|
||||||
return (ArmorStand) n;
|
return (ArmorStand) n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,14 +37,21 @@ public final class ReactorHologram {
|
|||||||
return hologram;
|
return hologram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isPossibleHologram(@Nonnull Entity n) {
|
||||||
|
if (n instanceof ArmorStand) {
|
||||||
|
ArmorStand armorstand = (ArmorStand) n;
|
||||||
|
return armorstand.isValid() && armorstand.isSilent() && armorstand.isMarker() && !armorstand.hasGravity();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static void update(@Nonnull Location l, @Nonnull String name) {
|
public static void update(@Nonnull Location l, @Nonnull String name) {
|
||||||
SlimefunPlugin.runSync(() -> {
|
SlimefunPlugin.runSync(() -> {
|
||||||
ArmorStand hologram = getArmorStand(l, true);
|
ArmorStand hologram = getArmorStand(l, true);
|
||||||
|
|
||||||
if (!hologram.isCustomNameVisible()) {
|
|
||||||
hologram.setCustomNameVisible(true);
|
hologram.setCustomNameVisible(true);
|
||||||
}
|
|
||||||
|
|
||||||
hologram.setCustomName(ChatColors.color(name));
|
hologram.setCustomName(ChatColors.color(name));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.utils.holograms;
|
package io.github.thebusybiscuit.slimefun4.utils.holograms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -42,9 +44,10 @@ public final class SimpleHologram {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static ArmorStand getArmorStand(@Nonnull Block b, boolean createIfNoneExists) {
|
private static ArmorStand getArmorStand(@Nonnull Block b, boolean createIfNoneExists) {
|
||||||
Location l = new Location(b.getWorld(), b.getX() + 0.5, b.getY() + 0.7F, b.getZ() + 0.5);
|
Location l = new Location(b.getWorld(), b.getX() + 0.5, b.getY() + 0.7F, b.getZ() + 0.5);
|
||||||
|
Collection<Entity> holograms = b.getWorld().getNearbyEntities(l, 0.2, 0.2, 0.2, SimpleHologram::isPossibleHologram);
|
||||||
|
|
||||||
for (Entity n : l.getChunk().getEntities()) {
|
for (Entity n : holograms) {
|
||||||
if (n instanceof ArmorStand && l.distanceSquared(n.getLocation()) < 0.4D && isPossibleHologram((ArmorStand) n)) {
|
if (n instanceof ArmorStand) {
|
||||||
return (ArmorStand) n;
|
return (ArmorStand) n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,8 +59,14 @@ public final class SimpleHologram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPossibleHologram(@Nonnull ArmorStand armorstand) {
|
private static boolean isPossibleHologram(@Nonnull Entity n) {
|
||||||
|
if (n instanceof ArmorStand) {
|
||||||
|
ArmorStand armorstand = (ArmorStand) n;
|
||||||
return armorstand.isValid() && armorstand.isSilent() && armorstand.isMarker() && !armorstand.hasGravity() && armorstand.isCustomNameVisible();
|
return armorstand.isValid() && armorstand.isSilent() && armorstand.isMarker() && !armorstand.hasGravity() && armorstand.isCustomNameVisible();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -202,7 +202,7 @@ public abstract class AGenerator extends AbstractEnergyProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemStackWrapper wrapper = new ItemStackWrapper(item);
|
ItemStackWrapper wrapper = new ItemStackWrapper(item);
|
||||||
return SlimefunUtils.isItemSimilar(wrapper, new ItemStack(Material.LAVA_BUCKET), true) || SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.FUEL_BUCKET, true) || SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.OIL_BUCKET, true);
|
return item.getType() == Material.LAVA_BUCKET || SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.FUEL_BUCKET, true) || SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.OIL_BUCKET, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MachineFuel findRecipe(BlockMenu menu, Map<Integer, Integer> found) {
|
private MachineFuel findRecipe(BlockMenu menu, Map<Integer, Integer> found) {
|
||||||
|
@ -49,8 +49,6 @@ public class BlockInfoConfig extends Config {
|
|||||||
throw new UnsupportedOperationException("Can't set \"" + path + "\" to \"" + value + "\" (type: " + value.getClass().getSimpleName() + ") because BlockInfoConfig only supports Strings");
|
throw new UnsupportedOperationException("Can't set \"" + path + "\" to \"" + value + "\" (type: " + value.getClass().getSimpleName() + ") because BlockInfoConfig only supports Strings");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPath(path);
|
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
data.remove(path);
|
data.remove(path);
|
||||||
} else {
|
} else {
|
||||||
@ -58,15 +56,8 @@ public class BlockInfoConfig extends Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPath(String path) {
|
|
||||||
if (path.indexOf('.') != -1) {
|
|
||||||
throw new UnsupportedOperationException("BlockInfoConfig only supports Map<String,String> (path: " + path + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(String path) {
|
public boolean contains(String path) {
|
||||||
checkPath(path);
|
|
||||||
return data.containsKey(path);
|
return data.containsKey(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +68,6 @@ public class BlockInfoConfig extends Config {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getString(String path) {
|
public String getString(String path) {
|
||||||
checkPath(path);
|
|
||||||
return data.get(path);
|
return data.get(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,8 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -71,10 +69,6 @@ public class BlockStorage {
|
|||||||
return l.getWorld().getName() + ';' + l.getBlockX() + ';' + l.getBlockY() + ';' + l.getBlockZ();
|
return l.getWorld().getName() + ';' + l.getBlockX() + ';' + l.getBlockY() + ';' + l.getBlockZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String locationToChunkString(Location l) {
|
|
||||||
return l.getWorld().getName() + ";Chunk;" + (l.getBlockX() >> 4) + ';' + (l.getBlockZ() >> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String serializeChunk(World world, int x, int z) {
|
private static String serializeChunk(World world, int x, int z) {
|
||||||
return world.getName() + ";Chunk;" + x + ';' + z;
|
return world.getName() + ";Chunk;" + x + ';' + z;
|
||||||
}
|
}
|
||||||
@ -177,7 +171,6 @@ public class BlockStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String chunkString = locationToChunkString(l);
|
|
||||||
String json = cfg.getString(key);
|
String json = cfg.getString(key);
|
||||||
Config blockInfo = parseBlockInfo(l, json);
|
Config blockInfo = parseBlockInfo(l, json);
|
||||||
|
|
||||||
@ -195,9 +188,7 @@ public class BlockStorage {
|
|||||||
storage.put(l, blockInfo);
|
storage.put(l, blockInfo);
|
||||||
|
|
||||||
if (SlimefunPlugin.getRegistry().getTickerBlocks().contains(file.getName().replace(".sfb", ""))) {
|
if (SlimefunPlugin.getRegistry().getTickerBlocks().contains(file.getName().replace(".sfb", ""))) {
|
||||||
Map<String, Set<Location>> tickers = SlimefunPlugin.getTickerTask().getActiveTickers();
|
SlimefunPlugin.getTickerTask().enableTicker(l);
|
||||||
Set<Location> locations = tickers.computeIfAbsent(chunkString, id -> new HashSet<>());
|
|
||||||
locations.add(l);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
@ -495,11 +486,7 @@ public class BlockStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setBlockInfo(Block block, Config cfg, boolean updateTicker) {
|
private static void setBlockInfo(Location l, Config cfg, boolean updateTicker) {
|
||||||
setBlockInfo(block.getLocation(), cfg, updateTicker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setBlockInfo(Location l, Config cfg, boolean updateTicker) {
|
|
||||||
BlockStorage storage = getStorage(l.getWorld());
|
BlockStorage storage = getStorage(l.getWorld());
|
||||||
|
|
||||||
if (storage == null) {
|
if (storage == null) {
|
||||||
@ -590,17 +577,7 @@ public class BlockStorage {
|
|||||||
universalInventory.save();
|
universalInventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
String chunkString = locationToChunkString(l);
|
SlimefunPlugin.getTickerTask().disableTicker(l);
|
||||||
Map<String, Set<Location>> tickers = SlimefunPlugin.getTickerTask().getActiveTickers();
|
|
||||||
Set<Location> locations = tickers.get(chunkString);
|
|
||||||
|
|
||||||
if (locations != null) {
|
|
||||||
locations.remove(l);
|
|
||||||
|
|
||||||
if (locations.isEmpty()) {
|
|
||||||
tickers.remove(chunkString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,23 +615,15 @@ public class BlockStorage {
|
|||||||
refreshCache(storage, from, previousData.getString("id"), null, true);
|
refreshCache(storage, from, previousData.getString("id"), null, true);
|
||||||
storage.storage.remove(from);
|
storage.storage.remove(from);
|
||||||
|
|
||||||
String chunkString = locationToChunkString(from);
|
SlimefunPlugin.getTickerTask().disableTicker(from);
|
||||||
Map<String, Set<Location>> tickers = SlimefunPlugin.getTickerTask().getActiveTickers();
|
|
||||||
Set<Location> locations = tickers.get(chunkString);
|
|
||||||
|
|
||||||
if (locations != null) {
|
|
||||||
locations.remove(from);
|
|
||||||
|
|
||||||
if (locations.isEmpty()) {
|
|
||||||
tickers.remove(chunkString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void refreshCache(BlockStorage storage, Location l, String key, String value, boolean updateTicker) {
|
private static void refreshCache(BlockStorage storage, Location l, String key, String value, boolean updateTicker) {
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
// This Block is no longer valid...
|
/**
|
||||||
// Fixes #1577
|
* This Block is no longer valid...
|
||||||
|
* Fixes #1577
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,14 +633,8 @@ public class BlockStorage {
|
|||||||
if (updateTicker) {
|
if (updateTicker) {
|
||||||
SlimefunItem item = SlimefunItem.getByID(key);
|
SlimefunItem item = SlimefunItem.getByID(key);
|
||||||
|
|
||||||
if (item != null && item.isTicking()) {
|
if (item != null && item.isTicking() && value != null) {
|
||||||
String chunkString = locationToChunkString(l);
|
SlimefunPlugin.getTickerTask().enableTicker(l);
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
Map<String, Set<Location>> tickers = SlimefunPlugin.getTickerTask().getActiveTickers();
|
|
||||||
Set<Location> locations = tickers.computeIfAbsent(chunkString, id -> new HashSet<>());
|
|
||||||
locations.add(l);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,13 @@ public class Metrics {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.pluginId = pluginId;
|
this.pluginId = pluginId;
|
||||||
|
|
||||||
|
plugin.getLogger().log(Level.WARNING, "=================================================");
|
||||||
|
plugin.getLogger().log(Level.WARNING, "{0} is using a deprecated version of", plugin.getName());
|
||||||
|
plugin.getLogger().log(Level.WARNING, "bStats which is bundled with Slimefun.");
|
||||||
|
plugin.getLogger().log(Level.WARNING, "Future versions will not include this file anymore.");
|
||||||
|
plugin.getLogger().log(Level.WARNING, "{0} needs to be updated as soon as possible.", plugin.getName());
|
||||||
|
plugin.getLogger().log(Level.WARNING, "=================================================");
|
||||||
|
|
||||||
// Get the config file
|
// Get the config file
|
||||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||||
File configFile = new File(bStatsFolder, "config.yml");
|
File configFile = new File(bStatsFolder, "config.yml");
|
||||||
|
Loading…
Reference in New Issue
Block a user