mirror of
https://github.com/StarWishsama/Slimefun4.git
synced 2024-09-19 19:25:48 +00:00
Reduced technical debt / Refactoring
This commit is contained in:
parent
d18cb3a898
commit
8e07ada321
@ -29,6 +29,7 @@
|
||||
|
||||
#### Changes
|
||||
* Coolant Cells now last twice as long
|
||||
* Ticking blocks will now catch more errors caused by addons
|
||||
* Massive performance improvements
|
||||
|
||||
#### Fixes
|
||||
|
@ -18,6 +18,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
|
||||
import io.github.thebusybiscuit.slimefun4.api.events.GEOResourceGenerationEvent;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOMiner;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOScanner;
|
||||
@ -71,7 +72,9 @@ public class ResourceManager {
|
||||
SlimefunPlugin.getRegistry().getGEOResources().add(resource);
|
||||
}
|
||||
|
||||
config.save();
|
||||
if (SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) {
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
||||
public OptionalInt getSupplies(GEOResource resource, World world, int x, int z) {
|
||||
|
@ -64,15 +64,16 @@ public final class SlimefunItems {
|
||||
public static final SlimefunItemStack FILLED_FLASK_OF_KNOWLEDGE = new SlimefunItemStack("FILLED_FLASK_OF_KNOWLEDGE", Material.EXPERIENCE_BOTTLE, "&aFlask of Knowledge");
|
||||
|
||||
/* Backpacks */
|
||||
public static final SlimefunItemStack BACKPACK_SMALL = new SlimefunItemStack("SMALL_BACKPACK", HeadTexture.BACKPACK, "&eSmall Backpack", "", "&7Size: &e9", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack BACKPACK_MEDIUM = new SlimefunItemStack("MEDIUM_BACKPACK", HeadTexture.BACKPACK, "&eBackpack", "", "&7Size: &e18", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack BACKPACK_LARGE = new SlimefunItemStack("LARGE_BACKPACK", HeadTexture.BACKPACK, "&eLarge Backpack", "", "&7Size: &e27", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack WOVEN_BACKPACK = new SlimefunItemStack("WOVEN_BACKPACK", HeadTexture.BACKPACK, "&eWoven Backpack", "", "&7Size: &e36", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack GILDED_BACKPACK = new SlimefunItemStack("GILDED_BACKPACK", HeadTexture.BACKPACK, "&eGilded Backpack", "", "&7Size: &e45", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack RADIANT_BACKPACK = new SlimefunItemStack("RADIANT_BACKPACK", HeadTexture.BACKPACK, "&eRadiant Backpack", "", "&7Size: &e54 (Double chest)", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack BOUND_BACKPACK = new SlimefunItemStack("BOUND_BACKPACK", HeadTexture.ENDER_BACKPACK, "&cSoulbound Backpack", "", "&7Size: &e36", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack COOLER = new SlimefunItemStack("COOLER", HeadTexture.COOLER, "&bCooler", "&rAllows you to store Juices/Smoothies", "&rand automatically consumes them when you are hungry", "&rand you have this in your Inventory", "", "&7Size: &e27", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack RESTORED_BACKPACK = new SlimefunItemStack("RESTORED_BACKPACK", HeadTexture.RESTORED_BACKPACK, "&eRestored Backpack", "", "&7Retrieve your lost items", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
private static final String BACKPACK_ID = "&7ID: <ID>";
|
||||
public static final SlimefunItemStack BACKPACK_SMALL = new SlimefunItemStack("SMALL_BACKPACK", HeadTexture.BACKPACK, "&eSmall Backpack", "", "&7Size: &e9", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack BACKPACK_MEDIUM = new SlimefunItemStack("MEDIUM_BACKPACK", HeadTexture.BACKPACK, "&eBackpack", "", "&7Size: &e18", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack BACKPACK_LARGE = new SlimefunItemStack("LARGE_BACKPACK", HeadTexture.BACKPACK, "&eLarge Backpack", "", "&7Size: &e27", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack WOVEN_BACKPACK = new SlimefunItemStack("WOVEN_BACKPACK", HeadTexture.BACKPACK, "&eWoven Backpack", "", "&7Size: &e36", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack GILDED_BACKPACK = new SlimefunItemStack("GILDED_BACKPACK", HeadTexture.BACKPACK, "&eGilded Backpack", "", "&7Size: &e45", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack RADIANT_BACKPACK = new SlimefunItemStack("RADIANT_BACKPACK", HeadTexture.BACKPACK, "&eRadiant Backpack", "", "&7Size: &e54 (Double chest)", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack BOUND_BACKPACK = new SlimefunItemStack("BOUND_BACKPACK", HeadTexture.ENDER_BACKPACK, "&cSoulbound Backpack", "", "&7Size: &e36", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack COOLER = new SlimefunItemStack("COOLER", HeadTexture.COOLER, "&bCooler", "&rAllows you to store Juices/Smoothies", "&rand automatically consumes them when you are hungry", "&rand you have this in your Inventory", "", "&7Size: &e27", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
public static final SlimefunItemStack RESTORED_BACKPACK = new SlimefunItemStack("RESTORED_BACKPACK", HeadTexture.RESTORED_BACKPACK, "&eRestored Backpack", "", "&7Retrieve your lost items", BACKPACK_ID, "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
||||
|
||||
/* Jetpacks */
|
||||
public static final SlimefunItemStack DURALUMIN_JETPACK = new SlimefunItemStack("DURALUMIN_JETPACK", Material.LEATHER_CHESTPLATE, Color.SILVER, "&9Electric Jetpack &7- &eI", "", LoreBuilder.material("Duralumin"), LoreBuilder.powerCharged(0, 20), "&8\u21E8 &7Thrust: &c0.35", "", LoreBuilder.CROUCH_TO_USE);
|
||||
|
@ -156,64 +156,21 @@ public class AncientAltarListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private void useAltar(Block b, Player p) {
|
||||
private void useAltar(Block altar, Player p) {
|
||||
ItemStack catalyst = new CustomItem(p.getInventory().getItemInMainHand(), 1);
|
||||
List<Block> pedestals = getPedestals(b);
|
||||
List<Block> pedestals = getPedestals(altar);
|
||||
|
||||
if (!altars.contains(b)) {
|
||||
altars.add(b);
|
||||
if (!altars.contains(altar)) {
|
||||
altars.add(altar);
|
||||
|
||||
if (pedestals.size() == 8) {
|
||||
pedestals.forEach(block -> altarsInUse.add(block.getLocation()));
|
||||
|
||||
if (catalyst.getType() != Material.AIR) {
|
||||
List<ItemStack> input = new ArrayList<>();
|
||||
for (Block pedestal : pedestals) {
|
||||
Item stack = findItem(pedestal);
|
||||
|
||||
if (stack != null) {
|
||||
input.add(fixItemStack(stack.getItemStack(), stack.getCustomName()));
|
||||
}
|
||||
}
|
||||
|
||||
Optional<ItemStack> result = getRecipeOutput(catalyst, input);
|
||||
if (result.isPresent()) {
|
||||
if (Slimefun.hasUnlocked(p, result.get(), true)) {
|
||||
List<ItemStack> consumed = new ArrayList<>();
|
||||
consumed.add(catalyst);
|
||||
|
||||
if (p.getGameMode() != GameMode.CREATIVE) {
|
||||
ItemUtils.consumeItem(p.getInventory().getItemInMainHand(), false);
|
||||
}
|
||||
|
||||
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1);
|
||||
Slimefun.runSync(new AncientAltarTask(b, altar.getSpeed(), result.get(), pedestals, consumed, p), 10L);
|
||||
}
|
||||
else {
|
||||
altars.remove(b);
|
||||
|
||||
for (Block block : pedestals) {
|
||||
altarsInUse.remove(block.getLocation());
|
||||
}
|
||||
|
||||
// Item not unlocked, no longer in use.
|
||||
altarsInUse.remove(b.getLocation());
|
||||
}
|
||||
}
|
||||
else {
|
||||
altars.remove(b);
|
||||
SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-recipe", true);
|
||||
|
||||
for (Block block : pedestals) {
|
||||
altarsInUse.remove(block.getLocation());
|
||||
}
|
||||
|
||||
// Bad recipe, no longer in use.
|
||||
altarsInUse.remove(b.getLocation());
|
||||
}
|
||||
startRitual(p, altar, pedestals, catalyst);
|
||||
}
|
||||
else {
|
||||
altars.remove(b);
|
||||
altars.remove(altar);
|
||||
SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-catalyst", true);
|
||||
|
||||
for (Block block : pedestals) {
|
||||
@ -221,17 +178,65 @@ public class AncientAltarListener implements Listener {
|
||||
}
|
||||
|
||||
// Unknown catalyst, no longer in use
|
||||
altarsInUse.remove(b.getLocation());
|
||||
altarsInUse.remove(altar.getLocation());
|
||||
}
|
||||
}
|
||||
else {
|
||||
altars.remove(b);
|
||||
altars.remove(altar);
|
||||
SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.not-enough-pedestals", true, msg -> msg.replace("%pedestals%", String.valueOf(pedestals.size())));
|
||||
|
||||
// Not a valid altar so remove from inuse
|
||||
altarsInUse.remove(altar.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startRitual(Player p, Block b, List<Block> pedestals, ItemStack catalyst) {
|
||||
List<ItemStack> input = new ArrayList<>();
|
||||
|
||||
for (Block pedestal : pedestals) {
|
||||
Item stack = findItem(pedestal);
|
||||
|
||||
if (stack != null) {
|
||||
input.add(fixItemStack(stack.getItemStack(), stack.getCustomName()));
|
||||
}
|
||||
}
|
||||
|
||||
Optional<ItemStack> result = getRecipeOutput(catalyst, input);
|
||||
if (result.isPresent()) {
|
||||
if (Slimefun.hasUnlocked(p, result.get(), true)) {
|
||||
List<ItemStack> consumed = new ArrayList<>();
|
||||
consumed.add(catalyst);
|
||||
|
||||
if (p.getGameMode() != GameMode.CREATIVE) {
|
||||
ItemUtils.consumeItem(p.getInventory().getItemInMainHand(), false);
|
||||
}
|
||||
|
||||
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1);
|
||||
Slimefun.runSync(new AncientAltarTask(b, altar.getSpeed(), result.get(), pedestals, consumed, p), 10L);
|
||||
}
|
||||
else {
|
||||
altars.remove(b);
|
||||
|
||||
for (Block block : pedestals) {
|
||||
altarsInUse.remove(block.getLocation());
|
||||
}
|
||||
|
||||
// Item not unlocked, no longer in use.
|
||||
altarsInUse.remove(b.getLocation());
|
||||
}
|
||||
}
|
||||
else {
|
||||
altars.remove(b);
|
||||
SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-recipe", true);
|
||||
|
||||
for (Block block : pedestals) {
|
||||
altarsInUse.remove(block.getLocation());
|
||||
}
|
||||
|
||||
// Bad recipe, no longer in use.
|
||||
altarsInUse.remove(b.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
@ -353,16 +358,26 @@ public class AncientAltarListener implements Listener {
|
||||
private Optional<ItemStack> checkRecipe(ItemStack catalyst, List<ItemStackWrapper> items) {
|
||||
for (AltarRecipe recipe : altarRecipes) {
|
||||
if (SlimefunUtils.isItemSimilar(catalyst, recipe.getCatalyst(), true)) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (SlimefunUtils.isItemSimilar(items.get(i), recipe.getInput().get(0), true)) {
|
||||
for (int j = 1; j < 8; j++) {
|
||||
if (!SlimefunUtils.isItemSimilar(items.get((i + j) % items.size()), recipe.getInput().get(j), true)) {
|
||||
break;
|
||||
}
|
||||
else if (j == 7) {
|
||||
return Optional.of(recipe.getOutput());
|
||||
}
|
||||
}
|
||||
Optional<ItemStack> optional = checkPedestals(items, recipe);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
return optional;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ItemStack> checkPedestals(List<ItemStackWrapper> items, AltarRecipe recipe) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (SlimefunUtils.isItemSimilar(items.get(i), recipe.getInput().get(0), true)) {
|
||||
for (int j = 1; j < 8; j++) {
|
||||
if (!SlimefunUtils.isItemSimilar(items.get((i + j) % items.size()), recipe.getInput().get(j), true)) {
|
||||
break;
|
||||
}
|
||||
else if (j == 7) {
|
||||
return Optional.of(recipe.getOutput());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import org.bukkit.Tag;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -88,25 +89,9 @@ public class BlockListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onBlockUnregister(BlockBreakEvent e) {
|
||||
Block blockAbove = e.getBlock().getRelative(BlockFace.UP);
|
||||
|
||||
if (sensitiveMaterials.contains(blockAbove.getType())) {
|
||||
SlimefunItem sfItem = BlockStorage.check(blockAbove);
|
||||
|
||||
if (sfItem != null && !sfItem.useVanillaBlockBreaking()) {
|
||||
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getID());
|
||||
|
||||
if (blockHandler != null) {
|
||||
if (blockHandler.onBreak(e.getPlayer(), blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) {
|
||||
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove));
|
||||
blockAbove.setType(Material.AIR);
|
||||
}
|
||||
else {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasSensitiveBlockAbove(e.getPlayer(), e.getBlock())) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
SlimefunItem sfItem = BlockStorage.check(e.getBlock());
|
||||
@ -147,6 +132,10 @@ public class BlockListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
dropItems(e, drops);
|
||||
}
|
||||
|
||||
private void dropItems(BlockBreakEvent e, List<ItemStack> drops) {
|
||||
if (!drops.isEmpty()) {
|
||||
e.getBlock().setType(Material.AIR);
|
||||
|
||||
@ -160,6 +149,30 @@ public class BlockListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSensitiveBlockAbove(Player p, Block b) {
|
||||
Block blockAbove = b.getRelative(BlockFace.UP);
|
||||
|
||||
if (sensitiveMaterials.contains(blockAbove.getType())) {
|
||||
SlimefunItem sfItem = BlockStorage.check(blockAbove);
|
||||
|
||||
if (sfItem != null && !sfItem.useVanillaBlockBreaking()) {
|
||||
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getID());
|
||||
|
||||
if (blockHandler != null) {
|
||||
if (blockHandler.onBreak(p, blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) {
|
||||
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove));
|
||||
blockAbove.setType(Material.AIR);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getBonusDropsWithFortune(ItemStack item, Block b) {
|
||||
int fortune = 1;
|
||||
|
||||
|
@ -19,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
@ -103,14 +104,14 @@ public class DebugFishListener implements Listener {
|
||||
if (item.isTicking()) {
|
||||
p.sendMessage(ChatColors.color("&dTicker: " + enabledTooltip));
|
||||
p.sendMessage(ChatColors.color(" &dAsync: &e" + (BlockStorage.check(b).getBlockTicker().isSynchronized() ? disabledTooltip : enabledTooltip)));
|
||||
p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true)));
|
||||
p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + ticker.toMillis(ticker.getTimings(BlockStorage.checkID(b)), true)));
|
||||
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true)));
|
||||
p.sendMessage(ChatColors.color(" &dTimings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b))));
|
||||
p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(BlockStorage.checkID(b)))));
|
||||
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b.getChunk()))));
|
||||
}
|
||||
else if (item.getEnergyTicker() != null) {
|
||||
p.sendMessage(ChatColors.color("&dTicking: " + "&3Indirect"));
|
||||
p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true)));
|
||||
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true)));
|
||||
p.sendMessage(ChatColors.color(" &dTimings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b))));
|
||||
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b.getChunk()))));
|
||||
}
|
||||
else {
|
||||
p.sendMessage(ChatColors.color("&dTicker: " + disabledTooltip));
|
||||
|
@ -9,6 +9,7 @@ import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
@ -33,7 +34,7 @@ public class ExplosionsListener implements Listener {
|
||||
blocks.remove();
|
||||
|
||||
// Hardened Glass and WitherProof blocks cannot be destroyed by explosions
|
||||
if (!id.equalsIgnoreCase("HARDENED_GLASS") && !SlimefunPlugin.getRegistry().getWitherProofBlocks().containsKey(id)) {
|
||||
if (!id.equals(SlimefunItems.HARDENED_GLASS.getItemId()) && !SlimefunPlugin.getRegistry().getWitherProofBlocks().containsKey(id)) {
|
||||
boolean success = true;
|
||||
SlimefunItem sfItem = SlimefunItem.getByID(id);
|
||||
|
||||
|
@ -80,7 +80,7 @@ public class GrapplingHookListener implements Listener {
|
||||
Player p = (Player) arrow.getShooter();
|
||||
|
||||
if (p.getGameMode() != GameMode.CREATIVE && (boolean) grappleState.get(p.getUniqueId())) {
|
||||
arrow.getWorld().dropItem(arrow.getLocation(), SlimefunItems.GRAPPLING_HOOK);
|
||||
arrow.getWorld().dropItem(arrow.getLocation(), SlimefunItems.GRAPPLING_HOOK.clone());
|
||||
}
|
||||
|
||||
Vector velocity = new Vector(0.0, 0.2, 0.0);
|
||||
@ -135,7 +135,7 @@ public class GrapplingHookListener implements Listener {
|
||||
// To fix issue #253
|
||||
Slimefun.runSync(() -> {
|
||||
if (grappleState.containsKey(uuid)) {
|
||||
SlimefunPlugin.getBowListener().getBows().remove(uuid);
|
||||
SlimefunPlugin.getBowListener().getProjectileData().remove(uuid);
|
||||
|
||||
for (Entity n : temporaryEntities.get(uuid)) {
|
||||
if (n.isValid()) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Material;
|
||||
@ -9,9 +10,7 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.BasicCircuitBoard;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.Objects.handlers.EntityKillHandler;
|
||||
@ -19,8 +18,12 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
public class MobDropListener implements Listener {
|
||||
|
||||
public MobDropListener(SlimefunPlugin plugin) {
|
||||
private final BasicCircuitBoard circuitBoard;
|
||||
|
||||
public MobDropListener(SlimefunPlugin plugin, BasicCircuitBoard circuitBoard) {
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
|
||||
this.circuitBoard = circuitBoard;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -31,15 +34,7 @@ public class MobDropListener implements Listener {
|
||||
|
||||
Set<ItemStack> customDrops = SlimefunPlugin.getRegistry().getMobDrops(e.getEntityType());
|
||||
if (customDrops != null && !customDrops.isEmpty()) {
|
||||
for (ItemStack drop : customDrops) {
|
||||
if (Slimefun.hasUnlocked(p, drop, true)) {
|
||||
if (SlimefunUtils.isItemSimilar(drop, SlimefunItems.BASIC_CIRCUIT_BOARD, true) && !((BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem()).isDroppedFromGolems()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
e.getDrops().add(drop.clone());
|
||||
}
|
||||
}
|
||||
addDrops(p, customDrops, e.getDrops());
|
||||
}
|
||||
|
||||
if (item.getType() != Material.AIR) {
|
||||
@ -51,4 +46,16 @@ public class MobDropListener implements Listener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addDrops(Player p, Set<ItemStack> customDrops, List<ItemStack> drops) {
|
||||
for (ItemStack drop : customDrops) {
|
||||
if (Slimefun.hasUnlocked(p, drop, true)) {
|
||||
if (circuitBoard != null && circuitBoard.isItem(drop) && !circuitBoard.isDroppedFromGolems()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
drops.add(drop.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,16 +19,31 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.Objects.handlers.BowShootHandler;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* This {@link Listener} is responsible for tracking {@link Arrow Arrows} fired from a
|
||||
* {@link SlimefunBow}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see SlimefunBow
|
||||
*
|
||||
*/
|
||||
public class SlimefunBowListener implements Listener {
|
||||
|
||||
private final Map<UUID, SlimefunBow> bows = new HashMap<>();
|
||||
private final Map<UUID, SlimefunBow> projectiles = new HashMap<>();
|
||||
|
||||
public void register(SlimefunPlugin plugin) {
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public Map<UUID, SlimefunBow> getBows() {
|
||||
return bows;
|
||||
/**
|
||||
* This returns a {@link HashMap} holding the {@link UUID} of a {@link Arrow} and the
|
||||
* associated {@link SlimefunBow} with which this {@link Arrow} was fired from.
|
||||
*
|
||||
* @return A {@link HashMap} with all actively tracked {@link Arrow Arrows}
|
||||
*/
|
||||
public Map<UUID, SlimefunBow> getProjectileData() {
|
||||
return projectiles;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -37,7 +52,7 @@ public class SlimefunBowListener implements Listener {
|
||||
SlimefunItem bow = SlimefunItem.getByItem(e.getBow());
|
||||
|
||||
if (bow instanceof SlimefunBow) {
|
||||
bows.put(e.getProjectile().getUniqueId(), (SlimefunBow) bow);
|
||||
projectiles.put(e.getProjectile().getUniqueId(), (SlimefunBow) bow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +61,7 @@ public class SlimefunBowListener implements Listener {
|
||||
public void onArrowHit(ProjectileHitEvent e) {
|
||||
Slimefun.runSync(() -> {
|
||||
if (e.getEntity().isValid() && e.getEntity() instanceof Arrow) {
|
||||
bows.remove(e.getEntity().getUniqueId());
|
||||
projectiles.remove(e.getEntity().getUniqueId());
|
||||
}
|
||||
}, 4L);
|
||||
}
|
||||
@ -54,13 +69,13 @@ public class SlimefunBowListener implements Listener {
|
||||
@EventHandler
|
||||
public void onArrowSuccessfulHit(EntityDamageByEntityEvent e) {
|
||||
if (e.getDamager() instanceof Arrow && e.getEntity() instanceof LivingEntity) {
|
||||
SlimefunBow bow = bows.get(e.getDamager().getUniqueId());
|
||||
SlimefunBow bow = projectiles.get(e.getDamager().getUniqueId());
|
||||
|
||||
if (bow != null) {
|
||||
bow.callItemHandler(BowShootHandler.class, handler -> handler.onHit(e, (LivingEntity) e.getEntity()));
|
||||
}
|
||||
|
||||
bows.remove(e.getDamager().getUniqueId());
|
||||
projectiles.remove(e.getDamager().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.ChestedHorse;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -78,18 +79,41 @@ public class TalismanListener implements Listener {
|
||||
Projectile projectile = (Projectile) ((EntityDamageByEntityEvent) e).getDamager();
|
||||
|
||||
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
|
||||
Player p = (Player) e.getEntity();
|
||||
Vector direction = p.getEyeLocation().getDirection().multiply(2.0);
|
||||
Location loc = p.getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ());
|
||||
Projectile clone = (Projectile) e.getEntity().getWorld().spawnEntity(loc, projectile.getType());
|
||||
clone.setShooter(projectile.getShooter());
|
||||
clone.setVelocity(direction);
|
||||
projectile.remove();
|
||||
returnProjectile((Player) e.getEntity(), projectile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used for the {@link Talisman} of the whirlwind, it returns a copy
|
||||
* of a {@link Projectile} that was fired at a {@link Player}.
|
||||
*
|
||||
* @param p
|
||||
* The {@link Player} who was hit
|
||||
* @param projectile
|
||||
* The {@link Projectile} that hit this {@link Player}
|
||||
*/
|
||||
private void returnProjectile(Player p, Projectile projectile) {
|
||||
Vector direction = p.getEyeLocation().getDirection().multiply(2.0);
|
||||
Location loc = p.getEyeLocation().add(direction.getX(), direction.getY(), direction.getZ());
|
||||
|
||||
Projectile returnedProjectile = (Projectile) p.getWorld().spawnEntity(loc, projectile.getType());
|
||||
returnedProjectile.setShooter(projectile.getShooter());
|
||||
returnedProjectile.setVelocity(direction);
|
||||
|
||||
if (projectile instanceof AbstractArrow) {
|
||||
AbstractArrow firedArrow = (AbstractArrow) projectile;
|
||||
AbstractArrow returnedArrow = (AbstractArrow) returnedProjectile;
|
||||
|
||||
returnedArrow.setDamage(firedArrow.getDamage());
|
||||
returnedArrow.setPickupStatus(firedArrow.getPickupStatus());
|
||||
returnedArrow.setPierceLevel(firedArrow.getPierceLevel());
|
||||
}
|
||||
|
||||
projectile.remove();
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onKill(EntityDeathEvent e) {
|
||||
if (e.getDrops().isEmpty() || e.getEntity().getKiller() == null) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@ -9,11 +8,14 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
@ -28,6 +30,7 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.json.ChatComponent;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent;
|
||||
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
|
||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
@ -37,24 +40,29 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
public class TickerTask implements Runnable {
|
||||
|
||||
private final DecimalFormat decimalFormat = new DecimalFormat("#.##");
|
||||
private final ConcurrentMap<Location, Location> move = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Location, Boolean> delete = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Location, Long> blockTimings = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Integer> chunkItemCount = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Integer> machineCount = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Long> machineTimings = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Long> chunkTimings = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Location, Integer> buggedBlocks = new ConcurrentHashMap<>();
|
||||
private final Set<String> chunksSkipped = new HashSet<>();
|
||||
private static final int VISIBILITY_THRESHOLD = 200_000;
|
||||
|
||||
private final Set<BlockTicker> tickers = new HashSet<>();
|
||||
|
||||
// These are "Queues" of blocks that need to be removed or moved
|
||||
private final ConcurrentMap<Location, Location> movingQueue = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Location, Boolean> deletionQueue = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentMap<Location, Integer> buggedBlocks = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentMap<Location, Long> blockTimings = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Integer> machineCount = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Long> machineTimings = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentMap<String, Long> chunkTimings = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Integer> chunkItemCount = new ConcurrentHashMap<>();
|
||||
private final Set<String> skippedChunks = new HashSet<>();
|
||||
|
||||
private boolean halted = false;
|
||||
|
||||
private int skipped = 0;
|
||||
private int skippedBlocks = 0;
|
||||
private int chunks = 0;
|
||||
private int machines = 0;
|
||||
private int blocks = 0;
|
||||
private long time = 0;
|
||||
|
||||
private boolean running = false;
|
||||
@ -65,104 +73,60 @@ public class TickerTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (running) return;
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
long timestamp = System.nanoTime();
|
||||
|
||||
skipped = 0;
|
||||
skippedBlocks = 0;
|
||||
chunks = 0;
|
||||
machines = 0;
|
||||
blocks = 0;
|
||||
chunkItemCount.clear();
|
||||
machineCount.clear();
|
||||
time = 0;
|
||||
chunkTimings.clear();
|
||||
chunksSkipped.clear();
|
||||
skippedChunks.clear();
|
||||
machineTimings.clear();
|
||||
blockTimings.clear();
|
||||
|
||||
Map<Location, Integer> bugged = new HashMap<>(buggedBlocks);
|
||||
Map<Location, Integer> bugs = new HashMap<>(buggedBlocks);
|
||||
buggedBlocks.clear();
|
||||
|
||||
Map<Location, Boolean> remove = new HashMap<>(delete);
|
||||
Map<Location, Boolean> removals = new HashMap<>(deletionQueue);
|
||||
|
||||
for (Map.Entry<Location, Boolean> entry : remove.entrySet()) {
|
||||
for (Map.Entry<Location, Boolean> entry : removals.entrySet()) {
|
||||
BlockStorage._integrated_removeBlockInfo(entry.getKey(), entry.getValue());
|
||||
delete.remove(entry.getKey());
|
||||
deletionQueue.remove(entry.getKey());
|
||||
}
|
||||
|
||||
if (!halted) {
|
||||
for (String tickedChunk : BlockStorage.getTickingChunks()) {
|
||||
long timestamp2 = System.nanoTime();
|
||||
for (String chunk : BlockStorage.getTickingChunks()) {
|
||||
long chunkTimestamp = System.nanoTime();
|
||||
chunks++;
|
||||
|
||||
for (Location l : BlockStorage.getTickingLocations(tickedChunk)) {
|
||||
for (Location l : BlockStorage.getTickingLocations(chunk)) {
|
||||
if (l.getWorld().isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4)) {
|
||||
Block b = l.getBlock();
|
||||
SlimefunItem item = BlockStorage.check(l);
|
||||
|
||||
if (item != null && item.getBlockTicker() != null) {
|
||||
machines++;
|
||||
|
||||
try {
|
||||
item.getBlockTicker().update();
|
||||
|
||||
if (item.getBlockTicker().isSynchronized()) {
|
||||
Slimefun.runSync(() -> {
|
||||
try {
|
||||
long timestamp3 = System.nanoTime();
|
||||
item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l));
|
||||
|
||||
Long machinetime = machineTimings.get(item.getID());
|
||||
Integer chunk = chunkItemCount.get(tickedChunk);
|
||||
Integer machine = machineCount.get(item.getID());
|
||||
|
||||
machineTimings.put(item.getID(), (machinetime != null ? machinetime : 0) + (System.nanoTime() - timestamp3));
|
||||
chunkItemCount.put(tickedChunk, (chunk != null ? chunk : 0) + 1);
|
||||
machineCount.put(item.getID(), (machine != null ? machine : 0) + 1);
|
||||
blockTimings.put(l, System.nanoTime() - timestamp3);
|
||||
}
|
||||
catch (Exception x) {
|
||||
int errors = bugged.getOrDefault(l, 0);
|
||||
reportErrors(l, item, x, errors);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
long timestamp3 = System.nanoTime();
|
||||
item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l));
|
||||
|
||||
machineTimings.merge(item.getID(), (System.nanoTime() - timestamp3), Long::sum);
|
||||
chunkItemCount.merge(tickedChunk, 1, Integer::sum);
|
||||
machineCount.merge(item.getID(), 1, Integer::sum);
|
||||
blockTimings.put(l, System.nanoTime() - timestamp3);
|
||||
}
|
||||
|
||||
tickers.add(item.getBlockTicker());
|
||||
}
|
||||
catch (Exception x) {
|
||||
int errors = bugged.getOrDefault(l, 0);
|
||||
reportErrors(l, item, x, errors);
|
||||
}
|
||||
}
|
||||
else skipped++;
|
||||
tick(l, chunk, bugs);
|
||||
}
|
||||
else {
|
||||
skipped += BlockStorage.getTickingLocations(tickedChunk).size();
|
||||
chunksSkipped.add(tickedChunk);
|
||||
skippedBlocks += BlockStorage.getTickingLocations(chunk).size();
|
||||
skippedChunks.add(chunk);
|
||||
chunks--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chunkTimings.put(tickedChunk, System.nanoTime() - timestamp2);
|
||||
chunkTimings.put(chunk, System.nanoTime() - chunkTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Location, Location> entry : move.entrySet()) {
|
||||
for (Map.Entry<Location, Location> entry : movingQueue.entrySet()) {
|
||||
BlockStorage._integrated_moveLocationInfo(entry.getKey(), entry.getValue());
|
||||
}
|
||||
move.clear();
|
||||
|
||||
movingQueue.clear();
|
||||
|
||||
Iterator<BlockTicker> iterator = tickers.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
@ -174,23 +138,74 @@ public class TickerTask implements Runnable {
|
||||
running = false;
|
||||
}
|
||||
|
||||
private void reportErrors(Location l, SlimefunItem item, Exception x, int errors) {
|
||||
private void tick(Location l, String tickedChunk, Map<Location, Integer> bugs) {
|
||||
Block b = l.getBlock();
|
||||
SlimefunItem item = BlockStorage.check(l);
|
||||
|
||||
if (item != null && item.getBlockTicker() != null) {
|
||||
blocks++;
|
||||
|
||||
try {
|
||||
item.getBlockTicker().update();
|
||||
|
||||
if (item.getBlockTicker().isSynchronized()) {
|
||||
Slimefun.runSync(() -> {
|
||||
try {
|
||||
long timestamp = System.nanoTime();
|
||||
item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l));
|
||||
|
||||
long machinetime = NumberUtils.getLong(machineTimings.get(item.getID()), 0);
|
||||
int chunk = NumberUtils.getInt(chunkItemCount.get(tickedChunk), 0);
|
||||
int machine = NumberUtils.getInt(machineCount.get(item.getID()), 0);
|
||||
|
||||
machineTimings.put(item.getID(), machinetime + (System.nanoTime() - timestamp));
|
||||
chunkItemCount.put(tickedChunk, chunk + 1);
|
||||
machineCount.put(item.getID(), machine + 1);
|
||||
blockTimings.put(l, System.nanoTime() - timestamp);
|
||||
}
|
||||
catch (Exception | LinkageError x) {
|
||||
int errors = bugs.getOrDefault(l, 0);
|
||||
reportErrors(l, item, x, errors);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
long timestamp = System.nanoTime();
|
||||
item.getBlockTicker().tick(b, item, BlockStorage.getLocationInfo(l));
|
||||
|
||||
machineTimings.merge(item.getID(), (System.nanoTime() - timestamp), Long::sum);
|
||||
chunkItemCount.merge(tickedChunk, 1, Integer::sum);
|
||||
machineCount.merge(item.getID(), 1, Integer::sum);
|
||||
blockTimings.put(l, System.nanoTime() - timestamp);
|
||||
}
|
||||
|
||||
tickers.add(item.getBlockTicker());
|
||||
}
|
||||
catch (Exception x) {
|
||||
int errors = bugs.getOrDefault(l, 0);
|
||||
reportErrors(l, item, x, errors);
|
||||
}
|
||||
}
|
||||
else {
|
||||
skippedBlocks++;
|
||||
}
|
||||
}
|
||||
|
||||
private void reportErrors(Location l, SlimefunItem item, Throwable x, int errors) {
|
||||
errors++;
|
||||
|
||||
if (errors == 1) {
|
||||
// Generate a new Error-Report
|
||||
new ErrorReport(x, l, item);
|
||||
|
||||
buggedBlocks.put(l, errors);
|
||||
}
|
||||
else if (errors == 4) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, "X: {0} Y: {1} Z: {2} ({3})", new Object[] { l.getBlockX(), l.getBlockY(), l.getBlockZ(), item.getID() });
|
||||
Slimefun.getLogger().log(Level.SEVERE, "has thrown 4 Exceptions in the last 4 Ticks, the Block has been terminated.");
|
||||
Slimefun.getLogger().log(Level.SEVERE, "has thrown 4 error messages in the last 4 Ticks, the Block has been terminated.");
|
||||
Slimefun.getLogger().log(Level.SEVERE, "Check your /plugins/Slimefun/error-reports/ folder for details.");
|
||||
Slimefun.getLogger().log(Level.SEVERE, " ");
|
||||
|
||||
BlockStorage._integrated_removeBlockInfo(l, true);
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(SlimefunPlugin.instance, () -> l.getBlock().setType(Material.AIR));
|
||||
}
|
||||
else {
|
||||
@ -199,59 +214,41 @@ public class TickerTask implements Runnable {
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return toMillis(time, false);
|
||||
return NumberUtils.getAsMillis(time);
|
||||
}
|
||||
|
||||
public void info(CommandSender sender) {
|
||||
sender.sendMessage(ChatColors.color("&2== &aSlimefun Diagnostic Tool &2=="));
|
||||
sender.sendMessage(ChatColors.color("&6Halted: &e&l" + String.valueOf(halted).toUpperCase(Locale.ROOT)));
|
||||
sender.sendMessage("");
|
||||
sender.sendMessage(ChatColors.color("&6Impact: &e" + toMillis(time, true)));
|
||||
sender.sendMessage(ChatColors.color("&6Impact: &e" + NumberUtils.getAsMillis(time)));
|
||||
sender.sendMessage(ChatColors.color("&6Ticked Chunks: &e" + chunks));
|
||||
sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + machines));
|
||||
sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skipped));
|
||||
sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + blocks));
|
||||
sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skippedBlocks));
|
||||
sender.sendMessage("");
|
||||
sender.sendMessage(ChatColors.color("&6Ticking Machines:"));
|
||||
|
||||
List<Map.Entry<String, Long>> timings = machineCount.keySet().stream().map(key -> new AbstractMap.SimpleEntry<>(key, machineTimings.getOrDefault(key, 0L))).sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())).collect(Collectors.toList());
|
||||
summarizeTimings(sender, entry -> {
|
||||
int count = machineCount.get(entry.getKey());
|
||||
String timings = NumberUtils.getAsMillis(entry.getValue());
|
||||
String average = NumberUtils.getAsMillis(entry.getValue() / count);
|
||||
|
||||
if (sender instanceof Player) {
|
||||
ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info"));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int hidden = 0;
|
||||
|
||||
for (Map.Entry<String, Long> entry : timings) {
|
||||
int count = machineCount.get(entry.getKey());
|
||||
|
||||
if (entry.getValue() > 300_000) {
|
||||
builder.append("\n&c").append(entry.getKey()).append(" - ").append(count).append("x &7(").append(toMillis(entry.getValue(), true)).append(", ").append(toMillis(entry.getValue() / count, true)).append(" avg/machine)");
|
||||
}
|
||||
else hidden++;
|
||||
}
|
||||
|
||||
builder.append("\n\n&c+ &4").append(hidden).append(" Hidden");
|
||||
component.setHoverEvent(new HoverEvent(ChatColors.color(builder.toString())));
|
||||
|
||||
component.sendMessage((Player) sender);
|
||||
}
|
||||
else {
|
||||
int hidden = 0;
|
||||
|
||||
for (Map.Entry<String, Long> entry : timings) {
|
||||
int count = machineCount.get(entry.getKey());
|
||||
if (entry.getValue() > 300_000) {
|
||||
sender.sendMessage(" " + entry.getKey() + " - " + count + "x (" + toMillis(entry.getValue(), false) + ", " + toMillis(entry.getValue() / count, false) + " avg/machine)");
|
||||
}
|
||||
else hidden++;
|
||||
}
|
||||
|
||||
sender.sendMessage("+ " + hidden + " Hidden");
|
||||
}
|
||||
return entry.getKey() + " - " + count + "x (" + timings + ", " + average + " avg/machine)";
|
||||
}, machineCount.keySet().stream().map(key -> new AbstractMap.SimpleEntry<>(key, machineTimings.getOrDefault(key, 0L))));
|
||||
|
||||
sender.sendMessage("");
|
||||
sender.sendMessage(ChatColors.color("&6Ticking Chunks:"));
|
||||
|
||||
timings = chunkTimings.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList());
|
||||
summarizeTimings(sender, entry -> {
|
||||
int count = chunkItemCount.getOrDefault(entry.getKey(), 0);
|
||||
String timings = NumberUtils.getAsMillis(entry.getValue());
|
||||
|
||||
return formatChunk(entry.getKey()) + " - " + count + "x (" + timings + ")";
|
||||
}, chunkTimings.entrySet().stream().filter(entry -> !skippedChunks.contains(entry.getKey())));
|
||||
}
|
||||
|
||||
private void summarizeTimings(CommandSender sender, Function<Map.Entry<String, Long>, String> formatter, Stream<Map.Entry<String, Long>> stream) {
|
||||
List<Entry<String, Long>> timings = stream.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList());
|
||||
|
||||
if (sender instanceof Player) {
|
||||
ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info"));
|
||||
@ -259,11 +256,11 @@ public class TickerTask implements Runnable {
|
||||
int hidden = 0;
|
||||
|
||||
for (Map.Entry<String, Long> entry : timings) {
|
||||
if (!chunksSkipped.contains(entry.getKey())) {
|
||||
if (entry.getValue() > 0) {
|
||||
builder.append("\n&c").append(formatChunk(entry.getKey())).append(" - ").append(chunkItemCount.getOrDefault(entry.getKey(), 0)).append("x &7(").append(toMillis(entry.getValue(), true)).append(')');
|
||||
}
|
||||
else hidden++;
|
||||
if (entry.getValue() > VISIBILITY_THRESHOLD) {
|
||||
builder.append("\n&c").append(formatter.apply(entry));
|
||||
}
|
||||
else {
|
||||
hidden++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,15 +273,15 @@ public class TickerTask implements Runnable {
|
||||
int hidden = 0;
|
||||
|
||||
for (Map.Entry<String, Long> entry : timings) {
|
||||
if (!chunksSkipped.contains(entry.getKey())) {
|
||||
if (entry.getValue() > 0) {
|
||||
sender.sendMessage(" " + formatChunk(entry.getKey()) + " - " + (chunkItemCount.getOrDefault(entry.getKey(), 0)) + "x (" + toMillis(entry.getValue(), false) + ")");
|
||||
}
|
||||
else hidden++;
|
||||
if (entry.getValue() > VISIBILITY_THRESHOLD) {
|
||||
sender.sendMessage(" " + ChatColor.stripColor(formatter.apply(entry)));
|
||||
}
|
||||
else {
|
||||
hidden++;
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColors.color("&c+ &4" + hidden + " Hidden"));
|
||||
sender.sendMessage("+ " + hidden + " Hidden");
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,35 +315,17 @@ public class TickerTask implements Runnable {
|
||||
halted = true;
|
||||
}
|
||||
|
||||
public String toMillis(long nanoseconds, boolean colors) {
|
||||
String number = decimalFormat.format(nanoseconds / 1000000.0);
|
||||
|
||||
if (!colors) {
|
||||
return number;
|
||||
}
|
||||
else {
|
||||
String[] parts = PatternUtils.NUMBER_SEPERATOR.split(number);
|
||||
|
||||
if (parts.length == 1) {
|
||||
return parts[0];
|
||||
}
|
||||
else {
|
||||
return parts[0] + ',' + ChatColor.GRAY + parts[1] + "ms";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TickerTask {\n" + " HALTED = " + halted + "\n" + " tickers = " + tickers + "\n" + " move = " + move + "\n" + " delete = " + delete + "\n" + " chunks = " + chunkItemCount + "\n" + " machines = " + machineCount + "\n" + " machinetime = " + machineTimings + "\n" + " chunktime = " + chunkTimings + "\n" + " skipped = " + chunksSkipped + "\n" + "}";
|
||||
return "TickerTask {\n" + " HALTED = " + halted + "\n" + " tickers = " + tickers + "\n" + " move = " + movingQueue + "\n" + " delete = " + deletionQueue + "\n" + " chunks = " + chunkItemCount + "\n" + " machines = " + machineCount + "\n" + " machinetime = " + machineTimings + "\n" + " chunktime = " + chunkTimings + "\n" + " skipped = " + skippedChunks + "\n" + "}";
|
||||
}
|
||||
|
||||
public void queueMove(Location from, Location to) {
|
||||
move.put(from, to);
|
||||
movingQueue.put(from, to);
|
||||
}
|
||||
|
||||
public void queueDelete(Location l, boolean destroy) {
|
||||
delete.put(l, destroy);
|
||||
deletionQueue.put(l, destroy);
|
||||
}
|
||||
|
||||
public void start(SlimefunPlugin plugin) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.thebusybiscuit.slimefun4.utils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
@ -9,6 +10,8 @@ import org.bukkit.ChatColor;
|
||||
|
||||
public final class NumberUtils {
|
||||
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##");
|
||||
|
||||
private NumberUtils() {}
|
||||
|
||||
public static String formatBigNumber(int i) {
|
||||
@ -57,11 +60,31 @@ public final class NumberUtils {
|
||||
return timeleft + seconds + "s";
|
||||
}
|
||||
|
||||
public static int getInt(String str, int defaultVal) {
|
||||
public static int getInt(String str, int defaultValue) {
|
||||
if (PatternUtils.NUMERIC.matcher(str).matches()) {
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
|
||||
return defaultVal;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static String getAsMillis(long nanoseconds) {
|
||||
String number = DECIMAL_FORMAT.format(nanoseconds / 1000000.0);
|
||||
String[] parts = PatternUtils.NUMBER_SEPERATOR.split(number);
|
||||
|
||||
if (parts.length == 1) {
|
||||
return parts[0];
|
||||
}
|
||||
else {
|
||||
return parts[0] + ',' + ChatColor.GRAY + parts[1] + "ms";
|
||||
}
|
||||
}
|
||||
|
||||
public static long getLong(Long value, long defaultValue) {
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
public static int getInt(Integer value, int defaultValue) {
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.plugins.ThirdPartyPlugin
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.BasicCircuitBoard;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.SeismicAxe;
|
||||
@ -225,7 +226,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
new MultiBlockListener(this);
|
||||
new GadgetsListener(this);
|
||||
new DispenserListener(this);
|
||||
new MobDropListener(this);
|
||||
new BlockListener(this);
|
||||
new EnhancedFurnaceListener(this);
|
||||
new ItemPickupListener(this);
|
||||
@ -237,6 +237,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
new WitherListener(this);
|
||||
new IronGolemListener(this);
|
||||
|
||||
new MobDropListener(this, (BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem());
|
||||
|
||||
// Item-specific Listeners
|
||||
new VampireBladeListener(this, (VampireBlade) SlimefunItems.BLADE_OF_VAMPIRES.getItem());
|
||||
new CoolerListener(this, (Cooler) SlimefunItems.COOLER.getItem());
|
||||
@ -436,12 +438,18 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
|
||||
for (String folder : storageFolders) {
|
||||
File file = new File("data-storage/Slimefun", folder);
|
||||
if (!file.exists()) file.mkdirs();
|
||||
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
for (String folder : pluginFolders) {
|
||||
File file = new File("plugins/Slimefun", folder);
|
||||
if (!file.exists()) file.mkdirs();
|
||||
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,10 +75,15 @@ public class BlockStorage {
|
||||
private static Location deserializeLocation(String l) {
|
||||
try {
|
||||
String[] components = PatternUtils.SEMICOLON.split(l);
|
||||
if (components.length != 4) return null;
|
||||
if (components.length != 4) {
|
||||
return null;
|
||||
}
|
||||
|
||||
World w = Bukkit.getWorld(components[0]);
|
||||
if (w != null) return new Location(w, Integer.parseInt(components[1]), Integer.parseInt(components[2]), Integer.parseInt(components[3]));
|
||||
|
||||
if (w != null) {
|
||||
return new Location(w, Integer.parseInt(components[1]), Integer.parseInt(components[2]), Integer.parseInt(components[3]));
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException x) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Could not parse Number", x);
|
||||
@ -160,6 +165,7 @@ public class BlockStorage {
|
||||
Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to load " + file.getName() + '(' + key + ") for Slimefun " + SlimefunPlugin.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
done++;
|
||||
}
|
||||
}
|
||||
@ -253,7 +259,7 @@ public class BlockStorage {
|
||||
}
|
||||
|
||||
public void save(boolean remove) {
|
||||
this.save(true, remove);
|
||||
save(true, remove);
|
||||
}
|
||||
|
||||
public void save(boolean computeChanges, boolean remove) {
|
||||
@ -311,27 +317,31 @@ public class BlockStorage {
|
||||
}
|
||||
|
||||
if (chunkChanges > 0) {
|
||||
File chunks = new File(PATH_CHUNKS + "chunks.sfc");
|
||||
Config cfg = new Config(PATH_CHUNKS + "chunks.temp");
|
||||
|
||||
for (Map.Entry<String, BlockInfoConfig> entry : SlimefunPlugin.getRegistry().getChunks().entrySet()) {
|
||||
// Saving empty chunk data is pointless
|
||||
if (!entry.getValue().getKeys().isEmpty()) {
|
||||
cfg.setValue(entry.getKey(), entry.getValue().toJSON());
|
||||
}
|
||||
}
|
||||
|
||||
cfg.save(chunks);
|
||||
|
||||
if (remove) {
|
||||
SlimefunPlugin.getRegistry().getWorlds().remove(world.getName());
|
||||
}
|
||||
saveChunks(remove);
|
||||
}
|
||||
|
||||
changes = 0;
|
||||
chunkChanges = 0;
|
||||
}
|
||||
|
||||
private void saveChunks(boolean remove) {
|
||||
File chunks = new File(PATH_CHUNKS + "chunks.sfc");
|
||||
Config cfg = new Config(PATH_CHUNKS + "chunks.temp");
|
||||
|
||||
for (Map.Entry<String, BlockInfoConfig> entry : SlimefunPlugin.getRegistry().getChunks().entrySet()) {
|
||||
// Saving empty chunk data is pointless
|
||||
if (!entry.getValue().getKeys().isEmpty()) {
|
||||
cfg.setValue(entry.getKey(), entry.getValue().toJSON());
|
||||
}
|
||||
}
|
||||
|
||||
cfg.save(chunks);
|
||||
|
||||
if (remove) {
|
||||
SlimefunPlugin.getRegistry().getWorlds().remove(world.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void store(Block block, ItemStack item) {
|
||||
SlimefunItem sfitem = SlimefunItem.getByItem(item);
|
||||
if (sfitem != null) addBlockInfo(block, "id", sfitem.getID(), true);
|
||||
@ -511,15 +521,19 @@ public class BlockStorage {
|
||||
}
|
||||
|
||||
if (destroy) {
|
||||
if (storage.hasInventory(l)) storage.clearInventory(l);
|
||||
if (storage.hasInventory(l)) {
|
||||
storage.clearInventory(l);
|
||||
}
|
||||
|
||||
UniversalBlockMenu universalInventory = getUniversalInventory(l);
|
||||
|
||||
if (universalInventory != null) {
|
||||
universalInventory.close();
|
||||
universalInventory.save();
|
||||
}
|
||||
|
||||
String chunkString = locationToChunkString(l);
|
||||
|
||||
if (SlimefunPlugin.getRegistry().getActiveTickers().containsKey(chunkString)) {
|
||||
Set<Location> locations = SlimefunPlugin.getRegistry().getActiveTickers().get(chunkString);
|
||||
locations.remove(l);
|
||||
@ -528,7 +542,9 @@ public class BlockStorage {
|
||||
SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString);
|
||||
SlimefunPlugin.getRegistry().getActiveChunks().remove(chunkString);
|
||||
}
|
||||
else SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations);
|
||||
else {
|
||||
SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -538,7 +554,10 @@ public class BlockStorage {
|
||||
}
|
||||
|
||||
public static void _integrated_moveLocationInfo(Location from, Location to) {
|
||||
if (!hasBlockInfo(from)) return;
|
||||
if (!hasBlockInfo(from)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockStorage storage = getStorage(from.getWorld());
|
||||
|
||||
setBlockInfo(to, getLocationInfo(from), true);
|
||||
@ -563,7 +582,9 @@ public class BlockStorage {
|
||||
SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString);
|
||||
SlimefunPlugin.getRegistry().getActiveChunks().remove(chunkString);
|
||||
}
|
||||
else SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations);
|
||||
else {
|
||||
SlimefunPlugin.getRegistry().getActiveTickers().put(chunkString, locations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -600,7 +621,10 @@ public class BlockStorage {
|
||||
}
|
||||
|
||||
public static SlimefunItem check(Location l) {
|
||||
if (!hasBlockInfo(l)) return null;
|
||||
if (!hasBlockInfo(l)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SlimefunItem.getByID(getLocationInfo(l, "id"));
|
||||
}
|
||||
|
||||
@ -608,7 +632,9 @@ public class BlockStorage {
|
||||
if (SlimefunPlugin.getBlockDataService().isTileEntity(b.getType())) {
|
||||
Optional<String> blockData = SlimefunPlugin.getBlockDataService().getBlockData(b);
|
||||
|
||||
if (blockData.isPresent()) return blockData.get();
|
||||
if (blockData.isPresent()) {
|
||||
return blockData.get();
|
||||
}
|
||||
}
|
||||
|
||||
return checkID(b.getLocation());
|
||||
@ -692,8 +718,8 @@ public class BlockStorage {
|
||||
|
||||
if (menu != null) {
|
||||
for (HumanEntity human : new ArrayList<>(menu.toInventory().getViewers())) {
|
||||
// Prevents "java.lang.IllegalStateException: Asynchronous entity add!" when closing inventory while
|
||||
// holding an item
|
||||
// Prevents "java.lang.IllegalStateException: Asynchronous entity add!"
|
||||
// when closing the inventory while holding an item
|
||||
Slimefun.runSync(human::closeInventory);
|
||||
}
|
||||
|
||||
@ -729,8 +755,13 @@ public class BlockStorage {
|
||||
|
||||
public static boolean hasInventory(Block b) {
|
||||
BlockStorage storage = getStorage(b.getWorld());
|
||||
if (storage == null) return false;
|
||||
else return storage.hasInventory(b.getLocation());
|
||||
|
||||
if (storage == null) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return storage.hasInventory(b.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockMenu getInventory(Location l) {
|
||||
|
Loading…
Reference in New Issue
Block a user