1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00

A ton of performance improvements

This commit is contained in:
TheBusyBiscuit 2020-11-19 17:42:10 +01:00
parent 94752a9027
commit 7e657c9810
17 changed files with 184 additions and 70 deletions

View File

@ -42,6 +42,8 @@
* Magnets can no longer be placed down * Magnets can no longer be placed down
* Electromagnets can no longer be placed down * Electromagnets can no longer be placed down
* Performance improvements to Cargo network visualizations * Performance improvements to Cargo network visualizations
* General performance improvements
* Improved performance for radioactive items
#### Fixes #### Fixes
* Fixed #2448 * Fixed #2448

View File

@ -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</version> <version>0.27.2</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -10,6 +10,7 @@ import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponen
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.BlockStorage;
@ -65,14 +66,36 @@ public interface EnergyNetComponent extends ItemAttribute {
* @return The charge stored at that {@link Location} * @return The charge stored at that {@link Location}
*/ */
default int getCharge(@Nonnull Location l) { default int getCharge(@Nonnull Location l) {
// Emergency fallback, this cannot hold a charge, so we'll just return zero
if (!isChargeable()) {
return 0;
}
return getCharge(l, BlockStorage.getLocationInfo(l));
}
/**
* This returns the currently stored charge at a given {@link Location}.
* This is a more performance saving option if you already have a {@link Config}
* object for this {@link Location}.
*
* @param l
* The target {@link Location}
* @param data
* The data at this {@link Location}
*
* @return The charge stored at that {@link Location}
*/
default int getCharge(@Nonnull Location l, @Nonnull Config data) {
Validate.notNull(l, "Location was null!"); Validate.notNull(l, "Location was null!");
Validate.notNull(data, "data was null!");
// Emergency fallback, this cannot hold a charge, so we'll just return zero // Emergency fallback, this cannot hold a charge, so we'll just return zero
if (!isChargeable()) { if (!isChargeable()) {
return 0; return 0;
} }
String charge = BlockStorage.getLocationInfo(l, "energy-charge"); String charge = data.getString("energy-charge");
if (charge != null) { if (charge != null) {
return Integer.parseInt(charge); return Integer.parseInt(charge);

View File

@ -210,14 +210,14 @@ public class EnergyNet extends Network {
SlimefunItem item = (SlimefunItem) provider; SlimefunItem item = (SlimefunItem) provider;
try { try {
Config config = BlockStorage.getLocationInfo(loc); Config data = BlockStorage.getLocationInfo(loc);
int energy = provider.getGeneratedOutput(loc, config); int energy = provider.getGeneratedOutput(loc, data);
if (provider.isChargeable()) { if (provider.isChargeable()) {
energy += provider.getCharge(loc); energy += provider.getCharge(loc, data);
} }
if (provider.willExplode(loc, config)) { if (provider.willExplode(loc, data)) {
explodedBlocks.add(loc); explodedBlocks.add(loc);
BlockStorage.clearBlockInfo(loc); BlockStorage.clearBlockInfo(loc);
@ -228,9 +228,9 @@ public class EnergyNet extends Network {
} else { } else {
supply += energy; supply += energy;
} }
} catch (Exception | LinkageError t) { } catch (Exception | LinkageError throwable) {
explodedBlocks.add(loc); explodedBlocks.add(loc);
new ErrorReport<>(t, loc, item); new ErrorReport<>(throwable, loc, item);
} }
long time = SlimefunPlugin.getProfiler().closeEntry(loc, item, timestamp); long time = SlimefunPlugin.getProfiler().closeEntry(loc, item, timestamp);

View File

@ -93,25 +93,31 @@ public class BlockDataService implements Keyed {
* *
* @param b * @param b
* The {@link Block} to retrieve data from * The {@link Block} to retrieve data from
*
* @return The stored value * @return The stored value
*/ */
public Optional<String> getBlockData(@Nonnull Block b) { public Optional<String> getBlockData(@Nonnull Block b) {
Validate.notNull(b, "The block cannot be null!"); Validate.notNull(b, "The block cannot be null!");
/** BlockState state = PaperLib.getBlockState(b, false).getState();
* Don't use PaperLib here, it seems to be quite buggy in block-placing scenarios PersistentDataContainer container = getPersistentDataContainer(state);
* and it would be too tedious to check for individual build versions to circumvent this.
*/
BlockState state = b.getState();
if (state instanceof TileState) { if (container != null) {
PersistentDataContainer container = ((TileState) state).getPersistentDataContainer();
return Optional.ofNullable(container.get(namespacedKey, PersistentDataType.STRING)); return Optional.ofNullable(container.get(namespacedKey, PersistentDataType.STRING));
} else { } else {
return Optional.empty(); return Optional.empty();
} }
} }
@Nullable
private PersistentDataContainer getPersistentDataContainer(@Nonnull BlockState state) {
if (state instanceof TileState) {
return ((TileState) state).getPersistentDataContainer();
} else {
return null;
}
}
/** /**
* This method checks whether the given {@link Material} is a Tile Entity. * This method checks whether the given {@link Material} is a Tile Entity.
* This is used to determine whether the {@link Block} produced by this {@link Material} * This is used to determine whether the {@link Block} produced by this {@link Material}

View File

@ -39,10 +39,14 @@ class GitHubTask implements Runnable {
@Override @Override
public void run() { public void run() {
gitHubService.getConnectors().forEach(GitHubConnector::download); connectAndCache();
grabTextures(); grabTextures();
} }
private void connectAndCache() {
gitHubService.getConnectors().forEach(GitHubConnector::download);
}
/** /**
* This method will pull the skin textures for every {@link Contributor} and store * This method will pull the skin textures for every {@link Contributor} and store
* the {@link UUID} and received skin inside a local cache {@link File}. * the {@link UUID} and received skin inside a local cache {@link File}.

View File

@ -42,11 +42,14 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*/ */
public class SlimefunProfiler { public class SlimefunProfiler {
// A minecraft server tick is 50ms and Slimefun ticks are stretched across /**
// two ticks (sync and async blocks), so we use 100ms as a reference here * A minecraft server tick is 50ms and Slimefun ticks are stretched
* across two ticks (sync and async blocks), so we use 100ms as a reference here
*/
private static final int MAX_TICK_DURATION = 100; private static final int MAX_TICK_DURATION = 100;
private final ExecutorService executor = Executors.newFixedThreadPool(5); private final SlimefunThreadFactory threadFactory = new SlimefunThreadFactory(5);
private final ExecutorService executor = Executors.newFixedThreadPool(threadFactory.getThreadCount(), threadFactory);
private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicInteger queued = new AtomicInteger(0); private final AtomicInteger queued = new AtomicInteger(0);
@ -117,7 +120,7 @@ public class SlimefunProfiler {
long elapsedTime = System.nanoTime() - timestamp; long elapsedTime = System.nanoTime() - timestamp;
executor.execute(() -> { executor.submit(() -> {
ProfiledBlock block = new ProfiledBlock(l, item); ProfiledBlock block = new ProfiledBlock(l, item);
// Merge (if we have multiple samples for whatever reason) // Merge (if we have multiple samples for whatever reason)
@ -162,6 +165,7 @@ public class SlimefunProfiler {
iterator.next().sendMessage("Your timings report has timed out, we were still waiting for " + queued.get() + " samples to be collected :/"); iterator.next().sendMessage("Your timings report has timed out, we were still waiting for " + queued.get() + " samples to be collected :/");
iterator.remove(); iterator.remove();
} }
return; return;
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -0,0 +1,32 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler;
import java.util.concurrent.ThreadFactory;
/**
* This is our {@link ThreadFactory} for the {@link SlimefunProfiler}.
* It holds the amount of {@link Thread Threads} we dedicate towards our {@link SlimefunProfiler}
* and provides a naming convention for our {@link Thread Threads}.
*
* @author TheBusyBiscuit
*
* @see SlimefunProfiler
*
*/
final class SlimefunThreadFactory implements ThreadFactory {
private final int threadCount;
SlimefunThreadFactory(int threadCount) {
this.threadCount = threadCount;
}
int getThreadCount() {
return threadCount;
}
@Override
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "Slimefun Profiler");
}
}

View File

@ -183,7 +183,7 @@ public abstract class AbstractEntityAssembler<T extends Entity> extends SimpleSl
return; return;
} }
if (lifetime % 60 == 0 && getCharge(b.getLocation()) >= getEnergyConsumption()) { if (lifetime % 60 == 0 && getCharge(b.getLocation(), data) >= getEnergyConsumption()) {
BlockMenu menu = BlockStorage.getInventory(b); BlockMenu menu = BlockStorage.getInventory(b);
boolean hasBody = findResource(menu, getBody(), bodySlots); boolean hasBody = findResource(menu, getBody(), bodySlots);

View File

@ -60,7 +60,7 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem<BlockTicker> imp
@Override @Override
public void tick(Block b, SlimefunItem item, Config data) { public void tick(Block b, SlimefunItem item, Config data) {
int charge = getCharge(b.getLocation()); int charge = getCharge(b.getLocation(), data);
UUID owner = UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner")); UUID owner = UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner"));
if (charge >= getEnergyConsumption()) { if (charge >= getEnergyConsumption()) {

View File

@ -26,8 +26,10 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece; import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.SolarHelmet; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.SolarHelmet;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/** /**
* The {@link ArmorTask} is responsible for handling {@link PotionEffect PotionEffects} for * The {@link ArmorTask} is responsible for handling {@link PotionEffect PotionEffects} for
@ -167,8 +169,16 @@ public class ArmorTask implements Runnable {
return false; return false;
} }
for (SlimefunItem radioactiveItem : SlimefunPlugin.getRegistry().getRadioactiveItems()) { Set<SlimefunItem> radioactiveItems = SlimefunPlugin.getRegistry().getRadioactiveItems();
if (radioactiveItem.isItem(item) && Slimefun.isEnabled(p, radioactiveItem, true)) { ItemStack subject = item;
if (!(item instanceof SlimefunItemStack) && radioactiveItems.size() > 1) {
// Performance optimization to reduce ItemMeta calls
subject = new ItemStackWrapper(item);
}
for (SlimefunItem radioactiveItem : radioactiveItems) {
if (radioactiveItem.isItem(subject) && Slimefun.isEnabled(p, radioactiveItem, true)) {
// If the item is enabled in the world, then make radioactivity do its job // If the item is enabled in the world, then make radioactivity do its job
SlimefunPlugin.getLocalization().sendMessage(p, "messages.radiation"); SlimefunPlugin.getLocalization().sendMessage(p, "messages.radiation");

View File

@ -0,0 +1,51 @@
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
import javax.annotation.Nonnull;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.block.Block;
import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
/**
* This task is run whenever a {@link Capacitor} needs to update their texture.
* <strong>This must be executed on the main {@link Server} {@link Thread}!</strong>
*
* @author TheBusyBiscuit
*
*/
public class CapacitorTextureUpdateTask implements Runnable {
private final Location l;
private final double filledPercentage;
public CapacitorTextureUpdateTask(@Nonnull Location l, double charge, double capacity) {
Validate.notNull(l, "The Location cannot be null");
this.l = l;
this.filledPercentage = charge / capacity;
}
@Override
public void run() {
Block b = l.getBlock();
if (b.getType() == Material.PLAYER_HEAD || b.getType() == Material.PLAYER_WALL_HEAD) {
if (filledPercentage <= 0.25) {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_25.getTexture());
} else if (filledPercentage <= 0.5) {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_50.getTexture());
} else if (filledPercentage <= 0.75) {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_75.getTexture());
} else {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_100.getTexture());
}
}
}
}

View File

@ -14,7 +14,6 @@ import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.entity.Item; import org.bukkit.entity.Item;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -24,7 +23,6 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import io.github.thebusybiscuit.cscorelib2.item.ImmutableItemMeta; import io.github.thebusybiscuit.cscorelib2.item.ImmutableItemMeta;
import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock;
import io.github.thebusybiscuit.cscorelib2.skull.SkullItem; import io.github.thebusybiscuit.cscorelib2.skull.SkullItem;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.exceptions.PrematureCodeException; import io.github.thebusybiscuit.slimefun4.api.exceptions.PrematureCodeException;
@ -32,6 +30,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound; import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal; import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.CapacitorTextureUpdateTask;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.EmeraldEnchants.EmeraldEnchants; import me.mrCookieSlime.EmeraldEnchants.EmeraldEnchants;
import me.mrCookieSlime.EmeraldEnchants.ItemEnchantment; import me.mrCookieSlime.EmeraldEnchants.ItemEnchantment;
@ -337,23 +336,7 @@ public final class SlimefunUtils {
Validate.notNull(l, "Cannot update a texture for null"); Validate.notNull(l, "Cannot update a texture for null");
Validate.isTrue(capacity > 0, "Capacity must be greater than zero!"); Validate.isTrue(capacity > 0, "Capacity must be greater than zero!");
SlimefunPlugin.runSync(() -> { SlimefunPlugin.runSync(new CapacitorTextureUpdateTask(l, charge, capacity));
Block b = l.getBlock();
if (b.getType() == Material.PLAYER_HEAD || b.getType() == Material.PLAYER_WALL_HEAD) {
double level = (double) charge / capacity;
if (level <= 0.25) {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_25.getTexture());
} else if (level <= 0.5) {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_50.getTexture());
} else if (level <= 0.75) {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_75.getTexture());
} else {
SkullBlock.setFromHash(b, HeadTexture.CAPACITOR_100.getTexture());
}
}
});
} }
} }

View File

@ -384,11 +384,13 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock,
Validate.notNull(l, "Can't attempt to take charge from a null location!"); Validate.notNull(l, "Can't attempt to take charge from a null location!");
if (isChargeable()) { if (isChargeable()) {
if (getCharge(l) < getEnergyConsumption()) { int charge = getCharge(l);
if (charge < getEnergyConsumption()) {
return false; return false;
} }
removeCharge(l, getEnergyConsumption()); setCharge(l, charge - getEnergyConsumption());
return true; return true;
} else { } else {
return true; return true;

View File

@ -152,7 +152,7 @@ public abstract class AGenerator extends AbstractEnergyProvider {
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(l).getTicks(), getProgressBar()); ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(l).getTicks(), getProgressBar());
if (isChargeable()) { if (isChargeable()) {
int charge = getCharge(l); int charge = getCharge(l, data);
if (getCapacity() - charge >= getEnergyProduction()) { if (getCapacity() - charge >= getEnergyProduction()) {
progress.put(l, timeleft - 1); progress.put(l, timeleft - 1);

View File

@ -33,7 +33,6 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler; import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
@ -677,19 +676,20 @@ public class BlockStorage {
} }
} }
public static SlimefunItem check(Block block) { @Nullable
return check(block.getLocation()); public static SlimefunItem check(@Nonnull Block b) {
String id = checkID(b);
return id == null ? null : SlimefunItem.getByID(id);
} }
public static SlimefunItem check(Location l) { @Nullable
if (!hasBlockInfo(l)) { public static SlimefunItem check(@Nonnull Location l) {
return null; String id = checkID(l);
} return id == null ? null : SlimefunItem.getByID(id);
return SlimefunItem.getByID(getLocationInfo(l, "id"));
} }
public static String checkID(Block b) { @Nullable
public static String checkID(@Nonnull Block b) {
if (SlimefunPlugin.getBlockDataService().isTileEntity(b.getType())) { if (SlimefunPlugin.getBlockDataService().isTileEntity(b.getType())) {
Optional<String> blockData = SlimefunPlugin.getBlockDataService().getBlockData(b); Optional<String> blockData = SlimefunPlugin.getBlockDataService().getBlockData(b);
@ -714,18 +714,13 @@ public class BlockStorage {
return getLocationInfo(l, "id"); return getLocationInfo(l, "id");
} }
public static boolean check(Location l, String slimefunItem) { public static boolean check(@Nonnull Location l, @Nullable String slimefunItem) {
if (slimefunItem == null || !hasBlockInfo(l)) { if (slimefunItem == null) {
return false; return false;
} }
try { String id = checkID(l);
String id = getLocationInfo(l, "id"); return id != null && id.equals(slimefunItem);
return id != null && id.equalsIgnoreCase(slimefunItem);
} catch (Exception x) {
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while checking " + new BlockPosition(l) + " for: \"" + slimefunItem + "\"");
return false;
}
} }
public static boolean isWorldRegistered(String name) { public static boolean isWorldRegistered(String name) {

View File

@ -91,12 +91,14 @@ public class DirtyChestMenu extends ChestMenu {
} }
public boolean fits(@Nonnull ItemStack item, int... slots) { public boolean fits(@Nonnull ItemStack item, int... slots) {
if (getItemInSlot(slots[0]) == null) { for (int slot : slots) {
// Very small optimization // A small optimization for empty slots
return true; if (getItemInSlot(slot) == null) {
} else { return true;
return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots); }
} }
return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots);
} }
@Nullable @Nullable