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
|
#### Changes
|
||||||
* Coolant Cells now last twice as long
|
* Coolant Cells now last twice as long
|
||||||
|
* Ticking blocks will now catch more errors caused by addons
|
||||||
* Massive performance improvements
|
* Massive performance improvements
|
||||||
|
|
||||||
#### Fixes
|
#### Fixes
|
||||||
|
@ -18,6 +18,7 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
|
|
||||||
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
||||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
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.api.events.GEOResourceGenerationEvent;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOMiner;
|
import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOMiner;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOScanner;
|
import io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOScanner;
|
||||||
@ -71,7 +72,9 @@ public class ResourceManager {
|
|||||||
SlimefunPlugin.getRegistry().getGEOResources().add(resource);
|
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) {
|
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");
|
public static final SlimefunItemStack FILLED_FLASK_OF_KNOWLEDGE = new SlimefunItemStack("FILLED_FLASK_OF_KNOWLEDGE", Material.EXPERIENCE_BOTTLE, "&aFlask of Knowledge");
|
||||||
|
|
||||||
/* Backpacks */
|
/* Backpacks */
|
||||||
public static final SlimefunItemStack BACKPACK_SMALL = new SlimefunItemStack("SMALL_BACKPACK", HeadTexture.BACKPACK, "&eSmall Backpack", "", "&7Size: &e9", "&7ID: <ID>", "", LoreBuilder.RIGHT_CLICK_TO_OPEN);
|
private static final String BACKPACK_ID = "&7ID: <ID>";
|
||||||
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_SMALL = new SlimefunItemStack("SMALL_BACKPACK", HeadTexture.BACKPACK, "&eSmall Backpack", "", "&7Size: &e9", BACKPACK_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 BACKPACK_MEDIUM = new SlimefunItemStack("MEDIUM_BACKPACK", HeadTexture.BACKPACK, "&eBackpack", "", "&7Size: &e18", BACKPACK_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 BACKPACK_LARGE = new SlimefunItemStack("LARGE_BACKPACK", HeadTexture.BACKPACK, "&eLarge Backpack", "", "&7Size: &e27", BACKPACK_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 WOVEN_BACKPACK = new SlimefunItemStack("WOVEN_BACKPACK", HeadTexture.BACKPACK, "&eWoven Backpack", "", "&7Size: &e36", 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)", "&7ID: <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 BOUND_BACKPACK = new SlimefunItemStack("BOUND_BACKPACK", HeadTexture.ENDER_BACKPACK, "&cSoulbound Backpack", "", "&7Size: &e36", "&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)", 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", "&7ID: <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 RESTORED_BACKPACK = new SlimefunItemStack("RESTORED_BACKPACK", HeadTexture.RESTORED_BACKPACK, "&eRestored Backpack", "", "&7Retrieve your lost items", "&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", 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 */
|
/* 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);
|
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);
|
ItemStack catalyst = new CustomItem(p.getInventory().getItemInMainHand(), 1);
|
||||||
List<Block> pedestals = getPedestals(b);
|
List<Block> pedestals = getPedestals(altar);
|
||||||
|
|
||||||
if (!altars.contains(b)) {
|
if (!altars.contains(altar)) {
|
||||||
altars.add(b);
|
altars.add(altar);
|
||||||
|
|
||||||
if (pedestals.size() == 8) {
|
if (pedestals.size() == 8) {
|
||||||
pedestals.forEach(block -> altarsInUse.add(block.getLocation()));
|
pedestals.forEach(block -> altarsInUse.add(block.getLocation()));
|
||||||
|
|
||||||
if (catalyst.getType() != Material.AIR) {
|
if (catalyst.getType() != Material.AIR) {
|
||||||
List<ItemStack> input = new ArrayList<>();
|
startRitual(p, altar, pedestals, catalyst);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
altars.remove(b);
|
altars.remove(altar);
|
||||||
SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-catalyst", true);
|
SlimefunPlugin.getLocal().sendMessage(p, "machines.ANCIENT_ALTAR.unknown-catalyst", true);
|
||||||
|
|
||||||
for (Block block : pedestals) {
|
for (Block block : pedestals) {
|
||||||
@ -221,17 +178,65 @@ public class AncientAltarListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unknown catalyst, no longer in use
|
// Unknown catalyst, no longer in use
|
||||||
altarsInUse.remove(b.getLocation());
|
altarsInUse.remove(altar.getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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())));
|
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
|
// 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());
|
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)
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
@ -353,16 +358,26 @@ public class AncientAltarListener implements Listener {
|
|||||||
private Optional<ItemStack> checkRecipe(ItemStack catalyst, List<ItemStackWrapper> items) {
|
private Optional<ItemStack> checkRecipe(ItemStack catalyst, List<ItemStackWrapper> items) {
|
||||||
for (AltarRecipe recipe : altarRecipes) {
|
for (AltarRecipe recipe : altarRecipes) {
|
||||||
if (SlimefunUtils.isItemSimilar(catalyst, recipe.getCatalyst(), true)) {
|
if (SlimefunUtils.isItemSimilar(catalyst, recipe.getCatalyst(), true)) {
|
||||||
for (int i = 0; i < 8; i++) {
|
Optional<ItemStack> optional = checkPedestals(items, recipe);
|
||||||
if (SlimefunUtils.isItemSimilar(items.get(i), recipe.getInput().get(0), true)) {
|
|
||||||
for (int j = 1; j < 8; j++) {
|
if (optional.isPresent()) {
|
||||||
if (!SlimefunUtils.isItemSimilar(items.get((i + j) % items.size()), recipe.getInput().get(j), true)) {
|
return optional;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
else if (j == 7) {
|
}
|
||||||
return Optional.of(recipe.getOutput());
|
|
||||||
}
|
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.Block;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@ -88,25 +89,9 @@ public class BlockListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onBlockUnregister(BlockBreakEvent e) {
|
public void onBlockUnregister(BlockBreakEvent e) {
|
||||||
Block blockAbove = e.getBlock().getRelative(BlockFace.UP);
|
if (hasSensitiveBlockAbove(e.getPlayer(), e.getBlock())) {
|
||||||
|
e.setCancelled(true);
|
||||||
if (sensitiveMaterials.contains(blockAbove.getType())) {
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SlimefunItem sfItem = BlockStorage.check(e.getBlock());
|
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()) {
|
if (!drops.isEmpty()) {
|
||||||
e.getBlock().setType(Material.AIR);
|
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) {
|
private int getBonusDropsWithFortune(ItemStack item, Block b) {
|
||||||
int fortune = 1;
|
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.SlimefunItems;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
|
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
@ -103,14 +104,14 @@ public class DebugFishListener implements Listener {
|
|||||||
if (item.isTicking()) {
|
if (item.isTicking()) {
|
||||||
p.sendMessage(ChatColors.color("&dTicker: " + enabledTooltip));
|
p.sendMessage(ChatColors.color("&dTicker: " + enabledTooltip));
|
||||||
p.sendMessage(ChatColors.color(" &dAsync: &e" + (BlockStorage.check(b).getBlockTicker().isSynchronized() ? disabledTooltip : 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(" &dTimings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b))));
|
||||||
p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + ticker.toMillis(ticker.getTimings(BlockStorage.checkID(b)), true)));
|
p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(BlockStorage.checkID(b)))));
|
||||||
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true)));
|
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b.getChunk()))));
|
||||||
}
|
}
|
||||||
else if (item.getEnergyTicker() != null) {
|
else if (item.getEnergyTicker() != null) {
|
||||||
p.sendMessage(ChatColors.color("&dTicking: " + "&3Indirect"));
|
p.sendMessage(ChatColors.color("&dTicking: " + "&3Indirect"));
|
||||||
p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true)));
|
p.sendMessage(ChatColors.color(" &dTimings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b))));
|
||||||
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true)));
|
p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + NumberUtils.getAsMillis(ticker.getTimings(b.getChunk()))));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p.sendMessage(ChatColors.color("&dTicker: " + disabledTooltip));
|
p.sendMessage(ChatColors.color("&dTicker: " + disabledTooltip));
|
||||||
|
@ -9,6 +9,7 @@ import org.bukkit.event.EventPriority;
|
|||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||||
|
|
||||||
|
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
@ -33,7 +34,7 @@ public class ExplosionsListener implements Listener {
|
|||||||
blocks.remove();
|
blocks.remove();
|
||||||
|
|
||||||
// Hardened Glass and WitherProof blocks cannot be destroyed by explosions
|
// 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;
|
boolean success = true;
|
||||||
SlimefunItem sfItem = SlimefunItem.getByID(id);
|
SlimefunItem sfItem = SlimefunItem.getByID(id);
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ public class GrapplingHookListener implements Listener {
|
|||||||
Player p = (Player) arrow.getShooter();
|
Player p = (Player) arrow.getShooter();
|
||||||
|
|
||||||
if (p.getGameMode() != GameMode.CREATIVE && (boolean) grappleState.get(p.getUniqueId())) {
|
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);
|
Vector velocity = new Vector(0.0, 0.2, 0.0);
|
||||||
@ -135,7 +135,7 @@ public class GrapplingHookListener implements Listener {
|
|||||||
// To fix issue #253
|
// To fix issue #253
|
||||||
Slimefun.runSync(() -> {
|
Slimefun.runSync(() -> {
|
||||||
if (grappleState.containsKey(uuid)) {
|
if (grappleState.containsKey(uuid)) {
|
||||||
SlimefunPlugin.getBowListener().getBows().remove(uuid);
|
SlimefunPlugin.getBowListener().getProjectileData().remove(uuid);
|
||||||
|
|
||||||
for (Entity n : temporaryEntities.get(uuid)) {
|
for (Entity n : temporaryEntities.get(uuid)) {
|
||||||
if (n.isValid()) {
|
if (n.isValid()) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
|
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@ -9,9 +10,7 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.entity.EntityDeathEvent;
|
import org.bukkit.event.entity.EntityDeathEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
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.implementation.items.electric.BasicCircuitBoard;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
|
||||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.handlers.EntityKillHandler;
|
import me.mrCookieSlime.Slimefun.Objects.handlers.EntityKillHandler;
|
||||||
@ -19,8 +18,12 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
|||||||
|
|
||||||
public class MobDropListener implements Listener {
|
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);
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
|
||||||
|
this.circuitBoard = circuitBoard;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@ -31,15 +34,7 @@ public class MobDropListener implements Listener {
|
|||||||
|
|
||||||
Set<ItemStack> customDrops = SlimefunPlugin.getRegistry().getMobDrops(e.getEntityType());
|
Set<ItemStack> customDrops = SlimefunPlugin.getRegistry().getMobDrops(e.getEntityType());
|
||||||
if (customDrops != null && !customDrops.isEmpty()) {
|
if (customDrops != null && !customDrops.isEmpty()) {
|
||||||
for (ItemStack drop : customDrops) {
|
addDrops(p, customDrops, e.getDrops());
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.getType() != Material.AIR) {
|
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.Objects.handlers.BowShootHandler;
|
||||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
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 {
|
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) {
|
public void register(SlimefunPlugin plugin) {
|
||||||
plugin.getServer().getPluginManager().registerEvents(this, 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
|
@EventHandler
|
||||||
@ -37,7 +52,7 @@ public class SlimefunBowListener implements Listener {
|
|||||||
SlimefunItem bow = SlimefunItem.getByItem(e.getBow());
|
SlimefunItem bow = SlimefunItem.getByItem(e.getBow());
|
||||||
|
|
||||||
if (bow instanceof SlimefunBow) {
|
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) {
|
public void onArrowHit(ProjectileHitEvent e) {
|
||||||
Slimefun.runSync(() -> {
|
Slimefun.runSync(() -> {
|
||||||
if (e.getEntity().isValid() && e.getEntity() instanceof Arrow) {
|
if (e.getEntity().isValid() && e.getEntity() instanceof Arrow) {
|
||||||
bows.remove(e.getEntity().getUniqueId());
|
projectiles.remove(e.getEntity().getUniqueId());
|
||||||
}
|
}
|
||||||
}, 4L);
|
}, 4L);
|
||||||
}
|
}
|
||||||
@ -54,13 +69,13 @@ public class SlimefunBowListener implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onArrowSuccessfulHit(EntityDamageByEntityEvent e) {
|
public void onArrowSuccessfulHit(EntityDamageByEntityEvent e) {
|
||||||
if (e.getDamager() instanceof Arrow && e.getEntity() instanceof LivingEntity) {
|
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) {
|
if (bow != null) {
|
||||||
bow.callItemHandler(BowShootHandler.class, handler -> handler.onHit(e, (LivingEntity) e.getEntity()));
|
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.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.AbstractArrow;
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.ChestedHorse;
|
import org.bukkit.entity.ChestedHorse;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
@ -78,18 +79,41 @@ public class TalismanListener implements Listener {
|
|||||||
Projectile projectile = (Projectile) ((EntityDamageByEntityEvent) e).getDamager();
|
Projectile projectile = (Projectile) ((EntityDamageByEntityEvent) e).getDamager();
|
||||||
|
|
||||||
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
|
if (Talisman.checkFor(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
|
||||||
Player p = (Player) e.getEntity();
|
returnProjectile((Player) e.getEntity(), projectile);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onKill(EntityDeathEvent e) {
|
public void onKill(EntityDeathEvent e) {
|
||||||
if (e.getDrops().isEmpty() || e.getEntity().getKiller() == null) {
|
if (e.getDrops().isEmpty() || e.getEntity().getKiller() == null) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
|
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -9,11 +8,14 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
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.ChatComponent;
|
||||||
import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent;
|
import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent;
|
||||||
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||||
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
|
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
|
||||||
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
|
||||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
@ -37,24 +40,29 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
|||||||
|
|
||||||
public class TickerTask implements Runnable {
|
public class TickerTask implements Runnable {
|
||||||
|
|
||||||
private final DecimalFormat decimalFormat = new DecimalFormat("#.##");
|
private static final int VISIBILITY_THRESHOLD = 200_000;
|
||||||
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 final Set<BlockTicker> tickers = new HashSet<>();
|
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 boolean halted = false;
|
||||||
|
|
||||||
private int skipped = 0;
|
private int skippedBlocks = 0;
|
||||||
private int chunks = 0;
|
private int chunks = 0;
|
||||||
private int machines = 0;
|
private int blocks = 0;
|
||||||
private long time = 0;
|
private long time = 0;
|
||||||
|
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
@ -65,104 +73,60 @@ public class TickerTask implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (running) return;
|
if (running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
running = true;
|
running = true;
|
||||||
long timestamp = System.nanoTime();
|
long timestamp = System.nanoTime();
|
||||||
|
|
||||||
skipped = 0;
|
skippedBlocks = 0;
|
||||||
chunks = 0;
|
chunks = 0;
|
||||||
machines = 0;
|
blocks = 0;
|
||||||
chunkItemCount.clear();
|
chunkItemCount.clear();
|
||||||
machineCount.clear();
|
machineCount.clear();
|
||||||
time = 0;
|
time = 0;
|
||||||
chunkTimings.clear();
|
chunkTimings.clear();
|
||||||
chunksSkipped.clear();
|
skippedChunks.clear();
|
||||||
machineTimings.clear();
|
machineTimings.clear();
|
||||||
blockTimings.clear();
|
blockTimings.clear();
|
||||||
|
|
||||||
Map<Location, Integer> bugged = new HashMap<>(buggedBlocks);
|
Map<Location, Integer> bugs = new HashMap<>(buggedBlocks);
|
||||||
buggedBlocks.clear();
|
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());
|
BlockStorage._integrated_removeBlockInfo(entry.getKey(), entry.getValue());
|
||||||
delete.remove(entry.getKey());
|
deletionQueue.remove(entry.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!halted) {
|
if (!halted) {
|
||||||
for (String tickedChunk : BlockStorage.getTickingChunks()) {
|
for (String chunk : BlockStorage.getTickingChunks()) {
|
||||||
long timestamp2 = System.nanoTime();
|
long chunkTimestamp = System.nanoTime();
|
||||||
chunks++;
|
chunks++;
|
||||||
|
|
||||||
for (Location l : BlockStorage.getTickingLocations(tickedChunk)) {
|
for (Location l : BlockStorage.getTickingLocations(chunk)) {
|
||||||
if (l.getWorld().isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4)) {
|
if (l.getWorld().isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4)) {
|
||||||
Block b = l.getBlock();
|
tick(l, chunk, bugs);
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skipped += BlockStorage.getTickingLocations(tickedChunk).size();
|
skippedBlocks += BlockStorage.getTickingLocations(chunk).size();
|
||||||
chunksSkipped.add(tickedChunk);
|
skippedChunks.add(chunk);
|
||||||
chunks--;
|
chunks--;
|
||||||
break;
|
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());
|
BlockStorage._integrated_moveLocationInfo(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
move.clear();
|
|
||||||
|
movingQueue.clear();
|
||||||
|
|
||||||
Iterator<BlockTicker> iterator = tickers.iterator();
|
Iterator<BlockTicker> iterator = tickers.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
@ -174,23 +138,74 @@ public class TickerTask implements Runnable {
|
|||||||
running = false;
|
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++;
|
errors++;
|
||||||
|
|
||||||
if (errors == 1) {
|
if (errors == 1) {
|
||||||
// Generate a new Error-Report
|
// Generate a new Error-Report
|
||||||
new ErrorReport(x, l, item);
|
new ErrorReport(x, l, item);
|
||||||
|
|
||||||
buggedBlocks.put(l, errors);
|
buggedBlocks.put(l, errors);
|
||||||
}
|
}
|
||||||
else if (errors == 4) {
|
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, "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, "Check your /plugins/Slimefun/error-reports/ folder for details.");
|
||||||
Slimefun.getLogger().log(Level.SEVERE, " ");
|
Slimefun.getLogger().log(Level.SEVERE, " ");
|
||||||
|
|
||||||
BlockStorage._integrated_removeBlockInfo(l, true);
|
BlockStorage._integrated_removeBlockInfo(l, true);
|
||||||
|
|
||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(SlimefunPlugin.instance, () -> l.getBlock().setType(Material.AIR));
|
Bukkit.getScheduler().scheduleSyncDelayedTask(SlimefunPlugin.instance, () -> l.getBlock().setType(Material.AIR));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -199,59 +214,41 @@ public class TickerTask implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getTime() {
|
public String getTime() {
|
||||||
return toMillis(time, false);
|
return NumberUtils.getAsMillis(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void info(CommandSender sender) {
|
public void info(CommandSender sender) {
|
||||||
sender.sendMessage(ChatColors.color("&2== &aSlimefun Diagnostic Tool &2=="));
|
sender.sendMessage(ChatColors.color("&2== &aSlimefun Diagnostic Tool &2=="));
|
||||||
sender.sendMessage(ChatColors.color("&6Halted: &e&l" + String.valueOf(halted).toUpperCase(Locale.ROOT)));
|
sender.sendMessage(ChatColors.color("&6Halted: &e&l" + String.valueOf(halted).toUpperCase(Locale.ROOT)));
|
||||||
sender.sendMessage("");
|
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 Chunks: &e" + chunks));
|
||||||
sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + machines));
|
sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + blocks));
|
||||||
sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skipped));
|
sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skippedBlocks));
|
||||||
sender.sendMessage("");
|
sender.sendMessage("");
|
||||||
sender.sendMessage(ChatColors.color("&6Ticking Machines:"));
|
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) {
|
return entry.getKey() + " - " + count + "x (" + timings + ", " + average + " avg/machine)";
|
||||||
ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info"));
|
}, machineCount.keySet().stream().map(key -> new AbstractMap.SimpleEntry<>(key, machineTimings.getOrDefault(key, 0L))));
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage("");
|
sender.sendMessage("");
|
||||||
sender.sendMessage(ChatColors.color("&6Ticking Chunks:"));
|
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) {
|
if (sender instanceof Player) {
|
||||||
ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info"));
|
ChatComponent component = new ChatComponent(ChatColors.color(" &7&oHover for more Info"));
|
||||||
@ -259,11 +256,11 @@ public class TickerTask implements Runnable {
|
|||||||
int hidden = 0;
|
int hidden = 0;
|
||||||
|
|
||||||
for (Map.Entry<String, Long> entry : timings) {
|
for (Map.Entry<String, Long> entry : timings) {
|
||||||
if (!chunksSkipped.contains(entry.getKey())) {
|
if (entry.getValue() > VISIBILITY_THRESHOLD) {
|
||||||
if (entry.getValue() > 0) {
|
builder.append("\n&c").append(formatter.apply(entry));
|
||||||
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 {
|
||||||
else hidden++;
|
hidden++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,15 +273,15 @@ public class TickerTask implements Runnable {
|
|||||||
int hidden = 0;
|
int hidden = 0;
|
||||||
|
|
||||||
for (Map.Entry<String, Long> entry : timings) {
|
for (Map.Entry<String, Long> entry : timings) {
|
||||||
if (!chunksSkipped.contains(entry.getKey())) {
|
if (entry.getValue() > VISIBILITY_THRESHOLD) {
|
||||||
if (entry.getValue() > 0) {
|
sender.sendMessage(" " + ChatColor.stripColor(formatter.apply(entry)));
|
||||||
sender.sendMessage(" " + formatChunk(entry.getKey()) + " - " + (chunkItemCount.getOrDefault(entry.getKey(), 0)) + "x (" + toMillis(entry.getValue(), false) + ")");
|
}
|
||||||
}
|
else {
|
||||||
else hidden++;
|
hidden++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage(ChatColors.color("&c+ &4" + hidden + " Hidden"));
|
sender.sendMessage("+ " + hidden + " Hidden");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,35 +315,17 @@ public class TickerTask implements Runnable {
|
|||||||
halted = true;
|
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
|
@Override
|
||||||
public String toString() {
|
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) {
|
public void queueMove(Location from, Location to) {
|
||||||
move.put(from, to);
|
movingQueue.put(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queueDelete(Location l, boolean destroy) {
|
public void queueDelete(Location l, boolean destroy) {
|
||||||
delete.put(l, destroy);
|
deletionQueue.put(l, destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(SlimefunPlugin plugin) {
|
public void start(SlimefunPlugin plugin) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.thebusybiscuit.slimefun4.utils;
|
package io.github.thebusybiscuit.slimefun4.utils;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -9,6 +10,8 @@ import org.bukkit.ChatColor;
|
|||||||
|
|
||||||
public final class NumberUtils {
|
public final class NumberUtils {
|
||||||
|
|
||||||
|
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##");
|
||||||
|
|
||||||
private NumberUtils() {}
|
private NumberUtils() {}
|
||||||
|
|
||||||
public static String formatBigNumber(int i) {
|
public static String formatBigNumber(int i) {
|
||||||
@ -57,11 +60,31 @@ public final class NumberUtils {
|
|||||||
return timeleft + seconds + "s";
|
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()) {
|
if (PatternUtils.NUMERIC.matcher(str).matches()) {
|
||||||
return Integer.parseInt(str);
|
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.SlimefunItems;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar;
|
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.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.electric.reactors.Reactor;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook;
|
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook;
|
||||||
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.SeismicAxe;
|
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 MultiBlockListener(this);
|
||||||
new GadgetsListener(this);
|
new GadgetsListener(this);
|
||||||
new DispenserListener(this);
|
new DispenserListener(this);
|
||||||
new MobDropListener(this);
|
|
||||||
new BlockListener(this);
|
new BlockListener(this);
|
||||||
new EnhancedFurnaceListener(this);
|
new EnhancedFurnaceListener(this);
|
||||||
new ItemPickupListener(this);
|
new ItemPickupListener(this);
|
||||||
@ -237,6 +237,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
|||||||
new WitherListener(this);
|
new WitherListener(this);
|
||||||
new IronGolemListener(this);
|
new IronGolemListener(this);
|
||||||
|
|
||||||
|
new MobDropListener(this, (BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem());
|
||||||
|
|
||||||
// Item-specific Listeners
|
// Item-specific Listeners
|
||||||
new VampireBladeListener(this, (VampireBlade) SlimefunItems.BLADE_OF_VAMPIRES.getItem());
|
new VampireBladeListener(this, (VampireBlade) SlimefunItems.BLADE_OF_VAMPIRES.getItem());
|
||||||
new CoolerListener(this, (Cooler) SlimefunItems.COOLER.getItem());
|
new CoolerListener(this, (Cooler) SlimefunItems.COOLER.getItem());
|
||||||
@ -436,12 +438,18 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
|||||||
|
|
||||||
for (String folder : storageFolders) {
|
for (String folder : storageFolders) {
|
||||||
File file = new File("data-storage/Slimefun", folder);
|
File file = new File("data-storage/Slimefun", folder);
|
||||||
if (!file.exists()) file.mkdirs();
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.mkdirs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String folder : pluginFolders) {
|
for (String folder : pluginFolders) {
|
||||||
File file = new File("plugins/Slimefun", folder);
|
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) {
|
private static Location deserializeLocation(String l) {
|
||||||
try {
|
try {
|
||||||
String[] components = PatternUtils.SEMICOLON.split(l);
|
String[] components = PatternUtils.SEMICOLON.split(l);
|
||||||
if (components.length != 4) return null;
|
if (components.length != 4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
World w = Bukkit.getWorld(components[0]);
|
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) {
|
catch (NumberFormatException x) {
|
||||||
Slimefun.getLogger().log(Level.WARNING, "Could not parse Number", 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());
|
Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to load " + file.getName() + '(' + key + ") for Slimefun " + SlimefunPlugin.getVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done++;
|
done++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,7 +259,7 @@ public class BlockStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void save(boolean remove) {
|
public void save(boolean remove) {
|
||||||
this.save(true, remove);
|
save(true, remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(boolean computeChanges, boolean remove) {
|
public void save(boolean computeChanges, boolean remove) {
|
||||||
@ -311,27 +317,31 @@ public class BlockStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (chunkChanges > 0) {
|
if (chunkChanges > 0) {
|
||||||
File chunks = new File(PATH_CHUNKS + "chunks.sfc");
|
saveChunks(remove);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changes = 0;
|
changes = 0;
|
||||||
chunkChanges = 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) {
|
public static void store(Block block, ItemStack item) {
|
||||||
SlimefunItem sfitem = SlimefunItem.getByItem(item);
|
SlimefunItem sfitem = SlimefunItem.getByItem(item);
|
||||||
if (sfitem != null) addBlockInfo(block, "id", sfitem.getID(), true);
|
if (sfitem != null) addBlockInfo(block, "id", sfitem.getID(), true);
|
||||||
@ -511,15 +521,19 @@ public class BlockStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (destroy) {
|
if (destroy) {
|
||||||
if (storage.hasInventory(l)) storage.clearInventory(l);
|
if (storage.hasInventory(l)) {
|
||||||
|
storage.clearInventory(l);
|
||||||
|
}
|
||||||
|
|
||||||
UniversalBlockMenu universalInventory = getUniversalInventory(l);
|
UniversalBlockMenu universalInventory = getUniversalInventory(l);
|
||||||
|
|
||||||
if (universalInventory != null) {
|
if (universalInventory != null) {
|
||||||
universalInventory.close();
|
universalInventory.close();
|
||||||
universalInventory.save();
|
universalInventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
String chunkString = locationToChunkString(l);
|
String chunkString = locationToChunkString(l);
|
||||||
|
|
||||||
if (SlimefunPlugin.getRegistry().getActiveTickers().containsKey(chunkString)) {
|
if (SlimefunPlugin.getRegistry().getActiveTickers().containsKey(chunkString)) {
|
||||||
Set<Location> locations = SlimefunPlugin.getRegistry().getActiveTickers().get(chunkString);
|
Set<Location> locations = SlimefunPlugin.getRegistry().getActiveTickers().get(chunkString);
|
||||||
locations.remove(l);
|
locations.remove(l);
|
||||||
@ -528,7 +542,9 @@ public class BlockStorage {
|
|||||||
SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString);
|
SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString);
|
||||||
SlimefunPlugin.getRegistry().getActiveChunks().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) {
|
public static void _integrated_moveLocationInfo(Location from, Location to) {
|
||||||
if (!hasBlockInfo(from)) return;
|
if (!hasBlockInfo(from)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BlockStorage storage = getStorage(from.getWorld());
|
BlockStorage storage = getStorage(from.getWorld());
|
||||||
|
|
||||||
setBlockInfo(to, getLocationInfo(from), true);
|
setBlockInfo(to, getLocationInfo(from), true);
|
||||||
@ -563,7 +582,9 @@ public class BlockStorage {
|
|||||||
SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString);
|
SlimefunPlugin.getRegistry().getActiveTickers().remove(chunkString);
|
||||||
SlimefunPlugin.getRegistry().getActiveChunks().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) {
|
public static SlimefunItem check(Location l) {
|
||||||
if (!hasBlockInfo(l)) return null;
|
if (!hasBlockInfo(l)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return SlimefunItem.getByID(getLocationInfo(l, "id"));
|
return SlimefunItem.getByID(getLocationInfo(l, "id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,7 +632,9 @@ public class BlockStorage {
|
|||||||
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);
|
||||||
|
|
||||||
if (blockData.isPresent()) return blockData.get();
|
if (blockData.isPresent()) {
|
||||||
|
return blockData.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkID(b.getLocation());
|
return checkID(b.getLocation());
|
||||||
@ -692,8 +718,8 @@ public class BlockStorage {
|
|||||||
|
|
||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
for (HumanEntity human : new ArrayList<>(menu.toInventory().getViewers())) {
|
for (HumanEntity human : new ArrayList<>(menu.toInventory().getViewers())) {
|
||||||
// Prevents "java.lang.IllegalStateException: Asynchronous entity add!" when closing inventory while
|
// Prevents "java.lang.IllegalStateException: Asynchronous entity add!"
|
||||||
// holding an item
|
// when closing the inventory while holding an item
|
||||||
Slimefun.runSync(human::closeInventory);
|
Slimefun.runSync(human::closeInventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,8 +755,13 @@ public class BlockStorage {
|
|||||||
|
|
||||||
public static boolean hasInventory(Block b) {
|
public static boolean hasInventory(Block b) {
|
||||||
BlockStorage storage = getStorage(b.getWorld());
|
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) {
|
public static BlockMenu getInventory(Location l) {
|
||||||
|
Loading…
Reference in New Issue
Block a user