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
* Electromagnets can no longer be placed down
* Performance improvements to Cargo network visualizations
* General performance improvements
* Improved performance for radioactive items
#### Fixes
* Fixed #2448

View File

@ -337,7 +337,7 @@
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>CS-CoreLib2</artifactId>
<version>0.27</version>
<version>0.27.2</version>
<scope>compile</scope>
</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.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
@ -65,14 +66,36 @@ public interface EnergyNetComponent extends ItemAttribute {
* @return The charge stored at that {@link Location}
*/
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(data, "data was null!");
// Emergency fallback, this cannot hold a charge, so we'll just return zero
if (!isChargeable()) {
return 0;
}
String charge = BlockStorage.getLocationInfo(l, "energy-charge");
String charge = data.getString("energy-charge");
if (charge != null) {
return Integer.parseInt(charge);

View File

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

View File

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

View File

@ -39,10 +39,14 @@ class GitHubTask implements Runnable {
@Override
public void run() {
gitHubService.getConnectors().forEach(GitHubConnector::download);
connectAndCache();
grabTextures();
}
private void connectAndCache() {
gitHubService.getConnectors().forEach(GitHubConnector::download);
}
/**
* 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}.

View File

@ -42,11 +42,14 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*/
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 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 AtomicInteger queued = new AtomicInteger(0);
@ -117,7 +120,7 @@ public class SlimefunProfiler {
long elapsedTime = System.nanoTime() - timestamp;
executor.execute(() -> {
executor.submit(() -> {
ProfiledBlock block = new ProfiledBlock(l, item);
// 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.remove();
}
return;
}
} 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;
}
if (lifetime % 60 == 0 && getCharge(b.getLocation()) >= getEnergyConsumption()) {
if (lifetime % 60 == 0 && getCharge(b.getLocation(), data) >= getEnergyConsumption()) {
BlockMenu menu = BlockStorage.getInventory(b);
boolean hasBody = findResource(menu, getBody(), bodySlots);

View File

@ -60,7 +60,7 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem<BlockTicker> imp
@Override
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"));
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.electric.gadgets.SolarHelmet;
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.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link ArmorTask} is responsible for handling {@link PotionEffect PotionEffects} for
@ -167,8 +169,16 @@ public class ArmorTask implements Runnable {
return false;
}
for (SlimefunItem radioactiveItem : SlimefunPlugin.getRegistry().getRadioactiveItems()) {
if (radioactiveItem.isItem(item) && Slimefun.isEnabled(p, radioactiveItem, true)) {
Set<SlimefunItem> radioactiveItems = SlimefunPlugin.getRegistry().getRadioactiveItems();
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
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.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.entity.Item;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
@ -24,7 +23,6 @@ import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
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.slimefun4.api.MinecraftVersion;
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.implementation.SlimefunPlugin;
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 me.mrCookieSlime.EmeraldEnchants.EmeraldEnchants;
import me.mrCookieSlime.EmeraldEnchants.ItemEnchantment;
@ -337,23 +336,7 @@ public final class SlimefunUtils {
Validate.notNull(l, "Cannot update a texture for null");
Validate.isTrue(capacity > 0, "Capacity must be greater than zero!");
SlimefunPlugin.runSync(() -> {
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());
}
}
});
SlimefunPlugin.runSync(new CapacitorTextureUpdateTask(l, charge, capacity));
}
}

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!");
if (isChargeable()) {
if (getCharge(l) < getEnergyConsumption()) {
int charge = getCharge(l);
if (charge < getEnergyConsumption()) {
return false;
}
removeCharge(l, getEnergyConsumption());
setCharge(l, charge - getEnergyConsumption());
return true;
} else {
return true;

View File

@ -152,7 +152,7 @@ public abstract class AGenerator extends AbstractEnergyProvider {
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(l).getTicks(), getProgressBar());
if (isChargeable()) {
int charge = getCharge(l);
int charge = getCharge(l, data);
if (getCapacity() - charge >= getEnergyProduction()) {
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.stream.JsonWriter;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
@ -677,19 +676,20 @@ public class BlockStorage {
}
}
public static SlimefunItem check(Block block) {
return check(block.getLocation());
@Nullable
public static SlimefunItem check(@Nonnull Block b) {
String id = checkID(b);
return id == null ? null : SlimefunItem.getByID(id);
}
public static SlimefunItem check(Location l) {
if (!hasBlockInfo(l)) {
return null;
}
return SlimefunItem.getByID(getLocationInfo(l, "id"));
@Nullable
public static SlimefunItem check(@Nonnull Location l) {
String id = checkID(l);
return id == null ? null : SlimefunItem.getByID(id);
}
public static String checkID(Block b) {
@Nullable
public static String checkID(@Nonnull Block b) {
if (SlimefunPlugin.getBlockDataService().isTileEntity(b.getType())) {
Optional<String> blockData = SlimefunPlugin.getBlockDataService().getBlockData(b);
@ -714,18 +714,13 @@ public class BlockStorage {
return getLocationInfo(l, "id");
}
public static boolean check(Location l, String slimefunItem) {
if (slimefunItem == null || !hasBlockInfo(l)) {
public static boolean check(@Nonnull Location l, @Nullable String slimefunItem) {
if (slimefunItem == null) {
return false;
}
try {
String id = getLocationInfo(l, "id");
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;
}
String id = checkID(l);
return id != null && id.equals(slimefunItem);
}
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) {
if (getItemInSlot(slots[0]) == null) {
// Very small optimization
return true;
} else {
return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots);
for (int slot : slots) {
// A small optimization for empty slots
if (getItemInSlot(slot) == null) {
return true;
}
}
return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots);
}
@Nullable