- entity = getPlacedItem(b);
+
+ if (entity.isPresent()) {
+ Item stack = entity.get();
+
+ if (stack.isValid()) {
+ stack.removeMetadata("no_pickup", SlimefunPlugin.instance());
+ b.getWorld().dropItem(b.getLocation(), getOriginalItemStack(stack));
+ stack.remove();
+ }
}
}
-
- return true;
- });
+ };
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java
index 51c458d5a..77bb55601 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ButcherAndroid.java
@@ -38,20 +38,20 @@ public class ButcherAndroid extends ProgrammableAndroid {
boolean attack = false;
switch (face) {
- case NORTH:
- attack = n.getLocation().getZ() < b.getZ();
- break;
- case EAST:
- attack = n.getLocation().getX() > b.getX();
- break;
- case SOUTH:
- attack = n.getLocation().getZ() > b.getZ();
- break;
- case WEST:
- attack = n.getLocation().getX() < b.getX();
- break;
- default:
- break;
+ case NORTH:
+ attack = n.getLocation().getZ() < b.getZ();
+ break;
+ case EAST:
+ attack = n.getLocation().getX() > b.getX();
+ break;
+ case SOUTH:
+ attack = n.getLocation().getZ() > b.getZ();
+ break;
+ case WEST:
+ attack = n.getLocation().getX() < b.getX();
+ break;
+ default:
+ break;
}
if (attack) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java
index 44948ab4b..1bafdcd3f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java
@@ -64,22 +64,22 @@ public class FarmerAndroid extends ProgrammableAndroid {
Random random = ThreadLocalRandom.current();
switch (crop) {
- case WHEAT:
- return new ItemStack(Material.WHEAT, random.nextInt(2) + 1);
- case POTATOES:
- return new ItemStack(Material.POTATO, random.nextInt(3) + 1);
- case CARROTS:
- return new ItemStack(Material.CARROT, random.nextInt(3) + 1);
- case BEETROOTS:
- return new ItemStack(Material.BEETROOT, random.nextInt(3) + 1);
- case COCOA:
- return new ItemStack(Material.COCOA_BEANS, random.nextInt(3) + 1);
- case NETHER_WART:
- return new ItemStack(Material.NETHER_WART, random.nextInt(3) + 1);
- case SWEET_BERRY_BUSH:
- return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1);
- default:
- return null;
+ case WHEAT:
+ return new ItemStack(Material.WHEAT, random.nextInt(2) + 1);
+ case POTATOES:
+ return new ItemStack(Material.POTATO, random.nextInt(3) + 1);
+ case CARROTS:
+ return new ItemStack(Material.CARROT, random.nextInt(3) + 1);
+ case BEETROOTS:
+ return new ItemStack(Material.BEETROOT, random.nextInt(3) + 1);
+ case COCOA:
+ return new ItemStack(Material.COCOA_BEANS, random.nextInt(3) + 1);
+ case NETHER_WART:
+ return new ItemStack(Material.NETHER_WART, random.nextInt(3) + 1);
+ case SWEET_BERRY_BUSH:
+ return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1);
+ default:
+ return null;
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java
index 4328e6c0e..8e87a3e72 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java
@@ -3,40 +3,73 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import java.util.Collection;
import java.util.UUID;
+import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
+import org.bukkit.Particle;
+import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
+import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
+/**
+ * The {@link MinerAndroid} is a variant of the {@link ProgrammableAndroid} which
+ * is able to break blocks.
+ * The core functionalities boil down to {@link #dig(Block, BlockMenu, Block)} and
+ * {@link #moveAndDig(Block, BlockMenu, BlockFace, Block)}.
+ * Otherwise the functionality is similar to a regular android.
+ *
+ * The {@link MinerAndroid} will also fire an {@link AndroidMineEvent} when breaking a {@link Block}.
+ *
+ * @author TheBusyBiscuit
+ * @author creator3
+ * @author poma123
+ * @author Sfiguz7
+ * @author CyberPatriot
+ * @author Redemption198
+ * @author Poslovitch
+ *
+ * @see AndroidMineEvent
+ *
+ */
public class MinerAndroid extends ProgrammableAndroid {
// Determines the drops a miner android will get
private final ItemStack effectivePickaxe = new ItemStack(Material.DIAMOND_PICKAXE);
+ private final ItemSetting firesEvent = new ItemSetting<>("trigger-event-for-generators", false);
+ private final ItemSetting applyOptimizations = new ItemSetting<>("reduced-block-updates", true);
+
+ @ParametersAreNonnullByDefault
public MinerAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, tier, item, recipeType, recipe);
+ addItemSetting(firesEvent);
}
@Override
+ @Nonnull
public AndroidType getAndroidType() {
return AndroidType.MINER;
}
@Override
+ @ParametersAreNonnullByDefault
protected void dig(Block b, BlockMenu menu, Block block) {
Collection drops = block.getDrops(effectivePickaxe);
@@ -52,22 +85,16 @@ public class MinerAndroid extends ProgrammableAndroid {
}
// We only want to break non-Slimefun blocks
- String blockId = BlockStorage.checkID(block);
- if (blockId == null) {
- for (ItemStack drop : drops) {
- if (menu.fits(drop, getOutputSlots())) {
- menu.pushItem(drop, getOutputSlots());
- }
- }
-
+ if (!BlockStorage.hasBlockInfo(block)) {
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
- block.setType(Material.AIR);
+ breakBlock(menu, drops, block);
}
}
}
}
@Override
+ @ParametersAreNonnullByDefault
protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block) {
Collection drops = block.getDrops(effectivePickaxe);
@@ -83,17 +110,9 @@ public class MinerAndroid extends ProgrammableAndroid {
}
// We only want to break non-Slimefun blocks
- SlimefunItem blockId = BlockStorage.check(block);
- if (blockId == null) {
- for (ItemStack drop : drops) {
- if (menu.fits(drop, getOutputSlots())) {
- menu.pushItem(drop, getOutputSlots());
- }
- }
-
+ if (!BlockStorage.hasBlockInfo(block)) {
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
-
- block.setType(Material.AIR);
+ breakBlock(menu, drops, block);
move(b, face, block);
}
} else {
@@ -104,4 +123,32 @@ public class MinerAndroid extends ProgrammableAndroid {
}
}
+ @ParametersAreNonnullByDefault
+ private void breakBlock(BlockMenu menu, Collection drops, Block block) {
+ // Push our drops to the inventory
+ for (ItemStack drop : drops) {
+ menu.pushItem(drop, getOutputSlots());
+ }
+
+ // Check if Block Generator optimizations should be applied.
+ if (applyOptimizations.getValue()) {
+ InfiniteBlockGenerator generator = InfiniteBlockGenerator.findAt(block);
+
+ // If we found a generator, continue.
+ if (generator != null) {
+ if (firesEvent.getValue()) {
+ generator.callEvent(block);
+ }
+
+ // "poof" a "new" block was generated
+ block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.075F, 0.8F);
+ block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getX() + 0.5, block.getY() + 1.25, block.getZ() + 0.5, 8, 0.5, 0.5, 0.5, 0.015);
+ } else {
+ block.setType(Material.AIR);
+ }
+ } else {
+ block.setType(Material.AIR);
+ }
+ }
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java
index 525739b61..806384d2d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java
@@ -56,7 +56,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
-import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
@@ -133,6 +132,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
}
};
+ // TODO: Move this into a BlockBreakHandler
registerBlockHandler(getId(), (p, b, stack, reason) -> {
boolean allow = reason == UnregisterReason.PLAYER_BREAK && (BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(p.getUniqueId().toString()) || p.hasPermission("slimefun.android.bypass"));
@@ -151,7 +151,8 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
addItemHandler(onPlace());
}
- private ItemHandler onPlace() {
+ @Nonnull
+ private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@Override
@@ -194,14 +195,14 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
*/
public AndroidFuelSource getFuelSource() {
switch (getTier()) {
- case 1:
- return AndroidFuelSource.SOLID;
- case 2:
- return AndroidFuelSource.LIQUID;
- case 3:
- return AndroidFuelSource.NUCLEAR;
- default:
- throw new IllegalStateException("Cannot convert the following Android tier to a fuel type: " + getTier());
+ case 1:
+ return AndroidFuelSource.SOLID;
+ case 2:
+ return AndroidFuelSource.LIQUID;
+ case 3:
+ return AndroidFuelSource.NUCLEAR;
+ default:
+ throw new IllegalStateException("Cannot convert the following Android tier to a fuel type: " + getTier());
}
}
@@ -564,38 +565,38 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
private void registerDefaultFuelTypes() {
switch (getFuelSource()) {
- case SOLID:
- registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK)));
- registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD)));
- registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK)));
+ case SOLID:
+ registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK)));
+ registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD)));
+ registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK)));
- // Coal & Charcoal
- registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL)));
- registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL)));
+ // Coal & Charcoal
+ registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL)));
+ registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL)));
- // Logs
- for (Material mat : Tag.LOGS.getValues()) {
- registerFuelType(new MachineFuel(2, new ItemStack(mat)));
- }
+ // Logs
+ for (Material mat : Tag.LOGS.getValues()) {
+ registerFuelType(new MachineFuel(2, new ItemStack(mat)));
+ }
- // Wooden Planks
- for (Material mat : Tag.PLANKS.getValues()) {
- registerFuelType(new MachineFuel(1, new ItemStack(mat)));
- }
+ // Wooden Planks
+ for (Material mat : Tag.PLANKS.getValues()) {
+ registerFuelType(new MachineFuel(1, new ItemStack(mat)));
+ }
- break;
- case LIQUID:
- registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET)));
- registerFuelType(new MachineFuel(200, SlimefunItems.OIL_BUCKET));
- registerFuelType(new MachineFuel(500, SlimefunItems.FUEL_BUCKET));
- break;
- case NUCLEAR:
- registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM));
- registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM));
- registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM));
- break;
- default:
- throw new IllegalStateException("Unhandled Fuel Source: " + getFuelSource());
+ break;
+ case LIQUID:
+ registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET)));
+ registerFuelType(new MachineFuel(200, SlimefunItems.OIL_BUCKET));
+ registerFuelType(new MachineFuel(500, SlimefunItems.FUEL_BUCKET));
+ break;
+ case NUCLEAR:
+ registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM));
+ registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM));
+ registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM));
+ break;
+ default:
+ throw new IllegalStateException("Unhandled Fuel Source: " + getFuelSource());
}
}
@@ -685,26 +686,26 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
BlockFace face = rotationData == null ? BlockFace.NORTH : BlockFace.valueOf(rotationData);
switch (instruction) {
- case START:
- case WAIT:
- // We are "waiting" here, so we only move a step forward
- BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
- break;
- case REPEAT:
- // "repeat" just means, we reset our index
- BlockStorage.addBlockInfo(b, "index", String.valueOf(0));
- break;
- case CHOP_TREE:
- // We only move to the next step if we finished chopping wood
- if (chopTree(b, inv, face)) {
+ case START:
+ case WAIT:
+ // We are "waiting" here, so we only move a step forward
BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
- }
- break;
- default:
- // We set the index here in advance to fix moving android issues
- BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
- instruction.execute(this, b, inv, face);
- break;
+ break;
+ case REPEAT:
+ // "repeat" just means, we reset our index
+ BlockStorage.addBlockInfo(b, "index", String.valueOf(0));
+ break;
+ case CHOP_TREE:
+ // We only move to the next step if we finished chopping wood
+ if (chopTree(b, inv, face)) {
+ BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
+ }
+ break;
+ default:
+ // We set the index here in advance to fix moving android issues
+ BlockStorage.addBlockInfo(b, "index", String.valueOf(index));
+ instruction.execute(this, b, inv, face);
+ break;
}
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java
index 2d79132b2..eb5775bf1 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java
@@ -1,8 +1,11 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import java.util.List;
-import java.util.Optional;
import java.util.UUID;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
@@ -14,9 +17,10 @@ import org.bukkit.block.BlockFace;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.blocks.Vein;
-import io.github.thebusybiscuit.cscorelib2.materials.MaterialConverter;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
+import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
@@ -59,6 +63,7 @@ public class WoodcutterAndroid extends ProgrammableAndroid {
return true;
}
+ @ParametersAreNonnullByDefault
private void breakLog(Block log, Block android, BlockMenu menu, BlockFace face) {
ItemStack drop = new ItemStack(log.getType());
@@ -67,13 +72,96 @@ public class WoodcutterAndroid extends ProgrammableAndroid {
log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType());
if (log.getY() == android.getRelative(face).getY()) {
- Optional sapling = MaterialConverter.getSaplingFromLog(log.getType());
-
- sapling.ifPresent(log::setType);
+ replant(log);
} else {
log.setType(Material.AIR);
}
}
}
+ private void replant(@Nonnull Block block) {
+ Material logType = block.getType();
+ Material saplingType = null;
+ Predicate soilRequirement = null;
+
+ switch (logType) {
+ case OAK_LOG:
+ case OAK_WOOD:
+ case STRIPPED_OAK_LOG:
+ case STRIPPED_OAK_WOOD:
+ saplingType = Material.OAK_SAPLING;
+ soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
+ break;
+ case BIRCH_LOG:
+ case BIRCH_WOOD:
+ case STRIPPED_BIRCH_LOG:
+ case STRIPPED_BIRCH_WOOD:
+ saplingType = Material.BIRCH_SAPLING;
+ soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
+ break;
+ case JUNGLE_LOG:
+ case JUNGLE_WOOD:
+ case STRIPPED_JUNGLE_LOG:
+ case STRIPPED_JUNGLE_WOOD:
+ saplingType = Material.JUNGLE_SAPLING;
+ soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
+ break;
+ case SPRUCE_LOG:
+ case SPRUCE_WOOD:
+ case STRIPPED_SPRUCE_LOG:
+ case STRIPPED_SPRUCE_WOOD:
+ saplingType = Material.SPRUCE_SAPLING;
+ soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
+ break;
+ case ACACIA_LOG:
+ case ACACIA_WOOD:
+ case STRIPPED_ACACIA_LOG:
+ case STRIPPED_ACACIA_WOOD:
+ saplingType = Material.ACACIA_SAPLING;
+ soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
+ break;
+ case DARK_OAK_LOG:
+ case DARK_OAK_WOOD:
+ case STRIPPED_DARK_OAK_LOG:
+ case STRIPPED_DARK_OAK_WOOD:
+ saplingType = Material.DARK_OAK_SAPLING;
+ soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
+ break;
+ default:
+ break;
+ }
+
+ if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
+ switch (logType) {
+ case CRIMSON_STEM:
+ case CRIMSON_HYPHAE:
+ case STRIPPED_CRIMSON_STEM:
+ case STRIPPED_CRIMSON_HYPHAE:
+ saplingType = Material.CRIMSON_FUNGUS;
+ soilRequirement = SlimefunTag.FUNGUS_SOIL::isTagged;
+ break;
+ case WARPED_STEM:
+ case WARPED_HYPHAE:
+ case STRIPPED_WARPED_STEM:
+ case STRIPPED_WARPED_HYPHAE:
+ saplingType = Material.WARPED_FUNGUS;
+ soilRequirement = SlimefunTag.FUNGUS_SOIL::isTagged;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (saplingType != null && soilRequirement != null) {
+ if (soilRequirement.test(block.getRelative(BlockFace.DOWN).getType())) {
+ // Replant the block
+ block.setType(saplingType);
+ } else {
+ // Simply drop the sapling if the soil does not fit
+ block.getWorld().dropItemNaturally(block.getLocation(), new ItemStack(saplingType));
+ block.setType(Material.AIR);
+ }
+ }
+ }
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java
index f5800321d..445a96bc1 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/BlockPlacer.java
@@ -3,6 +3,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import java.util.List;
import java.util.UUID;
+import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Location;
@@ -10,18 +13,21 @@ import org.bukkit.Material;
import org.bukkit.Nameable;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
import org.bukkit.block.Dispenser;
import org.bukkit.entity.Player;
+import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
-import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.MaterialTagSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@@ -47,15 +53,17 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/
public class BlockPlacer extends SlimefunItem {
- private final ItemSetting> blacklist = new MaterialTagSetting("unplaceable-blocks", SlimefunTag.UNBREAKABLE_MATERIALS);
+ private final ItemSetting> unplaceableBlocks = new MaterialTagSetting("unplaceable-blocks", SlimefunTag.UNBREAKABLE_MATERIALS);
+ @ParametersAreNonnullByDefault
public BlockPlacer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
- addItemSetting(blacklist);
- addItemHandler(onPlace(), onBlockDispense());
+ addItemSetting(unplaceableBlocks);
+ addItemHandler(onPlace(), onBlockBreak(), onBlockDispense());
}
+ @Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@@ -69,6 +77,33 @@ public class BlockPlacer extends SlimefunItem {
};
}
+ @Nonnull
+ private BlockBreakHandler onBlockBreak() {
+ /*
+ * Explosions don't need explicit handling here.
+ * The default of "destroy the dispenser and drop the contents" is
+ * fine for our purposes already.
+ */
+ return new BlockBreakHandler(false, true) {
+
+ @Override
+ public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List drops) {
+ // Fixes #2852 - Manually drop inventory contents
+ Block b = e.getBlock();
+ BlockState state = PaperLib.getBlockState(b, false).getState();
+
+ if (state instanceof Dispenser) {
+ for (ItemStack stack : ((Dispenser) state).getInventory()) {
+ if (stack != null && !stack.getType().isAir()) {
+ drops.add(stack);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ @Nonnull
private BlockDispenseHandler onBlockDispense() {
return (e, dispenser, facedBlock, machine) -> {
if (!hasPermission(dispenser, facedBlock)) {
@@ -79,7 +114,7 @@ public class BlockPlacer extends SlimefunItem {
Material material = e.getItem().getType();
if (SlimefunTag.SHULKER_BOXES.isTagged(material)) {
- /**
+ /*
* Since vanilla Dispensers can already place Shulker boxes,
* we simply fallback to the vanilla behaviour.
*/
@@ -89,7 +124,7 @@ public class BlockPlacer extends SlimefunItem {
e.setCancelled(true);
if (!material.isBlock() || SlimefunTag.BLOCK_PLACER_IGNORED_MATERIALS.isTagged(material)) {
- /**
+ /*
* Some materials cannot be reliably placed, like beds,
* it would look kinda wonky, so we just ignore these altogether.
* The event has already been cancelled too, so they won't drop.
@@ -97,7 +132,7 @@ public class BlockPlacer extends SlimefunItem {
return;
}
- if (facedBlock.isEmpty() && !isBlacklisted(material) && dispenser.getInventory().getViewers().isEmpty()) {
+ if (facedBlock.isEmpty() && isAllowed(material) && dispenser.getInventory().getViewers().isEmpty()) {
SlimefunItem item = SlimefunItem.getByItem(e.getItem());
if (item != null) {
@@ -123,11 +158,12 @@ public class BlockPlacer extends SlimefunItem {
*
* @return Whether this action is permitted or not
*/
+ @ParametersAreNonnullByDefault
private boolean hasPermission(Dispenser dispenser, Block target) {
String owner = BlockStorage.getLocationInfo(dispenser.getLocation(), "owner");
if (owner == null) {
- /**
+ /*
* If no owner was set, then we will fallback to the previous behaviour:
* Allowing block placers to bypass protection, newly placed Block placers
* will respect protection plugins.
@@ -135,20 +171,30 @@ public class BlockPlacer extends SlimefunItem {
return true;
}
+ // Get the corresponding OfflinePlayer
OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(owner));
return SlimefunPlugin.getProtectionManager().hasPermission(player, target, ProtectableAction.PLACE_BLOCK);
}
- private boolean isBlacklisted(Material type) {
- for (String blockType : blacklist.getValue()) {
+ /**
+ * This checks if the given {@link Material} is allowed to be placed.
+ *
+ * @param type
+ * The {@link Material} to check
+ *
+ * @return Whether placing this {@link Material} is allowed
+ */
+ private boolean isAllowed(@Nonnull Material type) {
+ for (String blockType : unplaceableBlocks.getValue()) {
if (type.toString().equals(blockType)) {
- return true;
+ return false;
}
}
- return false;
+ return true;
}
+ @ParametersAreNonnullByDefault
private void placeSlimefunBlock(SlimefunItem sfItem, ItemStack item, Block block, Dispenser dispenser) {
BlockPlacerPlaceEvent e = new BlockPlacerPlaceEvent(dispenser.getBlock(), item, block);
Bukkit.getPluginManager().callEvent(e);
@@ -156,68 +202,78 @@ public class BlockPlacer extends SlimefunItem {
if (!e.isCancelled()) {
boolean hasItemHandler = sfItem.callItemHandler(BlockPlaceHandler.class, handler -> {
if (handler.isBlockPlacerAllowed()) {
- block.setType(item.getType());
- block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, item.getType());
+ schedulePlacement(block, dispenser.getInventory(), item, () -> {
+ block.setType(item.getType());
+ BlockStorage.store(block, sfItem.getId());
- BlockStorage.store(block, sfItem.getId());
- handler.onBlockPlacerPlace(e);
-
- if (dispenser.getInventory().containsAtLeast(item, 2)) {
- dispenser.getInventory().removeItem(new CustomItem(item, 1));
- } else {
- SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
- }
+ handler.onBlockPlacerPlace(e);
+ });
}
});
if (!hasItemHandler) {
- block.setType(item.getType());
- block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, item.getType());
-
- BlockStorage.store(block, sfItem.getId());
-
- if (dispenser.getInventory().containsAtLeast(item, 2)) {
- dispenser.getInventory().removeItem(new CustomItem(item, 1));
- } else {
- SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
- }
+ schedulePlacement(block, dispenser.getInventory(), item, () -> {
+ block.setType(item.getType());
+ BlockStorage.store(block, sfItem.getId());
+ });
}
}
}
+ @ParametersAreNonnullByDefault
private void placeBlock(ItemStack item, Block facedBlock, Dispenser dispenser) {
BlockPlacerPlaceEvent e = new BlockPlacerPlaceEvent(dispenser.getBlock(), item, facedBlock);
Bukkit.getPluginManager().callEvent(e);
if (!e.isCancelled()) {
- facedBlock.setType(item.getType());
+ schedulePlacement(facedBlock, dispenser.getInventory(), item, () -> {
+ facedBlock.setType(item.getType());
- if (item.hasItemMeta()) {
- ItemMeta meta = item.getItemMeta();
+ if (item.hasItemMeta()) {
+ ItemMeta meta = item.getItemMeta();
- if (meta.hasDisplayName()) {
- BlockStateSnapshotResult blockState = PaperLib.getBlockState(facedBlock, false);
+ if (meta.hasDisplayName()) {
+ BlockStateSnapshotResult blockState = PaperLib.getBlockState(facedBlock, false);
- if ((blockState.getState() instanceof Nameable)) {
- Nameable nameable = ((Nameable) blockState.getState());
- nameable.setCustomName(meta.getDisplayName());
+ if ((blockState.getState() instanceof Nameable)) {
+ Nameable nameable = ((Nameable) blockState.getState());
+ nameable.setCustomName(meta.getDisplayName());
- if (blockState.isSnapshot()) {
- // Update block state after changing name
- blockState.getState().update(true, false);
+ if (blockState.isSnapshot()) {
+ // Update block state after changing name
+ blockState.getState().update(true, false);
+ }
}
}
+
}
-
- }
-
- facedBlock.getWorld().playEffect(facedBlock.getLocation(), Effect.STEP_SOUND, item.getType());
-
- if (dispenser.getInventory().containsAtLeast(item, 2)) {
- dispenser.getInventory().removeItem(new CustomItem(item, 1));
- } else {
- SlimefunPlugin.runSync(() -> dispenser.getInventory().removeItem(item), 2L);
- }
+ });
}
}
+
+ @ParametersAreNonnullByDefault
+ private void schedulePlacement(Block b, Inventory inv, ItemStack item, Runnable runnable) {
+ // We need to delay this due to Dispenser-Inventory synchronization issues in Spigot.
+ SlimefunPlugin.runSync(() -> {
+ // Make sure the Block has not been occupied yet
+ if (b.isEmpty()) {
+ // Only remove 1 item.
+ ItemStack removedItem = item.clone();
+ removedItem.setAmount(1);
+
+ // Play particles
+ b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, item.getType());
+
+ // Make sure the item was actually removed (fixes #2817)
+
+ try {
+ if (inv.removeItem(removedItem).isEmpty()) {
+ runnable.run();
+ }
+ } catch (Exception x) {
+ error("An Exception was thrown while a BlockPlacer was performing its action", x);
+ }
+ }
+ }, 2L);
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java
index 9f84d8bf9..4c9a6563c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/Crucible.java
@@ -8,8 +8,10 @@ import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
+import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.Tag;
+import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Levelled;
@@ -19,6 +21,7 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
+import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@@ -30,14 +33,26 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+/**
+ * The {@link Crucible} is a machine which turns blocks into liquids.
+ * It is a very reliable source of lava and water.
+ * The liquids will accumulate over time above the machine.
+ *
+ * @author TheBusyBiscuit
+ * @author Sfiguz7
+ *
+ */
public class Crucible extends SimpleSlimefunItem implements RecipeDisplayItem {
+ private final ItemSetting allowWaterInNether = new ItemSetting<>("allow-water-in-nether", false);
private final List recipes;
+ @ParametersAreNonnullByDefault
public Crucible(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
recipes = getMachineRecipes();
+ addItemSetting(allowWaterInNether);
}
@Override
@@ -45,6 +60,7 @@ public class Crucible extends SimpleSlimefunItem implements Rec
return recipes;
}
+ @Nonnull
private List getMachineRecipes() {
List items = new LinkedList<>();
@@ -113,11 +129,11 @@ public class Crucible extends SimpleSlimefunItem implements Rec
@ParametersAreNonnullByDefault
private boolean craft(Player p, ItemStack input) {
for (int i = 0; i < recipes.size(); i += 2) {
- ItemStack convert = recipes.get(i);
+ ItemStack catalyst = recipes.get(i);
- if (SlimefunUtils.isItemSimilar(input, convert, true)) {
+ if (SlimefunUtils.isItemSimilar(input, catalyst, true)) {
ItemStack removing = input.clone();
- removing.setAmount(convert.getAmount());
+ removing.setAmount(catalyst.getAmount());
p.getInventory().removeItem(removing);
return true;
@@ -127,15 +143,31 @@ public class Crucible extends SimpleSlimefunItem implements Rec
return false;
}
- private void generateLiquid(@Nonnull Block block, boolean water) {
- if (block.getType() == (water ? Material.WATER : Material.LAVA)) {
- addLiquidLevel(block, water);
- } else if (block.getType() == (water ? Material.LAVA : Material.WATER)) {
+ /**
+ * This method starts the process of generating liquids.
+ *
+ * @param block
+ * The {@link Block} where to generate the liquid
+ * @param isWater
+ * Whether we generate water or lava.
+ */
+ private void generateLiquid(@Nonnull Block block, boolean isWater) {
+ // Fixes #2877 - If water in the nether is disabled, abort and play an effect.
+ if (isWater && block.getWorld().getEnvironment() == Environment.NETHER && !allowWaterInNether.getValue()) {
+ // We will still consume the items but won't generate water in the Nether.
+ block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getLocation().add(0.5, 0.5, 0.5), 4);
+ block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
+ return;
+ }
+
+ if (block.getType() == (isWater ? Material.WATER : Material.LAVA)) {
+ addLiquidLevel(block, isWater);
+ } else if (block.getType() == (isWater ? Material.LAVA : Material.WATER)) {
int level = ((Levelled) block.getBlockData()).getLevel();
block.setType(level == 0 || level == 8 ? Material.OBSIDIAN : Material.STONE);
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
} else {
- SlimefunPlugin.runSync(() -> placeLiquid(block, water), 50L);
+ SlimefunPlugin.runSync(() -> placeLiquid(block, isWater), 50L);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java
index 67d40365b..0e853ad6e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/HologramProjector.java
@@ -1,5 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
+import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -16,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
@@ -30,12 +34,14 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
private static final String OFFSET_PARAMETER = "offset";
+ @ParametersAreNonnullByDefault
public HologramProjector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
addItemHandler(onPlace(), onRightClick(), onBreak());
}
+ @Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@@ -52,13 +58,18 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
};
}
+ @Nonnull
private BlockBreakHandler onBreak() {
- return (e, item, fortune, drops) -> {
- remove(e.getBlock());
- return true;
+ return new SimpleBlockBreakHandler() {
+
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ remove(b);
+ }
};
}
+ @Nonnull
public BlockUseHandler onRightClick() {
return e -> {
e.cancel();
@@ -72,7 +83,7 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
};
}
- private static void openEditor(Player p, Block projector) {
+ private static void openEditor(@Nonnull Player p, @Nonnull Block projector) {
ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocalization().getMessage(p, "machines.HOLOGRAM_PROJECTOR.inventory-title"));
menu.addItem(0, new CustomItem(Material.NAME_TAG, "&7Text &e(Click to edit)", "", "&r" + ChatColors.color(BlockStorage.getLocationInfo(projector.getLocation(), "text"))));
@@ -105,7 +116,7 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
menu.open(p);
}
- private static ArmorStand getArmorStand(Block projector, boolean createIfNoneExists) {
+ private static ArmorStand getArmorStand(@Nonnull Block projector, boolean createIfNoneExists) {
String nametag = BlockStorage.getLocationInfo(projector.getLocation(), "text");
double offset = Double.parseDouble(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER));
Location l = new Location(projector.getWorld(), projector.getX() + 0.5, projector.getY() + offset, projector.getZ() + 0.5);
@@ -129,7 +140,7 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
return hologram;
}
- private static void remove(Block b) {
+ private static void remove(@Nonnull Block b) {
ArmorStand hologram = getArmorStand(b, false);
if (hologram != null) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/IgnitionChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/IgnitionChamber.java
new file mode 100644
index 000000000..d2a558362
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/IgnitionChamber.java
@@ -0,0 +1,62 @@
+package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
+
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.Dropper;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.inventory.ItemStack;
+
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
+import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
+import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.Smeltery;
+import io.papermc.lib.PaperLib;
+import me.mrCookieSlime.Slimefun.Lists.RecipeType;
+import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+
+/**
+ * The {@link IgnitionChamber} is used to re-ignite a {@link Smeltery}.
+ *
+ * @author TheBusyBiscuit
+ *
+ * @see Smeltery
+ *
+ */
+public class IgnitionChamber extends SimpleSlimefunItem {
+
+ @ParametersAreNonnullByDefault
+ public IgnitionChamber(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ super(category, item, recipeType, recipe);
+ }
+
+ @Override
+ public BlockBreakHandler getItemHandler() {
+ /*
+ * Explosions don't need explicit handling here.
+ * The default of "destroy the dispenser and drop the contents" is
+ * fine for our purposes already.
+ */
+ return new BlockBreakHandler(false, true) {
+
+ @Override
+ public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List drops) {
+ // Fixes #2856 - Manually drop inventory contents
+ Block b = e.getBlock();
+ BlockState state = PaperLib.getBlockState(b, false).getState();
+
+ if (state instanceof Dropper) {
+ for (ItemStack stack : ((Dropper) state).getInventory()) {
+ if (stack != null && !stack.getType().isAir()) {
+ drops.add(stack);
+ }
+ }
+ }
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/OutputChest.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/OutputChest.java
new file mode 100644
index 000000000..931ad4180
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/OutputChest.java
@@ -0,0 +1,63 @@
+package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
+
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.Chest;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.inventory.ItemStack;
+
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
+import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine;
+import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
+import io.papermc.lib.PaperLib;
+import me.mrCookieSlime.Slimefun.Lists.RecipeType;
+import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+
+/**
+ * The {@link OutputChest} can be used to capture the output items from a {@link MultiBlockMachine}.
+ *
+ * @author TheBusyBiscuit
+ *
+ * @see MultiBlockMachine
+ *
+ */
+public class OutputChest extends SimpleSlimefunItem {
+
+ @ParametersAreNonnullByDefault
+ public OutputChest(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ super(category, item, recipeType, recipe);
+ }
+
+ @Override
+ public BlockBreakHandler getItemHandler() {
+ /*
+ * Explosions don't need explicit handling here.
+ * The default of "destroy the chest and drop the contents" is
+ * fine for our purposes already.
+ */
+ return new BlockBreakHandler(false, true) {
+
+ @Override
+ public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List drops) {
+ // Fixes #2849 - Manually drop inventory contents
+ Block b = e.getBlock();
+ BlockState state = PaperLib.getBlockState(b, false).getState();
+
+ if (state instanceof Chest) {
+ // Fixes #2851 - Only drop the actual BlockInventory
+ for (ItemStack stack : ((Chest) state).getBlockInventory()) {
+ if (stack != null && !stack.getType().isAir()) {
+ drops.add(stack);
+ }
+ }
+ }
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java
index b06e8668f..7145619be 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/AbstractFilterNode.java
@@ -11,7 +11,9 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
@@ -39,15 +41,27 @@ abstract class AbstractFilterNode extends AbstractCargoNode {
public AbstractFilterNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
- registerBlockHandler(getId(), (p, b, stack, reason) -> {
- BlockMenu inv = BlockStorage.getInventory(b);
+ addItemHandler(onBreak());
+ }
- if (inv != null) {
- inv.dropItems(b.getLocation(), SLOTS);
+ @Override
+ public boolean hasItemFilter() {
+ return true;
+ }
+
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new SimpleBlockBreakHandler() {
+
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ BlockMenu inv = BlockStorage.getInventory(b);
+
+ if (inv != null) {
+ inv.dropItems(b.getLocation(), SLOTS);
+ }
}
-
- return true;
- });
+ };
}
@Nonnull
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java
index 508d70ddd..979c6c0d5 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java
@@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
import java.util.Optional;
+import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.ChatColor;
@@ -11,8 +12,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
@@ -27,10 +30,18 @@ public class CargoManager extends SlimefunItem implements HologramOwner {
public CargoManager(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
- registerBlockHandler(getId(), (p, b, tool, reason) -> {
- removeHologram(b);
- return true;
- });
+ addItemHandler(onBreak());
+ }
+
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new SimpleBlockBreakHandler() {
+
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ removeHologram(b);
+ }
+ };
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java
index c5828d573..0c2fc06bb 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoNode.java
@@ -14,7 +14,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
* @author TheBusyBiscuit
*
*/
-@FunctionalInterface
public interface CargoNode {
/**
@@ -27,4 +26,11 @@ public interface CargoNode {
*/
int getSelectedChannel(@Nonnull Block b);
+ /**
+ * This returns whether this {@link CargoNode} has item filtering capabilities.
+ *
+ * @return Whether this {@link CargoNode} can filter items
+ */
+ boolean hasItemFilter();
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java
index 6d33b69e2..bfaefdcfc 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoOutputNode.java
@@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -18,10 +20,16 @@ public class CargoOutputNode extends AbstractCargoNode {
private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
+ @ParametersAreNonnullByDefault
public CargoOutputNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
}
+ @Override
+ public boolean hasItemFilter() {
+ return false;
+ }
+
@Override
protected void onPlace(BlockPlaceEvent e) {
// We only require the default values
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java
index e1bada9b5..599828883 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/ReactorAccessPort.java
@@ -12,9 +12,11 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.CoolantCell;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@@ -50,6 +52,8 @@ public class ReactorAccessPort extends SlimefunItem {
public ReactorAccessPort(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
+ addItemHandler(onBreak());
+
new BlockMenuPreset(getId(), "&2Reactor Access Port") {
@Override
@@ -108,18 +112,23 @@ public class ReactorAccessPort extends SlimefunItem {
}
}
};
+ }
- registerBlockHandler(getId(), (p, b, tool, reason) -> {
- BlockMenu inv = BlockStorage.getInventory(b);
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new SimpleBlockBreakHandler() {
- if (inv != null) {
- inv.dropItems(b.getLocation(), getFuelSlots());
- inv.dropItems(b.getLocation(), getCoolantSlots());
- inv.dropItems(b.getLocation(), getOutputSlots());
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ BlockMenu inv = BlockStorage.getInventory(b);
+
+ if (inv != null) {
+ inv.dropItems(b.getLocation(), getFuelSlots());
+ inv.dropItems(b.getLocation(), getCoolantSlots());
+ inv.dropItems(b.getLocation(), getOutputSlots());
+ }
}
-
- return true;
- });
+ };
}
private void constructMenu(@Nonnull BlockMenuPreset preset) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java
index f8735c063..3ab81a185 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java
@@ -9,8 +9,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
@@ -34,10 +36,18 @@ public class EnergyRegulator extends SlimefunItem implements HologramOwner {
public EnergyRegulator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
- SlimefunItem.registerBlockHandler(getId(), (p, b, stack, reason) -> {
- removeHologram(b);
- return true;
- });
+ addItemHandler(onBreak());
+ }
+
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new SimpleBlockBreakHandler() {
+
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ removeHologram(b);
+ }
+ };
}
@Nonnull
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java
index 4e0e59903..4494fb95c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/gadgets/MultiTool.java
@@ -110,14 +110,14 @@ public class MultiTool extends SlimefunItem implements Rechargeable {
return (e, item, offhand) -> {
// Fixes #2217 - Prevent them from being used to shear entities
switch (e.getRightClicked().getType()) {
- case MUSHROOM_COW:
- case SHEEP:
- case SNOWMAN:
- SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears");
- e.setCancelled(true);
- break;
- default:
- break;
+ case MUSHROOM_COW:
+ case SHEEP:
+ case SNOWMAN:
+ SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.multi-tool.not-shears");
+ e.setCancelled(true);
+ break;
+ default:
+ break;
}
};
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java
index 065f57e1c..dbc7c49ee 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractGrowthAccelerator.java
@@ -2,84 +2,25 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine
import javax.annotation.ParametersAreNonnullByDefault;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
-import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
-import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
-import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
-import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
-import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
-import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
-import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
-public abstract class AbstractGrowthAccelerator extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
-
- private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
+/**
+ * This has been moved.
+ *
+ * @deprecated Moved to
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AbstractGrowthAccelerator}
+ *
+ */
+@Deprecated
+public abstract class AbstractGrowthAccelerator extends io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AbstractGrowthAccelerator {
@ParametersAreNonnullByDefault
public AbstractGrowthAccelerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
-
- createPreset(this, this::constructMenu);
-
- registerBlockHandler(getId(), (p, b, tool, reason) -> {
- BlockMenu inv = BlockStorage.getInventory(b);
-
- if (inv != null) {
- inv.dropItems(b.getLocation(), getInputSlots());
- }
-
- return true;
- });
}
- private void constructMenu(BlockMenuPreset preset) {
- for (int i : BORDER) {
- preset.addItem(i, new CustomItem(Material.CYAN_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler());
- }
- }
-
- @Override
- public EnergyNetComponentType getEnergyComponentType() {
- return EnergyNetComponentType.CONSUMER;
- }
-
- @Override
- public int[] getInputSlots() {
- return new int[] { 10, 11, 12, 13, 14, 15, 16 };
- }
-
- @Override
- public int[] getOutputSlots() {
- return new int[0];
- }
-
- @Override
- public void preRegister() {
- super.preRegister();
- addItemHandler(new BlockTicker() {
-
- @Override
- public void tick(Block b, SlimefunItem sf, Config data) {
- AbstractGrowthAccelerator.this.tick(b);
- }
-
- @Override
- public boolean isSynchronized() {
- return true;
- }
- });
- }
-
- protected abstract void tick(Block b);
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java
index 45ca141b7..ec01e2299 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoDisenchanter.java
@@ -1,140 +1,26 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.EnchantmentStorageMeta;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.Repairable;
-import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
-import io.github.thebusybiscuit.slimefun4.api.events.AutoDisenchantEvent;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
/**
- * The {@link AutoDisenchanter}, in contrast to the {@link AutoEnchanter}, removes
- * {@link Enchantment Enchantments} from a given {@link ItemStack} and transfers them
- * to a book.
+ * This has been moved.
*
- * @author TheBusyBiscuit
- * @author Walshy
- * @author poma123
- *
- * @see AutoEnchanter
+ * @deprecated Moved to
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter}
*
*/
-public class AutoDisenchanter extends AContainer {
+@Deprecated
+public class AutoDisenchanter extends io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter {
@ParametersAreNonnullByDefault
public AutoDisenchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
- @Override
- public ItemStack getProgressBar() {
- return new ItemStack(Material.DIAMOND_CHESTPLATE);
- }
-
- @Override
- protected MachineRecipe findNextRecipe(BlockMenu menu) {
- Map enchantments = new HashMap<>();
-
- for (int slot : getInputSlots()) {
- ItemStack item = menu.getItemInSlot(slot);
-
- if (!isDisenchantable(item)) {
- return null;
- }
-
- AutoDisenchantEvent event = new AutoDisenchantEvent(item);
- Bukkit.getPluginManager().callEvent(event);
-
- if (event.isCancelled()) {
- return null;
- }
-
- ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
-
- // Disenchanting
- if (target != null && target.getType() == Material.BOOK) {
- int amount = 0;
-
- for (Map.Entry entry : item.getEnchantments().entrySet()) {
- enchantments.put(entry.getKey(), entry.getValue());
- amount++;
- }
-
- if (amount > 0) {
- ItemStack disenchantedItem = item.clone();
- disenchantedItem.setAmount(1);
-
- ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
- transferEnchantments(disenchantedItem, book, enchantments);
-
- MachineRecipe recipe = new MachineRecipe(90 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { disenchantedItem, book });
-
- if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
- return null;
- }
-
- for (int inputSlot : getInputSlots()) {
- menu.consumeItem(inputSlot);
- }
-
- return recipe;
- }
- }
- }
-
- return null;
- }
-
- private void transferEnchantments(ItemStack item, ItemStack book, Map enchantments) {
- ItemMeta itemMeta = item.getItemMeta();
- ItemMeta bookMeta = book.getItemMeta();
- ((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost());
- ((Repairable) itemMeta).setRepairCost(0);
- item.setItemMeta(itemMeta);
- book.setItemMeta(bookMeta);
-
- EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta();
-
- for (Map.Entry entry : enchantments.entrySet()) {
- item.removeEnchantment(entry.getKey());
- meta.addStoredEnchant(entry.getKey(), entry.getValue(), true);
- }
-
- book.setItemMeta(meta);
- }
-
- private boolean isDisenchantable(@Nullable ItemStack item) {
- if (item == null) {
- return false;
- } else if (item.getType() != Material.BOOK) {
- // ^ This stops endless checks of getByItem for books
- SlimefunItem sfItem = SlimefunItem.getByItem(item);
- return sfItem == null || sfItem.isDisenchantable();
- } else {
- return true;
- }
- }
-
- @Override
- public String getMachineIdentifier() {
- return "AUTO_DISENCHANTER";
- }
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java
index e1550792e..d55af6b1b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoEnchanter.java
@@ -1,102 +1,26 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
-import java.util.HashMap;
-import java.util.Map;
-
import javax.annotation.ParametersAreNonnullByDefault;
-import org.bukkit.Material;
-import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.EnchantmentStorageMeta;
-import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
-public class AutoEnchanter extends AContainer {
+/**
+ * This has been moved.
+ *
+ * @deprecated Moved to
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter}
+ *
+ */
+@Deprecated
+public class AutoEnchanter extends io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter {
@ParametersAreNonnullByDefault
public AutoEnchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
- @Override
- public ItemStack getProgressBar() {
- return new ItemStack(Material.GOLDEN_CHESTPLATE);
- }
-
- @Override
- protected MachineRecipe findNextRecipe(BlockMenu menu) {
- for (int slot : getInputSlots()) {
- ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
-
- // Check if the item is enchantable
- if (!isEnchantable(target)) {
- return null;
- }
-
- ItemStack item = menu.getItemInSlot(slot);
-
- if (item != null && item.getType() == Material.ENCHANTED_BOOK && target != null) {
- Map enchantments = new HashMap<>();
- int amount = 0;
- EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta();
-
- for (Map.Entry e : meta.getStoredEnchants().entrySet()) {
- if (e.getKey().canEnchantItem(target)) {
- amount++;
- enchantments.put(e.getKey(), e.getValue());
- }
- }
-
- if (amount > 0) {
- ItemStack enchantedItem = target.clone();
- enchantedItem.setAmount(1);
-
- for (Map.Entry entry : enchantments.entrySet()) {
- enchantedItem.addUnsafeEnchantment(entry.getKey(), entry.getValue());
- }
-
- MachineRecipe recipe = new MachineRecipe(75 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { enchantedItem, new ItemStack(Material.BOOK) });
-
- if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
- return null;
- }
-
- for (int inputSlot : getInputSlots()) {
- menu.consumeItem(inputSlot);
- }
-
- return recipe;
- }
-
- return null;
- }
- }
-
- return null;
- }
-
- private boolean isEnchantable(ItemStack item) {
- SlimefunItem sfItem = null;
-
- // stops endless checks of getByItem for enchanted book stacks.
- if (item != null && item.getType() != Material.ENCHANTED_BOOK) {
- sfItem = SlimefunItem.getByItem(item);
- }
-
- return sfItem == null || sfItem.isEnchantable();
- }
-
- @Override
- public String getMachineIdentifier() {
- return "AUTO_ENCHANTER";
- }
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java
index 93031d45c..69295f738 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutomatedCraftingChamber.java
@@ -7,6 +7,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@@ -57,10 +60,11 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
private final Map craftingRecipes = new HashMap<>();
+ @ParametersAreNonnullByDefault
public AutomatedCraftingChamber(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
- new BlockMenuPreset(getId(), "&6Automated Crafting Chamber") {
+ new BlockMenuPreset(getId(), "&4Deprecated item. Do not use.") {
@Override
public void init() {
@@ -94,6 +98,7 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
@Override
public boolean canOpen(Block b, Player p) {
+ p.sendMessage(ChatColor.DARK_RED + "This item has been deprecated. It will be removed soon!");
return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK);
}
@@ -145,6 +150,7 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
@Override
public void onPlayerPlace(BlockPlaceEvent e) {
+ e.getPlayer().sendMessage(ChatColor.DARK_RED + "This item has been deprecated. It will be removed soon!");
BlockStorage.addBlockInfo(e.getBlock(), "enabled", String.valueOf(false));
}
@@ -308,4 +314,4 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
craftingRecipes.put(builder.toString(), RecipeType.getRecipeOutputList(machine, inputs));
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AbstractGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AbstractGrowthAccelerator.java
new file mode 100644
index 000000000..e7e57a2ea
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AbstractGrowthAccelerator.java
@@ -0,0 +1,85 @@
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.inventory.ItemStack;
+
+import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
+import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
+import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
+import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
+import me.mrCookieSlime.Slimefun.Lists.RecipeType;
+import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
+import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
+import me.mrCookieSlime.Slimefun.api.BlockStorage;
+import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
+import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
+
+public abstract class AbstractGrowthAccelerator extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
+
+ private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
+
+ @ParametersAreNonnullByDefault
+ public AbstractGrowthAccelerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ super(category, item, recipeType, recipe);
+
+ createPreset(this, this::constructMenu);
+
+ registerBlockHandler(getId(), (p, b, tool, reason) -> {
+ BlockMenu inv = BlockStorage.getInventory(b);
+
+ if (inv != null) {
+ inv.dropItems(b.getLocation(), getInputSlots());
+ }
+
+ return true;
+ });
+ }
+
+ private void constructMenu(BlockMenuPreset preset) {
+ for (int i : BORDER) {
+ preset.addItem(i, new CustomItem(Material.CYAN_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler());
+ }
+ }
+
+ @Override
+ public EnergyNetComponentType getEnergyComponentType() {
+ return EnergyNetComponentType.CONSUMER;
+ }
+
+ @Override
+ public int[] getInputSlots() {
+ return new int[] { 10, 11, 12, 13, 14, 15, 16 };
+ }
+
+ @Override
+ public int[] getOutputSlots() {
+ return new int[0];
+ }
+
+ @Override
+ public void preRegister() {
+ super.preRegister();
+ addItemHandler(new BlockTicker() {
+
+ @Override
+ public void tick(Block b, SlimefunItem sf, Config data) {
+ AbstractGrowthAccelerator.this.tick(b);
+ }
+
+ @Override
+ public boolean isSynchronized() {
+ return true;
+ }
+ });
+ }
+
+ protected abstract void tick(Block b);
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java
similarity index 98%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java
index c8e774573..1629bc8bf 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/AnimalGrowthAccelerator.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import org.bukkit.Particle;
import org.bukkit.block.Block;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/CropGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java
similarity index 98%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/CropGrowthAccelerator.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java
index f132a751b..893f3d070 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/CropGrowthAccelerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/CropGrowthAccelerator.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import org.bukkit.Particle;
import org.bukkit.block.Block;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/TreeGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java
similarity index 98%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/TreeGrowthAccelerator.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java
index 5e3b21ba2..b3ef10fb6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/TreeGrowthAccelerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/TreeGrowthAccelerator.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
import org.bukkit.Particle;
import org.bukkit.Tag;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/package-info.java
new file mode 100644
index 000000000..96accec69
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/accelerators/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This package contains any electric machines related to growth accelerations.
+ * These growth accelerators speed up the growth of animals or plants.
+ */
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators;
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoDisenchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoDisenchanter.java
new file mode 100644
index 000000000..7af3f137f
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoDisenchanter.java
@@ -0,0 +1,140 @@
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.EnchantmentStorageMeta;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.Repairable;
+
+import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
+import io.github.thebusybiscuit.slimefun4.api.events.AutoDisenchantEvent;
+import me.mrCookieSlime.Slimefun.Lists.RecipeType;
+import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
+import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
+
+/**
+ * The {@link AutoDisenchanter}, in contrast to the {@link AutoEnchanter}, removes
+ * {@link Enchantment Enchantments} from a given {@link ItemStack} and transfers them
+ * to a book.
+ *
+ * @author TheBusyBiscuit
+ * @author Walshy
+ * @author poma123
+ *
+ * @see AutoEnchanter
+ *
+ */
+public class AutoDisenchanter extends AContainer {
+
+ @ParametersAreNonnullByDefault
+ public AutoDisenchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ super(category, item, recipeType, recipe);
+ }
+
+ @Override
+ public ItemStack getProgressBar() {
+ return new ItemStack(Material.DIAMOND_CHESTPLATE);
+ }
+
+ @Override
+ protected MachineRecipe findNextRecipe(BlockMenu menu) {
+ Map enchantments = new HashMap<>();
+
+ for (int slot : getInputSlots()) {
+ ItemStack item = menu.getItemInSlot(slot);
+
+ if (!isDisenchantable(item)) {
+ return null;
+ }
+
+ AutoDisenchantEvent event = new AutoDisenchantEvent(item);
+ Bukkit.getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return null;
+ }
+
+ ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
+
+ // Disenchanting
+ if (target != null && target.getType() == Material.BOOK) {
+ int amount = 0;
+
+ for (Map.Entry entry : item.getEnchantments().entrySet()) {
+ enchantments.put(entry.getKey(), entry.getValue());
+ amount++;
+ }
+
+ if (amount > 0) {
+ ItemStack disenchantedItem = item.clone();
+ disenchantedItem.setAmount(1);
+
+ ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
+ transferEnchantments(disenchantedItem, book, enchantments);
+
+ MachineRecipe recipe = new MachineRecipe(90 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { disenchantedItem, book });
+
+ if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
+ return null;
+ }
+
+ for (int inputSlot : getInputSlots()) {
+ menu.consumeItem(inputSlot);
+ }
+
+ return recipe;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private void transferEnchantments(ItemStack item, ItemStack book, Map enchantments) {
+ ItemMeta itemMeta = item.getItemMeta();
+ ItemMeta bookMeta = book.getItemMeta();
+ ((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost());
+ ((Repairable) itemMeta).setRepairCost(0);
+ item.setItemMeta(itemMeta);
+ book.setItemMeta(bookMeta);
+
+ EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta();
+
+ for (Map.Entry entry : enchantments.entrySet()) {
+ item.removeEnchantment(entry.getKey());
+ meta.addStoredEnchant(entry.getKey(), entry.getValue(), true);
+ }
+
+ book.setItemMeta(meta);
+ }
+
+ private boolean isDisenchantable(@Nullable ItemStack item) {
+ if (item == null) {
+ return false;
+ } else if (item.getType() != Material.BOOK) {
+ // ^ This stops endless checks of getByItem for books
+ SlimefunItem sfItem = SlimefunItem.getByItem(item);
+ return sfItem == null || sfItem.isDisenchantable();
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public String getMachineIdentifier() {
+ return "AUTO_DISENCHANTER";
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java
new file mode 100644
index 000000000..637f6ddf7
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AutoEnchanter.java
@@ -0,0 +1,102 @@
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.EnchantmentStorageMeta;
+
+import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
+import me.mrCookieSlime.Slimefun.Lists.RecipeType;
+import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
+import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
+
+public class AutoEnchanter extends AContainer {
+
+ @ParametersAreNonnullByDefault
+ public AutoEnchanter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ super(category, item, recipeType, recipe);
+ }
+
+ @Override
+ public ItemStack getProgressBar() {
+ return new ItemStack(Material.GOLDEN_CHESTPLATE);
+ }
+
+ @Override
+ protected MachineRecipe findNextRecipe(BlockMenu menu) {
+ for (int slot : getInputSlots()) {
+ ItemStack target = menu.getItemInSlot(slot == getInputSlots()[0] ? getInputSlots()[1] : getInputSlots()[0]);
+
+ // Check if the item is enchantable
+ if (!isEnchantable(target)) {
+ return null;
+ }
+
+ ItemStack item = menu.getItemInSlot(slot);
+
+ if (item != null && item.getType() == Material.ENCHANTED_BOOK && target != null) {
+ Map enchantments = new HashMap<>();
+ int amount = 0;
+ EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta();
+
+ for (Map.Entry e : meta.getStoredEnchants().entrySet()) {
+ if (e.getKey().canEnchantItem(target)) {
+ amount++;
+ enchantments.put(e.getKey(), e.getValue());
+ }
+ }
+
+ if (amount > 0) {
+ ItemStack enchantedItem = target.clone();
+ enchantedItem.setAmount(1);
+
+ for (Map.Entry entry : enchantments.entrySet()) {
+ enchantedItem.addUnsafeEnchantment(entry.getKey(), entry.getValue());
+ }
+
+ MachineRecipe recipe = new MachineRecipe(75 * amount / this.getSpeed(), new ItemStack[] { target, item }, new ItemStack[] { enchantedItem, new ItemStack(Material.BOOK) });
+
+ if (!InvUtils.fitAll(menu.toInventory(), recipe.getOutput(), getOutputSlots())) {
+ return null;
+ }
+
+ for (int inputSlot : getInputSlots()) {
+ menu.consumeItem(inputSlot);
+ }
+
+ return recipe;
+ }
+
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean isEnchantable(ItemStack item) {
+ SlimefunItem sfItem = null;
+
+ // stops endless checks of getByItem for enchanted book stacks.
+ if (item != null && item.getType() != Material.ENCHANTED_BOOK) {
+ sfItem = SlimefunItem.getByItem(item);
+ }
+
+ return sfItem == null || sfItem.isEnchantable();
+ }
+
+ @Override
+ public String getMachineIdentifier() {
+ return "AUTO_ENCHANTER";
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/BookBinder.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java
similarity index 80%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/BookBinder.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java
index 5f8355715..009c75ea4 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/BookBinder.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
import java.util.HashMap;
import java.util.Map;
@@ -54,6 +54,7 @@ public class BookBinder extends AContainer {
Map storedTargetEnchantments = targetMeta.getStoredEnchants();
Map enchantments = combineEnchantments(storedItemEnchantments, storedTargetEnchantments);
+ // Just return if no enchantments exist. This shouldn't ever happen. :NotLikeThis:
if (enchantments.size() > 0) {
ItemStack book = new ItemStack(Material.ENCHANTED_BOOK);
@@ -63,6 +64,11 @@ public class BookBinder extends AContainer {
enchantMeta.addStoredEnchant(entry.getKey(), entry.getValue(), bypassVanillaMaxLevel.getValue());
}
+ // Make sure we never return an enchanted book with no enchantments.
+ if (enchantMeta.getStoredEnchants().isEmpty()) {
+ return null;
+ }
+
book.setItemMeta(enchantMeta);
MachineRecipe recipe = new MachineRecipe(25 * (enchantments.size() / this.getSpeed()), new ItemStack[] { target, item }, new ItemStack[] { book });
@@ -109,15 +115,25 @@ public class BookBinder extends AContainer {
for (Map.Entry entry : ech2.entrySet()) {
for (Map.Entry conflictsWith : enchantments.entrySet()) {
- if (entry.getKey().conflictsWith(conflictsWith.getKey())) {
+
+ // Check if entry enchantment and conflictsWith enchantment conflict, and confirm that the enchantsments
+ // aren't the exact same.
+ if (entry.getKey().conflictsWith(conflictsWith.getKey()) && !entry.getKey().equals(conflictsWith.getKey())) {
conflicts = true;
}
}
if (!conflicts) {
enchantments.merge(entry.getKey(), entry.getValue(), (a, b) -> {
+ int enchantMaxLevel = entry.getKey().getMaxLevel();
+
if (a.intValue() == b.intValue()) {
- if (hasCustomMaxLevel.getValue()) {
+
+ // Confirm the entry's enchant level doesn't go over the maximum unless it uses
+ // bypass-vanilla-max-level
+ if (enchantMaxLevel <= a && !bypassVanillaMaxLevel.getValue()) {
+ return enchantMaxLevel;
+ } else if (hasCustomMaxLevel.getValue()) {
return a + 1 > customMaxLevel.getValue() ? customMaxLevel.getValue() : a + 1;
} else {
return a + 1;
@@ -125,7 +141,11 @@ public class BookBinder extends AContainer {
} else {
int highestLevel = Math.max(a, b);
- if (hasCustomMaxLevel.getValue()) {
+ // Confirm the entry's enchant level doesn't go over the maximum unless it uses
+ // bypass-vanilla-max-level
+ if (enchantMaxLevel <= highestLevel && !bypassVanillaMaxLevel.getValue()) {
+ return enchantMaxLevel;
+ } else if (hasCustomMaxLevel.getValue()) {
return highestLevel > customMaxLevel.getValue() ? customMaxLevel.getValue() : highestLevel;
} else {
return highestLevel;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/package-info.java
new file mode 100644
index 000000000..b4e98ffd6
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * This package contains any electric machines related to enchanting.
+ * Prominent examples are the
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter} and
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter}
+ */
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/AbstractEntityAssembler.java
similarity index 99%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/AbstractEntityAssembler.java
index 8c9959b58..1f887237f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AbstractEntityAssembler.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/AbstractEntityAssembler.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import org.bukkit.Effect;
import org.bukkit.Location;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/XPCollector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java
similarity index 94%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/XPCollector.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java
index ea96f836a..d9aeb5f5d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/XPCollector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.Iterator;
@@ -25,14 +25,14 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
-public class XPCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
+public class ExpCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent {
private final int[] border = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
private static final int ENERGY_CONSUMPTION = 10;
private static final String DATA_KEY = "stored-exp";
- public XPCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ public ExpCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
createPreset(this, this::constructMenu);
@@ -91,7 +91,7 @@ public class XPCollector extends SlimefunItem implements InventoryBlock, EnergyN
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
- XPCollector.this.tick(b);
+ ExpCollector.this.tick(b);
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/IronGolemAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/IronGolemAssembler.java
similarity index 98%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/IronGolemAssembler.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/IronGolemAssembler.java
index 71426fc7d..398b23f8b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/IronGolemAssembler.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/IronGolemAssembler.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import org.bukkit.Location;
import org.bukkit.Material;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/WitherAssembler.java
similarity index 98%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/WitherAssembler.java
index 07b4c34e2..51801cd37 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/WitherAssembler.java
@@ -1,4 +1,4 @@
-package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import org.bukkit.Location;
import org.bukkit.Material;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/package-info.java
new file mode 100644
index 000000000..d7723caf7
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package contains any electric machines related to {@link org.bukkit.entity.Entity} interactions, most notably
+ * the
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.AbstractEntityAssembler}.
+ */
+package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java
index 58c594f2e..2bf988182 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/reactors/Reactor.java
@@ -24,10 +24,12 @@ import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.events.ReactorExplodeEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.core.attributes.Processor;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.machines.FuelOperation;
import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.ReactorAccessPort;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.AbstractEnergyProvider;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@@ -73,7 +75,6 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram
private static final int[] border_4 = { 25, 34, 43 };
private final Set explosionsQueue = new HashSet<>();
-
private final MachineProcessor processor = new MachineProcessor<>();
@ParametersAreNonnullByDefault
@@ -109,20 +110,7 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram
}
};
- registerBlockHandler(getId(), (p, b, tool, reason) -> {
- BlockMenu inv = BlockStorage.getInventory(b);
-
- if (inv != null) {
- inv.dropItems(b.getLocation(), getFuelSlots());
- inv.dropItems(b.getLocation(), getCoolantSlots());
- inv.dropItems(b.getLocation(), getOutputSlots());
- }
-
- processor.removeOperation(b);
- removeHologram(b);
- return true;
- });
-
+ addItemHandler(onBreak());
registerDefaultFuelTypes();
}
@@ -131,6 +119,26 @@ public abstract class Reactor extends AbstractEnergyProvider implements Hologram
return processor;
}
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new SimpleBlockBreakHandler() {
+
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ BlockMenu inv = BlockStorage.getInventory(b);
+
+ if (inv != null) {
+ inv.dropItems(b.getLocation(), getFuelSlots());
+ inv.dropItems(b.getLocation(), getCoolantSlots());
+ inv.dropItems(b.getLocation(), getOutputSlots());
+ }
+
+ processor.removeOperation(b);
+ removeHologram(b);
+ }
+ };
+ }
+
protected void updateInventory(@Nonnull BlockMenu menu, @Nonnull Block b) {
ReactorMode mode = getReactorMode(b.getLocation());
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
index a0dc9eb4c..05b151298 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
@@ -21,12 +21,15 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.core.attributes.Processor;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor;
import io.github.thebusybiscuit.slimefun4.core.machines.MiningOperation;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
+// github.com/Slimefun/Slimefun4.git
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
@@ -56,20 +59,10 @@ public class GEOMiner extends SlimefunItem implements RecipeDisplayItem, EnergyN
processor.setProgressBar(new ItemStack(Material.DIAMOND_PICKAXE));
createPreset(this, getItemName(), this::constructMenu);
- addItemHandler(onPlace());
+ addItemHandler(onPlace(), onBreak());
- registerBlockHandler(getId(), (p, b, stack, reason) -> {
- removeHologram(b);
-
- BlockMenu inv = BlockStorage.getInventory(b);
-
- if (inv != null) {
- inv.dropItems(b.getLocation(), OUTPUT_SLOTS);
- }
-
- getMachineProcessor().removeOperation(b);
- return true;
- });
+ // Unregister the Block handler from AContainer (Fixes #2861)
+ registerBlockHandler(getId(), null);
}
@Override
@@ -88,6 +81,24 @@ public class GEOMiner extends SlimefunItem implements RecipeDisplayItem, EnergyN
};
}
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new SimpleBlockBreakHandler() {
+
+ @Override
+ public void onBlockBreak(@Nonnull Block b) {
+ removeHologram(b);
+ BlockMenu inv = BlockStorage.getInventory(b);
+
+ if (inv != null) {
+ inv.dropItems(b.getLocation(), OUTPUT_SLOTS);
+ }
+
+ processor.removeOperation(b);
+ }
+ };
+ }
+
@Override
public List getDisplayRecipes() {
List displayRecipes = new LinkedList<>();
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java
index ecdf45d34..b47aeb4dd 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java
@@ -1,12 +1,19 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.gps;
+import java.util.List;
import java.util.UUID;
+import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.bukkit.Location;
import org.bukkit.block.Block;
+import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@@ -23,16 +30,12 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem imp
private final int capacity;
+ @ParametersAreNonnullByDefault
public GPSTransmitter(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
this.capacity = 4 << (2 * tier);
- addItemHandler(onPlace());
- registerBlockHandler(getId(), (p, b, stack, reason) -> {
- UUID owner = UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner"));
- SlimefunPlugin.getGPSNetwork().updateTransmitter(b.getLocation(), owner, false);
- return true;
- });
+ addItemHandler(onPlace(), onBreak());
}
@Override
@@ -40,6 +43,7 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem imp
return capacity;
}
+ @Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@@ -50,6 +54,19 @@ public abstract class GPSTransmitter extends SimpleSlimefunItem imp
};
}
+ @Nonnull
+ private BlockBreakHandler onBreak() {
+ return new BlockBreakHandler(false, false) {
+
+ @Override
+ public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List drops) {
+ Location l = e.getBlock().getLocation();
+ UUID owner = UUID.fromString(BlockStorage.getLocationInfo(l, "owner"));
+ SlimefunPlugin.getGPSNetwork().updateTransmitter(l, owner, false);
+ }
+ };
+ }
+
public abstract int getMultiplier(int y);
public abstract int getEnergyConsumption();
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java
index 4ca91cec6..1ba0242f7 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/EnchantmentRune.java
@@ -9,6 +9,9 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
+import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
@@ -25,7 +28,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunIte
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@@ -42,6 +44,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
private static final double RANGE = 1.5;
private final Map> applicableEnchantments = new EnumMap<>(Material.class);
+ @ParametersAreNonnullByDefault
public EnchantmentRune(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
@@ -49,7 +52,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
List enchantments = new ArrayList<>();
for (Enchantment enchantment : Enchantment.values()) {
- if (enchantment == Enchantment.BINDING_CURSE || enchantment == Enchantment.VANISHING_CURSE) {
+ if (enchantment.equals(Enchantment.BINDING_CURSE) || enchantment.equals(Enchantment.VANISHING_CURSE)) {
continue;
}
@@ -66,7 +69,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
public ItemDropHandler getItemHandler() {
return (e, p, item) -> {
if (isItem(item.getItemStack())) {
- if (Slimefun.hasUnlocked(p, this, true)) {
+ if (canUse(p, true)) {
SlimefunPlugin.runSync(() -> {
try {
addRandomEnchantment(p, item);
@@ -83,7 +86,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
};
}
- private void addRandomEnchantment(Player p, Item rune) {
+ private void addRandomEnchantment(@Nonnull Player p, @Nonnull Item rune) {
// Being sure the entity is still valid and not picked up or whatsoever.
if (!rune.isValid()) {
return;
@@ -106,8 +109,18 @@ public class EnchantmentRune extends SimpleSlimefunItem {
potentialEnchantments = new ArrayList<>(potentialEnchantments);
}
- // Removing the enchantments that the item already has from enchantmentSet
- // This also removes any conflicting enchantments
+ SlimefunItem slimefunItem = SlimefunItem.getByItem(itemStack);
+
+ // Fixes #2878 - Respect enchatability config setting.
+ if (slimefunItem != null && !slimefunItem.isEnchantable()) {
+ SlimefunPlugin.getLocalization().sendMessage(p, "messages.enchantment-rune.fail", true);
+ return;
+ }
+
+ /*
+ * Removing the enchantments that the item already has from enchantmentSet.
+ * This also removes any conflicting enchantments
+ */
removeIllegalEnchantments(itemStack, potentialEnchantments);
if (potentialEnchantments.isEmpty()) {
@@ -144,7 +157,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
}
}
- private int getRandomlevel(Enchantment enchantment) {
+ private int getRandomlevel(@Nonnull Enchantment enchantment) {
int level = 1;
if (enchantment.getMaxLevel() != 1) {
@@ -154,7 +167,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
return level;
}
- private void removeIllegalEnchantments(ItemStack target, List potentialEnchantments) {
+ private void removeIllegalEnchantments(@Nonnull ItemStack target, @Nonnull List potentialEnchantments) {
for (Enchantment enchantment : target.getEnchantments().keySet()) {
Iterator iterator = potentialEnchantments.iterator();
@@ -169,7 +182,7 @@ public class EnchantmentRune extends SimpleSlimefunItem {
}
}
- private boolean findCompatibleItem(Entity n) {
+ private boolean findCompatibleItem(@Nonnull Entity n) {
if (n instanceof Item) {
Item item = (Item) n;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java
index dfde7821e..997a08acc 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/runes/SoulboundRune.java
@@ -3,6 +3,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes;
import java.util.Collection;
import java.util.Optional;
+import javax.annotation.Nonnull;
+
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
@@ -19,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@@ -47,7 +48,7 @@ public class SoulboundRune extends SimpleSlimefunItem {
return (e, p, item) -> {
if (isItem(item.getItemStack())) {
- if (!Slimefun.hasUnlocked(p, this, true)) {
+ if (!canUse(p, true)) {
return true;
}
@@ -59,7 +60,7 @@ public class SoulboundRune extends SimpleSlimefunItem {
};
}
- private void activate(Player p, Item rune) {
+ private void activate(@Nonnull Player p, @Nonnull Item rune) {
// Being sure the entity is still valid and not picked up or whatsoever.
if (!rune.isValid()) {
return;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java
index 2d9959a11..0b6758bbe 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/MagicianTalisman.java
@@ -1,5 +1,18 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans;
+import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
+import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment;
+import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -7,20 +20,6 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.logging.Level;
import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import org.apache.commons.lang.Validate;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-
-import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
-import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
-import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment;
-import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
-
/**
* The {@link MagicianTalisman} is a special kind of {@link Talisman} which awards a {@link Player}
* with an extra {@link Enchantment} when they enchant their {@link ItemStack}.
@@ -30,12 +29,16 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/
public class MagicianTalisman extends Talisman {
+ private final ItemSetting allowEnchantmentBooks = new ItemSetting<>("allow-enchantment-books", false);
+
private final Set enchantments = new HashSet<>();
@ParametersAreNonnullByDefault
public MagicianTalisman(SlimefunItemStack item, ItemStack[] recipe) {
super(item, recipe, false, false, "magician", 80);
+ addItemSetting(allowEnchantmentBooks);
+
for (Enchantment enchantment : Enchantment.values()) {
try {
for (int i = 1; i <= enchantment.getMaxLevel(); i++) {
@@ -70,7 +73,7 @@ public class MagicianTalisman extends Talisman {
// @formatter:off
List enabled = enchantments.stream()
- .filter(e -> e.getEnchantment().canEnchantItem(item))
+ .filter(e -> (isEnchantmentBookAllowed() && item.getType() == Material.BOOK) || e.getEnchantment().canEnchantItem(item))
.filter(e -> hasConflicts(existingEnchantments, e))
.filter(TalismanEnchantment::getValue)
.collect(Collectors.toList());
@@ -90,4 +93,13 @@ public class MagicianTalisman extends Talisman {
return true;
}
+ /**
+ * This method checks whether enchantment books
+ * can be given an extra {@link Enchantment} or not.
+ *
+ * @return Whether enchantment books can receive an extra {@link Enchantment}
+ */
+ public boolean isEnchantmentBookAllowed() {
+ return allowEnchantmentBooks.getValue();
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java
index 203ee5b74..8c9f34f6f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java
@@ -9,6 +9,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
+import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
@@ -33,7 +34,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class Talisman extends SlimefunItem {
@@ -113,10 +113,6 @@ public class Talisman extends SlimefunItem {
return effects;
}
- protected String getMessageSuffix() {
- return suffix;
- }
-
protected boolean isEventCancelled() {
return cancel;
}
@@ -147,36 +143,44 @@ public class Talisman extends SlimefunItem {
}
}
- private static boolean hasMessage(@Nonnull Talisman talisman) {
- return talisman.getMessageSuffix() != null;
+ @ParametersAreNonnullByDefault
+ public static boolean trigger(Event e, SlimefunItemStack stack) {
+ return trigger(e, stack.getItem(), true);
}
@ParametersAreNonnullByDefault
- public static boolean checkFor(Event e, SlimefunItemStack stack) {
- return checkFor(e, stack.getItem());
+ public static boolean trigger(Event e, SlimefunItemStack stack, boolean sendMessage) {
+ return trigger(e, stack.getItem(), sendMessage);
}
@ParametersAreNonnullByDefault
- public static boolean checkFor(Event e, SlimefunItem item) {
+ public static boolean trigger(Event e, SlimefunItem item) {
+ return trigger(e, item, true);
+ }
+
+ @ParametersAreNonnullByDefault
+ public static boolean trigger(Event e, SlimefunItem item, boolean sendMessage) {
if (!(item instanceof Talisman)) {
return false;
}
Talisman talisman = (Talisman) item;
+
if (ThreadLocalRandom.current().nextInt(100) > talisman.getChance()) {
return false;
}
Player p = getPlayerByEventType(e);
- if (p == null || !pass(p, talisman)) {
+
+ if (p == null || !talisman.canEffectsBeApplied(p)) {
return false;
}
ItemStack talismanItem = talisman.getItem();
if (SlimefunUtils.containsSimilarItem(p.getInventory(), talismanItem, true)) {
- if (Slimefun.hasUnlocked(p, talisman, true)) {
- activateTalisman(e, p, p.getInventory(), talisman, talismanItem);
+ if (talisman.canUse(p, true)) {
+ activateTalisman(e, p, p.getInventory(), talisman, talismanItem, sendMessage);
return true;
} else {
return false;
@@ -185,8 +189,8 @@ public class Talisman extends SlimefunItem {
ItemStack enderTalisman = talisman.getEnderVariant();
if (SlimefunUtils.containsSimilarItem(p.getEnderChest(), enderTalisman, true)) {
- if (Slimefun.hasUnlocked(p, talisman, true)) {
- activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman);
+ if (talisman.canUse(p, true)) {
+ activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman, sendMessage);
return true;
} else {
return false;
@@ -198,11 +202,30 @@ public class Talisman extends SlimefunItem {
}
@ParametersAreNonnullByDefault
- private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismanItem) {
+ private static void activateTalisman(Event e, Player p, Inventory inv, Talisman talisman, ItemStack talismanItem, boolean sendMessage) {
consumeItem(inv, talisman, talismanItem);
applyTalismanEffects(p, talisman);
cancelEvent(e, talisman);
- sendMessage(p, talisman);
+
+ if (sendMessage) {
+ talisman.sendMessage(p);
+ }
+ }
+
+ @ParametersAreNonnullByDefault
+ private static void consumeItem(Inventory inv, Talisman talisman, ItemStack talismanItem) {
+ if (talisman.isConsumable()) {
+ ItemStack[] contents = inv.getContents();
+
+ for (int i = 0; i < contents.length; i++) {
+ ItemStack item = contents[i];
+
+ if (SlimefunUtils.isItemSimilar(item, talismanItem, true, false)) {
+ ItemUtils.consumeItem(item, false);
+ return;
+ }
+ }
+ }
}
@ParametersAreNonnullByDefault
@@ -219,29 +242,63 @@ public class Talisman extends SlimefunItem {
}
}
- @ParametersAreNonnullByDefault
- private static void sendMessage(Player p, Talisman talisman) {
- if (hasMessage(talisman)) {
- SlimefunPlugin.getLocalization().sendMessage(p, "messages.talisman." + talisman.getMessageSuffix(), true);
- }
+ /**
+ * This returns whether the {@link Talisman} is silent.
+ * A silent {@link Talisman} will not send a message to a {@link Player}
+ * when activated.
+ *
+ * @return Whether this {@link Talisman} is silent
+ */
+ public boolean isSilent() {
+ return getMessageSuffix() == null;
}
- @ParametersAreNonnullByDefault
- private static void consumeItem(Inventory inv, Talisman talisman, ItemStack talismanItem) {
- if (talisman.isConsumable()) {
- ItemStack[] contents = inv.getContents();
- for (int i = 0; i < contents.length; i++) {
- ItemStack item = contents[i];
+ @Nullable
+ protected final String getMessageSuffix() {
+ return suffix;
+ }
- if (SlimefunUtils.isItemSimilar(item, talismanItem, true, false)) {
- ItemUtils.consumeItem(item, false);
- return;
+ /**
+ * This method sends the given {@link Player} the message of this {@link Talisman}.
+ * Dependent on the selected config setting, the message will be sent via the actionbar
+ * or in the chat window.
+ *
+ * @param p
+ * The {@link Player} who shall receive the message
+ */
+ public void sendMessage(@Nonnull Player p) {
+ Validate.notNull(p, "The Player must not be null.");
+
+ // Check if this Talisman has a message
+ if (!isSilent()) {
+ try {
+ String messageKey = "messages.talisman." + getMessageSuffix();
+
+ if (SlimefunPlugin.getRegistry().useActionbarForTalismans()) {
+ // Use the actionbar
+ SlimefunPlugin.getLocalization().sendActionbarMessage(p, messageKey, false);
+ } else {
+ // Send the message via chat
+ SlimefunPlugin.getLocalization().sendMessage(p, messageKey, true);
}
+ } catch (Exception x) {
+ error("An Exception was thrown while trying to send a Talisman message", x);
}
}
}
- private static Player getPlayerByEventType(Event e) {
+ private boolean canEffectsBeApplied(@Nonnull Player p) {
+ for (PotionEffect effect : getEffects()) {
+ if (effect != null && p.hasPotionEffect(effect.getType())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Nullable
+ private static Player getPlayerByEventType(@Nonnull Event e) {
if (e instanceof EntityDeathEvent) {
return ((EntityDeathEvent) e).getEntity().getKiller();
} else if (e instanceof BlockBreakEvent) {
@@ -259,14 +316,4 @@ public class Talisman extends SlimefunItem {
return null;
}
- private static boolean pass(Player p, SlimefunItem talisman) {
- for (PotionEffect effect : ((Talisman) talisman).getEffects()) {
- if (effect != null && p.hasPotionEffect(effect.getType())) {
- return false;
- }
- }
-
- return true;
- }
-
}
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java
index ff29a0426..539583f19 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFertilizer.java
@@ -4,9 +4,9 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CropGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodComposter;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.TreeGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.TreeGrowthAccelerator;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java
index 9b4edbbb1..0b86ee8c3 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/misc/OrganicFood.java
@@ -6,8 +6,8 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AnimalGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodFabricator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AnimalGrowthAccelerator;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java
index 632e95f0a..2dd1632a2 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AbstractSmeltery.java
@@ -19,7 +19,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@@ -48,7 +47,7 @@ abstract class AbstractSmeltery extends MultiBlockMachine {
if (canCraft(inv, inputs, i)) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
- if (Slimefun.hasUnlocked(p, output, true)) {
+ if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
Inventory outputInv = findOutputInventory(output, dispBlock, inv);
if (outputInv != null) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java
index ff68a91e1..7d66099fc 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/ArmorForge.java
@@ -21,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class ArmorForge extends AbstractCraftingTable {
@@ -44,7 +43,7 @@ public class ArmorForge extends AbstractCraftingTable {
if (isCraftable(inv, inputs.get(i))) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
- if (Slimefun.hasUnlocked(p, output, true)) {
+ if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
craft(p, output, inv, dispenser);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java
index a55a804c2..5aeab8fb5 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/EnhancedCraftingTable.java
@@ -20,7 +20,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class EnhancedCraftingTable extends AbstractCraftingTable {
@@ -43,7 +42,7 @@ public class EnhancedCraftingTable extends AbstractCraftingTable {
if (isCraftable(inv, inputs.get(i))) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
- if (Slimefun.hasUnlocked(p, output, true)) {
+ if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
craft(inv, dispenser, p, b, output);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java
index 3c1533a98..54d28c391 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/GrindStone.java
@@ -4,6 +4,7 @@ import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.Sound;
@@ -27,6 +28,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class GrindStone extends MultiBlockMachine {
+ @ParametersAreNonnullByDefault
public GrindStone(Category category, SlimefunItemStack item) {
super(category, item, new ItemStack[] { null, null, null, null, new ItemStack(Material.OAK_FENCE), null, null, new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), null }, BlockFace.SELF);
}
@@ -71,6 +73,9 @@ public class GrindStone extends MultiBlockMachine {
recipes.add(new ItemStack(Material.PRISMARINE));
recipes.add(new ItemStack(Material.PRISMARINE_SHARD, 4));
+
+ recipes.add(new ItemStack(Material.NETHER_WART_BLOCK));
+ recipes.add(new ItemStack(Material.NETHER_WART, 9));
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java
index fd0056e6a..d98935eb1 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MagicWorkbench.java
@@ -21,7 +21,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class MagicWorkbench extends AbstractCraftingTable {
@@ -50,7 +49,7 @@ public class MagicWorkbench extends AbstractCraftingTable {
if (isCraftable(inv, inputs.get(i))) {
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
- if (Slimefun.hasUnlocked(p, output, true)) {
+ if (SlimefunUtils.canPlayerUseItem(p, output, true)) {
craft(inv, dispenser, p, b, output);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java
index 83b044271..1efbe73f3 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/MakeshiftSmeltery.java
@@ -3,6 +3,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.Effect;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -17,6 +19,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class MakeshiftSmeltery extends AbstractSmeltery {
+ @ParametersAreNonnullByDefault
public MakeshiftSmeltery(Category category, SlimefunItemStack item) {
super(category, item, new ItemStack[] { null, new ItemStack(Material.OAK_FENCE), null, new ItemStack(Material.BRICKS), new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), new ItemStack(Material.BRICKS), null, new ItemStack(Material.FLINT_AND_STEEL), null }, BlockFace.DOWN);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java
index bb857f3d5..87df574ae 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java
@@ -25,7 +25,6 @@ import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
@@ -135,7 +134,7 @@ public class OreCrusher extends MultiBlockMachine {
ItemStack adding = RecipeType.getRecipeOutput(this, convert);
Inventory outputInv = findOutputInventory(adding, dispBlock, inv);
- if (Slimefun.hasUnlocked(p, adding, true)) {
+ if (SlimefunUtils.canPlayerUseItem(p, adding, true)) {
if (outputInv != null) {
ItemStack removing = current.clone();
removing.setAmount(convert.getAmount());
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java
index 0d447e193..f119ce20b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/Smeltery.java
@@ -7,6 +7,8 @@ import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect;
import org.bukkit.Material;
@@ -26,6 +28,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.IgnitionChamber;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
@@ -36,6 +39,7 @@ public class Smeltery extends AbstractSmeltery {
private final BlockFace[] faces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };
private final ItemSetting fireBreakingChance = new IntRangeSetting("fire-breaking-chance", 0, 34, 100);
+ @ParametersAreNonnullByDefault
public Smeltery(Category category, SlimefunItemStack item) {
super(category, item, new ItemStack[] { null, new ItemStack(Material.NETHER_BRICK_FENCE), null, new ItemStack(Material.NETHER_BRICKS), new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), new ItemStack(Material.NETHER_BRICKS), null, new ItemStack(Material.FLINT_AND_STEEL), null }, BlockFace.DOWN);
@@ -73,6 +77,7 @@ public class Smeltery extends AbstractSmeltery {
}
}
+ @ParametersAreNonnullByDefault
private void consumeFire(Player p, Block dispenser, Block b) {
Inventory chamber = findIgnitionChamber(dispenser);
@@ -103,9 +108,12 @@ public class Smeltery extends AbstractSmeltery {
}
}
+ @Nullable
private Inventory findIgnitionChamber(@Nonnull Block b) {
for (BlockFace face : faces) {
- if (b.getRelative(face).getType() == Material.DROPPER && BlockStorage.check(b.getRelative(face), "IGNITION_CHAMBER")) {
+ Block block = b.getRelative(face);
+
+ if (block.getType() == Material.DROPPER && BlockStorage.check(block) instanceof IgnitionChamber) {
BlockState state = PaperLib.getBlockState(b.getRelative(face), false).getState();
if (state instanceof Dropper) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java
index 157b26954..06ec908ed 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/miner/IndustrialMiner.java
@@ -120,21 +120,21 @@ public class IndustrialMiner extends MultiBlockMachine {
Random random = ThreadLocalRandom.current();
switch (ore) {
- case COAL_ORE:
- return new ItemStack(Material.COAL);
- case DIAMOND_ORE:
- return new ItemStack(Material.DIAMOND);
- case EMERALD_ORE:
- return new ItemStack(Material.EMERALD);
- case NETHER_QUARTZ_ORE:
- return new ItemStack(Material.QUARTZ);
- case REDSTONE_ORE:
- return new ItemStack(Material.REDSTONE, 4 + random.nextInt(2));
- case LAPIS_ORE:
- return new ItemStack(Material.LAPIS_LAZULI, 4 + random.nextInt(4));
- default:
- // This includes Iron and Gold ore (and Ancient Debris)
- return new ItemStack(ore);
+ case COAL_ORE:
+ return new ItemStack(Material.COAL);
+ case DIAMOND_ORE:
+ return new ItemStack(Material.DIAMOND);
+ case EMERALD_ORE:
+ return new ItemStack(Material.EMERALD);
+ case NETHER_QUARTZ_ORE:
+ return new ItemStack(Material.QUARTZ);
+ case REDSTONE_ORE:
+ return new ItemStack(Material.REDSTONE, 4 + random.nextInt(2));
+ case LAPIS_ORE:
+ return new ItemStack(Material.LAPIS_LAZULI, 4 + random.nextInt(4));
+ default:
+ // This includes Iron and Gold ore (and Ancient Debris)
+ return new ItemStack(ore);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java
index da52e9750..2aedace52 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java
@@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.tools;
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
@@ -15,6 +16,7 @@ import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
+import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
@@ -39,7 +41,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* @see ExplosiveShovel
*
*/
-class ExplosiveTool extends SimpleSlimefunItem implements NotPlaceable, DamageableItem {
+public class ExplosiveTool extends SimpleSlimefunItem implements NotPlaceable, DamageableItem {
private final ItemSetting damageOnUse = new ItemSetting<>("damage-on-use", true);
private final ItemSetting callExplosionEvent = new ItemSetting<>("call-explosion-event", false);
@@ -51,6 +53,7 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla
addItemSetting(damageOnUse, callExplosionEvent);
}
+ @Nonnull
@Override
public ToolUseHandler getItemHandler() {
return (e, tool, fortune, drops) -> {
@@ -67,6 +70,8 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla
@ParametersAreNonnullByDefault
private void breakBlocks(Player p, ItemStack item, Block b, List blocks, List drops) {
+ List blocksToDestroy = new ArrayList<>();
+
if (callExplosionEvent.getValue().booleanValue()) {
BlockExplodeEvent blockExplodeEvent = new BlockExplodeEvent(b, blocks, 0);
Bukkit.getServer().getPluginManager().callEvent(blockExplodeEvent);
@@ -74,17 +79,26 @@ class ExplosiveTool extends SimpleSlimefunItem implements NotPla
if (!blockExplodeEvent.isCancelled()) {
for (Block block : blockExplodeEvent.blockList()) {
if (canBreak(p, block)) {
- breakBlock(p, item, block, drops);
+ blocksToDestroy.add(block);
}
}
}
} else {
for (Block block : blocks) {
if (canBreak(p, block)) {
- breakBlock(p, item, block, drops);
+ blocksToDestroy.add(block);
}
}
}
+
+ ExplosiveToolBreakBlocksEvent event = new ExplosiveToolBreakBlocksEvent(p, blocksToDestroy, item, this);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+
+ if (!event.isCancelled()) {
+ for (Block block : blocksToDestroy) {
+ breakBlock(p, item, block, drops);
+ }
+ }
}
private List findBlocks(Block b) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java
index 16848bbd7..c2cada5b9 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java
@@ -96,10 +96,6 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
for (GoldPanDrop setting : drops) {
randomizer.add(setting.getOutput(), setting.getValue());
}
-
- if (randomizer.sumWeights() < 100) {
- randomizer.add(new ItemStack(Material.AIR), 100 - randomizer.sumWeights());
- }
}
/**
@@ -110,7 +106,10 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
*/
@Nonnull
public ItemStack getRandomOutput() {
- return randomizer.getRandom();
+ ItemStack item = randomizer.getRandom();
+
+ // Fixes #2804
+ return item != null ? item : new ItemStack(Material.AIR);
}
@Override
@@ -126,12 +125,14 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
if (block.isPresent()) {
Block b = block.get();
+ // Check the clicked block type and for protections
if (b.getType() == getTargetMaterial() && SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), b.getLocation(), ProtectableAction.BREAK_BLOCK)) {
ItemStack output = getRandomOutput();
b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType());
b.setType(Material.AIR);
+ // Make sure that the randomly selected item is not air
if (output.getType() != Material.AIR) {
b.getWorld().dropItemNaturally(b.getLocation(), output.clone());
}
@@ -148,6 +149,7 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
*
* @return the {@link EntityInteractHandler} of this {@link SlimefunItem}
*/
+ @Nonnull
public EntityInteractHandler onEntityInteract() {
return (e, item, offHand) -> {
if (!(e.getRightClicked() instanceof ItemFrame)) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java
index aee48bdf8..b93704cb9 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SwordOfBeheading.java
@@ -56,39 +56,39 @@ public class SwordOfBeheading extends SimpleSlimefunItem {
Random random = ThreadLocalRandom.current();
switch (e.getEntityType()) {
- case ZOMBIE:
- if (random.nextInt(100) < chanceZombie.getValue()) {
- e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD));
- }
- break;
- case SKELETON:
- if (random.nextInt(100) < chanceSkeleton.getValue()) {
- e.getDrops().add(new ItemStack(Material.SKELETON_SKULL));
- }
- break;
- case CREEPER:
- if (random.nextInt(100) < chanceCreeper.getValue()) {
- e.getDrops().add(new ItemStack(Material.CREEPER_HEAD));
- }
- break;
- case WITHER_SKELETON:
- if (random.nextInt(100) < chanceWitherSkeleton.getValue()) {
- e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL));
- }
- break;
- case PLAYER:
- if (random.nextInt(100) < chancePlayer.getValue()) {
- ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
+ case ZOMBIE:
+ if (random.nextInt(100) < chanceZombie.getValue()) {
+ e.getDrops().add(new ItemStack(Material.ZOMBIE_HEAD));
+ }
+ break;
+ case SKELETON:
+ if (random.nextInt(100) < chanceSkeleton.getValue()) {
+ e.getDrops().add(new ItemStack(Material.SKELETON_SKULL));
+ }
+ break;
+ case CREEPER:
+ if (random.nextInt(100) < chanceCreeper.getValue()) {
+ e.getDrops().add(new ItemStack(Material.CREEPER_HEAD));
+ }
+ break;
+ case WITHER_SKELETON:
+ if (random.nextInt(100) < chanceWitherSkeleton.getValue()) {
+ e.getDrops().add(new ItemStack(Material.WITHER_SKELETON_SKULL));
+ }
+ break;
+ case PLAYER:
+ if (random.nextInt(100) < chancePlayer.getValue()) {
+ ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
- ItemMeta meta = skull.getItemMeta();
- ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity());
- skull.setItemMeta(meta);
+ ItemMeta meta = skull.getItemMeta();
+ ((SkullMeta) meta).setOwningPlayer((Player) e.getEntity());
+ skull.setItemMeta(meta);
- e.getDrops().add(skull);
- }
- break;
- default:
- break;
+ e.getDrops().add(skull);
+ }
+ break;
+ default:
+ break;
}
};
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java
index 646ed0476..58c7d1a3c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java
@@ -41,7 +41,6 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for providing the core mechanics of the {@link AncientAltar}
@@ -105,12 +104,13 @@ public class AncientAltarListener implements Listener {
}
String id = slimefunBlock.get().getId();
+ Player p = e.getPlayer();
if (id.equals(pedestalItem.getId())) {
e.cancel();
- usePedestal(b, e.getPlayer());
+ usePedestal(b, p);
} else if (id.equals(altarItem.getId())) {
- if (!Slimefun.hasUnlocked(e.getPlayer(), altarItem, true) || altarsInUse.contains(b.getLocation())) {
+ if (!altarItem.canUse(p, true) || altarsInUse.contains(b.getLocation())) {
e.cancel();
return;
}
@@ -119,7 +119,7 @@ public class AncientAltarListener implements Listener {
altarsInUse.add(b.getLocation());
e.cancel();
- useAltar(b, e.getPlayer());
+ useAltar(b, p);
}
}
@@ -212,8 +212,9 @@ public class AncientAltarListener implements Listener {
}
Optional result = getRecipeOutput(catalyst, input);
+
if (result.isPresent()) {
- if (Slimefun.hasUnlocked(p, result.get(), true)) {
+ if (SlimefunUtils.canPlayerUseItem(p, result.get(), true)) {
List consumed = new ArrayList<>();
consumed.add(catalyst);
@@ -248,7 +249,7 @@ public class AncientAltarListener implements Listener {
}
}
- @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
if (altarItem == null || altarItem.isDisabled()) {
return;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java
index 99da8142f..8d800cb10 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java
@@ -31,7 +31,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for all events centered around a {@link SlimefunBackpack}.
@@ -122,7 +121,7 @@ public class BackpackListener implements Listener {
@ParametersAreNonnullByDefault
public void openBackpack(Player p, ItemStack item, SlimefunBackpack backpack) {
if (item.getAmount() == 1) {
- if (Slimefun.hasUnlocked(p, backpack, true) && !PlayerProfile.get(p, profile -> openBackpack(p, item, profile, backpack.getSize()))) {
+ if (backpack.canUse(p, true) && !PlayerProfile.get(p, profile -> openBackpack(p, item, profile, backpack.getSize()))) {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.opening-backpack");
}
} else {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java
index 3ac4ec600..6fc179556 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BeeWingsListener.java
@@ -11,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.BeeWingsTask;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for the slow falling effect given to the {@link Player}
@@ -44,7 +43,7 @@ public class BeeWingsListener implements Listener {
Player player = (Player) e.getEntity();
ItemStack chestplate = player.getInventory().getChestplate();
- if (wings.isItem(chestplate) && Slimefun.hasUnlocked(player, chestplate, true)) {
+ if (wings.isItem(chestplate) && wings.canUse(player, true)) {
new BeeWingsTask(player).scheduleRepeating(3, 1);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java
index a97cf123e..e13610986 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java
@@ -56,14 +56,9 @@ public class BlockListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockPlaceExisting(BlockPlaceEvent e) {
- /*
- * This prevents Players from placing a block where another block already exists.
- * While this can cause ghost blocks it also prevents them from replacing grass
- * or saplings etc...
- */
Block block = e.getBlock();
- // Fixes #2636
+ // Fixes #2636 - This will solve the "ghost blocks" issue
if (e.getBlockReplacedState().getType().isAir()) {
SlimefunItem sfItem = BlockStorage.check(block);
@@ -77,6 +72,7 @@ public class BlockListener implements Listener {
BlockStorage.clearBlockInfo(block);
}
} else if (BlockStorage.hasBlockInfo(e.getBlock())) {
+ // If there is no air (e.g. grass) then don't let the block be placed
e.setCancelled(true);
}
}
@@ -87,7 +83,7 @@ public class BlockListener implements Listener {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null && !(sfItem instanceof NotPlaceable) && Slimefun.isEnabled(e.getPlayer(), sfItem, true)) {
- if (!Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) {
+ if (!sfItem.canUse(e.getPlayer(), true)) {
e.setCancelled(true);
} else {
if (SlimefunPlugin.getBlockDataService().isTileEntity(e.getBlock().getType())) {
@@ -117,18 +113,18 @@ public class BlockListener implements Listener {
return;
}
- checkForSensitiveBlockAbove(e.getPlayer(), e.getBlock());
-
ItemStack item = e.getPlayer().getInventory().getItemInMainHand();
+ checkForSensitiveBlockAbove(e, item);
+
int fortune = getBonusDropsWithFortune(item, e.getBlock());
List drops = new ArrayList<>();
- if (!item.getType().isAir()) {
+ if (!e.isCancelled() && !item.getType().isAir()) {
callToolHandler(e, item, fortune, drops);
}
if (!e.isCancelled()) {
- callBlockHandler(e, item, fortune, drops);
+ callBlockHandler(e, item, drops);
}
dropItems(e, drops);
@@ -139,7 +135,7 @@ public class BlockListener implements Listener {
SlimefunItem tool = SlimefunItem.getByItem(item);
if (tool != null) {
- if (Slimefun.hasUnlocked(e.getPlayer(), tool, true)) {
+ if (tool.canUse(e.getPlayer(), true)) {
tool.callItemHandler(ToolUseHandler.class, handler -> handler.onToolUse(e, item, fortune, drops));
} else {
e.setCancelled(true);
@@ -148,7 +144,7 @@ public class BlockListener implements Listener {
}
@ParametersAreNonnullByDefault
- private void callBlockHandler(BlockBreakEvent e, ItemStack item, int fortune, List drops) {
+ private void callBlockHandler(BlockBreakEvent e, ItemStack item, List drops) {
SlimefunItem sfItem = BlockStorage.check(e.getBlock());
if (sfItem == null && SlimefunPlugin.getBlockDataService().isTileEntity(e.getBlock().getType())) {
@@ -172,7 +168,7 @@ public class BlockListener implements Listener {
sfItem.error("Something went wrong while triggering a BlockHandler", x);
}
} else {
- sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onBlockBreak(e, item, fortune, drops));
+ sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(e, item, drops));
}
drops.addAll(sfItem.getDrops());
@@ -182,13 +178,15 @@ public class BlockListener implements Listener {
@ParametersAreNonnullByDefault
private void dropItems(BlockBreakEvent e, List drops) {
- if (!drops.isEmpty()) {
- e.getBlock().setType(Material.AIR);
-
+ if (!drops.isEmpty() && !e.isCancelled()) {
// Notify plugins like CoreProtect
SlimefunPlugin.getProtectionManager().logAction(e.getPlayer(), e.getBlock(), ProtectableAction.BREAK_BLOCK);
+ // Fixes #2560
if (e.isDropItems()) {
+ // Disable normal block drops
+ e.setDropItems(false);
+
for (ItemStack drop : drops) {
if (drop != null && drop.getType() != Material.AIR) {
e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), drop);
@@ -209,8 +207,8 @@ public class BlockListener implements Listener {
* The {@link Block} that was broken
*/
@ParametersAreNonnullByDefault
- private void checkForSensitiveBlockAbove(Player p, Block b) {
- Block blockAbove = b.getRelative(BlockFace.UP);
+ private void checkForSensitiveBlockAbove(BlockBreakEvent e, ItemStack item) {
+ Block blockAbove = e.getBlock().getRelative(BlockFace.UP);
if (SlimefunTag.SENSITIVE_MATERIALS.isTagged(blockAbove.getType())) {
SlimefunItem sfItem = BlockStorage.check(blockAbove);
@@ -219,13 +217,29 @@ public class BlockListener implements Listener {
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getId());
if (blockHandler != null) {
- if (blockHandler.onBreak(p, blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) {
+ if (blockHandler.onBreak(e.getPlayer(), blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) {
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove));
blockAbove.setType(Material.AIR);
}
} else {
- blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove));
+ /*
+ * We create a dummy here to pass onto the BlockBreakHandler.
+ * This will set the correct block context.
+ */
+ BlockBreakEvent dummyEvent = new BlockBreakEvent(blockAbove, e.getPlayer());
+ List drops = new ArrayList<>();
+ drops.addAll(sfItem.getDrops(e.getPlayer()));
+
+ sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));
blockAbove.setType(Material.AIR);
+
+ if (!dummyEvent.isCancelled() && dummyEvent.isDropItems()) {
+ for (ItemStack drop : drops) {
+ if (drop != null && drop.getType() != Material.AIR) {
+ blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), drop);
+ }
+ }
+ }
}
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java
index bd3b8f760..42bec19e6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java
@@ -84,9 +84,10 @@ public class BlockPhysicsListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onLiquidFlow(BlockFromToEvent e) {
Block block = e.getToBlock();
+ Material type = block.getType();
// Check if this Material can be destroyed by fluids
- if (SlimefunTag.FLUID_SENSITIVE_MATERIALS.isTagged(block.getType())) {
+ if (SlimefunTag.FLUID_SENSITIVE_MATERIALS.isTagged(type)) {
// Check if this Block holds any data
if (BlockStorage.hasBlockInfo(block)) {
e.setCancelled(true);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java
index 87a5a88a6..c2f836bdd 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/CoolerListener.java
@@ -21,7 +21,6 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.Juice;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} listens for a {@link FoodLevelChangeEvent} or an {@link EntityDamageEvent} for starvation
@@ -74,7 +73,7 @@ public class CoolerListener implements Listener {
for (ItemStack item : p.getInventory().getContents()) {
if (cooler.isItem(item)) {
- if (Slimefun.hasUnlocked(p, cooler, true)) {
+ if (cooler.canUse(p, true)) {
takeJuiceFromCooler(p, item);
} else {
return;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java
index 8b065acc6..9b40e0fc1 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ElytraImpactListener.java
@@ -18,7 +18,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.ElytraCap;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* The {@link Listener} for the {@link ElytraCap}.
@@ -57,7 +56,7 @@ public class ElytraImpactListener implements Listener {
if (helmet.isPresent()) {
SlimefunItem item = helmet.get();
- if (Slimefun.hasUnlocked(p, item, true) && profile.hasFullProtectionAgainst(ProtectionType.FLYING_INTO_WALL)) {
+ if (item.canUse(p, true) && profile.hasFullProtectionAgainst(ProtectionType.FLYING_INTO_WALL)) {
e.setDamage(0);
p.playSound(p.getLocation(), Sound.BLOCK_STONE_HIT, 20, 1);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java
index c527cc7c5..7026f4f4c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/ExplosionsListener.java
@@ -1,6 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
+import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
import javax.annotation.Nonnull;
@@ -9,15 +11,29 @@ import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
+import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
+/**
+ * The {@link ExplosionsListener} is a {@link Listener} which listens to any explosion events.
+ * Any {@link WitherProof} block is excluded from these explosions and this {@link Listener} also
+ * calls the explosive part of the {@link BlockBreakHandler}.
+ *
+ * @author TheBusyBiscuit
+ *
+ * @see BlockBreakHandler
+ * @see WitherProof
+ *
+ */
public class ExplosionsListener implements Listener {
public ExplosionsListener(@Nonnull SlimefunPlugin plugin) {
@@ -26,12 +42,19 @@ public class ExplosionsListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent e) {
- Iterator blocks = e.blockList().iterator();
+ removeResistantBlocks(e.blockList().iterator());
+ }
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onBlockExplode(BlockExplodeEvent e) {
+ removeResistantBlocks(e.blockList().iterator());
+ }
+
+ private void removeResistantBlocks(@Nonnull Iterator blocks) {
while (blocks.hasNext()) {
Block block = blocks.next();
-
SlimefunItem item = BlockStorage.check(block);
+
if (item != null) {
blocks.remove();
@@ -41,6 +64,24 @@ public class ExplosionsListener implements Listener {
if (blockHandler != null) {
success = blockHandler.onBreak(null, block, item, UnregisterReason.EXPLODE);
+ } else {
+ item.callItemHandler(BlockBreakHandler.class, handler -> {
+ if (handler.isExplosionAllowed(block)) {
+ BlockStorage.clearBlockInfo(block);
+ block.setType(Material.AIR);
+
+ List drops = new ArrayList<>();
+ handler.onExplode(block, drops);
+
+ for (ItemStack drop : drops) {
+ if (drop != null && !drop.getType().isAir()) {
+ block.getWorld().dropItemNaturally(block.getLocation(), drop);
+ }
+ }
+ }
+ });
+
+ return;
}
if (success) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java
index 2e2b0fecf..f3002e775 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GadgetsListener.java
@@ -14,13 +14,12 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.armor.Parachute;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.JetBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.Jetpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedMagnet;
+import io.github.thebusybiscuit.slimefun4.implementation.tasks.InfusedMagnetTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.JetBootsTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.JetpackTask;
-import io.github.thebusybiscuit.slimefun4.implementation.tasks.InfusedMagnetTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ParachuteTask;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for listening to the {@link PlayerToggleSneakEvent}
@@ -59,7 +58,7 @@ public class GadgetsListener implements Listener {
if (SlimefunUtils.containsSimilarItem(p.getInventory(), SlimefunItems.INFUSED_MAGNET, true)) {
InfusedMagnet magnet = (InfusedMagnet) SlimefunItems.INFUSED_MAGNET.getItem();
- if (Slimefun.hasUnlocked(p, magnet, true)) {
+ if (magnet.canUse(p, true)) {
new InfusedMagnetTask(p, magnet.getRadius()).scheduleRepeating(0, 8);
}
}
@@ -67,7 +66,7 @@ public class GadgetsListener implements Listener {
}
private void handleChestplate(@Nonnull Player p, @Nullable SlimefunItem chestplate) {
- if (chestplate == null || !Slimefun.hasUnlocked(p, chestplate, true)) {
+ if (chestplate == null || !chestplate.canUse(p, true)) {
return;
}
@@ -83,7 +82,7 @@ public class GadgetsListener implements Listener {
}
private void handleBoots(@Nonnull Player p, @Nullable SlimefunItem boots) {
- if (boots instanceof JetBoots && Slimefun.hasUnlocked(p, boots, true)) {
+ if (boots instanceof JetBoots && boots.canUse(p, true)) {
double speed = ((JetBoots) boots).getSpeed();
if (speed > 0.2) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MiningAndroidListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MiningAndroidListener.java
new file mode 100644
index 000000000..34a43fcdf
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MiningAndroidListener.java
@@ -0,0 +1,45 @@
+package io.github.thebusybiscuit.slimefun4.implementation.listeners;
+
+import javax.annotation.Nonnull;
+
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+
+import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
+import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+import me.mrCookieSlime.Slimefun.api.BlockStorage;
+
+/**
+ * This {@link Listener} makes sure that an {@link AndroidMineEvent} gets properly propagated
+ * to the {@link BlockBreakHandler#onAndroidBreak(AndroidMineEvent)} method of a placed block.
+ * If that block is a {@link SlimefunItem} of course.
+ *
+ * @author TheBusyBiscuit
+ *
+ * @see BlockBreakHandler
+ *
+ */
+public class MiningAndroidListener implements Listener {
+
+ public MiningAndroidListener(@Nonnull SlimefunPlugin plugin) {
+ plugin.getServer().getPluginManager().registerEvents(this, plugin);
+ }
+
+ @EventHandler(ignoreCancelled = true)
+ public void onAndroidMine(AndroidMineEvent e) {
+ SlimefunItem slimefunItem = BlockStorage.check(e.getBlock());
+
+ // Fixes #2839 - Can't believe we forgot a null check here
+ if (slimefunItem != null) {
+ slimefunItem.callItemHandler(BlockBreakHandler.class, handler -> {
+ if (handler.isAndroidAllowed(e.getBlock())) {
+ handler.onAndroidBreak(e);
+ } else {
+ e.setCancelled(true);
+ }
+ });
+ }
+ }
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java
index d684a274b..0d40e4e3e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/MultiBlockListener.java
@@ -62,8 +62,13 @@ public class MultiBlockListener implements Listener {
e.setCancelled(true);
MultiBlock mb = multiblocks.getLast();
- mb.getSlimefunItem().callItemHandler(MultiBlockInteractionHandler.class, handler -> handler.onInteract(p, mb, b));
- Bukkit.getPluginManager().callEvent(new MultiBlockInteractEvent(p, mb, b, e.getBlockFace()));
+ MultiBlockInteractEvent event = new MultiBlockInteractEvent(p, mb, b, e.getBlockFace());
+ Bukkit.getPluginManager().callEvent(event);
+
+ // Fixes #2809
+ if (!event.isCancelled()) {
+ mb.getSlimefunItem().callItemHandler(MultiBlockInteractionHandler.class, handler -> handler.onInteract(p, mb, b));
+ }
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java
index 0db770f40..5c04c7e49 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBootsListener.java
@@ -23,7 +23,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.armor.LongFallBoo
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.StomperBoots;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for handling all boots provided by
@@ -53,7 +52,7 @@ public class SlimefunBootsListener implements Listener {
Player p = (Player) e.getEntity();
SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots());
- if (boots instanceof EnderBoots && Slimefun.hasUnlocked(p, boots, true)) {
+ if (boots instanceof EnderBoots && boots.canUse(p, true)) {
e.setCancelled(true);
}
}
@@ -65,7 +64,7 @@ public class SlimefunBootsListener implements Listener {
if (boots != null) {
// Check if the boots were researched
- if (!Slimefun.hasUnlocked(p, boots, true)) {
+ if (!boots.canUse(p, true)) {
return;
}
@@ -91,7 +90,7 @@ public class SlimefunBootsListener implements Listener {
Player p = e.getPlayer();
SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots());
- if (boots instanceof FarmerShoes && Slimefun.hasUnlocked(p, boots, true)) {
+ if (boots instanceof FarmerShoes && boots.canUse(p, true)) {
e.setCancelled(true);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java
index bfd4d657a..fdbd271e2 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemConsumeListener.java
@@ -11,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for handling the {@link ItemConsumptionHandler}
@@ -33,7 +32,7 @@ public class SlimefunItemConsumeListener implements Listener {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem != null) {
- if (Slimefun.hasUnlocked(p, sfItem, true)) {
+ if (sfItem.canUse(p, true)) {
sfItem.callItemHandler(ItemConsumptionHandler.class, handler -> handler.onConsume(e, p, item));
} else {
e.setCancelled(true);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java
index ee276c3d3..d17fa55d4 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java
@@ -25,7 +25,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
@@ -94,8 +93,10 @@ public class SlimefunItemInteractListener implements Listener {
Optional optional = event.getSlimefunItem();
if (optional.isPresent()) {
- if (Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) {
- return optional.get().callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(event));
+ SlimefunItem sfItem = optional.get();
+
+ if (sfItem.canUse(e.getPlayer(), true)) {
+ return sfItem.callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(event));
} else {
event.setUseItem(Result.DENY);
}
@@ -109,19 +110,20 @@ public class SlimefunItemInteractListener implements Listener {
Optional optional = event.getSlimefunBlock();
if (optional.isPresent()) {
- if (!Slimefun.hasUnlocked(event.getPlayer(), optional.get(), true)) {
+ SlimefunItem sfItem = optional.get();
+
+ if (!sfItem.canUse(event.getPlayer(), true)) {
event.getInteractEvent().setCancelled(true);
return false;
}
- boolean interactable = optional.get().callItemHandler(BlockUseHandler.class, handler -> handler.onRightClick(event));
+ boolean interactable = sfItem.callItemHandler(BlockUseHandler.class, handler -> handler.onRightClick(event));
if (!interactable) {
- String id = optional.get().getId();
Player p = event.getPlayer();
- if (BlockMenuPreset.isInventory(id)) {
- openInventory(p, id, event.getInteractEvent().getClickedBlock(), event);
+ if (BlockMenuPreset.isInventory(sfItem.getId())) {
+ openInventory(p, sfItem, event.getInteractEvent().getClickedBlock(), event);
return false;
}
}
@@ -131,27 +133,31 @@ public class SlimefunItemInteractListener implements Listener {
}
@ParametersAreNonnullByDefault
- private void openInventory(Player p, String id, Block clickedBlock, PlayerRightClickEvent event) {
- if (!p.isSneaking() || event.getItem().getType() == Material.AIR) {
- event.getInteractEvent().setCancelled(true);
+ private void openInventory(Player p, SlimefunItem item, Block clickedBlock, PlayerRightClickEvent event) {
+ try {
+ if (!p.isSneaking() || event.getItem().getType() == Material.AIR) {
+ event.getInteractEvent().setCancelled(true);
- if (BlockStorage.hasUniversalInventory(id)) {
- UniversalBlockMenu menu = BlockStorage.getUniversalInventory(id);
+ if (BlockStorage.hasUniversalInventory(item.getId())) {
+ UniversalBlockMenu menu = BlockStorage.getUniversalInventory(item.getId());
- if (menu.canOpen(clickedBlock, p)) {
- menu.open(p);
- } else {
- SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true);
- }
- } else if (BlockStorage.getStorage(clickedBlock.getWorld()).hasInventory(clickedBlock.getLocation())) {
- BlockMenu menu = BlockStorage.getInventory(clickedBlock.getLocation());
+ if (menu.canOpen(clickedBlock, p)) {
+ menu.open(p);
+ } else {
+ SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true);
+ }
+ } else if (BlockStorage.getStorage(clickedBlock.getWorld()).hasInventory(clickedBlock.getLocation())) {
+ BlockMenu menu = BlockStorage.getInventory(clickedBlock.getLocation());
- if (menu.canOpen(clickedBlock, p)) {
- menu.open(p);
- } else {
- SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true);
+ if (menu.canOpen(clickedBlock, p)) {
+ menu.open(p);
+ } else {
+ SlimefunPlugin.getLocalization().sendMessage(p, "inventory.no-access", true);
+ }
}
}
+ } catch (Exception | LinkageError x) {
+ item.error("An Exception was caught while trying to open the Inventory", x);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java
index 445935569..ce21c0f35 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/TalismanListener.java
@@ -61,24 +61,24 @@ public class TalismanListener implements Listener {
public void onDamageGet(EntityDamageEvent e) {
if (e.getEntity() instanceof Player) {
if (e.getCause() == DamageCause.LAVA) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_LAVA);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_LAVA);
}
if (e.getCause() == DamageCause.DROWNING) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_WATER);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_WATER);
}
if (e.getCause() == DamageCause.FALL) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_ANGEL);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_ANGEL);
}
if (e.getCause() == DamageCause.FIRE) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_FIRE);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_FIRE);
}
if (e.getCause() == DamageCause.ENTITY_ATTACK) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_KNIGHT);
- Talisman.checkFor(e, SlimefunItems.TALISMAN_WARRIOR);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_KNIGHT);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_WARRIOR);
}
if (e.getCause() == DamageCause.PROJECTILE && e instanceof EntityDamageByEntityEvent) {
@@ -91,7 +91,7 @@ public class TalismanListener implements Listener {
if (e.getDamager() instanceof Projectile && !(e.getDamager() instanceof Trident)) {
Projectile projectile = (Projectile) e.getDamager();
- if (Talisman.checkFor(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
+ if (Talisman.trigger(e, SlimefunItems.TALISMAN_WHIRLWIND)) {
Player p = (Player) e.getEntity();
returnProjectile(p, projectile);
}
@@ -143,7 +143,7 @@ public class TalismanListener implements Listener {
// We are also excluding entities which can pickup items, this is not perfect
// but it at least prevents dupes by tossing items to zombies
- if (!entity.getCanPickupItems() && Talisman.checkFor(e, SlimefunItems.TALISMAN_HUNTER)) {
+ if (!entity.getCanPickupItems() && Talisman.trigger(e, SlimefunItems.TALISMAN_HUNTER)) {
Collection extraDrops = getExtraDrops(e.getEntity(), e.getDrops());
for (ItemStack drop : extraDrops) {
@@ -192,7 +192,7 @@ public class TalismanListener implements Listener {
@EventHandler
public void onItemBreak(PlayerItemBreakEvent e) {
- if (Talisman.checkFor(e, SlimefunItems.TALISMAN_ANVIL)) {
+ if (Talisman.trigger(e, SlimefunItems.TALISMAN_ANVIL)) {
PlayerInventory inv = e.getPlayer().getInventory();
int slot = inv.getHeldItemSlot();
@@ -225,7 +225,7 @@ public class TalismanListener implements Listener {
@EventHandler
public void onSprint(PlayerToggleSprintEvent e) {
if (e.isSprinting()) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_TRAVELLER);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_TRAVELLER);
}
}
@@ -235,17 +235,23 @@ public class TalismanListener implements Listener {
Map enchantments = e.getEnchantsToAdd();
// Magician Talisman
- if (Talisman.checkFor(e, SlimefunItems.TALISMAN_MAGICIAN)) {
- MagicianTalisman talisman = (MagicianTalisman) SlimefunItems.TALISMAN_MAGICIAN.getItem();
- TalismanEnchantment enchantment = talisman.getRandomEnchantment(e.getItem(), enchantments.keySet());
+ MagicianTalisman talisman = (MagicianTalisman) SlimefunItems.TALISMAN_MAGICIAN.getItem();
+ TalismanEnchantment enchantment = talisman.getRandomEnchantment(e.getItem(), enchantments.keySet());
- if (enchantment != null) {
+ if (enchantment != null && Talisman.trigger(e, SlimefunItems.TALISMAN_MAGICIAN)) {
+ /*
+ * Fix #2679
+ * By default, the Bukkit API doesn't allow us to give enchantment books extra enchantments.
+ */
+ if (talisman.isEnchantmentBookAllowed() && e.getItem().getType() == Material.BOOK) {
+ e.getItem().addUnsafeEnchantment(enchantment.getEnchantment(), enchantment.getLevel());
+ } else {
enchantments.put(enchantment.getEnchantment(), enchantment.getLevel());
}
}
// Wizard Talisman
- if (!enchantments.containsKey(Enchantment.SILK_TOUCH) && Enchantment.LOOT_BONUS_BLOCKS.canEnchantItem(e.getItem()) && Talisman.checkFor(e, SlimefunItems.TALISMAN_WIZARD)) {
+ if (!enchantments.containsKey(Enchantment.SILK_TOUCH) && Enchantment.LOOT_BONUS_BLOCKS.canEnchantItem(e.getItem()) && Talisman.trigger(e, SlimefunItems.TALISMAN_WIZARD)) {
// Randomly lower some enchantments
for (Map.Entry entry : enchantments.entrySet()) {
if (entry.getValue() > 1 && random.nextInt(100) < 40) {
@@ -260,7 +266,8 @@ public class TalismanListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onExperienceReceive(PlayerExpChangeEvent e) {
- if (e.getAmount() > 0 && Talisman.checkFor(e, SlimefunItems.TALISMAN_WISE)) {
+ // Check if the experience change was positive.
+ if (e.getAmount() > 0 && Talisman.trigger(e, SlimefunItems.TALISMAN_WISE)) {
// Double-XP
e.setAmount(e.getAmount() * 2);
}
@@ -268,21 +275,27 @@ public class TalismanListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlockDropItems(BlockDropItemEvent e) {
- // We only want to double ores
- Material type = e.getBlockState().getType();
- if (type.name().endsWith("_ORE")) {
- ItemStack item = e.getPlayer().getInventory().getItemInMainHand();
+ ItemStack item = e.getPlayer().getInventory().getItemInMainHand();
- if (item.getType() != Material.AIR && item.getAmount() > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) {
+ // We are going to ignore Silk Touch here
+ if (item.getType() != Material.AIR && item.getAmount() > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) {
+ Material type = e.getBlockState().getType();
+
+ // We only want to double ores
+ if (SlimefunTag.MINER_TALISMAN_TRIGGERS.isTagged(type)) {
Collection- drops = e.getItems();
- if (Talisman.checkFor(e, SlimefunItems.TALISMAN_MINER)) {
+ if (Talisman.trigger(e, SlimefunItems.TALISMAN_MINER, false)) {
int dropAmount = getAmountWithFortune(type, item.getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS));
+
+ // Keep track of whether we actually doubled the drops or not
boolean doubledDrops = false;
+ // Loop through all dropped items
for (Item drop : drops) {
ItemStack droppedItem = drop.getItemStack();
+ // We do not want to dupe blocks
if (!droppedItem.getType().isBlock()) {
int amount = Math.max(1, (dropAmount * 2) - droppedItem.getAmount());
e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), new CustomItem(droppedItem, amount));
@@ -290,8 +303,14 @@ public class TalismanListener implements Listener {
}
}
+ // Fixes #2077
if (doubledDrops) {
- SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.talisman.miner", true);
+ Talisman talisman = SlimefunItems.TALISMAN_MINER.getItem(Talisman.class);
+
+ // Fixes #2818
+ if (talisman != null) {
+ talisman.sendMessage(e.getPlayer());
+ }
}
}
}
@@ -301,7 +320,7 @@ public class TalismanListener implements Listener {
@EventHandler
public void onBlockBreak(BlockBreakEvent e) {
if (SlimefunTag.CAVEMAN_TALISMAN_TRIGGERS.isTagged(e.getBlock().getType())) {
- Talisman.checkFor(e, SlimefunItems.TALISMAN_CAVEMAN);
+ Talisman.trigger(e, SlimefunItems.TALISMAN_CAVEMAN);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java
index 31e7444ac..e91d2660f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/VampireBladeListener.java
@@ -13,7 +13,6 @@ import org.bukkit.potion.PotionEffect;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.VampireBlade;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is exclusively used for the {@link VampireBlade}.
@@ -44,7 +43,7 @@ public class VampireBladeListener implements Listener {
Player p = (Player) e.getDamager();
if (blade.isItem(p.getInventory().getItemInMainHand())) {
- if (Slimefun.hasUnlocked(p, blade, true)) {
+ if (blade.canUse(p, true)) {
blade.heal(p);
} else {
e.setCancelled(true);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java
index 47bf84f4f..f9aaa6abe 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/EntityInteractionListener.java
@@ -14,7 +14,6 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* The {@link Listener} responsible for a {@link Player} interacting with an {@link Entity}.
@@ -48,7 +47,7 @@ public class EntityInteractionListener implements Listener {
SlimefunItem sfItem = SlimefunItem.getByItem(itemStack);
if (sfItem != null) {
- if (Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) {
+ if (sfItem.canUse(e.getPlayer(), true)) {
sfItem.callItemHandler(EntityInteractHandler.class, handler -> handler.onInteract(e, itemStack, e.getHand() == EquipmentSlot.OFF_HAND));
} else if (sfItem.getState() != ItemState.VANILLA_FALLBACK) {
/*
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java
index 47579d295..b0f8b85b1 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/entity/MobDropListener.java
@@ -18,7 +18,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.BasicCircuitBoard;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for handling any custom mob drops.
@@ -55,7 +54,7 @@ public class MobDropListener implements Listener {
if (item.getType() != Material.AIR) {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
- if (sfItem != null && Slimefun.hasUnlocked(p, sfItem, true)) {
+ if (sfItem != null && sfItem.canUse(p, true)) {
sfItem.callItemHandler(EntityKillHandler.class, handler -> handler.onKill(e, e.getEntity(), p, item));
}
}
@@ -63,21 +62,21 @@ public class MobDropListener implements Listener {
}
private boolean canDrop(@Nonnull Player p, @Nonnull ItemStack item) {
- SlimefunItem sfi = SlimefunItem.getByItem(item);
+ SlimefunItem sfItem = SlimefunItem.getByItem(item);
- if (sfi == null) {
+ if (sfItem == null) {
return true;
- } else if (Slimefun.hasUnlocked(p, sfi, true)) {
- if (sfi instanceof RandomMobDrop) {
+ } else if (sfItem.canUse(p, true)) {
+ if (sfItem instanceof RandomMobDrop) {
int random = ThreadLocalRandom.current().nextInt(100);
- if (((RandomMobDrop) sfi).getMobDropChance() <= random) {
+ if (((RandomMobDrop) sfItem).getMobDropChance() <= random) {
return false;
}
}
- if (sfi instanceof BasicCircuitBoard) {
- return ((BasicCircuitBoard) sfi).isDroppedFromGolems();
+ if (sfItem instanceof BasicCircuitBoard) {
+ return ((BasicCircuitBoard) sfItem).isDroppedFromGolems();
}
return true;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java
index c45cc768d..e73b3cfe6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/OilResource.java
@@ -32,56 +32,56 @@ class OilResource extends SlimefunResource {
}
switch (biome) {
- case SNOWY_BEACH:
- case STONE_SHORE:
- case BEACH:
- return 6;
+ case SNOWY_BEACH:
+ case STONE_SHORE:
+ case BEACH:
+ return 6;
- case DESERT:
- case DESERT_HILLS:
- case DESERT_LAKES:
- return 45;
+ case DESERT:
+ case DESERT_HILLS:
+ case DESERT_LAKES:
+ return 45;
- case MOUNTAINS:
- case GRAVELLY_MOUNTAINS:
- case MOUNTAIN_EDGE:
- case RIVER:
- return 17;
+ case MOUNTAINS:
+ case GRAVELLY_MOUNTAINS:
+ case MOUNTAIN_EDGE:
+ case RIVER:
+ return 17;
- case SNOWY_MOUNTAINS:
- case SNOWY_TUNDRA:
- case ICE_SPIKES:
- case FROZEN_OCEAN:
- case FROZEN_RIVER:
- return 14;
+ case SNOWY_MOUNTAINS:
+ case SNOWY_TUNDRA:
+ case ICE_SPIKES:
+ case FROZEN_OCEAN:
+ case FROZEN_RIVER:
+ return 14;
- case BADLANDS:
- case BADLANDS_PLATEAU:
- case WOODED_BADLANDS_PLATEAU:
- case ERODED_BADLANDS:
- case MODIFIED_BADLANDS_PLATEAU:
- case MODIFIED_WOODED_BADLANDS_PLATEAU:
- case MUSHROOM_FIELDS:
- case MUSHROOM_FIELD_SHORE:
- return 24;
+ case BADLANDS:
+ case BADLANDS_PLATEAU:
+ case WOODED_BADLANDS_PLATEAU:
+ case ERODED_BADLANDS:
+ case MODIFIED_BADLANDS_PLATEAU:
+ case MODIFIED_WOODED_BADLANDS_PLATEAU:
+ case MUSHROOM_FIELDS:
+ case MUSHROOM_FIELD_SHORE:
+ return 24;
- case DEEP_OCEAN:
- case OCEAN:
- case COLD_OCEAN:
- case DEEP_COLD_OCEAN:
- case DEEP_FROZEN_OCEAN:
- case DEEP_LUKEWARM_OCEAN:
- case DEEP_WARM_OCEAN:
- case LUKEWARM_OCEAN:
- case WARM_OCEAN:
- return 62;
+ case DEEP_OCEAN:
+ case OCEAN:
+ case COLD_OCEAN:
+ case DEEP_COLD_OCEAN:
+ case DEEP_FROZEN_OCEAN:
+ case DEEP_LUKEWARM_OCEAN:
+ case DEEP_WARM_OCEAN:
+ case LUKEWARM_OCEAN:
+ case WARM_OCEAN:
+ return 62;
- case SWAMP:
- case SWAMP_HILLS:
- return 20;
+ case SWAMP:
+ case SWAMP_HILLS:
+ return 20;
- default:
- return 10;
+ default:
+ return 10;
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java
index 532bfa339..f6c14c79d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/resources/SaltResource.java
@@ -26,33 +26,33 @@ class SaltResource extends SlimefunResource {
}
switch (biome) {
- case SNOWY_BEACH:
- case STONE_SHORE:
- case BEACH:
- case DESERT_LAKES:
- case RIVER:
- case ICE_SPIKES:
- case FROZEN_RIVER:
- return 40;
+ case SNOWY_BEACH:
+ case STONE_SHORE:
+ case BEACH:
+ case DESERT_LAKES:
+ case RIVER:
+ case ICE_SPIKES:
+ case FROZEN_RIVER:
+ return 40;
- case DEEP_OCEAN:
- case OCEAN:
- case COLD_OCEAN:
- case DEEP_COLD_OCEAN:
- case DEEP_FROZEN_OCEAN:
- case DEEP_LUKEWARM_OCEAN:
- case DEEP_WARM_OCEAN:
- case FROZEN_OCEAN:
- case LUKEWARM_OCEAN:
- case WARM_OCEAN:
- return 60;
+ case DEEP_OCEAN:
+ case OCEAN:
+ case COLD_OCEAN:
+ case DEEP_COLD_OCEAN:
+ case DEEP_FROZEN_OCEAN:
+ case DEEP_LUKEWARM_OCEAN:
+ case DEEP_WARM_OCEAN:
+ case FROZEN_OCEAN:
+ case LUKEWARM_OCEAN:
+ case WARM_OCEAN:
+ return 60;
- case SWAMP:
- case SWAMP_HILLS:
- return 20;
+ case SWAMP:
+ case SWAMP_HILLS:
+ return 20;
- default:
- return 6;
+ default:
+ return 6;
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java
index 3fd2d11c3..3cc10b874 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java
@@ -52,6 +52,8 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.Crucible;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.EnhancedFurnace;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HardenedGlass;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramProjector;
+import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.IgnitionChamber;
+import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.OutputChest;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RainbowBlock;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RepairedSpawner;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.UnplaceableBlock;
@@ -77,18 +79,13 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generato
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators.LavaGenerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators.MagnesiumGenerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators.SolarGenerator;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AnimalGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoAnvil;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoBreeder;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoBrewer;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDrier;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoEnchanter;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutomatedCraftingChamber;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.BookBinder;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CarbonPress;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ChargingBench;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CropGrowthAccelerator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricDustWasher;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricFurnace;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricGoldPan;
@@ -103,11 +100,16 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.FoodFabricator;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.Freezer;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.HeatedPressureChamber;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.IronGolemAssembler;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.Refinery;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.TreeGrowthAccelerator;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.WitherAssembler;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.XPCollector;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AnimalGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.TreeGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.BookBinder;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.IronGolemAssembler;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.WitherAssembler;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.ExpCollector;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.NetherStarReactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.NuclearReactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.elevator.ElevatorPlate;
@@ -243,7 +245,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {new ItemStack(Material.COOKIE), SlimefunItems.ELYTRA_SCALE, null, null, null, null, null, null, null})
.register(plugin);
- new SlimefunItem(categories.basicMachines, SlimefunItems.OUTPUT_CHEST, RecipeType.ENHANCED_CRAFTING_TABLE,
+ new OutputChest(categories.basicMachines, SlimefunItems.OUTPUT_CHEST, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {SlimefunItems.LEAD_INGOT, new ItemStack(Material.HOPPER), SlimefunItems.LEAD_INGOT, SlimefunItems.LEAD_INGOT, new ItemStack(Material.CHEST), SlimefunItems.LEAD_INGOT, null, SlimefunItems.LEAD_INGOT, null})
.register(plugin);
@@ -401,7 +403,7 @@ public final class SlimefunItemSetup {
new MakeshiftSmeltery(categories.basicMachines, SlimefunItems.MAKESHIFT_SMELTERY).register(plugin);
new Smeltery(categories.basicMachines, SlimefunItems.SMELTERY).register(plugin);
- new SlimefunItem(categories.basicMachines, SlimefunItems.IGNITION_CHAMBER, RecipeType.ENHANCED_CRAFTING_TABLE,
+ new IgnitionChamber(categories.basicMachines, SlimefunItems.IGNITION_CHAMBER, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {new ItemStack(Material.IRON_INGOT), new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.IRON_INGOT), new ItemStack(Material.IRON_INGOT), SlimefunItems.BASIC_CIRCUIT_BOARD, new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.OBSERVER), null})
.register(plugin);
@@ -2287,7 +2289,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {null, SlimefunItems.CARBONADO, null, SlimefunItems.ELECTRIC_MOTOR, new ItemStack(Material.DIAMOND_AXE), SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.MAGNESIUM_SALT, SlimefunItems.BIG_CAPACITOR, SlimefunItems.MAGNESIUM_SALT})
.register(plugin);
- new XPCollector(categories.electricity, SlimefunItems.EXP_COLLECTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
+ new ExpCollector(categories.electricity, SlimefunItems.EXP_COLLECTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, SlimefunItems.BLISTERING_INGOT_3, null, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.AUTO_ENCHANTER, SlimefunItems.WITHER_PROOF_OBSIDIAN, SlimefunItems.ALUMINUM_BRONZE_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_BRONZE_INGOT})
.register(plugin);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java
index ed1c04fa3..510dfc07d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/ArmorTask.java
@@ -117,7 +117,7 @@ public class ArmorTask implements Runnable {
SlimefunPlugin.runSync(() -> {
SlimefunArmorPiece slimefunArmor = armorpiece.getItem().get();
- if (Slimefun.hasUnlocked(p, slimefunArmor, true)) {
+ if (slimefunArmor.canUse(p, true)) {
for (PotionEffect effect : slimefunArmor.getPotionEffects()) {
p.removePotionEffect(effect.getType());
p.addPotionEffect(effect);
@@ -138,7 +138,7 @@ public class ArmorTask implements Runnable {
SlimefunItem item = SlimefunItem.getByItem(helmet);
- if (item instanceof SolarHelmet && Slimefun.hasUnlocked(p, item, true)) {
+ if (item instanceof SolarHelmet && item.canUse(p, true)) {
((SolarHelmet) item).rechargeItems(p);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java
index 92ef1ec56..794751805 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java
@@ -4,7 +4,9 @@ import java.util.function.Consumer;
import java.util.logging.Level;
import javax.annotation.Nonnull;
+import javax.annotation.ParametersAreNonnullByDefault;
+import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.block.Block;
@@ -158,6 +160,30 @@ public class IntegrationsManager {
}
}
+ /**
+ * This method logs a {@link Throwable} that was caused by a {@link Plugin}
+ * we integrate into.
+ * Calling this method will probably log the error and provide the version of this {@link Plugin}
+ * for error analysis.
+ *
+ * @param name
+ * The name of the {@link Plugin}
+ * @param throwable
+ * The {@link Throwable} to throw
+ */
+ @ParametersAreNonnullByDefault
+ protected void logError(String name, Throwable throwable) {
+ Plugin externalPlugin = Bukkit.getPluginManager().getPlugin(name);
+
+ if (externalPlugin != null) {
+ String version = externalPlugin.getDescription().getVersion();
+ SlimefunPlugin.logger().log(Level.WARNING, "Is {0} v{1} up to date?", new Object[] { name, version });
+ SlimefunPlugin.logger().log(Level.SEVERE, throwable, () -> "An unknown error was detected while interacting with \"" + name + " v" + version + "\"");
+ } else {
+ SlimefunPlugin.logger().log(Level.SEVERE, throwable, () -> "An unknown error was detected while interacting with the plugin \"" + name + "\"");
+ }
+ }
+
/**
* This method loads an integration with a {@link Plugin} of the specified name.
* If that {@link Plugin} is installed and enabled, the provided callback will be run.
@@ -220,7 +246,15 @@ public class IntegrationsManager {
*/
@SuppressWarnings("deprecation")
public boolean isCustomBlock(@Nonnull Block block) {
- return isItemsAdderInstalled && ItemsAdder.isCustomBlock(block);
+ if (isItemsAdderInstalled) {
+ try {
+ return ItemsAdder.isCustomBlock(block);
+ } catch (Exception | LinkageError x) {
+ logError("ItemsAdder", x);
+ }
+ }
+
+ return false;
}
public boolean isPlaceholderAPIInstalled() {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java
index 722864a0f..2f82b935f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/McMMOIntegration.java
@@ -36,7 +36,11 @@ class McMMOIntegration implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlacerPlace(BlockPlacerPlaceEvent e) {
// This registers blocks placed by the BlockPlacer as "player-placed"
- mcMMO.getPlaceStore().setTrue(e.getBlock());
+ try {
+ mcMMO.getPlaceStore().setTrue(e.getBlock());
+ } catch (Exception | LinkageError x) {
+ SlimefunPlugin.getIntegrations().logError("mcMMO", x);
+ }
}
@EventHandler(ignoreCancelled = true)
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java
index e5a4d9b04..d71b68e92 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/PlaceholderAPIIntegration.java
@@ -62,7 +62,12 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion {
private boolean isPlaceholder(@Nullable OfflinePlayer p, boolean requiresProfile, @Nonnull String params, @Nonnull String placeholder) {
if (requiresProfile) {
- return p != null && placeholder.equals(params) && PlayerProfile.request(p);
+ if (p != null && placeholder.equals(params)) {
+ PlayerProfile.request(p);
+ return true;
+ } else {
+ return false;
+ }
} else {
return placeholder.equals(params);
}
@@ -77,7 +82,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion {
Stream stream = profile.get().getResearches().stream();
return String.valueOf(stream.mapToInt(Research::getCost).sum());
} else if (p instanceof Player) {
- return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading");
+ return getProfilePlaceholder((Player) p);
}
}
@@ -88,7 +93,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion {
Set set = profile.get().getResearches();
return String.valueOf(set.size());
} else if (p instanceof Player) {
- return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading");
+ return getProfilePlaceholder((Player) p);
}
}
@@ -103,7 +108,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion {
Set set = profile.get().getResearches();
return String.valueOf(Math.round(((set.size() * 100.0F) / SlimefunPlugin.getRegistry().getResearches().size()) * 100.0F) / 100.0F);
} else if (p instanceof Player) {
- return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading");
+ return getProfilePlaceholder((Player) p);
}
}
@@ -113,7 +118,7 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion {
if (profile.isPresent()) {
return profile.get().getTitle();
} else if (p instanceof Player) {
- return SlimefunPlugin.getLocalization().getMessage((Player) p, "placeholderapi.profile-loading");
+ return getProfilePlaceholder((Player) p);
}
}
@@ -133,4 +138,9 @@ class PlaceholderAPIIntegration extends PlaceholderExpansion {
return null;
}
+ @Nonnull
+ private String getProfilePlaceholder(@Nonnull Player p) {
+ return SlimefunPlugin.getLocalization().getMessage(p, "placeholderapi.profile-loading");
+ }
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java
index fb791fda3..4f6826508 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ColoredMaterial.java
@@ -47,6 +47,28 @@ public enum ColoredMaterial {
Material.BLACK_WOOL
}),
+ /**
+ * This {@link List} contains all carpet colors ordered by their appearance ingame.
+ */
+ CARPET(new Material[] {
+ Material.WHITE_CARPET,
+ Material.ORANGE_CARPET,
+ Material.MAGENTA_CARPET,
+ Material.LIGHT_BLUE_CARPET,
+ Material.YELLOW_CARPET,
+ Material.LIME_CARPET,
+ Material.PINK_CARPET,
+ Material.GRAY_CARPET,
+ Material.LIGHT_GRAY_CARPET,
+ Material.CYAN_CARPET,
+ Material.PURPLE_CARPET,
+ Material.BLUE_CARPET,
+ Material.BROWN_CARPET,
+ Material.GREEN_CARPET,
+ Material.RED_CARPET,
+ Material.BLACK_CARPET
+ }),
+
/**
* This {@link List} contains all stained glass colors ordered by their appearance ingame.
*/
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/InfiniteBlockGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/InfiniteBlockGenerator.java
new file mode 100644
index 000000000..de44929e9
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/InfiniteBlockGenerator.java
@@ -0,0 +1,175 @@
+package io.github.thebusybiscuit.slimefun4.utils;
+
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.BlockState;
+import org.bukkit.event.block.BlockFormEvent;
+
+import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
+import io.github.thebusybiscuit.slimefun4.implementation.items.androids.MinerAndroid;
+import io.papermc.lib.PaperLib;
+
+/**
+ * This enum holds various ways of infinite block generators.
+ * The most prominent member of these is the standard Cobblestone Generator.
+ * We use this enum for performance optimizations for the {@link MinerAndroid}.
+ *
+ * @author TheBusyBiscuit
+ *
+ */
+public enum InfiniteBlockGenerator implements Predicate {
+
+ /**
+ * Your standard Cobblestone Generator with flowing lava and water.
+ */
+ COBBLESTONE_GENERATOR("COBBLESTONE"),
+
+ /**
+ * When lava flows onto a stationary water block it generates normal stone.
+ */
+ STONE_GENERATOR("STONE"),
+
+ /**
+ * The Basalt Generator (1.16+ only) allows you to generate infinite Basalt!
+ */
+ BASALT_GENERATOR("BASALT");
+
+ public static final InfiniteBlockGenerator[] values = values();
+ private static final BlockFace[] sameLevelFaces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };
+
+ private final Material material;
+
+ InfiniteBlockGenerator(@Nonnull String type) {
+ this.material = Material.matchMaterial(type);
+ }
+
+ /**
+ * This returns the generated {@link Material} of this {@link InfiniteBlockGenerator}.
+ * This method can return null if the associated {@link Material} is not available in the current
+ * {@link MinecraftVersion}.
+ *
+ * @return The generated {@link Material} or null
+ */
+ @Nullable
+ public Material getGeneratedMaterial() {
+ return material;
+ }
+
+ /**
+ * Similar to {@link #test(Block)} this tests whether this {@link InfiniteBlockGenerator}
+ * exists at the given {@link Block}.
+ *
+ * @param b
+ * The {@link Block}
+ *
+ * @return Whether this {@link InfiniteBlockGenerator} exists at the given {@link Block}
+ */
+ @Override
+ public boolean test(@Nonnull Block b) {
+ Validate.notNull(b, "Block cannot be null!");
+
+ /*
+ * This will eliminate non-matching base materials If we
+ * are on a version without Basalt, it will be null here and not match.
+ */
+ if (b.getType() == getGeneratedMaterial()) {
+ switch (this) {
+ case COBBLESTONE_GENERATOR:
+ return hasSurroundingMaterials(b, Material.WATER, Material.LAVA);
+ case STONE_GENERATOR:
+ if (b.getRelative(BlockFace.UP).getType() == Material.LAVA) {
+ return hasSurroundingMaterials(b, Material.WATER);
+ } else {
+ return false;
+ }
+ case BASALT_GENERATOR:
+ if (b.getRelative(BlockFace.DOWN).getType() == Material.SOUL_SOIL) {
+ return hasSurroundingMaterials(b, Material.LAVA, Material.BLUE_ICE);
+ } else {
+ return false;
+ }
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ @ParametersAreNonnullByDefault
+ private boolean hasSurroundingMaterials(Block b, Material... materials) {
+ Validate.notNull(b, "The Block cannot be null!");
+ Validate.notEmpty(materials, "Materials need to have a size of at least one!");
+
+ boolean[] matches = new boolean[materials.length];
+ int count = 0;
+
+ for (BlockFace face : sameLevelFaces) {
+ Block neighbour = b.getRelative(face);
+ Material neighbourType = neighbour.getType();
+
+ for (int i = 0; i < materials.length; i++) {
+ if (neighbourType == materials[i] && !matches[i]) {
+ matches[i] = true;
+ count++;
+ break;
+ }
+ }
+
+ if (count == materials.length) {
+ return true;
+ }
+ }
+
+ return count == materials.length;
+ }
+
+ /**
+ * This method calls a {@link BlockFormEvent} for this {@link InfiniteBlockGenerator}.
+ * There are a few plugins who catch these events to inject custom {@link Material Materials} into
+ * Cobblestone Generators, so we wanna give them the oppurtunity to catch this as well.
+ *
+ * @param block
+ * The {@link Block} where the liquid has solidified
+ *
+ * @return Our called {@link BlockFormEvent}
+ */
+ @Nonnull
+ public BlockFormEvent callEvent(@Nonnull Block block) {
+ Validate.notNull(block, "The Block cannot be null!");
+ BlockState state = PaperLib.getBlockState(block, false).getState();
+ BlockFormEvent event = new BlockFormEvent(block, state);
+ Bukkit.getPluginManager().callEvent(event);
+ return event;
+ }
+
+ /**
+ * This will attempt to find an {@link InfiniteBlockGenerator} at the given {@link Block}.
+ *
+ * @param b
+ * The {@link Block}
+ *
+ * @return An {@link InfiniteBlockGenerator} or null if none was found.
+ */
+ @Nullable
+ public static InfiniteBlockGenerator findAt(@Nonnull Block b) {
+ Validate.notNull(b, "Cannot find a generator without a Location!");
+
+ for (InfiniteBlockGenerator generator : values) {
+ if (generator.test(b)) {
+ return generator;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java
index 8b6eff1ac..c7446de7f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java
@@ -15,6 +15,7 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Item;
+import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@@ -358,4 +359,31 @@ public final class SlimefunUtils {
SlimefunPlugin.runSync(new CapacitorTextureUpdateTask(l, charge, capacity));
}
+ /**
+ * This checks whether the {@link Player} is able to use the given {@link ItemStack}.
+ * It will always return
true
for non-Slimefun items.
+ *
+ * If you already have an instance of {@link SlimefunItem}, please use {@link SlimefunItem#canUse(Player, boolean)}.
+ *
+ * @param p
+ * The {@link Player}
+ * @param item
+ * The {@link ItemStack} to check
+ * @param sendMessage
+ * Whether to send a message response to the {@link Player}
+ *
+ * @return Whether the {@link Player} is able to use that item.
+ */
+ public static boolean canPlayerUseItem(@Nonnull Player p, @Nullable ItemStack item, boolean sendMessage) {
+ Validate.notNull(p, "The player cannot be null");
+
+ SlimefunItem sfItem = SlimefunItem.getByItem(item);
+
+ if (sfItem != null) {
+ return sfItem.canUse(p, sendMessage);
+ } else {
+ return true;
+ }
+ }
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java
index 855485681..c8bbd4b86 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/tags/SlimefunTag.java
@@ -21,7 +21,8 @@ import org.bukkit.block.data.Waterlogged;
import io.github.thebusybiscuit.slimefun4.api.exceptions.TagMisconfigurationException;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.BlockPlacer;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.CropGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator;
+import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.miner.IndustrialMiner;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ClimbingPick;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosiveShovel;
@@ -120,6 +121,12 @@ public enum SlimefunTag implements Tag {
*/
DIRT_VARIANTS,
+ /**
+ * All soil blocks for a fungus to grow on.
+ * This includes all dirt variants, nylium and soul soil.
+ */
+ FUNGUS_SOIL,
+
/**
* All variants of concrete powder.
* Can you believe there is no tag for this already?
@@ -184,6 +191,11 @@ public enum SlimefunTag implements Tag {
*/
INDUSTRIAL_MINER_ORES,
+ /**
+ * All materials (ores) which can be doubled using a Miner {@link Talisman}.
+ */
+ MINER_TALISMAN_TRIGGERS,
+
/**
* All materials (crops) which the {@link CropGrowthAccelerator} will recognize.
*/
@@ -210,8 +222,16 @@ public enum SlimefunTag implements Tag {
*/
CAVEMAN_TALISMAN_TRIGGERS;
+ /**
+ * Lookup table for tag names.
+ */
private static final Map nameLookup = new HashMap<>();
- public static final SlimefunTag[] valuesCache = values();
+
+ /**
+ * Speed up lookups by caching the values instead of creating a new array
+ * on every method call.
+ */
+ private static final SlimefunTag[] valuesCache = values();
static {
for (SlimefunTag tag : valuesCache) {
diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java
index d28037ba3..6c6b7860f 100644
--- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java
+++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/Item/CustomItemSerializer.java
@@ -59,49 +59,49 @@ public class CustomItemSerializer {
builder.append(flag.toString() + "=");
switch (flag) {
- case AMOUNT: {
- builder.append(item.getAmount());
- break;
- }
- case DATA: {
- builder.append((int) item.getData().getData());
- break;
- }
- case DURABILITY: {
- builder.append((int) item.getDurability());
- break;
- }
- case ENCHANTMENTS:
- for (Enchantment enchantment : Enchantment.values()) {
- if (item.getEnchantments().containsKey(enchantment)) {
- builder.append(enchantment.getName() + ":" + item.getEnchantmentLevel(enchantment));
- } else {
- builder.append(enchantment.getName() + ":0");
+ case AMOUNT: {
+ builder.append(item.getAmount());
+ break;
+ }
+ case DATA: {
+ builder.append((int) item.getData().getData());
+ break;
+ }
+ case DURABILITY: {
+ builder.append((int) item.getDurability());
+ break;
+ }
+ case ENCHANTMENTS:
+ for (Enchantment enchantment : Enchantment.values()) {
+ if (item.getEnchantments().containsKey(enchantment)) {
+ builder.append(enchantment.getName() + ":" + item.getEnchantmentLevel(enchantment));
+ } else {
+ builder.append(enchantment.getName() + ":0");
+ }
}
+ break;
+ case ITEMMETA_DISPLAY_NAME: {
+ if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
+ builder.append(item.getItemMeta().getDisplayName().replaceAll("\\u00a7", "&"));
+ } else {
+ builder.append("NONE");
+ }
+ break;
}
- break;
- case ITEMMETA_DISPLAY_NAME: {
- if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
- builder.append(item.getItemMeta().getDisplayName().replaceAll("\\u00a7", "&"));
- } else {
- builder.append("NONE");
+ case ITEMMETA_LORE: {
+ if (item.hasItemMeta() && item.getItemMeta().hasLore()) {
+ builder.append(item.getItemMeta().getLore().toString().replaceAll("\\u00a7", "&"));
+ } else {
+ builder.append("NONE");
+ }
+ break;
}
- break;
- }
- case ITEMMETA_LORE: {
- if (item.hasItemMeta() && item.getItemMeta().hasLore()) {
- builder.append(item.getItemMeta().getLore().toString().replaceAll("\\u00a7", "&"));
- } else {
- builder.append("NONE");
+ case MATERIAL: {
+ builder.append(item.getType().toString());
+ break;
}
- break;
- }
- case MATERIAL: {
- builder.append(item.getType().toString());
- break;
- }
- default:
- break;
+ default:
+ break;
}
i++;
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java b/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java
index 084a6bbe8..635643bb3 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java
@@ -9,6 +9,8 @@ import java.util.Locale;
import java.util.Set;
import java.util.function.BiConsumer;
+import javax.annotation.ParametersAreNonnullByDefault;
+
import org.bukkit.ChatColor;
import org.bukkit.Keyed;
import org.bukkit.Material;
@@ -138,16 +140,32 @@ public class RecipeType implements Keyed {
}
@Override
- public NamespacedKey getKey() {
+ public final NamespacedKey getKey() {
return key;
}
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj instanceof RecipeType) {
+ return ((RecipeType) obj).getKey().equals(this.getKey());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public final int hashCode() {
+ return getKey().hashCode();
+ }
+
+ @ParametersAreNonnullByDefault
private static void registerBarterDrop(ItemStack[] recipe, ItemStack output) {
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
SlimefunPlugin.getRegistry().getBarteringDrops().add(output);
}
}
+ @ParametersAreNonnullByDefault
private static void registerMobDrop(ItemStack[] recipe, ItemStack output) {
String mob = ChatColor.stripColor(recipe[4].getItemMeta().getDisplayName()).toUpperCase(Locale.ROOT).replace(' ', '_');
EntityType entity = EntityType.valueOf(mob);
@@ -211,4 +229,4 @@ public class RecipeType implements Keyed {
List recipes = machine.getRecipes();
return recipes.get((recipes.indexOf(input) + 1))[0];
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java
index cf95721f3..2a2ac688e 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java
@@ -26,7 +26,6 @@ import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* Represents a category, which structure multiple {@link SlimefunItem} in the {@link SlimefunGuide}.
@@ -90,7 +89,8 @@ public class Category implements Keyed {
}
@Override
- public NamespacedKey getKey() {
+ @Nonnull
+ public final NamespacedKey getKey() {
return key;
}
@@ -226,7 +226,7 @@ public class Category implements Keyed {
*
* @return Whether the given {@link SlimefunItem} was found in this {@link Category}
*/
- public boolean contains(SlimefunItem item) {
+ public boolean contains(@Nullable SlimefunItem item) {
return item != null && items.contains(item);
}
@@ -240,6 +240,20 @@ public class Category implements Keyed {
return tier;
}
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj instanceof Category) {
+ return ((Category) obj).getKey().equals(getKey());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public final int hashCode() {
+ return key.hashCode();
+ }
+
@Override
public String toString() {
return getClass().getSimpleName() + " {" + key + ",tier=" + tier + "}";
@@ -258,7 +272,7 @@ public class Category implements Keyed {
*/
public boolean isHidden(@Nonnull Player p) {
for (SlimefunItem slimefunItem : getItems()) {
- if (!slimefunItem.isHidden() && Slimefun.isEnabled(p, slimefunItem, false)) {
+ if (!slimefunItem.isHidden() && !slimefunItem.isDisabledIn(p.getWorld())) {
return false;
}
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java
index 2fcce02eb..6009883e6 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunBlockHandler.java
@@ -4,6 +4,7 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
@@ -16,8 +17,10 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
*
* @author TheBusyBiscuit
*
+ * @deprecated Please use the {@link BlockBreakHandler} instead.
*
*/
+@Deprecated
@FunctionalInterface
public interface SlimefunBlockHandler {
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java
index 5cca61a0d..4473093fb 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java
@@ -16,9 +16,11 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
+import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.permissions.Permission;
import io.github.thebusybiscuit.cscorelib2.collections.OptionalMap;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
@@ -32,22 +34,23 @@ import io.github.thebusybiscuit.slimefun4.api.exceptions.UnregisteredItemExcepti
import io.github.thebusybiscuit.slimefun4.api.exceptions.WrongItemStackException;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
+import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotConfigurable;
import io.github.thebusybiscuit.slimefun4.core.attributes.Placeable;
import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
+import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter;
-import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoEnchanter;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter;
+import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
@@ -242,6 +245,13 @@ public class SlimefunItem implements Placeable {
return recipe;
}
+ /**
+ * This method returns the {@link RecipeType}.
+ * The {@link RecipeType} determines how this {@link SlimefunItem} is crafted.
+ *
+ * @return The {@link RecipeType} of this {@link SlimefunItem}
+ */
+ @Nonnull
public RecipeType getRecipeType() {
return recipeType;
}
@@ -377,6 +387,26 @@ public class SlimefunItem implements Placeable {
return state != ItemState.ENABLED;
}
+ /**
+ * This method returns whether this {@link SlimefunItem} is disabled
+ * for that specific {@link World}.
+ * Note that if the item is disabled globally, this method will still return false.
+ *
+ * @param world
+ * The {@link World} to check
+ *
+ * @return Whether this {@link SlimefunItem} is disabled in that world (or in general).
+ */
+ public boolean isDisabledIn(@Nonnull World world) {
+ if (state == ItemState.UNREGISTERED) {
+ error("isDisabled(World) cannot be called before registering the item", new UnregisteredItemException(this));
+ return false;
+ }
+
+ // Check if the Item is disabled globally or in this specific world
+ return isDisabled() || !SlimefunPlugin.getWorldSettingsService().isEnabled(world, this);
+ }
+
/**
* This method returns the {@link SlimefunAddon} that registered this
* {@link SlimefunItem}. If this Item is from Slimefun itself, the current
@@ -906,6 +936,7 @@ public class SlimefunItem implements Placeable {
*
* @return Whether or not an {@link ItemHandler} was found.
*/
+ @ParametersAreNonnullByDefault
public boolean callItemHandler(Class c, Consumer callable) {
Optional handler = itemhandlers.get(c);
@@ -996,7 +1027,6 @@ public class SlimefunItem implements Placeable {
*/
public void error(@Nonnull String message, @Nonnull Throwable throwable) {
Validate.notNull(addon, "Cannot send an error for an unregistered item!");
-
addon.getLogger().log(Level.SEVERE, "Item \"{0}\" from {1} v{2} has caused an Error!", new Object[] { id, addon.getName(), addon.getPluginVersion() });
if (addon.getBugTrackerURL() != null) {
@@ -1012,6 +1042,88 @@ public class SlimefunItem implements Placeable {
}
}
+ /**
+ * This method checks if the given {@link Player} is able to use this {@link SlimefunItem}.
+ * A {@link Player} can use it if the following conditions apply:
+ *
+ *
+ * - The {@link SlimefunItem} is not disabled
+ *
- The {@link SlimefunItem} was not disabled for that {@link Player}'s {@link World}.
+ *
- The {@link Player} has the required {@link Permission} (if present)
+ *
- The {@link Player} has unlocked the required {@link Research} (if present)
+ *
+ *
+ * If any of these conditions evaluate to false
, then an optional message will be
+ * sent to the {@link Player}.
+ *
+ * @param p
+ * The {@link Player} to check
+ * @param sendMessage
+ * Whether to send that {@link Player} a message response.
+ *
+ * @return Whether this {@link Player} is able to use this {@link SlimefunItem}.
+ */
+ public boolean canUse(@Nonnull Player p, boolean sendMessage) {
+ Validate.notNull(p, "The Player cannot be null!");
+
+ if (getState() == ItemState.VANILLA_FALLBACK) {
+ // Vanilla items (which fell back) can always be used.
+ return true;
+ } else if (isDisabled()) {
+ // The Item has been disabled in the config
+ if (sendMessage) {
+ SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-item", true);
+ }
+
+ return false;
+ } else if (!SlimefunPlugin.getWorldSettingsService().isEnabled(p.getWorld(), this)) {
+ // The Item was disabled in the current World
+ if (sendMessage) {
+ SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-in-world", true);
+ }
+
+ return false;
+ } else if (!SlimefunPlugin.getPermissionsService().hasPermission(p, this)) {
+ // The Player does not have the required permission node
+ if (sendMessage) {
+ SlimefunPlugin.getLocalization().sendMessage(p, "messages.no-permission", true);
+ }
+
+ return false;
+ } else if (hasResearch()) {
+ Optional profile = PlayerProfile.find(p);
+
+ if (!profile.isPresent()) {
+ /*
+ * We will return false since we cannot know the answer yet.
+ * But we will schedule the Profile for loading and not send
+ * any message.
+ */
+ PlayerProfile.request(p);
+ return false;
+ } else if (!profile.get().hasUnlocked(getResearch())) {
+ /*
+ * The Profile is loaded but Player has not unlocked the
+ * required Research to use this SlimefunItem.
+ */
+ if (sendMessage && !(this instanceof VanillaItem)) {
+ SlimefunPlugin.getLocalization().sendMessage(p, "messages.not-researched", true);
+ }
+
+ return false;
+ } else {
+ /*
+ * The PlayerProfile is loaded and the Player has unlocked
+ * the required Research.
+ */
+ return true;
+ }
+ } else {
+ // All checks have passed, the Player can use this item.
+ return true;
+ }
+ }
+
@Override
public final boolean equals(Object obj) {
if (obj instanceof SlimefunItem) {
@@ -1052,12 +1164,16 @@ public class SlimefunItem implements Placeable {
// This wrapper improves the heavy ItemStack#getItemMeta() call by caching it.
ItemStackWrapper wrapper = new ItemStackWrapper(item);
- // Quite expensive performance-wise
- // But necessary for supporting legacy items
+ /*
+ * Quite expensive performance-wise.
+ * But necessary for supporting legacy items
+ */
for (SlimefunItem sfi : SlimefunPlugin.getRegistry().getAllSlimefunItems()) {
if (sfi.isItem(wrapper)) {
- // If we have to loop all items for the given item, then at least
- // set the id via PersistentDataAPI for future performance boosts
+ /*
+ * If we have to loop all items for the given item, then at least
+ * set the id via PersistentDataAPI for future performance boosts
+ */
SlimefunPlugin.getItemDataService().setItemData(item, sfi.getId());
return sfi;
@@ -1068,12 +1184,24 @@ public class SlimefunItem implements Placeable {
return null;
}
- public static Set getPublicItemHandlers(Class extends ItemHandler> identifier) {
+ @Nonnull
+ public static Set getPublicItemHandlers(@Nonnull Class extends ItemHandler> identifier) {
return SlimefunPlugin.getRegistry().getPublicItemHandlers().computeIfAbsent(identifier, c -> new HashSet<>());
}
- public static void registerBlockHandler(String id, SlimefunBlockHandler handler) {
+ /**
+ * This has been deprecated.
+ *
+ * @deprecated Please use {@link #addItemHandler(ItemHandler...)} and {@link BlockBreakHandler} instead
+ *
+ * @param id
+ * The id
+ * @param handler
+ * The handler
+ */
+ @Deprecated
+ public static void registerBlockHandler(@Nonnull String id, @Nullable me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler handler) {
SlimefunPlugin.getRegistry().getBlockHandlers().put(id, handler);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java
index fd76a81c9..3361d2787 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/UnregisterReason.java
@@ -10,9 +10,12 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
*
* @author TheBusyBiscuit
*
+ * @deprecated This enum is no longer needed
+ *
* @see SlimefunBlockHandler
*
*/
+@Deprecated
public enum UnregisterReason {
/**
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java
index b09f898e8..59c1bb77c 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/interfaces/InventoryBlock.java
@@ -16,7 +16,8 @@ import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
/**
*
- * @deprecated This interface is not designed to be used by addons.
+ * @deprecated This interface is not designed to be used by addons. The entire inventory system will be replaced
+ * eventually.
*
*/
public interface InventoryBlock {
@@ -60,7 +61,7 @@ public interface InventoryBlock {
@Override
public boolean canOpen(Block b, Player p) {
- return p.hasPermission("slimefun.inventory.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES) && Slimefun.hasUnlocked(p, item, false));
+ return p.hasPermission("slimefun.inventory.bypass") || (SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK) && Slimefun.hasUnlocked(p, item, false));
}
};
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java
index 7333724c2..e2a33f7fe 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/ItemHandler.java
@@ -2,6 +2,8 @@ package me.mrCookieSlime.Slimefun.Objects.handlers;
import java.util.Optional;
+import javax.annotation.Nonnull;
+
import io.github.thebusybiscuit.slimefun4.api.exceptions.IncompatibleItemHandlerException;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BowShootHandler;
@@ -51,7 +53,8 @@ public interface ItemHandler {
* @return An {@link Optional} describing the result, it will contain an {@link IncompatibleItemHandlerException}
* should there be an issue
*/
- default Optional validate(SlimefunItem item) {
+ @Nonnull
+ default Optional validate(@Nonnull SlimefunItem item) {
return Optional.empty();
}
@@ -61,5 +64,6 @@ public interface ItemHandler {
*
* @return The {@link Class} identifier for this {@link ItemHandler}
*/
+ @Nonnull
Class extends ItemHandler> getIdentifier();
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java
index c04900fa7..5c75ac863 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java
@@ -378,7 +378,8 @@ public class BlockStorage {
* This will return an {@link ImmutableMap} of the underline {@code Map} of
* this worlds {@link BlockStorage}. If there is no registered world then this will return null.
*
- * @param world The world of which to fetch the data from.
+ * @param world
+ * The world of which to fetch the data from.
* @return An {@link ImmutableMap} of the raw data or null if the world isn't registered.
*/
@Nullable
@@ -416,19 +417,14 @@ public class BlockStorage {
* @return the SlimefunItem's ItemStack corresponding to the block if it has one, otherwise null
*/
@Nullable
- public static ItemStack retrieve(Block block) {
- if (!hasBlockInfo(block)) {
+ public static ItemStack retrieve(@Nonnull Block block) {
+ SlimefunItem item = check(block);
+
+ if (item == null) {
return null;
} else {
- String id = getLocationInfo(block.getLocation(), "id");
- SlimefunItem item = SlimefunItem.getByID(id);
clearBlockInfo(block);
-
- if (item == null) {
- return null;
- } else {
- return item.getItem();
- }
+ return item.getItem();
}
}
@@ -704,6 +700,11 @@ public class BlockStorage {
return id == null ? null : SlimefunItem.getByID(id);
}
+ public static boolean check(Block block, String slimefunItem) {
+ String id = checkID(block);
+ return id != null && id.equals(slimefunItem);
+ }
+
@Nullable
public static String checkID(@Nonnull Block b) {
// Only access the BlockState when on the main thread
@@ -718,16 +719,8 @@ public class BlockStorage {
return checkID(b.getLocation());
}
- public static boolean check(Block block, String slimefunItem) {
- String id = checkID(block);
- return id != null && id.equals(slimefunItem);
- }
-
- public static String checkID(Location l) {
- if (!hasBlockInfo(l)) {
- return null;
- }
-
+ @Nullable
+ public static String checkID(@Nonnull Location l) {
return getLocationInfo(l, "id");
}
@@ -740,7 +733,7 @@ public class BlockStorage {
return id != null && id.equals(slimefunItem);
}
- public static boolean isWorldLoaded(World world) {
+ public static boolean isWorldLoaded(@Nonnull World world) {
return SlimefunPlugin.getRegistry().getWorlds().containsKey(world.getName());
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java
index 6b843802c..de397d152 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java
@@ -1,18 +1,15 @@
package me.mrCookieSlime.Slimefun.api;
-import java.util.Optional;
-
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
-import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
-import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
-import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
+import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* Provides a few static convenience methods.
+ * This class is slowly getting stripped away in favour of a more object-oriented approach.
*
* @author TheBusyBiscuit
* @author Walshy
@@ -31,19 +28,17 @@ public final class Slimefun {
* the item to check, not null
* @param message
* whether a message should be sent to the player or not
+ *
+ * @deprecated Moved to
+ * {@link SlimefunUtils#canPlayerUseItem(Player, ItemStack, boolean)}
*
* @return true
if the item is a SlimefunItem, enabled, researched and if the player has the permission
* to use it,
* false
otherwise.
*/
+ @Deprecated
public static boolean hasUnlocked(Player p, ItemStack item, boolean message) {
- SlimefunItem sfItem = SlimefunItem.getByItem(item);
-
- if (sfItem != null) {
- return hasUnlocked(p, sfItem, message);
- } else {
- return true;
- }
+ return SlimefunUtils.canPlayerUseItem(p, item, message);
}
/**
@@ -55,39 +50,15 @@ public final class Slimefun {
* the item to check, not null
* @param message
* whether a message should be sent to the player or not
+ *
+ * @deprecated Please use {@link SlimefunItem#canUse(Player, boolean)} instead.
*
* @return true
if the item is enabled, researched and the player has the permission to use it,
* false
otherwise.
*/
+ @Deprecated
public static boolean hasUnlocked(Player p, SlimefunItem sfItem, boolean message) {
- if (sfItem.getState() == ItemState.VANILLA_FALLBACK) {
- return true;
- }
-
- if (isEnabled(p, sfItem, message) && hasPermission(p, sfItem, message)) {
- if (sfItem.getResearch() == null) {
- return true;
- } else {
- Optional profile = PlayerProfile.find(p);
-
- if (!profile.isPresent()) {
- // We will return false since we cannot know the answer yet
- // But we will schedule the Profile for loading.
- PlayerProfile.request(p);
- return false;
- } else if (profile.get().hasUnlocked(sfItem.getResearch())) {
- return true;
- } else {
- if (message && !(sfItem instanceof VanillaItem)) {
- SlimefunPlugin.getLocalization().sendMessage(p, "messages.not-researched", true);
- }
-
- return false;
- }
- }
- }
-
- return false;
+ return sfItem.canUse(p, message);
}
/**
@@ -126,10 +97,13 @@ public final class Slimefun {
* the item to check, not null
* @param message
* whether a message should be sent to the player or not
+ *
+ * @deprecated This method will be removed.
*
* @return true
if the item is a SlimefunItem and is enabled in the world the player is in,
* false
otherwise.
*/
+ @Deprecated
public static boolean isEnabled(Player p, ItemStack item, boolean message) {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 84aff21b3..a0f9cd53a 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -38,9 +38,8 @@ networks:
enable-visualizer: true
delete-excess-items: false
-items:
- talismans: true
- soulbound: true
+talismans:
+ use-actionbar: true
metrics:
auto-update: true
diff --git a/src/main/resources/languages/categories_cs.yml b/src/main/resources/languages/categories_cs.yml
index 1facb887f..6a4ea3f5b 100644
--- a/src/main/resources/languages/categories_cs.yml
+++ b/src/main/resources/languages/categories_cs.yml
@@ -1,25 +1,26 @@
---
slimefun:
- armor: Brnění
- basic_machines: Základní stroje
- birthday: TheBusyBiscuitovy narozeniny (26. Říjen)
- cargo: Cargo systém
- christmas: Vánoce (Prosinec)
- easter: Velikonoce (Duben)
- electricity: Energie a elektrika
- ender_talismans: Ender Talismany (Tier II)
- food: Jídlo
- gps: GPS stroje
- halloween: Halloween (31. Října)
- items: Užitečné itemy
- magical_armor: Magická zbroj
- magical_gadgets: Magické pomůcky
- magical_items: Magické itemy
- resources: Materiály
- talismans: Talismany (Tier I)
- tech_misc: Technické komponenty
- technical_gadgets: Technické pomůcky
- tools: Nástroje
weapons: Zbraně
- misc: Smíšené položky
- valentines_day: Svatého Valentýna (14. Února)
+ tools: Nástroje
+ items: Užitečné předměty
+ food: Jídlo
+ basic_machines: Základní stroje
+ electricity: Energie a elektrika
+ gps: GPS stroje
+ armor: Brnění
+ magical_items: Magické předměty
+ magical_gadgets: Magické pomůcky
+ misc: Smíšené předměty
+ technical_gadgets: Technické pomůcky
+ resources: Materiály
+ cargo: Cargo systém
+ tech_misc: Technické komponenty
+ magical_armor: Magická zbroj
+ talismans: Talismany (Tier I)
+ ender_talismans: Enderitové talismany (Tier II)
+ christmas: Vánoce (prosinec)
+ valentines_day: Svatého Valentýna (14. února)
+ easter: Velikonoce (duben)
+ birthday: TheBusyBiscuitovy narozeniny (26. říjen)
+ halloween: Halloween (31. října)
+ androids: Programovatelné androidy
diff --git a/src/main/resources/languages/categories_fi.yml b/src/main/resources/languages/categories_fi.yml
new file mode 100644
index 000000000..df0ad816b
--- /dev/null
+++ b/src/main/resources/languages/categories_fi.yml
@@ -0,0 +1,26 @@
+---
+slimefun:
+ weapons: Aseet
+ tools: Työkalut
+ items: Hyödyllisiä Tuotteita
+ food: Ruoka
+ basic_machines: Peruskoneet
+ electricity: Energia ja sähkö
+ gps: GPS-pohjaiset koneet
+ armor: Panssari
+ magical_items: Maagiset esineet
+ magical_gadgets: Maagiset gadgetit
+ misc: Sekalaiset tuotteet
+ technical_gadgets: Tekniset gadgetit
+ resources: Resurssit
+ cargo: Cargo Management
+ tech_misc: Tekniset komponentit
+ magical_armor: Maaginen panssari
+ talismans: Talismanit (Taso I)
+ ender_talismans: Ender Talismanit (Taso II)
+ christmas: Joulu (joulukuu)
+ valentines_day: Ystävänpäivä (14. helmikuuta)
+ easter: Pääsiäinen (huhtikuu)
+ birthday: TheBusyBiscuit syntymäpäivä (26. lokakuuta)
+ halloween: Halloween (31. lokakuuta)
+ androids: Ohjelmoitavat androidit
diff --git a/src/main/resources/languages/categories_nl.yml b/src/main/resources/languages/categories_nl.yml
index eef15e6b7..54f830d80 100644
--- a/src/main/resources/languages/categories_nl.yml
+++ b/src/main/resources/languages/categories_nl.yml
@@ -2,7 +2,7 @@
slimefun:
weapons: Wapens
tools: Gereedschappen
- items: Voorwerpen
+ items: Handige Voorwerpen
food: Eten
basic_machines: Standaard machines
electricity: Energie en Elektriciteit
@@ -13,7 +13,7 @@ slimefun:
misc: Diverse Voorwerpen
technical_gadgets: Technische Gadgets
resources: Grondstoffen
- cargo: Cargobehering
+ cargo: Opslagbehering
tech_misc: Technische Componenten
magical_armor: Magische Bescherming
talismans: Amuletten (Niveau I)
diff --git a/src/main/resources/languages/categories_vi.yml b/src/main/resources/languages/categories_vi.yml
index 0fa2393dc..f8a0798b4 100644
--- a/src/main/resources/languages/categories_vi.yml
+++ b/src/main/resources/languages/categories_vi.yml
@@ -14,7 +14,7 @@ slimefun:
technical_gadgets: Những Đồ Dùng Kỹ Thuật
resources: Những Tài Nguyên
cargo: Quản Lý Hàng Hoá
- tech_misc: Những Thành Phần Kỷ Thuật
+ tech_misc: Những Thành Phần Kỹ Thuật
magical_armor: Giáp Ma Thuật
talismans: Bùa Hộ Mệnh ( Loại I )
ender_talismans: Bùa Hộ Mệnh ( Loại II )
@@ -23,4 +23,4 @@ slimefun:
easter: Lệ Phục Sinh (Tháng Tư)
birthday: Sinh Nhật TheBusyBiscuit (26 Tháng 10)
halloween: Halloween (31 tháng 10)
- androids: Programmable Androids
+ androids: Android lập trình
diff --git a/src/main/resources/languages/messages_bg.yml b/src/main/resources/languages/messages_bg.yml
index 699fa7f3c..bfa337459 100644
--- a/src/main/resources/languages/messages_bg.yml
+++ b/src/main/resources/languages/messages_bg.yml
@@ -4,7 +4,7 @@ commands:
cheat: Позволява Ви да чийтвате Предмети
give: Позволява Ви да давате на някого Slimefun Предмети
guide: Дава ви Slimefun Ръководство
- teleporter: Вижте пътни точки от други играчи
+ teleporter: Вижте пътни точки на други играчи
versions: Лист с всички инсталирани Добавки
search: Претърсва вашето Ръководство за даден термин / предмет
open_guide: Отваря Ви Slimefun Ръководството без да използвате книгата
@@ -48,10 +48,10 @@ guide:
selected-language: 'Избран в момента:'
change: Натисни, за да избереш нов език
description:
- - "&7Сега имаш опцията да промениш"
- - "&7езика, на който е Slimefun"
- - "&7той ще се промени само за теб. Предметите"
- - "&7не могат да бъдат преведени за момента."
+ '0': "&7Сега имаш опцията да промениш"
+ '1': "&7езика, на който е Slimefun"
+ '2': "&7той ще се промени само за теб. Предметите"
+ '3': "&7не могат да бъдат преведени за момента."
title:
main: Slimefun Ръководство
settings: Настройки & Информация
@@ -73,10 +73,10 @@ guide:
profile-link: Натиснете, за да видите техния профил в GitHub
open: Натисни, за да видиш нашите контрибутори
description:
- - "&7Slimefun е проект с отворен код"
- - "&7и е поддържан от голямо общество от хора."
- - "&7Над &e%contributors% &7хора са работили върху"
- - "&7Slimefun през всички тези години."
+ '0': "&7Slimefun е проект с отворен код"
+ '1': "&7и е поддържан от голямо общество от хора."
+ '2': "&7Над &e%contributors% &7хора са работили върху"
+ '3': "&7Slimefun през всички тези години."
pages:
previous: Предишна страница
next: Следваща страница
@@ -96,9 +96,9 @@ guide:
settings: Върнете се обратно в Панела с Настройки(Settings Panel)
locked: ЗАКЛЮЧЕНО
locked-category:
- - За да отключите тази категория
- - ще трябва да отключите всички предмети от
- - следните категории
+ '0': За да отключите тази категория
+ '1': ще трябва да отключите всички предмети от
+ '2': следните категории
work-in-progress: Тази функция не е завършена все още!
messages:
not-researched: "&4Нямате достатъчно познания, за да разберете това"
@@ -154,22 +154,22 @@ messages:
link-prompt: "&eНатиснете тук:"
diet-cookie: "&eЗапочнахте да се чувствате доста лекичък..."
fortune-cookie:
- - "&7Помогнете ми, аз съм затворен в Фабрика за Късметлийски Бисквитки!"
- - "&7Утре Вие ще умрете... от Creeper"
- - "&7В някакъв момент от живота Ви нещо лошо ще се случи!!!"
- - "&7Следващата седмица ще забележите, че това не е реалния свят, а всъщност Вие
- сте в компютърна игра"
- - "&7Тази бисквитка ще стане вкусна в следващите няколко секунди"
- - '&7Последната дума, която ще чуете ще бъде "УНИЩОЖЕТЕ!!!"'
- - "&7Каквото и да правите никога, ама никога не прегръщайте Creeper... Аз опитах.
- Доста добре е, но не си заслужава."
- - "&742. Отговорът е 42."
- - "&7Walshy веднъж на ден ще пази неприятностите далече."
- - "&7Никога не копайте право надолу!"
- - "&7Туй е само плътна рана!"
- - "&7Винаги гледайте от към хубавата страна на живота!"
- - "&7Това беше Бисквитка, а не Курабийка"
- - "&7Неоновите табели светят!"
+ '0': "&7Помогнете ми, аз съм затворен в Фабрика за Късметлийски Бисквитки!"
+ '1': "&7Утре Вие ще умрете... от Creeper"
+ '2': "&7В някакъв момент от живота Ви нещо лошо ще се случи!!!"
+ '3': "&7Следващата седмица ще забележите, че това не е реалния свят, а всъщност
+ Вие сте в компютърна игра"
+ '4': "&7Тази бисквитка ще стане вкусна в следващите няколко секунди"
+ '5': '&7Последната дума, която ще чуете ще бъде "УНИЩОЖЕТЕ!!!"'
+ '6': "&7Каквото и да правите никога, ама никога не прегръщайте Creeper... Аз опитах.
+ Доста добре е, но не си заслужава."
+ '7': "&742. Отговорът е 42."
+ '8': "&7Walshy веднъж на ден ще пази неприятностите далече."
+ '9': "&7Никога не копайте право надолу!"
+ '10': "&7Туй е само плътна рана!"
+ '11': "&7Винаги гледайте от към хубавата страна на живота!"
+ '12': "&7Това беше Бисквитка, а не Курабийка"
+ '13': "&7Неоновите табели светят!"
piglin-barter: "&4Не може да разменяте предмети с Пиглините използвайки предмети
от Slimefun"
enchantment-rune:
@@ -269,9 +269,9 @@ gps:
max: "&4Достигнахте максималната бройка локации"
duplicate: "&4Вие вече сте създал локация на име: &f%waypoint%"
insufficient-complexity:
- - "&4Недостатъчна Сложност на GPS Мрежата: &c%complexity%"
- - "&4a) Все още нямате направена GPS Мрежа"
- - "&4b) Вашата GPS Мрежа не е достатъчно сложна"
+ '0': "&4Недостатъчна Сложност на GPS Мрежата: &c%complexity%"
+ '1': "&4a) Все още нямате направена GPS Мрежа"
+ '2': "&4b) Вашата GPS Мрежа не е достатъчно сложна"
geo:
scan-required: "&4GEO-Scan изискан! &cПърво сканирайте този чънк използвайки GEO-Scanner!"
inventory:
@@ -310,11 +310,10 @@ android:
INTERFACE_ITEMS: "&9Изпратни съдаржанието на Инвентара към лицевия Интерфейс"
INTERFACE_FUEL: "&cИзвадете Гориво от лицевия Интерфейс"
enter-name:
- -
- - "&eМоля въведете име за скрипта си"
+ '1': "&eМоля въведете име за скрипта си"
uploaded:
- - "&bКачване..."
- - "&aУспешно качихме твоя скрипт!"
+ '0': "&bКачване..."
+ '1': "&aУспешно качихме твоя скрипт!"
rating:
own: "&4Не може да оцените собствения си скрипт!"
already: "&4Вие вече сте оставили рейтинг за този скрипт!"
@@ -370,3 +369,5 @@ cartography_table:
not-working: "&4Не може да използвате Slimefun предмети в картографска маса!"
cauldron:
no-discoloring: "&4Не можете да обезцветявате Slimefun брони"
+placeholderapi:
+ profile-loading: Зареждане...
diff --git a/src/main/resources/languages/messages_cs.yml b/src/main/resources/languages/messages_cs.yml
index 89f93a40f..127b0d438 100644
--- a/src/main/resources/languages/messages_cs.yml
+++ b/src/main/resources/languages/messages_cs.yml
@@ -1,34 +1,38 @@
---
commands:
help: Zobrazí tuto nápovědu
- cheat: Umožňuje nacheatovat věci
- give: Dejte někomu nějaké Slimefun věci
- guide: Dá vám Slimefun příručku
- timings: Lag-Info vašeho serveru
- teleporter: "Zobrazí \nznačky \nostatních hráčů"
- versions: Seznam všech nainstalovaných doplňků
- search: Vyhledá ve vaší příručce daný příkaz
+ cheat: Umožní našvindlovat si věci
+ give: Dá hráči vybrané Slimefun předměty
+ guide: Dá Slimefun příručku
+ teleporter: Zobrazí záchytné body ostatních hráčů
+ versions: Zobrazí všechny nainstalované doplňky
+ search: Vyhledá v příručce daný předmět
open_guide: Otevře Slimefun příručku bez použití knihy
stats: Ukáže statistiky hráče
research:
- description: Odemkne/Resetuje výzkum daného hráče
+ description: Odemkne či resetuje výzkum daného hráče
reset: "&cResetoval jsi výzkum hráče %player%"
reset-target: "&cTvoje znalost byla resetována "
backpack:
description: Načíst kopii existujícího batohu
invalid-id: "&4Id nesmí být záporné!"
player-never-joined: "&4Hráče s tímto jménem nelze nalézt!"
- backpack-does-not-exist: "&4Určený batoh neexistuje!"
+ backpack-does-not-exist: "&4Zadaný batoh neexistuje!"
restored-backpack-given: "&aTvůj batoh byl obnoven a navrácen do tvého inventáře!"
+ charge:
+ description: Nabije předmět, který držíš
+ charge-success: Předmět byl nabit!
+ not-rechargeable: Tento předmět nelze nabít!
+ timings: Lag-Info vašeho serveru
guide:
search:
message: "&bCo bys chtěl vyhledat?"
name: "&7Hledat..."
- tooltip: "&bKliknutím vyhledejte položku"
+ tooltip: "&bKlikni pro vyhledání předmětu"
inventory: 'Hledání: %item%'
lore:
- - "&bCo bys chtěl vyhledat?"
- - "&7Napiš do chatu co chceš vyhledat"
+ '1': "&7Napiš do chatu co chceš vyhledat"
+ '0': "&bCo bys chtěl vyhledat?"
cheat:
no-multiblocks: "&4Nemůžeš podvádět v multiblocích, musíš je postavit!"
languages:
@@ -41,157 +45,169 @@ guide:
selected-language: 'Aktuálně vybráno:'
change: Klikni pro výběr nového jazyka
description:
- - "&7Nyní máš možnost to změnit"
- - "&7jazyk, ve kterém bude Slimefun"
- - "&7bude ti představeno. Předměty"
- - "&7nelze prozatím přeložit."
+ '0': "&7Nyní máš možnost změnit"
+ '1': "&7jazyk, ve kterém ti bude"
+ '2': "&7Slimefun prezentován. Předměty"
+ '3': "&7nelze prozatím přeložit."
title:
main: Slimefun příručka
settings: Nastavení a informace
- languages: Zvol tvůj preferovaný jazyk
+ languages: Zvol svůj preferovaný jazyk
credits: Slimefun4 pomocníci
wiki: Slimefun4 Wiki
- addons: Addony pro Slimefun4
+ addons: Doplňky pro Slimefun4
bugs: Nahlášení chyb
source: Zdrojový kód
versions: Nainstalovaná verze
credits:
+ commit: Commit
commits: Commits
roles:
developer: "&6Vývojář"
wiki: "&3Wiki správce"
- resourcepack: "&cTvůrce Resourcepacku"
- translator: "&9Překladač"
- profile-link: Klikni pro navštívení jejich profilu na GitHubu
- open: Klikni pro zobrazení našich spoluúčastníků
+ resourcepack: "&cTvůrce modifikačního balíčku"
+ translator: "&9Překladatel"
+ profile-link: Klikni pro navštívení jeho profilu na GitHubu
+ open: Klikni pro zobrazení našich pomocníků
description:
- - "&7Slimefun je open-source projekt"
- - "&7a udržován velkou komunitou lidí."
- - "&Přes&e%contributors% &7lidí na tom pracovalo"
- - "&7Slimefun za všechny ty roky."
+ '0': "&7Slimefun je open-source projekt"
+ '1': "&7udržován velkou komunitou lidí."
+ '2': "&7Na Slimefunu za všechny ty roky pracovalo"
+ '3': "&7přes &e%contributors% &7lidí."
pages:
previous: Předchozí strana
next: Následující strana
tooltips:
open-category: Klikni pro otevření
versions-notice: To jsou velmi důležité při hlášení chyb!
- wiki: Zobrazit tento předmět na oficiální SlimeFun Wiki
+ wiki: Zobrazit tento předmět na oficiální Slimefun Wiki
recipes:
machine: Recepty vytvářené tímto strojem
miner: Materiály, které můžeš získat tímto těžebním robotem
generator: Dostupné typy paliv
gold-pan: Materiály, které můžeš získat
+ climbing-pick: Povrchy, na které můžeš lézt
back:
title: Zpět
- guide: Zpět do Slimefun Guide
- settings: Zpět do Settings Panel
+ guide: Zpět do Slimefun příručky
+ settings: Zpět do panelu nastavení
locked: ZAMČENO
locked-category:
- - Chcete-li odemknout tuto kategorii, budete
- - 'je třeba odemknout všechny položky z '
- - následující kategorie
+ '0': Chceš-li odemknout tuto kategorii,
+ '1': je potřeba odemknout všechny předměty
+ '2': z předchozích kategorií
work-in-progress: Tato funkce ještě není zcela dokončena!
messages:
not-researched: "&4Ještě jsi nepostoupil tak daleko, abys pochopil tuhle věc"
- not-enough-xp: "&4Nemáš dostatek XP levelů na to, abys vyzkoumal tuhle věc"
- unlocked: '&bMáš vyzkoumáno &7"%research%"'
+ not-enough-xp: "&4Nemáš dostatek XP úrovní na to, abys vyzkoumal tuhle věc"
+ unlocked: "&bMáš vyzkoumáno &7„%research%”"
only-players: "&4Tenhle příkaz je jenom pro hráče"
unknown-player: "&4Neznámý hráč: &c%player%"
- no-permission: "&4Na tohle nemáš dostatečné povolení"
+ no-permission: "&4Na tohle nemáš dostatečné oprávnění"
usage: "&4Použití: &c%usage%"
not-online: "&4%player% &czrovna není připojen!"
- invalid-item: "&4%item% &cnení platný item!"
- invalid-amount: "&4%amount% &cnení platné číslo : musí být větší než 0!"
- given-item: '&bDostal jsi &a%amount% &7"%item%&7"'
- give-item: '&bDal jsi %player% &a%amount% &7"%item%&7"'
- invalid-research: "&4%research% &cnení platný výzkum!"
+ given-item: "&bDostal jsi &a%amount% &7„%item%&7”"
+ give-item: "&bDal jsi %player% &a%amount% &7„%item%&7”"
give-research: '&bUdělil jsi %player% výzkum &7"%research%&7"'
hungry: "&cJsi moc hladový na to, abys to zvládl!"
disabled-in-world: "&4&lTahle věc není v tomhle světě povolená"
disabled-item: |-
&4&lTahle věc není povolená!
Jak jsi ji vůbec dostal?
- no-tome-yourself: "&cNemůžeš použít svůj &4Tome of Knowledge &c..."
+ no-tome-yourself: "&cNemůžeš použít svůj &4Tome of Knowledge&c..."
multimeter: "&bEnergie: &3%stored% &b/ &3%capacity%"
talisman:
anvil: "&a&oTvůj talisman zachránil tvůj nástroj od rozbití"
- miner: "&a&oTvůj talisman zdvojnásobil tvoje dropy"
- hunter: "&a&oTvůj talisman zdvojnásobil tvoje dropy"
+ miner: "&a&oTvůj talisman zdvojnásobil tvou kořist"
+ hunter: "&a&oTvůj talisman zdvojnásobil tvou kořist"
lava: "&a&oTvůj talisman tě zachránil před uhořením"
water: "&a&oTvůj talisman tě zachránil před utopením"
angel: "&a&oTvůj talisman tě zachránil před poškození pádem"
fire: "&a&oTvůj talisman tě zachránil před uhořením"
- magician: "&a&oTvůj talisman ti dal přídavné enchanty"
+ magician: "&a&oTvůj talisman ti dal dodatečná očarování"
traveller: "&a&oTvůj talisman ti dal rychlost"
- warrior: "&a&oTvůj talisman ti dal efekt síly na nějakou tu chvíli"
- knight: "&a&oTvůj talisman ti dal 5 vteřin regenerace"
+ warrior: "&a&oTvůj talisman ti dal na určitou chvilku efekt síly"
+ knight: "&a&oTvůj talisman ti dal 5 sekund regenerace"
whirlwind: "&a&oTvůj talisman odrazil projektil"
- wizard: "&a&oTvůj talisman ti dal větší level Štěstí, ale možná snížil level jiných
- enchantů"
+ wizard: "&a&oTvůj talisman ti dal větší úroveň štěstí, ale možná snížil úroveň
+ jiných očarování"
+ caveman: "&a&oTvůj talisman ti dal spěch"
+ wise: "& a&aTvůj talisman zdvojnásobil zisk tvých zkušeností"
soulbound-rune:
- fail: "&cKe své duši můžeš přidat jen jeden předmět."
- success: "&aÚspěšně jsi přidal tento item ke své duši. Pokud zemřeš, item ti zůstane."
+ fail: "&cSvou duši můžeš spoutat jen s jedním předmětem."
+ success: "&aÚspěšně jsi spoutal tento předmět se svou duši. Pokud zemřeš, předmět
+ ti zůstane."
research:
- start: "&7Antičtí duchové šeptají magické slova do tvého ucha..."
+ start: "&7Antičtí duchové šeptají magická slova do tvého ucha..."
progress: "&7Začal jsi přemýšlet nad &b%research% &e(%progress%)"
fire-extinguish: "&7Uhasil ses"
cannot-place: "&cZde nemůžeš položit blok!"
no-pvp: "&cZde nemůžeš bojovat s hráči!"
radiation: "&4Byl jsi vystaven smrtelné radiaci! &cVyhoď radioaktivní předmět nebo
- si obleč Hazmat oblek."
- opening-guide: "&bOtevírání příručky, může to pár sekund trvat..."
- opening-backpack: "&bOtevírání batohu, může to pár sekund trvat..."
- no-iron-golem-heal: "&cTo není Iron Ingot! S tímto nemůžeš léčit Iron Golemy!"
+ si obleč hazmat oblek."
+ opening-guide: "&bOtevírá se příručka, může to pár sekund trvat..."
+ opening-backpack: "&bOtevírá se batoh, může to pár sekund trvat..."
+ no-iron-golem-heal: "&cTohle není železný ingot, a proto s ním nemůžeš léčit železné
+ golemy!"
link-prompt: "&eKlikni zde:"
- diet-cookie: "&eZačínáš se cítit velice lehký..."
+ diet-cookie: "&eZačínáš se cítit velice lehce..."
fortune-cookie:
- - "&7POMOOC!! Jsem uvězněn v továrně na sušenky štěstí!"
- - "&7Zítra zemřeš... s láskou od pana Creepera"
- - "&7V nějaké části tvého života se stane něco špatného!!!"
- - "&7Příští týden si uvědomíš, že toto není reálný život, ale jsi v počítačové hře."
- - "&7Sušenka ti bude za pár vteřin velice chutnat"
- - '&7Poslední slovo, které uslyšíš bude "VYHUBIT!!!"'
- - "&7Ať se stane cokoliv, nepokoušej se mazlit Creepera... Zkusil jsem to. Je to
- dobrý pocit, ale nestojí to za to."
- - "&742. Odpověď je 42."
- - "&7Walshy udrží den problémy pryč."
- - "&7Nikdy nekopej pod sebe!"
- - "&7To je jen rána masa!"
- - "&7Vždy se podívejte na světlou stránku života!"
- - "&7Tohle byl vlastně Biscuit a ne Cookie"
- - "&7Neonové cedule jsou LIT!"
- piglin-barter: "&4Nemůžete měnit s pigliny Slimefun předměty"
+ '0': "&7POMOOC!! Jsem uvězněn v továrně na sušenky štěstí!"
+ '1': "&7Zítra zemřeš... s láskou od pana creepera"
+ '2': "&7V nějaké části tvého života se stane něco špatného!!!"
+ '3': "&7Příští týden si uvědomíš, že toto není reálný život, ale že jsi v počítačové
+ hře"
+ '4': "&7Sušenka ti bude za pár sekund velice chutnat"
+ '5': "&7Poslední slovo, které uslyšíš bude „VYHUBIT!!!”"
+ '6': "&7Ať se stane cokoliv, nepokoušej se mazlit creepera... Zkusil jsem to.
+ Je to dobrý pocit, ale nestojí to za to."
+ '7': "&742. Odpověď je 42."
+ '8': "&7Walshy udrží den problémy pryč."
+ '9': "&7Nikdy nekopej pod sebe!"
+ '10': "&7To je jen rána masa!"
+ '11': "&7Vždy se podívej na světlou stránku života!"
+ '12': "&7Tohle byl vlastně Biscuit, a ne Cookie"
+ '13': "&7Neonové cedule jsou LIT!"
+ piglin-barter: "&4S pigliny nemůžeš vyměňovat Slimefun předměty"
enchantment-rune:
- fail: "&cNemůžeš enchantovat tento předmět"
- no-enchantment: "&cPro tento předmět nelze najít žádný vhodný enchant."
- success: "&aÚspěšně jsi na tento předmět daů náhodný enchant."
+ fail: "&cNemůžeš očarovat tento předmět."
+ no-enchantment: "&cPro tento předmět nelze najít žádné vhodné očarování."
+ success: "&aÚspěšně jsi na tento předmět dal náhodné vhodné očarování."
tape-measure:
- no-anchor: "&cMusíš nastavit kotvu než začneš měřit! "
+ no-anchor: "&cPřed začátkem měření musíš nastavit kotvu! "
wrong-world: "&cTvoje kotva je pravděpodobně v jiném světa!"
distance: "&7Měření zahájeno. &eVzdálenost: %distance%"
anchor-set: "&aÚspěšně nastavena kotva:&e %anchor%"
multi-tool:
mode-change: "&b%device% mód změněn na: &9%mode%"
not-shears: "&cMulti Tool nemůže být použit jako nůžky!"
+ climbing-pick:
+ dual-wielding: "&4Musíš držet Climbing Picks v obou rukou pro jeho použití!"
+ wrong-material: "&cNa tento povrch nemůžeš vylézt. Zkontroluj Slimefun Guide,
+ kde najdeš další informace!"
+ invalid-item: "&4%item% &cnení platný předmět!"
+ invalid-amount: "&4%amount% &cnení platné číslo. Musí být větší než 0!"
+ invalid-research: "&4%research% &cnení platný výzkum!"
+ bee-suit-slow-fall: "&eTvé Bee Wings ti pomohou bezpečně a pomalu se vrátit na zem"
mode-change: "&b%device% mód změněn na: &9%mode%"
machines:
- pattern-not-found: "&eOmlouvám se, ale nerozpoznal jsem tento recept. Dej do dispenseru
+ pattern-not-found: "&eBohužel se nepodařilo rozpoznat tento recept. Dej do dávkovače
předměty tak, aby odpovídaly receptu."
- unknown-material: "&eOmlouvám se, ale nepoznal jsem předmět v dispenseru. Dej tam
- něco, co znám."
- wrong-item: "&eOmlouvám se, ale nerozpoznal jsem předmět, se kterým jsi na mě kliknul.
+ unknown-material: "&eBohužel se nepodařilo rozpoznat tento předmět v dávkovači.
+ Dej tam něco správného."
+ wrong-item: "&eBohužel se nepodařilo rozpoznat předmět, se kterým jsi na mě kliknul.
Zkontroluj recept a koukni se, jaké předměty můžeš použít."
- full-inventory: "&eOmlouvám se, můj inventář je plný."
- in-use: "&cInventář tohoto bloku je právě otevřen jiným hráčem"
+ full-inventory: "&eBohužel, můj inventář je plný."
+ in-use: "&cInventář tohoto bloku je právě otevřen jiným hráčem."
ignition-chamber-no-flint: "&cIgnition Chamberu chybí křesadlo."
ANCIENT_ALTAR:
- not-enough-pedestals: "&4Altáři chybí podstavce &c(%pedestals% / 8)"
+ not-enough-pedestals: "&4Altar nemá dostatek Pedestal &c(%pedestals% / 8)"
unknown-catalyst: "&4Neznámý katalyst. &cPoužij správný recept!"
unknown-recipe: "&4Neznámý recept! &cPoužij správný recept!"
ANCIENT_PEDESTAL:
- obstructed: "&4Podstavce jsou zablokované! &cOdstraň cokoliv nad podstavcema!"
+ obstructed: "&4Pedestal je zablokován! &cOdstraň cokoliv nad ním!"
HOLOGRAM_PROJECTOR:
- enter-text: "&7Napiš do chatu zprávu, kterou chceš, aby Hologram ukazoval. &r(Barvy
+ enter-text: "&7Napiš do chatu zprávu, kterou chceš, aby hologram ukazoval. &r(Barvy
jsou podporovány!)"
inventory-title: Editor hologramu
ELEVATOR:
@@ -199,62 +215,63 @@ machines:
pick-a-floor: "&3- Vyber si patro -"
current-floor: "&eAktuální patro:"
click-to-teleport: "&eKliknutím &7se teleportuješ na toto patro:"
- enter-name: "&7Prosím, zadejte název podlaží do chatu. &r(Barvy jsou podporovány!)"
- named: "&2Podlaží úspěšně pojmenováno na: &r%floor%"
+ enter-name: "&7Zadej název podlaží do chatu. &r(Barvy jsou podporovány!)"
+ named: "&2Podlaží úspěšně pojmenováno: &r%floor%"
TELEPORTER:
teleporting: "&3Teleportuji..."
teleported: "&3Teleportace dokončena!"
cancelled: "&4Teleportace zrušena!"
invulnerability: "&b&lZískal jsi 30 sekund nezranitelnosti!"
gui:
- title: Vaše waypointy
- tooltip: Klikněte pro teleportaci
+ title: Tvé záchytné body
+ tooltip: Klikni pro teleportaci
time: Předpokládaný čas
CARGO_NODES:
must-be-placed: "&4Musí být umístěn na truhlu nebo stroj!"
GPS_CONTROL_PANEL:
title: GPS - Kontrolní panel
transmitters: Přehled vysílačů
- waypoints: Přehled waypointů
+ waypoints: Přehled záchytných bodů
INDUSTRIAL_MINER:
- no-fuel: "&cTvému průmyslovému horníku došlo palivo! Vložte palivo do bedny nad."
+ no-fuel: "&cTvému průmyslovému horníku došlo palivo! Vlož palivo do bedny nad."
piston-facing: "&cTvůj průmyslový horník potřebuje píst směřující nahoru!"
piston-space: "&cDva písty potřebují prázdný blok nad nimi!"
- destroyed: "&cZdá se, váš průmysloví horník byl rozbit."
+ destroyed: "&cZdá se, že tvůj průmyslový horník byl zničen."
already-running: "&cTento průmyslový horník již běží!"
full-chest: "&cBedna vašeho průmyslového horníka je plná!"
- no-permission: "&4Zdá se, nemáte oprávnění používat průmyslového horníka zde!"
- finished: "&eVáš průmysloví horník dokončil práci! Získal %ores% hornin!"
+ no-permission: "&4Zdá se, že zde nemáš oprávnění používat průmyslového horníka!"
+ finished: "&eTvůj průmysloví horník dokončil práci! Získal %ores% rud!"
anvil:
not-working: "&4Předměty ze Slimefunu nelze použít v kovadlině!"
+ mcmmo-salvaging: "&4Nemůžeš zachránit Slimefun předměty!"
backpack:
- already-open: "&cOmlouváme se, tento batoh je otevřený již někde jinde!"
- no-stack: "&cNemůžeš stackovat batohy"
+ already-open: "&cBohužel, tento batoh je již otevřený někde jinde!"
+ no-stack: "&cNemůžeš shromažďovat batohy"
workbench:
- not-enhanced: "&4Nemůžeš použít itemy ze Slimefunu v normální výrobě"
+ not-enhanced: "&4Nemůžeš použít předměty ze Slimefunu v normální pracovním stole"
gps:
deathpoint: "&4Bod úmrtí &7%date%"
waypoint:
- new: "&eProsím, zadejte název waypointu do chatu. &7(Barvy jsou podporovány!)"
- added: "&aÚspěšně přidán nový waypoint"
- max: "&4Dosáhl jsi maxima waypointů"
- duplicate: "&4Již jsi vytvořil waypoint pojmenovaný: &f%waypoint%"
+ new: "&eZadej název záchytného bodu do chatu. &7(Barvy jsou podporovány!)"
+ added: "&aÚspěšně přidán nový záchytný bod"
+ max: "&4Dosáhl jsi maxima záchytných bodů"
+ duplicate: "&4Již jsi vytvořil záchytný bod pojmenovaný: &f%waypoint%"
insufficient-complexity:
- - "&4Nedostatečná komplexita GPS Networku: &c%complexity%"
- - "&4a) Nemáš nastavený GPS Network"
- - "&4b) TvůjGPS Network není dostatečně komplexní"
+ '0': "&4Nedostatečná komplexita GPS Networku: &c%complexity%"
+ '1': "&4a) Nemáš nastavený GPS Network"
+ '2': "&4b) Tvůj GPS Network není dostatečně komplexní"
geo:
- scan-required: "&4GEO-Scan je požadován! &cProzkoumejte tento chunk pomocí GEO-Scanneru!"
+ scan-required: "&4GEO-Scan je požadován! &cProzkoumej tento chunk pomocí GEO-Scanneru!"
inventory:
no-access: "&4Nemáš přístup k tomuto bloku"
android:
- started: "&7Tvůj Android právě začal používat jemu přidělený script"
- stopped: "&7Tvůj Android pozastavil jemu přidělený script"
+ started: "&7Tvůj Android právě začal používat jemu přidělený skript"
+ stopped: "&7Tvůj Android pozastavil jemu přidělený skript"
scripts:
- already-uploaded: "&4Tento script byl již nahrán."
+ already-uploaded: "&4Tento skript již byl nahrán."
instructions:
- START: "&2Začít Script"
- REPEAT: "&9Opakovat Script"
+ START: "&2Začít skript"
+ REPEAT: "&9Opakovat skript"
WAIT: "&ePočkej 0.5s"
GO_FORWARD: "&7Posuň se vpřed"
GO_UP: "&7Posuň se nahoru"
@@ -267,10 +284,10 @@ android:
MOVE_AND_DIG_UP: "&bPosuň se a zároveň kopej nahoru"
MOVE_AND_DIG_FORWARD: "&bPosuň se a zároveň kopej dopředu"
MOVE_AND_DIG_DOWN: "&bPosuň se a zároveň kopej dolů"
- ATTACK_MOBS_ANIMALS: "&4Útoč na &cnepřátelské moby a zvířata"
- ATTACK_MOBS: "&4Útoč na &cnepřátelské moby"
+ ATTACK_MOBS_ANIMALS: "&4Útoč na &cnepřátelská stvoření a zvířata"
+ ATTACK_MOBS: "&4Útoč na &cnepřátelská stvoření"
ATTACK_ANIMALS: "&4Útoč na &czvířata"
- ATTACK_ANIMALS_ADULT: "&4Útoč na &czvířata&7[Dospělá]"
+ ATTACK_ANIMALS_ADULT: "&4Útoč na &czvířata &7[Dospělá]"
CHOP_TREE: "&cPokácej a zasaď"
CATCH_FISH: "&bRybař"
FARM_FORWARD: "&bSkliď a zasaď"
@@ -280,15 +297,15 @@ android:
INTERFACE_ITEMS: "&9Přesuň obsah inventáře do rozhraní na přední straně"
INTERFACE_FUEL: "&cVyndej palivo z rozhraní přední strany"
enter-name:
- -
- - "&eProsíme, zadejte název vašeho scriptu"
+ '1': "&eZadej název tvého skriptu"
uploaded:
- - "&bNahrávání..."
- - "&aTvůj script byl úspěšně nahrán!"
+ '0': "&bNahrávání..."
+ '1': "&aTvůj skript byl úspěšně nahrán!"
rating:
- own: "&4Nemůžeš hodnotit vlastní script!"
- already: "&4K tomuto scriptu jsi již zanechal hlasování!"
+ own: "&4Nemůžeš hodnotit vlastní skript!"
+ already: "&4K tomuto skriptu jsi již zanechal hlasování!"
editor: Editor skriptu
+ too-long: "&cSkript je příliš dlouhý na úpravu!"
languages:
default: Výchozí-serverový
en: Angličtina
@@ -298,7 +315,7 @@ languages:
es: Španělština
pl: Polština
sv: Švédština
- nl: Holandština
+ nl: Nizozemština
cs: Čeština
hu: Maďarština
lv: Lotyština
@@ -310,8 +327,6 @@ languages:
zh-CN: Čínština (Čína)
el: Řečtina
he: Hebrejština
- pt: Portugalština (Portugalsko)
- pt-BR: Portugalština (Brazílie)
ar: Arabština
af: Afrikánština
da: Dánština
@@ -323,6 +338,8 @@ languages:
fa: Perština
th: Thajština
ro: Rumunština
+ pt: Portugalština (Portugalsko)
+ pt-BR: Portugalština (Brazílie)
bg: Bulharština
ko: Korejština
tr: Turečtina
@@ -330,9 +347,16 @@ languages:
mk: Makedonština
sr: Srbština
be: Běloruština
+ tl: 'Tagalština '
brewing_stand:
not-working: "&4Nemůžeš používat Slimefun předměty ve varném stojanu!"
villagers:
- no-trading: "&4Nemůžeš měnit Slimefun předměty s vesničany!"
+ no-trading: "&4Nemůžeš vyměňovat Slimefun předměty s vesničany!"
+cartography_table:
+ not-working: "&4Nemůžeš použít Slimefun předměty v kartografickém stole!"
+cauldron:
+ no-discoloring: "&4Nemůžeš odebrat barvu ze Slimefun brnění"
+placeholderapi:
+ profile-loading: Načítání...
miner:
no-ores: "&eOmlouvám se, nemohu najít rudy v okolí!"
diff --git a/src/main/resources/languages/messages_de.yml b/src/main/resources/languages/messages_de.yml
index 6853972c2..86aaf9a9c 100644
--- a/src/main/resources/languages/messages_de.yml
+++ b/src/main/resources/languages/messages_de.yml
@@ -342,7 +342,6 @@ languages:
zh-CN: Chinesisch (China)
el: Griechisch
he: Hebräisch
- pt: Portugiesisch (Portugal)
pt-BR: Portugiesisch (Brasilien)
ar: Arabisch
af: Afrikaans
@@ -355,6 +354,7 @@ languages:
fa: Persisch
th: Thailändisch
ro: Rumänisch
+ pt: Portugiesisch (Portugal)
bg: Bulgarisch
ko: Koreanisch
tr: Türkisch
@@ -373,3 +373,5 @@ cauldron:
no-discoloring: "&4Du kannst Slimefun-Rüstung nicht entfärben"
miner:
no-ores: "&eIch konnte leider keine Erze in der Nähe finden!"
+placeholderapi:
+ profile-loading: Lade...
diff --git a/src/main/resources/languages/messages_fr.yml b/src/main/resources/languages/messages_fr.yml
index a3d15040a..f7c71ae96 100644
--- a/src/main/resources/languages/messages_fr.yml
+++ b/src/main/resources/languages/messages_fr.yml
@@ -4,7 +4,6 @@ commands:
cheat: Vous permet de vous donnez des objets
give: Donne à quelqu'un des objets Slimefun
guide: Vous donne un guide Slimefun
- timings: Informations sur la latence de votre serveur
teleporter: Affiche les waypoints d'un autre joueur
versions: Affiche toutes les extensions installées
search: Recherche dans votre guide le terme donné
@@ -25,6 +24,11 @@ commands:
description: Charge l'objet que vous avez en main
charge-success: L'objet a été chargé !
not-rechargeable: Cet objet ne peut pas être chargé !
+ timings:
+ description: Timings pour Slimefun et ses addons
+ please-wait: "&eAttendez s'il vous plaît, les résultats arrivent !"
+ verbose-player: "&4Ce flag ne peux pas être utiliser par un joueur!"
+ unknown-flag: "&4Flag inconnu: &c%flag%"
guide:
search:
message: "&bQue souhaitez-vous rechercher?"
@@ -134,6 +138,7 @@ messages:
wizard: "&a&oVotre talisman vous a donné un meilleur niveau de Fortune mais a
peut-être diminué plusieurs autres enchantements"
caveman: "&a&oVotre Talisman vous a donné Célérité"
+ wise: "&a&oVotre talisman a doublé votre XP"
soulbound-rune:
fail: "&cVous pouvez lier un seul objet à la fois à votre âme"
success: "&aVous avez réussi à lier cet objet à votre âme! Vous le garderez quand
@@ -193,9 +198,9 @@ messages:
invalid-amount: "&4%amount% &cn'est pas un montant valide: il doit être supérieur
à 0!"
invalid-research: "&4%research% &cn'est pas une recherche valide!"
- mode-change: 'Vous avez changé votre &b%device% en mode : &9%mode%'
bee-suit-slow-fall: "&eVos ailes d'abeille vous aideront à revenir au sol lentement
et en toute sécurité"
+ mode-change: 'Vous avez changé votre &b%device% en mode : &9%mode%'
machines:
pattern-not-found: "&eDésolé, je ne reconnais pas cette recette. Veuillez disposer
les objets correctement dans le distributeur."
diff --git a/src/main/resources/languages/messages_he.yml b/src/main/resources/languages/messages_he.yml
index 3e26c0d63..170137953 100644
--- a/src/main/resources/languages/messages_he.yml
+++ b/src/main/resources/languages/messages_he.yml
@@ -1,11 +1,18 @@
---
commands:
help: הצגת מסך עזרה
- teleporter: ראה נקודות ציון של שחקנים אחרים
- search: חפש במדריך את המונח הנתון
cheat: מאפשר לזמן פריטים ברמאות
give: נותן למישהו פירטי סליים פאן
guide: תן לעצמך מדריך סליים פאן
+ teleporter: ראה נקודות ציון של שחקנים אחרים
+ versions: הצגת תוספים מותקנים
+ search: חפש במדריך את המונח הנתון
+ open_guide: פתח את המדריך בלי להשתמש בספר
+ stats: מציג כמה נתונים סטטיסטיים על שחקן
+ research:
+ description: 'בטל נעילה /מחקרים עבור שחקן זה '
+ reset: "&c איפס את הידע של %שחקן% זה"
+ reset-target: "&cהידע שלך אופס "
backpack:
description: אחזר עותק של גיבוי קיים
invalid-id: " המספר המזהה חייב להיות מספר לא שלילי!&4"
@@ -21,46 +28,15 @@ commands:
please-wait: "&e !אנא המתן שנייה ... התוצאות מגיעות"
verbose-player: "&4 האיתות המילולי אינו יכול להיות בשימוש על ידי שחקן!"
unknown-flag: "&4איתות לא ידוע: &c%flag%"
- versions: הצגת תוספים מותקנים
- open_guide: פתח את המדריך בלי להשתמש בספר
- stats: מציג כמה נתונים סטטיסטיים על שחקן
- research:
- description: 'בטל נעילה /מחקרים עבור שחקן זה '
- reset: "&c איפס את הידע של %שחקן% זה"
- reset-target: "&cהידע שלך אופס "
guide:
- title:
- main: סליים פאן מדריך
- credits: סליים פאן4 תורמים
- wiki: סליים פאן4 ויקי
- addons: 'תוספות לסליים פאן '
- versions: גרסאות מותקנות
- settings: 'הגדרות & מידע '
- languages: בחר את השפה המועדפת עליך
- bugs: דיווחי שגיאות
- source: קוד מקור
- back:
- guide: חזור למדריך סליים פאן
- title: חזור
- settings: חזור ללוח ההגדרות
- tooltips:
- wiki: ראה פריט זה באתר הרשימי של סליים פאן ויקי
- recipes:
- climbing-pick: משטחים שאפשר לטפס עליהם
- machine: מתכונים שנעשו במכונה זו
- miner: משאבים שתוכלו להשיג אצל כורה זה
- generator: סוגי דלק זמינים
- gold-pan: משאבים שתוכלו להשיג
- open-category: לחץ לפתיחה
- versions-notice: אלה חשובים מאוד כשמדווחים על באגים!
- work-in-progress: תכונה זו עדיין לא הושלמה במלואה!
+ search:
+ message: מה תרצה לחפש?
+ name: "&7חפש...."
+ tooltip: "&b לחץ לחפש פריט"
+ inventory: "%item% מחפש עבור: "
+ cheat:
+ no-multiblocks: "&4 אתה לא יכול לרמות בריבוי מבנים אתה חייב לבנות אותם!"
languages:
- change: לחץ כדי לבחור שפה חדשה
- description:
- - "&7כעת יש לך אפשרות לשנות"
- - "&7השפה שבה סליים פאן"
- - "&7יוצג בפניך. פריטים"
- - "&7לא ניתן לתרגם לעת עתה."
updated: "&a :השפה שלך הוגדרה בהצלחה ל &b%lang%"
translations:
name: "&aIs משהו חסר?"
@@ -68,13 +44,23 @@ guide:
select: 'לחץ כדי לבחור שפה זאת '
select-default: לחץ לבחירת שפת ברירת המחדל
selected-language: 'נבחר כעת:'
- credits:
- open: לחץ כדי לראות את התורמים שלנו
+ change: לחץ כדי לבחור שפה חדשה
description:
- - "&7 סליים פאן הוא פרויקט קוד פתוח "
- - "&7ומתוחזק על ידי קהילה גדולה של אנשים."
- - "&7על &e%contributors% &7אנשים עבדו"
- - "&7.סליים פאן לאורך כל השנים האלה "
+ - "&7כעת יש לך אפשרות לשנות"
+ - "&7השפה שבה סליים פאן"
+ - "&7יוצג בפניך. פריטים"
+ - "&7לא ניתן לתרגם לעת עתה."
+ title:
+ main: סליים פאן מדריך
+ settings: 'הגדרות & מידע '
+ languages: בחר את השפה המועדפת עליך
+ credits: סליים פאן4 תורמים
+ wiki: סליים פאן4 ויקי
+ addons: 'תוספות לסליים פאן '
+ bugs: דיווחי שגיאות
+ source: קוד מקור
+ versions: גרסאות מותקנות
+ credits:
commit: להתחייב
commits: מתחייב
roles:
@@ -83,32 +69,60 @@ guide:
resourcepack: "&c אמן חבילת משאבים"
translator: "&9מתרגם"
profile-link: "לחץ כדי לבקר את הפרופיל שלהם \nב -GitHub"
- search:
- message: &b מה תרצה לחפש?
- name: "&7חפש...."
- tooltip: "&b לחץ לחפש פריט"
- inventory: "%item% מחפש עבור: "
- cheat:
- no-multiblocks: "&4 אתה לא יכול לרמות בריבוי מבנים אתה חייב לבנות אותם!"
+ open: לחץ כדי לראות את התורמים שלנו
+ description:
+ - "&7 סליים פאן הוא פרויקט קוד פתוח "
+ - "&7ומתוחזק על ידי קהילה גדולה של אנשים."
+ - "&7על &e%contributors% &7אנשים עבדו"
+ - "&7.סליים פאן לאורך כל השנים האלה "
pages:
previous: עמוד קודם
next: עמוד הבא
+ tooltips:
+ open-category: לחץ לפתיחה
+ versions-notice: אלה חשובים מאוד כשמדווחים על באגים!
+ wiki: ראה פריט זה באתר הרשימי של סליים פאן ויקי
+ recipes:
+ machine: מתכונים שנעשו במכונה זו
+ miner: משאבים שתוכלו להשיג אצל כורה זה
+ generator: סוגי דלק זמינים
+ gold-pan: משאבים שתוכלו להשיג
+ climbing-pick: משטחים שאפשר לטפס עליהם
+ back:
+ title: חזור
+ guide: חזור למדריך סליים פאן
+ settings: חזור ללוח ההגדרות
locked: נעול
locked-category:
- כדי לבטל את הנעילה של קטגוריה זו
- 'צריך לפתוח את כל הפריטים מה '
- הקטגוריות הבאות
+ work-in-progress: תכונה זו עדיין לא הושלמה במלואה!
messages:
+ not-researched: "&4אין לך מספיק ידע להבין זאת "
not-enough-xp: "&4אין לך מספיק נקודות ניסיון\nכדי לפתוח את זה "
+ unlocked: "&b אתה פתחת %research% "
+ only-players: "&4 פקודה זו מיועדת רק לשחקנים"
+ unknown-player: "&4 :שחקן לא מוכר &c%player%"
+ no-permission: "&4 אין לך את ההרשאה הנדרשת לעשות זאת"
+ usage: "&4 שימוש: &c %שימוש%"
+ not-online: "&4 %שחקן%cis לא ברשת!"
+ given-item: '&b ניתן לך סכום &a %amount% &7"%item%7'
+ give-item: "&b %ניתן לך %amount% &a %item%"
+ give-research: '&b נתת %player% את המח"%research%&7"'
+ hungry: "&cאתה רעב מדיי כדי לעשות את זה!"
+ disabled-in-world: "&4 פריט זה הושבת בעולם זה"
+ disabled-item: "&4 פריט זה הושבת איך בכלל השגת את זה ?"
+ no-tome-yourself: "&c אינך יכול להשתמש ב- 4 כרך של מידע צמך...."
+ multimeter: "&bStored Energy: &3%stored% &b/ &3%capacity%"
talisman:
- angel: "&a&o הקמע שלך הציל אותך מלקבל נזק נפילה"
- fire: "&a&oהקמע שלך הציל אותך מלהישרף למוות"
- caveman: "&a&oהקמע שלך נתן לך מהירות"
anvil: "&a&o הקמע שלך הציל את הכלי שלך מלהישבר"
miner: "&a&o הקמע שלך בכפיל את הפריטים הנופלים"
hunter: "&a&o הקמע שלך בכפיל את הפריטים הנופלים"
lava: "&a&oהקמע שלך הציל אותך מלהישרף למוות"
water: "&a&oהקמע שלך הציל אותך מלטבוע "
+ angel: "&a&o הקמע שלך הציל אותך מלקבל נזק נפילה"
+ fire: "&a&oהקמע שלך הציל אותך מלהישרף למוות"
magician: "&a%o הקמע שלך העניק לך כישוף נוסף"
traveller: "&a&o הקמע שלך נתן לך דחיפת מהירות"
warrior: "&a&oהקמע שלך שיפר את כוחך לזמן מה"
@@ -116,54 +130,8 @@ messages:
whirlwind: "&a&o הקמע שלך שיקף את הטיל"
wizard: "&a&o הקמע שלך העניק לך רמת הון טובה יותר אבל אולי גם הוריד כמה רמות הקסם
אחרות"
- fortune-cookie:
- - "&7 עזור לי, אני כלוא במפעל לעוגיות "
- - "&7אתה תמות מחר על ידי.... קריפר "
- - "&7 בשלב מסוים בחיים שלך משהו רע יקרה!!!"
- - "&7בשבוע הבא תבחין שזה לא העולם האמיתי, אתה נמצא במשחק מחשב"
- - "עוגיה זו תהיה טעימה תוך כמה שניות &7"
- - '&7 המילה האחרונה שתשמע תהיה "להשמיד !!!"'
- - "&7מה שלא תעשה אל תחבק קריפר ניסיתי. זה מרגיש טוב,אבל לא שווה את זה"
- - "&7התשובה היא 42"
- - "&7 וולשי ביום ירחיקו את הצרות."
- - "&7 לעולם אל תחפור ישר למטה!"
- - "&7זו רק שריטה!"
- - "&7תמיד תסתכל על הצד הטוב שבחיים"
- - "&7זה היה למעשה ביסקוויט ולא עוגיה"
- - "&7שלטי הניאון דולקים"
- piglin-barter: &4 אתה לא יכול לסחור עם חזירונים באמצעות חפצי סליים פאן
- enchantment-rune:
- fail: "&cאת לא יכול להחליף עם חזירונים חפצים של סליים פאן."
- no-enchantment: "&cלא נמצא שום קסם ישים לפריט הזה."
- success: "&aהחלת בהצלחה קסם אקראי החל על פריט זה."
- tape-measure:
- no-anchor: "&c אתה צריך להגדיר עוגן לפני שתוכל להתחיל למדוד!"
- wrong-world: "!&cנראה שהעוגן שלך נמצא בעולם אחר"
- distance: "&7המדידה נלקחה &eDistance: %distance%."
- anchor-set: "&aהעוגן הוגדר בהצלחה:&e %anchor%"
- multi-tool:
- mode-change: "&b%device% &9: המצב השתנה ל: %mode%"
- not-shears: "&c מולטי טול לא יכול לשמש כמזמרה!"
- climbing-pick:
- dual-wielding: "&4אתה צריך להחזיק מכושי טיפוס בשתי !הידיים כדי להשתמש בהם"
- wrong-material: "&cאתה לא יכול לטפס על המשטח הזה. עיין במדריך סליים פאן למידע
- נוסף!"
- bee-suit-slow-fall: "&eכנפי הדבורה שלך יעזרו לך להגיע לקרקע בצורה איטית ובטוחה"
- not-researched: "&4אין לך מספיק ידע להבין זאת "
- unlocked: "&b אתה פתחת %research% "
- only-players: "&4 פקודה זו מיועדת רק לשחקנים"
- unknown-player: "&4 :שחקן לא מוכר &c%player%"
- no-permission: "&4 אין לך את ההרשאה הנדרשת לעשות זאת"
- usage: "&4 שימוש: &c %שימוש%"
- not-online: "&4 %שחקן%cis לא ברשת!"
- given-item: "&b ניתן לך סכום &a %amount% &7\"%item%7"
- give-item: '&b %ניתן לך %amount% &a %item%'
- give-research: "&b נתת %player% את המח\"%research%&7\""
- hungry: "&cאתה רעב מדיי כדי לעשות את זה!"
- disabled-in-world: "&4 פריט זה הושבת בעולם זה"
- disabled-item: "&4 פריט זה הושבת איך בכלל השגת את זה ?"
- no-tome-yourself: "&c אינך יכול להשתמש ב- 4 כרך של מידע צמך...."
- multimeter: '&bStored Energy: &3%stored% &b/ &3%capacity%'
+ caveman: "&a&oהקמע שלך נתן לך מהירות"
+ wise: "&a&oהקמע שלך הכפיל את ירידת נקודות הניסיון שלך"
soulbound-rune:
fail: "&c אתה יכול לקשור פריט אחד בלבד לנשמתך בכל פעם."
success: "&a אתה קושרת פריט זה בהצלחה לנשמתך! אתה תשמור עליו כשתמות."
@@ -182,87 +150,43 @@ messages:
ברזל!"
link-prompt: "&e לחץ כאן:"
diet-cookie: "&eאתה מתחיל להרגיש מרחף...."
+ fortune-cookie:
+ - "&7 עזור לי, אני כלוא במפעל לעוגיות "
+ - "&7אתה תמות מחר על ידי.... קריפר "
+ - "&7 בשלב מסוים בחיים שלך משהו רע יקרה!!!"
+ - "&7בשבוע הבא תבחין שזה לא העולם האמיתי, אתה נמצא במשחק מחשב"
+ - עוגיה זו תהיה טעימה תוך כמה שניות &7
+ - '&7 המילה האחרונה שתשמע תהיה "להשמיד !!!"'
+ - "&7מה שלא תעשה אל תחבק קריפר ניסיתי. זה מרגיש טוב,אבל לא שווה את זה"
+ - "&7התשובה היא 42"
+ - "&7 וולשי ביום ירחיקו את הצרות."
+ - "&7 לעולם אל תחפור ישר למטה!"
+ - "&7זו רק שריטה!"
+ - "&7תמיד תסתכל על הצד הטוב שבחיים"
+ - "&7זה היה למעשה ביסקוויט ולא עוגיה"
+ - "&7שלטי הניאון דולקים"
+ piglin-barter: אתה לא יכול לסחור עם חזירונים באמצעות חפצי סליים פאן
+ enchantment-rune:
+ fail: "&cאת לא יכול להחליף עם חזירונים חפצים של סליים פאן."
+ no-enchantment: "&cלא נמצא שום קסם ישים לפריט הזה."
+ success: "&aהחלת בהצלחה קסם אקראי החל על פריט זה."
+ tape-measure:
+ no-anchor: "&c אתה צריך להגדיר עוגן לפני שתוכל להתחיל למדוד!"
+ wrong-world: "!&cנראה שהעוגן שלך נמצא בעולם אחר"
+ distance: "&7המדידה נלקחה &eDistance: %distance%."
+ anchor-set: "&aהעוגן הוגדר בהצלחה:&e %anchor%"
+ multi-tool:
+ mode-change: "&b%device% &9: המצב השתנה ל: %mode%"
+ not-shears: "&c מולטי טול לא יכול לשמש כמזמרה!"
+ climbing-pick:
+ dual-wielding: "&4אתה צריך להחזיק מכושי טיפוס בשתי !הידיים כדי להשתמש בהם"
+ wrong-material: "&cאתה לא יכול לטפס על המשטח הזה. עיין במדריך סליים פאן למידע
+ נוסף!"
invalid-item: "&4%item% &cאינו פריט בר תוקף!"
invalid-amount: "&4%amount% &cאינו כמות ברת תוקף : המספר חייב להיות גדול מאפס!"
invalid-research: "&4%research% &cאינו מחקר בר תוקף!"
-anvil:
- not-working: "&4אתה לא יכול להשתמש בפרטי סליים פאן בתוך סדן"
- mcmmo-salvaging: "&4אתה לא יכול להציל (לתקן) חפצי סליים פאן"
-workbench:
- not-enhanced: "&4 אתה לא יכול להשתמש בפרטי סליים פאן על שולחן עבודה רגיל"
-gps:
- geo:
- scan-required: |-
- &4-סורק גאולוגי נדרש!
- &c סרוק את הנתח הזה באמצעות סורק !גאולוגי-קודם
- waypoint:
- duplicate: "&4כבר יצרת נקודת ציון בשם: &f%waypoint%"
- new: "&eהקלד שם לנקודת הדרך החדשה שלך בצ'אט. (קודי צבע נתמכים!)"
- added: "&a נוסף בהצלחה נקודת דרך חדשה"
- max: "&4 הגעת לכמות הנקודות הדרך המרבית"
- deathpoint: |-
- &4נקודת מוות
- &7%date%
- insufficient-complexity:
- - "&4אין מספיק מורכבות ברשת ה GPS: &c%complexity%"
- - "&4a) אין לך הגדרות רשת GPS עדיין"
- - "&4b) הגדרות ה GPS שלך לא מספיק מורכבות"
-languages:
- zh-CN: "(מנדרינית(סין"
- tl: טגלית
- default: שרת ברירת מחדל
- en: אנגלית
- de: 'גרמנית '
- fr: צרפתית
- it: איטלקית
- es: ספרדית
- pl: פולנית
- sv: שוודית
- nl: הולנדית
- cs: צ'כית
- hu: הונגרית
- lv: לטבית
- ru: רוסית
- sk: סלובקית
- zh-TW: "(סינית (טייוואן"
- vi: וייטנאמי
- id: אינדונזית
- el: יווני
- he: עברית
- ar: ערבית
- af: אפריקנית
- da: דנית
- fi: פינית
- uk: אוקראינית
- ms: מלאית
- 'no': נורווגית
- ja: יפנית
- fa: פרסית
- th: תאילנדי
- ro: רומנית
- pt: "(פורטוגזית (פורטוגל"
- pt-BR: "(פורטוגזית (ברזיל"
- bg: בולגרית
- ko: קוריאנית
- tr: טורקי
- hr: קרואטית
- mk: מקדונית
- sr: סרבית
- be: בלארוסית
+ bee-suit-slow-fall: "&eכנפי הדבורה שלך יעזרו לך להגיע לקרקע בצורה איטית ובטוחה"
machines:
- GPS_CONTROL_PANEL:
- title: לוח בקרה - ג'י פי אס
- transmitters: סקירה משדר
- waypoints: סקירת נקודות דרך
- INDUSTRIAL_MINER:
- no-fuel: &c לכורה התעשייתית שלך אזל הדלק! שים את הדלק שלך בתיבה מעל.
- piston-facing: "&cהכורה התעשייתי שלך דורש בוכנות מופנות כלפי מעלה!"
- piston-space: "&cלשתי הבוכנות צריך להיות בלוק מעליהן!"
- destroyed: "&cנראה שכורה התעשייתי שלך הושמד."
- already-running: "&cהכורה התעשייתית הזה עדיין פועל."
- full-chest: "&cהתיבה של הכורה התעשייתי שלך מלאה!"
- no-permission: נראה שאין לך אישור להפעיל כאן כורה תעשייתי!&4
- finished: "&eהכורה התעשייתי שלך סיים את !%ores% ore(s)!עבודתו! הוא חצב"
pattern-not-found: "&e סליחה לא יכולתי \n .לזהות את המתכון \nאנא הכנס את \nהפריטים
בדפוס הנכון לתוך המתקן "
unknown-material: "&e סליחה, לא יכולתי לזהות את הפריט במתקן שלי. אנא הכנס משהו שאני
@@ -273,7 +197,8 @@ machines:
in-use: "&c המלאי של בלוק זה נפתח כרגע על ידי שחקן אחר."
ignition-chamber-no-flint: "&c תא הצתה חסר צור ופלדה."
ANCIENT_ALTAR:
- not-enough-pedestals: "&4 המזבח אני מוקף בכמות המתאימה של כינים &c(%pedestals% /\n8( "
+ not-enough-pedestals: "&4 המזבח אני מוקף בכמות המתאימה של כינים &c(%pedestals%
+ /\n8( "
unknown-catalyst: "&4 זרז לא ידוע! &c השתמש במתכון הנכון במקום זאת!"
unknown-recipe: "&4 מתכון לא ידוע! &cהשתמש במתכון הנכון במקום!"
ANCIENT_PEDESTAL:
@@ -301,17 +226,50 @@ machines:
time: זמן משוער
CARGO_NODES:
must-be-placed: "&4חייב להיות מונח על תיבה או מכונה!"
-brewing_stand:
- not-working: "&4אתה לא יכול לשים חפצי סליים פאן במבשלה!"
-villagers:
- no-trading: "&4אתה לא יכול להחליף עם ויליג'רים חפצי סליים פאן!"
-cartography_table:
- not-working: "&4אתה לא יכול להשתמש בחפצי סליים פאן בשולחן קרטוגרפיה!"
-cauldron:
- no-discoloring: "&4אתה לא יכול לשנות את הצבע של שריון סליים פאן"
+ GPS_CONTROL_PANEL:
+ title: לוח בקרה - ג'י פי אס
+ transmitters: סקירה משדר
+ waypoints: סקירת נקודות דרך
+ INDUSTRIAL_MINER:
+ no-fuel: לכורה התעשייתית שלך אזל הדלק! שים את הדלק שלך בתיבה מעל.
+ piston-facing: "&cהכורה התעשייתי שלך דורש בוכנות מופנות כלפי מעלה!"
+ piston-space: "&cלשתי הבוכנות צריך להיות בלוק מעליהן!"
+ destroyed: "&cנראה שכורה התעשייתי שלך הושמד."
+ already-running: "&cהכורה התעשייתית הזה עדיין פועל."
+ full-chest: "&cהתיבה של הכורה התעשייתי שלך מלאה!"
+ no-permission: נראה שאין לך אישור להפעיל כאן כורה תעשייתי!&4
+ finished: "&eהכורה התעשייתי שלך סיים את !%ores% ore(s)!עבודתו! הוא חצב"
+anvil:
+ not-working: "&4אתה לא יכול להשתמש בפרטי סליים פאן בתוך סדן"
+ mcmmo-salvaging: "&4אתה לא יכול להציל (לתקן) חפצי סליים פאן"
+backpack:
+ already-open: "&cסליחה התרמיל הזה פתוח במקום אחר "
+ no-stack: "&cאתה לא יכול לערום תרמילים"
+workbench:
+ not-enhanced: "&4 אתה לא יכול להשתמש בפרטי סליים פאן על שולחן עבודה רגיל"
+gps:
+ deathpoint: |-
+ &4נקודת מוות
+ &7%date%
+ waypoint:
+ new: "&eהקלד שם לנקודת הדרך החדשה שלך בצ'אט. (קודי צבע נתמכים!)"
+ added: "&a נוסף בהצלחה נקודת דרך חדשה"
+ max: "&4 הגעת לכמות הנקודות הדרך המרבית"
+ duplicate: "&4כבר יצרת נקודת ציון בשם: &f%waypoint%"
+ insufficient-complexity:
+ - "&4אין מספיק מורכבות ברשת ה GPS: &c%complexity%"
+ - "&4a) אין לך הגדרות רשת GPS עדיין"
+ - "&4b) הגדרות ה GPS שלך לא מספיק מורכבות"
+ geo:
+ scan-required: |-
+ &4-סורק גאולוגי נדרש!
+ &c סרוק את הנתח הזה באמצעות סורק !גאולוגי-קודם
+inventory:
+ no-access: "&4אין לך גישה לבלוק הזה"
android:
+ started: "&7 האנדרואיד שלך ממשיך את תסריט"
+ stopped: "&7 האנדרואיד שלך \nעצר את התסריט "
scripts:
- too-long: "&c!התסריט ארוך מכדי לערוך"
already-uploaded: "&4 התסריט הזה כבר הועלה."
instructions:
START: "&2 התחל תסריט"
@@ -350,10 +308,56 @@ android:
own: "&4אתה לא יכול לדרג את התסריט שלך עצמך!"
already: "&4אתה כבר השארת דירוג לתסריט זה!"
editor: עורך תסריט
- started: "&7 האנדרואיד שלך ממשיך את תסריט"
- stopped: "&7 האנדרואיד שלך \nעצר את התסריט "
-backpack:
- already-open: "&cסליחה התרמיל הזה פתוח במקום אחר "
- no-stack: "&cאתה לא יכול לערום תרמילים"
-inventory:
- no-access: "&4אין לך גישה לבלוק הזה"
+ too-long: "&c!התסריט ארוך מכדי לערוך"
+languages:
+ default: שרת ברירת מחדל
+ en: אנגלית
+ de: 'גרמנית '
+ fr: צרפתית
+ it: איטלקית
+ es: ספרדית
+ pl: פולנית
+ sv: שוודית
+ nl: הולנדית
+ cs: צ'כית
+ hu: הונגרית
+ lv: לטבית
+ ru: רוסית
+ sk: סלובקית
+ zh-TW: "(מנדרינית (טייוואן"
+ vi: וייטנאמי
+ id: אינדונזית
+ zh-CN: "(מנדרינית(סין"
+ el: יווני
+ he: עברית
+ ar: ערבית
+ af: אפריקנית
+ da: דנית
+ fi: פינית
+ uk: אוקראינית
+ ms: מלאית
+ 'no': נורווגית
+ ja: יפנית
+ fa: פרסית
+ th: תאילנדי
+ ro: רומנית
+ pt: "(פורטוגזית (פורטוגל"
+ pt-BR: "(פורטוגזית (ברזיל"
+ bg: בולגרית
+ ko: קוריאנית
+ tr: טורקי
+ hr: קרואטית
+ mk: מקדונית
+ sr: סרבית
+ be: בלארוסית
+ tl: טגלית
+brewing_stand:
+ not-working: "&4אתה לא יכול לשים חפצי סליים פאן במבשלה!"
+villagers:
+ no-trading: "&4אתה לא יכול להחליף עם ויליג'רים חפצי סליים פאן!"
+cartography_table:
+ not-working: "&4אתה לא יכול להשתמש בחפצי סליים פאן בשולחן קרטוגרפיה!"
+cauldron:
+ no-discoloring: "&4אתה לא יכול לשנות את הצבע של שריון סליים פאן"
+placeholderapi:
+ profile-loading: בטעינה...
diff --git a/src/main/resources/languages/messages_ja.yml b/src/main/resources/languages/messages_ja.yml
index c97fa1104..f01c7711e 100644
--- a/src/main/resources/languages/messages_ja.yml
+++ b/src/main/resources/languages/messages_ja.yml
@@ -319,7 +319,7 @@ languages:
zh-CN: 中国語(中国)
el: ギリシャ語
he: ヘブライ語
- pt-BR: ポルトガル語(ブラジル)
+ pt: ポルトガル語(ポルトガル)
ar: アラビア語
af: アフリカーンス語
da: デンマーク語
@@ -331,7 +331,7 @@ languages:
fa: ペルシア語
th: タイ語
ro: ルーマニア語
- pt: ポルトガル語(ポルトガル)
+ pt-BR: ポルトガル語(ブラジル)
bg: ブルガリア語
ko: 韓国語
tr: トルコ語
@@ -350,3 +350,5 @@ cauldron:
no-discoloring: "&4Slimefunアイテムの脱色はできません"
miner:
no-ores: "&e周辺には鉱石が見つかりませんでした!"
+placeholderapi:
+ profile-loading: ロード中…
diff --git a/src/main/resources/languages/messages_nl.yml b/src/main/resources/languages/messages_nl.yml
index 199735711..5297d9a27 100644
--- a/src/main/resources/languages/messages_nl.yml
+++ b/src/main/resources/languages/messages_nl.yml
@@ -4,7 +4,6 @@ commands:
cheat: Geeft je toestemming om gratis spullen in het spel te brengen
give: Geef iemand een aantal Slimefun spullen
guide: Geef jezelf een Slimefun Handboek
- timings: Laat informatie over de server's prestaties zien
teleporter: Bekijk de opgeslagen locaties van andere spelers
versions: Laat een lijst met alle geïnstalleerde uitbreidingen zien
search: Doorzoek de Slimefun handleiding voor een bepaald trefwoord
@@ -15,6 +14,18 @@ commands:
description: Ontgrendel of herstart Slimefun kennissen van een speler
reset: "&cJe hebt %player%'s Slimefun kennis herstart"
reset-target: "&cJe Slimefun kennis is herstart"
+ backpack:
+ description: Krijg een kopie van een al bestaande rugzak
+ invalid-id: "&4Het id moet een positieve nummer zijn!"
+ player-never-joined: "&4Er is geen speler met die naam gevonden!"
+ backpack-does-not-exist: "& 4De opgegeven rugzak bestaat niet!"
+ restored-backpack-given: "&aJouw rugzak is hersteld en is toegevoegd aan jouw
+ inventaris."
+ charge:
+ description: Laad het item wat je vasthoud op
+ charge-success: Item is opgeladen!
+ not-rechargeable: Dit item kan niet opgeladen worden!
+ timings: Laat informatie over de server's prestaties zien
guide:
search:
message: "&bOp welk woord zou je willen zoeken?"
@@ -22,8 +33,8 @@ guide:
tooltip: "&bKlik om naar een item te zoeken"
inventory: 'Zoeken naar: %item%'
lore:
- - "&bOp welk woord zou je willen zoeken?"
- - "&7Type je zoekterm in het gespreksvenster"
+ '1': "&7Type je zoekterm in het gespreksvenster"
+ '0': "&bOp welk woord zou je willen zoeken?"
cheat:
no-multiblocks: "&4Je kan geen Slimefun machines in het spel brengen, je moet
ze bouwen zoals aangegeven."
@@ -34,7 +45,13 @@ guide:
lore: Klik om een eigen vertaling toe the voegen
select: Klik om deze taal te selecteren
select-default: Klik om de standaard taal te selecteren
- selected-language: 'Momenteel geselecteerd:'
+ selected-language: " Op dit moment geselecteerd:"
+ change: Klik om een nieuwe taal te kiezen
+ description:
+ '0': "&7Je hebt nu de mogelijkheid om de taal"
+ '1': "&7van Slimefun te veranderen"
+ '2': "&7aan jou wordt vertoond. Items"
+ '3': "&7kunnen momenteel niet vertaald worden."
title:
main: Slimefun Handboek
settings: Instellingen & Informatie
@@ -44,6 +61,7 @@ guide:
addons: Uitbreidingen voor Slimefun4
bugs: Fouten rapporteren
source: Source Code
+ versions: Geïnstalleerde versies
credits:
commit: Bijdrage
commits: Bijdragen
@@ -53,6 +71,12 @@ guide:
resourcepack: "&cGrafische bundel Ontwikkelaar"
translator: "&9Vertaler"
profile-link: Klik om hun profielen op Github te bezoeken
+ open: Klik om onze bijdragers te zien
+ description:
+ '0': "&7Slimefun is een open-source project"
+ '1': "&7en wordt in stand gehouden door een grote gemeenschap van mensen."
+ '2': "&7Meer dan &e%contributors% &7mensen hebben hieraan"
+ '3': "&7al deze jaren gewerkt."
pages:
previous: Vorige bladzijde
next: Volgende bladzijde
@@ -65,15 +89,17 @@ guide:
miner: Grondstoffen die je met deze Miner kunt verkrijgen
generator: Beschikbare soorten brandstof
gold-pan: Grondstoffen die je kunt verkrijgen
+ climbing-pick: Oppervlakken die je kunt beklimmen
back:
title: Terug
guide: Ga terug naar de Slimefun Handleiding
settings: Ga terug naar Instellingen
locked: VERGRENDELD
locked-category:
- - Om deze categorie te ontgrendelen zul je
- - alle items moeten ontgrendelen van de
- - volgende categorieën
+ '0': Om deze categorie te ontgrendelen zul je
+ '1': alle items moeten ontgrendelen van de
+ '2': volgende categorieën
+ work-in-progress: Dit is nog niet helemaal klaar!
messages:
not-researched: "&4Je hebt niet genoeg Slimefun kennis om dit te begrijpen"
not-enough-xp: "&4Je hebt niet genoeg XP om dit te ontgrendelen"
@@ -83,12 +109,8 @@ messages:
no-permission: "&4Je hebt geen toestemming om deze actie uit te voeren"
usage: "&4Gebruik, zoals: &c%usage%"
not-online: "&4%player% &cis niet online!"
- invalid-item: "&4%item% &cis geen geldig voorwerp!"
- invalid-amount: "&4%amount% &cis geen geldige hoeveelheid: het moet meer zijn
- dan 0!"
given-item: '&bJe hebt &a%amount% keer &7"%item%&7" ontvangen'
give-item: '&bJe hebt %player% &a%amount% keer &7"%item%&7" gegeven'
- invalid-research: "&4%research% &cis geen geldig Slimefun onderzoek"
give-research: '&bJe hebt %player% de kennis over &7"%research%&7" gegeven'
hungry: "&cJe hebt teveel honger om zoiets te doen!"
disabled-in-world: "&4&lDit voorwerp is uitgeschakeld in deze wereld"
@@ -110,6 +132,8 @@ messages:
whirlwind: "&a&oJe Talisman heeft het projectiel weerkaatst"
wizard: "&a&oJe Talisman heeft je een hoger level van geluk gegeven, maar heeft
misschien ook de levels van andere betoveringen verlaagd"
+ caveman: "&a&oJe talisman gaf je haast"
+ wise: "&a&oJe Talisman heeft je verkregen experience punten verdubbeld"
soulbound-rune:
fail: "&cJe kan maar één voorwerp met je ziel verbinden op elk moment"
success: "&aJe hebt dit voorwerp succesvol met je ziel verbonden! Het blijft bij
@@ -129,19 +153,46 @@ messages:
link-prompt: "&eKlik mij:"
diet-cookie: "&eJe begint je zo ligt als een veertje te voelen..."
fortune-cookie:
- - "&7Hellup mij, ik zit vast in een gelukskoekjes-fabriek!"
- - "&7Je overlijdt morgen... door een creeper..."
- - "&7Ooit gaat er iets ergs gebeuren in je leven!!! Muhahaha"
- - "&7Volgende week zal je eindelijk doorhebben dat dit niet de echte wereld is,
- maar een simulatie"
- - "&7Dit koekje gaat over een paar seconden heerlijk smaken"
- - '&7De laatste woorden die je ooit zal horen zijn "Voor mij is deze wereld alleen
- maar vals!"'
- - "&7What je ook wilt worden, knuffels nooit een creeper... Ik heb het geprobeerd,
- maar het is het echt niet waard"
- - "&742. Het antwoord op alles is 42"
- - "&7A Walshy, één dag houdt alle problemen weg"
- - "&7Graaf nooit recht naar beneden!"
+ '0': "&7Hellup mij, ik zit vast in een gelukskoekjes-fabriek!"
+ '1': "&7Je overlijdt morgen... door een creeper..."
+ '2': "&7Ooit gaat er iets ergs gebeuren in je leven!!! Muhahaha"
+ '3': "&7Volgende week zal je eindelijk doorhebben dat dit niet de echte wereld
+ is, maar een simulatie"
+ '4': "&7Dit koekje gaat over een paar seconden heerlijk smaken"
+ '5': '&7De laatste woorden die je ooit zal horen zijn "Voor mij is deze wereld
+ alleen maar vals!"'
+ '6': "&7What je ook wilt worden, knuffels nooit een creeper... Ik heb het geprobeerd,
+ maar het is het echt niet waard"
+ '7': "&742. Het antwoord op alles is 42"
+ '8': "&7A Walshy, één dag houdt alle problemen weg"
+ '9': "&7Graaf nooit recht naar beneden!"
+ '10': "&7Het is slechts een vleeswonde!"
+ '11': "&7Kijk altijd naar de blije kant van je leven!"
+ '12': "&7Deze was eigenlijk een biscuitje en geen koekje"
+ '13': "&7Neon borden zijn LIT!"
+ piglin-barter: "&4Je kunt geen Slimefun spullen met piglins ruilen"
+ enchantment-rune:
+ fail: "&cJe kunt dit item niet betoveren."
+ no-enchantment: "&cKon geen mogelijke betoveringen vinden voor dit item."
+ success: "&aJe hebt succesvol een random betovering toegevoegd op dit item."
+ tape-measure:
+ no-anchor: "&cJe hebt nog een anker nodig voordat je kunt meten!"
+ wrong-world: "&cJe anker lijkt in een andere wereld te zitten!"
+ distance: "&7Afstand gemeten. &eAfstand: %distance%"
+ anchor-set: "&aHet is gelukt om het anker in te stellen:&e %anchor%"
+ multi-tool:
+ mode-change: "&b%device% mode veranderd naar: &9%mode%"
+ not-shears: "&cEen Mutli Tool kan niet gebruikt worden als een schaar!"
+ climbing-pick:
+ dual-wielding: "&4Je moet een klim-pickaxe in bijde handen hebben om hem te gebruiken!"
+ wrong-material: "&cJe kunt dit oppervlak niet beklimmen. Check je Slimefun Guide
+ voor meer info!"
+ invalid-item: "&4%item% &cis geen geldig voorwerp!"
+ invalid-amount: "&4%amount% &cis geen geldige hoeveelheid: het moet meer zijn dan
+ 0!"
+ invalid-research: "&4%research% &cis geen geldig Slimefun onderzoek"
+ bee-suit-slow-fall: "&eJe Bee Wings zullen je helpen om weer veilig op de grond
+ te komen"
mode-change: "&b%device% mode is veranderd naar: &9%mode%"
machines:
pattern-not-found: "&eSorry, ik heb het recept niet herkend. Plaats astublieft de
@@ -187,8 +238,20 @@ machines:
title: GPS - Configuratiescherm
transmitters: Transmitter-overzicht
waypoints: Waypoint-overzicht
+ INDUSTRIAL_MINER:
+ no-fuel: "& cUw Industrial Miner heeft geen brandstof meer! Doe de brandstof in
+ de kist erboven."
+ piston-facing: "&cJe Industrial Miner moet de duwmachines naar boven hebben!"
+ piston-space: "&cDe twee duwmachines moeten een leeg blok boven hem hebben!"
+ destroyed: "&cJouw Industrial Miner lijkt vernietigt te zijn!"
+ already-running: "&cDeze Industrial Miner draait al!"
+ full-chest: "&cDe kist van je Industrial Miner is vol!"
+ no-permission: "&4Het lijkt er op dat je geen permissie hebt om een Industrial
+ Miner hier te laten werken!"
+ finished: "&eJe Industrial Miner is klaar! Het heeft in totaal %ores% grondstof(fen)! "
anvil:
not-working: "&4Je kan geen Slimefun voorwerpen gebruiken in een aambeeld!"
+ mcmmo-salvaging: "&4Je kunt geen Slimefun items afbreken!"
backpack:
already-open: "&cSorry, deze rugzak is al ergens anders geopend!"
no-stack: "&cJe kan geen rugzakken stapelen"
@@ -201,10 +264,11 @@ gps:
&r(Kleurcodes zijn ondersteund)"
added: "&aEen nieuw locatiepunt is succesvol toegevoegd"
max: "&4Je hebt het maximum aantal locatiepunten bereikt"
+ duplicate: "&4Je hebt al een waypoint genaamd: &f%waypoint%"
insufficient-complexity:
- - "&4Er is te weinig GPS netwerk complexiteit: &c%complexity%"
- - "&4a) Je hebt nog geen GPS netwerk opgezet"
- - "&4b) Je GPS netwerk is niet complex genoeg"
+ '0': "&4Er is te weinig GPS netwerk complexiteit: &c%complexity%"
+ '1': "&4a) Je hebt nog geen GPS netwerk opgezet"
+ '2': "&4b) Je GPS netwerk is niet complex genoeg"
geo:
scan-required: "&4Een GEO-Scan is nodig! &cScan deze chunk eerst met behulp van
een GEO-Scanner!"
@@ -243,15 +307,15 @@ android:
INTERFACE_ITEMS: "&9Geef inventaris aan de geconfronteerde interface"
INTERFACE_FUEL: "&cOntvang brandstof van de geconfronteerde interface"
enter-name:
- -
- - "&eType astublieft de gewenste naam in voor het script"
+ '1': "&eType astublieft de gewenste naam in voor het script"
uploaded:
- - "&bBezig met uploaden..."
- - "&aHet script is succesvol geupload!"
+ '0': "&bBezig met uploaden..."
+ '1': "&aHet script is succesvol geupload!"
rating:
own: "&4Je kan je eigen script geen waardering geven!"
already: "&4Je hebt aan een waardering achtergelaten voor dit script!"
editor: Scripteditor
+ too-long: "&cDe code is te lang om te kunnen editen!"
languages:
default: Server-Standaard
en: Engels
@@ -284,10 +348,25 @@ languages:
fa: Perzisch
th: Thais
ro: Roemeens
- pt: Portugees (Portugal)
+ pt: Portugees (Portugal)
pt-BR: Portugees (Brazilië)
bg: Bulgaars
ko: Koreaans
tr: Turks
+ hr: Kroatisch
+ mk: Macedonisch
+ sr: Servisch
+ be: Wit-Russisch/Russisch
+ tl: Tagalog
+brewing_stand:
+ not-working: "&4Je kunt geen Slimefun spullen in een brouwstandaard doen!"
+villagers:
+ no-trading: "&4Je kunt geen Slimefun spullen met villagers ruilen!"
+cartography_table:
+ not-working: "&4Je kunt Slimefun items niet in een cartografie tafel gebruiken!"
+cauldron:
+ no-discoloring: "&4Je kunt de kleur van Slimefun Bescherming niet er af halen"
+placeholderapi:
+ profile-loading: Aan het laden...
miner:
no-ores: "&eSorry, ik kon geen ertsen vinden dichtbij!"
diff --git a/src/main/resources/languages/messages_vi.yml b/src/main/resources/languages/messages_vi.yml
index a889cff2d..f78002beb 100644
--- a/src/main/resources/languages/messages_vi.yml
+++ b/src/main/resources/languages/messages_vi.yml
@@ -26,8 +26,8 @@ commands:
not-rechargeable: Vật phẩm này không thể sạc được!
timings:
description: Độ trễ của slimefun và addon của nó
- verbose-player: "&4Cờ dài này không thể sử dụng bới Người chơi!"
please-wait: "&eVui lòng đợi một chút... Kết quả chuẩn bị đến!"
+ verbose-player: "&4Cờ dài này không thể sử dụng bới Người chơi!"
unknown-flag: "&4Không rõ cờ: &c%flag%"
guide:
search:
@@ -138,6 +138,7 @@ messages:
wizard: "&a&oBùa hộ mệnh của bạn đã cho bạn một Cấp độ may mắn tốt hơn nhưng cũng
có thể hạ thấp một số Cấp độ phù phép khác"
caveman: "&a&oBùa ma thuật của bạn cho bạn hiệu ứng Đào nhanh"
+ wise: "&a&oBùa ma thuật đã nhân đôi số kinh nghiệm của bạn"
soulbound-rune:
fail: "&cBạn chỉ có thể liên kết một vật phẩm với linh hồn của bạn trong cùng
một thời điểm."
@@ -375,3 +376,5 @@ cauldron:
no-discoloring: "&4Bạn không thể đổi màu giáp của Slimefun"
miner:
no-ores: "&eXin lỗi, tôi không thể tìm bất kì Khoáng sản nào xung quanh!"
+placeholderapi:
+ profile-loading: Đang tải...
diff --git a/src/main/resources/languages/messages_zh-CN.yml b/src/main/resources/languages/messages_zh-CN.yml
index 3d8453412..08ef7fbee 100644
--- a/src/main/resources/languages/messages_zh-CN.yml
+++ b/src/main/resources/languages/messages_zh-CN.yml
@@ -319,6 +319,7 @@ languages:
zh-CN: 简体中文 (中国)
el: 希腊语
he: 希伯来语
+ pt: 葡萄牙语 (葡萄牙)
ar: 阿拉伯语
af: 南非语
da: 丹麦语
@@ -330,7 +331,6 @@ languages:
fa: 波斯语
th: 泰语
ro: 罗马尼亚语
- pt: 葡萄牙语 (葡萄牙)
pt-BR: 葡萄牙语 (巴西)
bg: 保加利亚语
ko: 韩语
@@ -350,3 +350,5 @@ cauldron:
no-discoloring: "&4你不能用炼药锅洗去 Slimefun 物品的颜色"
miner:
no-ores: "&e抱歉, 周围找不到矿石了!"
+placeholderapi:
+ profile-loading: 加载中...
diff --git a/src/main/resources/languages/messages_zh-TW.yml b/src/main/resources/languages/messages_zh-TW.yml
index bf5967959..c3cdb0be1 100644
--- a/src/main/resources/languages/messages_zh-TW.yml
+++ b/src/main/resources/languages/messages_zh-TW.yml
@@ -350,3 +350,5 @@ cauldron:
no-discoloring: "&4你不能把 Slimefun 裝備的顏色消除!"
miner:
no-ores: "&e附近沒礦了!"
+placeholderapi:
+ profile-loading: 載入中……
diff --git a/src/main/resources/languages/recipes_cs.yml b/src/main/resources/languages/recipes_cs.yml
new file mode 100644
index 000000000..48fac2597
--- /dev/null
+++ b/src/main/resources/languages/recipes_cs.yml
@@ -0,0 +1,168 @@
+---
+slimefun:
+ multiblock:
+ name: Multiblock
+ lore:
+ '0': Postav ukázanou konstrukci,
+ '1': jak je ukázáno. Nevyrábí se.
+ enhanced_crafting_table:
+ name: Enhanced Crafting Table
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za pomocí Enhanced Crafting Table
+ '2': Normální pracovní stůl nebude stačit!
+ armor_forge:
+ name: Armor Forge
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Armor Forge
+ grind_stone:
+ name: Brusný kámen
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití brusného kamene
+ smeltery:
+ name: Smeltery
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Smeltery
+ ore_crusher:
+ name: Ore Crusher
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Ore Crusher
+ mob_drop:
+ lore:
+ '0': Zabij tohle stvoření
+ '1': k získání tohoto předmětu
+ name: Mob Drop
+ gold_pan:
+ name: Gold Pan
+ lore:
+ '0': Použij Gold Pan k
+ '1': získání tohoto předmětu
+ compressor:
+ name: Compressor
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Compressor
+ pressure_chamber:
+ name: Pressure Chamber
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Pressure Chamber
+ ore_washer:
+ name: Ore Washer
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Ore Washer
+ juicer:
+ name: Juicer
+ lore:
+ '0': Vyrob tento džus, jak je je ukázáno,
+ '1': za použití Juicer
+ magic_workbench:
+ name: Magic Workbench
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Magic Workbench
+ ancient_altar:
+ name: Ancient Altar
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Ancient Altar.
+ '2': Podívej se na Ancient Altar pro více informací
+ heated_pressure_chamber:
+ name: Heated Pressure Chamber
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Heated Pressure Chamber
+ food_fabricator:
+ name: Food Fabricator
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Food Fabricator
+ food_composter:
+ name: Food Composter
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Food Composter
+ freezer:
+ name: Freezer
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Freezer
+ geo_miner:
+ name: GEO Miner
+ lore:
+ '0': Tento předmět lze shromažďovat
+ '1': pomocí GEO Miner
+ nuclear_reactor:
+ name: Nuclear Reactor
+ lore:
+ '1': při provozování v Nuclear Reactor
+ '0': Tento předmět je vedlejší produkt
+ oil_pump:
+ name: Oil Pump
+ lore:
+ '0': Tento předmět lze shromažďovat
+ '1': pomocí Oil Pump
+ pickaxe_of_containment:
+ name: Pickaxe of Containment
+ lore:
+ '1': těžbou líhně pomocí
+ '2': Pickaxe of Containment
+ '0': Tento blok lze získat
+ refinery:
+ name: Refinery
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití Rafinery
+ barter_drop:
+ name: Piglin Bartering Drop
+ lore:
+ '0': Vyměňuj s pigliny zlaté
+ '1': ingoty k získání tohoto předmětu
+minecraft:
+ shaped:
+ name: Recept na výrobu ve tvaru
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': v normálním pracovním stole
+ '2': Tvar je důležitý.
+ shapeless:
+ name: U receptu nezáleží na tvaru
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': v normálním pracovním stole
+ '2': Tento recept je beztvarý.
+ furnace:
+ lore:
+ '0': Roztav tento předmět v peci
+ '1': k vyrobení vysněného předmětu
+ name: Recept na pec
+ blasting:
+ name: Recept na tavicí pec
+ lore:
+ '0': Roztav tento předmět v tavící peci
+ '1': k vyrobení vysněného předmětu
+ smoking:
+ name: Recept na troubu
+ lore:
+ '0': Upeč tenhle předmět v troubě
+ '1': k vyrobení vysněného předmětu
+ campfire:
+ lore:
+ '0': Upeč tenhle předmět v táboráku
+ '1': k vyrobení vysněného předmětu
+ name: Recept na táborák
+ stonecutting:
+ name: Recept na řezačku kamene
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití řezačky kamene
+ smithing:
+ name: 'Recept na kovářský stůl '
+ lore:
+ '0': Vyrob tento předmět, jak je ukázáno,
+ '1': za použití kovářského stolu
diff --git a/src/main/resources/languages/researches_cs.yml b/src/main/resources/languages/researches_cs.yml
index 98beb4b7a..3ab80b996 100644
--- a/src/main/resources/languages/researches_cs.yml
+++ b/src/main/resources/languages/researches_cs.yml
@@ -1,232 +1,252 @@
---
slimefun:
walking_sticks: Vycházkové hole
+ portable_crafter: Přenosný pracovní stůl
+ fortune_cookie: Sušenka štěstí
+ portable_dustbin: Přenosný koš
meat_jerky: Sušené maso
- armor_forge: Crafťák brnění
+ armor_forge: Kovadlina na brnění
+ glowstone_armor: Světlitové brnění
+ lumps: Kousky a magie
+ ender_backpack: Enderitový batoh
+ ender_armor: Enderitové Brnění
+ magic_eye_of_ender: Magické endové oko
+ magic_sugar: Magický cukr
monster_jerky: Sušené maso z monstra
- steel: Ocelová doba
- jetpacks: Jetpacks
- multitools: Víceúčelové nástroje
- synthetic_sapphire: Syntetické Safíry
- damascus_steel_armor: Brnění z Damašské Oceli
- portable_crafter: Přenosný Crafťák
- fortune_cookie: Sušenka Štěstí
- portable_dustbin: Přenosný Koš
- glowstone_armor: Světlitové Brnění
- lumps: Kousky a Magie
- ender_backpack: Ender Batoh
- ender_armor: Ender Brnění
- magic_eye_of_ender: Magické Oko Endu
- magic_sugar: Magický Cukr
- slime_armor: Slizové Brnění
- sword_of_beheading: Meč na Sekání Hlav
- basic_circuit_board: Základní Deska
- advanced_circuit_board: Pokročilá Deska
+ slime_armor: Brnění ze slizu
+ sword_of_beheading: Meč na sekání hlav
+ basic_circuit_board: Základní deska
+ advanced_circuit_board: Pokročilá deska s obvody
smeltery: Tavírna
- misc_power_items: Důležité itemy související s elekronikou
+ steel: Doba ocelová
+ misc_power_items: Důležité předměty související s elekronikou
battery: Tvoje první baterie
- steel_plate: Ocelové Plátování
- steel_thruster: Ocelová Tryska
+ steel_plate: Ocelový plát
+ steel_thruster: Ocelová tryska
parachute: Padák
- grappling_hook: Záchytný Hák
- solar_panel_and_helmet: Solární Energie
- elemental_staff: Hůlky Elementů
- grind_stone: Kámen na Broušení
- cactus_armor: Kaktusový Oblek
- gold_pan: Zlatá Pánev
- magical_book_cover: Magická Knižní Vazba
- slimefun_metals: Nové Kovy
- ore_crusher: Dvojnásobení Rud
- bronze: Vytvoření Bronzu
- alloys: Pokročíle Slitiny
- compressor_and_carbon: Vytvoření Karbonu
- gilded_iron_armor: Pozlacené Železné Brnění
- synthetic_diamond: Syntetické Diamanty
- pressure_chamber: Tlaková Komora
- damascus_steel: Damašská Ocel
- reinforced_alloy: Zesílená Slitina
- carbonado: Černé Diamanty
- magic_workbench: Magický Pracovní Stůl
- wind_staff: Větrná Hůl
- reinforced_armor: Zesílené Brnění
- ore_washer: Čištič Rud
- gold_carats: Čisté Zlato
- silicon: Silicon Valley
- fire_staff: Ohnivá Hůl
- smelters_pickaxe: Hutní Krumpáč
- common_talisman: Běžný Talisman
- anvil_talisman: Talisman Kovadliny
- miner_talisman: Talisman Horníka
- hunter_talisman: Talisman Lovce
- lava_talisman: Talisman Chodce po Lávě
- water_talisman: Talisman Dýchače Vody
- angel_talisman: Talisman Anděla
- fire_talisman: Talisman Požárníka
- lava_crystal: Ohnivá Situace
- magician_talisman: Talisman Kouzelníka
- traveller_talisman: Talisman Cestovatele
- warrior_talisman: Talisman Bojovníka
- knight_talisman: Talisman Rytíře
- gilded_iron: Lesklé Železo
- synthetic_emerald: Falešný Drahokam
- chainmail_armor: Řetězová Zbroj
- whirlwind_talisman: Talisman Vichřice
- wizard_talisman: Talisman Čaroděje
- lumber_axe: Dřevorubecká Sekera
- hazmat_suit: Hazmat Oblek
+ grappling_hook: Vystřelující hák
+ jetpacks: Raketový batoh
+ multitools: Víceúčelové nástroje
+ solar_panel_and_helmet: Solární energie
+ elemental_staff: Elementární hůlky
+ grind_stone: Brusný kámen
+ cactus_armor: Oblek z kaktusu
+ gold_pan: Rýžovací miska
+ magical_book_cover: Magické vázání knihy
+ slimefun_metals: Nové kovy
+ ore_crusher: Zdvojování rud
+ bronze: Výroby bronzu
+ alloys: Pokročilé slitiny
+ compressor_and_carbon: Výroby karbonu
+ gilded_iron_armor: Pozlacené železné brnění
+ synthetic_diamond: Syntetické diamanty
+ pressure_chamber: Tlaková komora
+ synthetic_sapphire: Syntetické safíry
+ damascus_steel: Damašková ocel
+ damascus_steel_armor: Brnění z damaškové ocely
+ reinforced_alloy: Zpevněná slitina
+ carbonado: Černé diamanty
+ magic_workbench: Magický pracovní stůl
+ wind_staff: Větrná hůl
+ reinforced_armor: Zpěvněné brnění
+ ore_washer: Čištič rud
+ gold_carats: Čisté zlato
+ silicon: Křemíkové údolí
+ fire_staff: Ohnivá hůl
+ smelters_pickaxe: Hutní krumpáč
+ common_talisman: Běžný talisman
+ anvil_talisman: Talisman kovadliny
+ miner_talisman: Talisman horníka
+ hunter_talisman: Talisman lovce
+ lava_talisman: Talisman chodce po lávě
+ water_talisman: Talisman dýchání pod vodou
+ angel_talisman: Talisman anděla
+ fire_talisman: Talisman hasiče
+ lava_crystal: Ohnivá situace
+ magician_talisman: Talisman kouzelníka
+ traveller_talisman: Talisman cestovatele
+ warrior_talisman: Talisman bojovníka
+ knight_talisman: Talisman rytíře
+ gilded_iron: Lesklé železo
+ synthetic_emerald: Falešný drahokam
+ chainmail_armor: Kroužková zbroj
+ whirlwind_talisman: Talisman vichřice
+ wizard_talisman: Talisman čaroděje
+ lumber_axe: Dřevorubecká sekera
+ hazmat_suit: Hazmat oblek
uranium: Radioaktivní
- crushed_ore: Čištění rud
- redstone_alloy: Ruditové Slitiny
- carbonado_tools: Nejlepší Stroje
- first_aid: První Pomoc
- gold_armor: Lesklé Brnění
- night_vision_googles: Brýle Nočního Vidění
- pickaxe_of_containment: Krumpáč Zadržení
- hercules_pickaxe: Herkulesův Krumpáč
- table_saw: Stolní Pila
- slime_steel_armor: Slizově-Ocelové Brnění
- blade_of_vampires: Čepel Vampírů
- water_staff: Vodní Hůl
- 24k_gold_block: Zlaté Město
- composter: Kompostování Hlíny
- farmer_shoes: Boty Farmáře
- explosive_tools: Výbušné Nastroje
- automated_panning_machine: Automatická Zlatá Pánev
- boots_of_the_stomper: Boty Dupače
- pickaxe_of_the_seeker: Krumpáč Hledače
+ crushed_ore: Očišťování rud
+ redstone_alloy: Ruditové slitiny
+ carbonado_tools: Nejlepší stroje
+ first_aid: První pomoc
+ gold_armor: Lesklé brnění
+ night_vision_googles: Brýle pro noční vidění
+ pickaxe_of_containment: Krumpáč zadržení
+ hercules_pickaxe: Herkulesův krumpáč
+ table_saw: Stolní pila
+ slime_steel_armor: Brnění ze slizu a oceli
+ blade_of_vampires: Čepel vampírů
+ water_staff: Vodní hůl
+ 24k_gold_block: Zlaté město
+ composter: Kompostování hlíny
+ farmer_shoes: Boty farmáře
+ explosive_tools: Výbušné nástroje
+ automated_panning_machine: Automatická rýžovací miska
+ boots_of_the_stomper: Boty dupače
+ pickaxe_of_the_seeker: Krumpáč hledače
backpacks: Batohy
- woven_backpack: Tkaný Batoh
+ woven_backpack: Tkaný batoh
crucible: Kotel
- gilded_backpack: Vázaný Batoh
- armored_jetpack: Trysky s Brněním
- ender_talismans: Ender Talismany
+ gilded_backpack: Vázaný batoh
+ armored_jetpack: Obrněný raketový batoh
+ ender_talismans: Enderitové talismany
nickel_and_cobalt: Ještě více rud
magnet: Magnetické kovy
- infused_magnet: Infuzovaný Magnet
- cobalt_pickaxe: Urychlený Krumpáč
- essence_of_afterlife: Necromancie
- bound_backpack: Duší-vázané Ůložistě
- jetboots: Tryskové Boty
- armored_jetboots: Obrněné Tryskové Boty
- seismic_axe: Seizmická Sekera
- pickaxe_of_vein_mining: Krumpáč Těžení Nalezišť
- bound_weapons: Duší-vázané Zbraně
- bound_tools: Duší-vázané Nástroje
- bound_armor: Duší-vázané Brnění
- juicer: Výborné Pití
- repaired_spawner: Opravování Spawnerů
- enhanced_furnace: Vylepšená Pec
- more_enhanced_furnaces: Lepší Pece
- high_tier_enhanced_furnaces: Nejlepší Pece
- reinforced_furnace: Vyztužená Pec
- carbonado_furnace: Carbonado Lemováná Pec
+ infused_magnet: Naplněný magnet
+ cobalt_pickaxe: Zrychlený krumpáč
+ essence_of_afterlife: Černá magie
+ bound_backpack: Uložiště spoutané duší
+ jetboots: Raketové boty
+ armored_jetboots: Obrněné raketové boty
+ seismic_axe: Seizmická sekera
+ pickaxe_of_vein_mining: Krumpáč těžby rud
+ bound_weapons: Zbraně spoutané duší
+ bound_tools: Nástroje spoutané duší
+ bound_armor: Brnění spoutané duší
+ juicer: Výborné pití
+ repaired_spawner: Opravování líhní
+ enhanced_furnace: Vylepšená pec
+ more_enhanced_furnaces: Lepší pece
+ high_tier_enhanced_furnaces: Nejlepší pece
+ reinforced_furnace: Zesílená pec
+ carbonado_furnace: Pec lemovaná černými diamanty
electric_motor: Zahřívání
- block_placer: Pokládač Bloků
- scroll_of_dimensional_teleposition: Otáčení věcí kolem
+ block_placer: Pokládač bloků
+ scroll_of_dimensional_teleposition: Otáčí věcí kolem
special_bows: Robin Hood
- tome_of_knowledge_sharing: Dělení z přátely
- flask_of_knowledge: XP Úložistě
- hardened_glass: Odoláválí Výbuchům
- golden_apple_juice: Zlatý Lektrvar
- cooler: Přenášení Nápojů
- ancient_altar: Starověký Oltář
- wither_proof_obsidian: Obsidian co vydrží Withera
- ancient_runes: Elementální Rudy
- special_runes: Purple Rudy
- infernal_bonemeal: Pekelný Bonemeal
- rainbow_blocks: duhové Bloky
- infused_hopper: Vylepšený Hopper
- wither_proof_glass: Sklo co vydrží Withera
- duct_tape: Lepící Páska
+ tome_of_knowledge_sharing: Dělení s přáteli
+ flask_of_knowledge: XP uložistě
+ hardened_glass: Odolávání výbuchům
+ golden_apple_juice: Zlatý lektvar
+ cooler: Přenašeč nápojů
+ ancient_altar: Starověký oltář
+ wither_proof_obsidian: Pevný obsidián proti witherovi
+ ancient_runes: Elementální rudy
+ special_runes: Fialové rudy
+ infernal_bonemeal: Pekelná kostní moučka
+ rainbow_blocks: Duhové bloky
+ infused_hopper: Vylepšená násypka
+ wither_proof_glass: Pevné sklo proti witherovi
+ duct_tape: Lepící páska
plastic_sheet: Plast
- android_memory_core: Memory Core
+ android_memory_core: Paměťové jádro
oil: Olej
fuel: Palivo
hologram_projector: Hologramy
- capacitors: Tier 1 Kondenzátory
- high_tier_capacitors: Tier 2 Kondenzátory
- solar_generators: Solární Elektrárna
- electric_furnaces: Elektrická Pec
- electric_ore_grinding: Drcení a Broušení
- heated_pressure_chamber: Vyhřívaná Tlaková Komora
- coal_generator: Uhelná Elektrárna
- bio_reactor: Bio-Reactor
- auto_enchanting: Automatická Enchantování and Oddělávání Enchantů
- auto_anvil: Automatická Kovadlina
- multimeter: Měření Energie
- gps_setup: Základní GPS Nastavení
- gps_emergency_transmitter: GPS Nouzový Cestovní Bod
- programmable_androids: Programovatelní Androidi
- android_interfaces: Androidové Rozhraní
- geo_scanner: GEO-Skeny
- combustion_reactor: Spalovací Reactor
- teleporter: Teleportovač - Základní Komponenty
- teleporter_activation_plates: Teleportovač - Aktivace
- better_solar_generators: Vylepšené Solární Panely
- better_gps_transmitters: Vylepšené Vysílače
+ capacitors: Kondenzátory 1. stupně
+ high_tier_capacitors: Kondenzátory 2. stupně
+ solar_generators: Solární elektrárna
+ electric_furnaces: Elektrická pec
+ electric_ore_grinding: Drcení a broušení
+ heated_pressure_chamber: Vytápěná tlaková komora
+ coal_generator: Uhelná elektrárna
+ bio_reactor: Bio reaktor
+ auto_enchanting: Automatické očarovávání a odčarovávání
+ auto_anvil: Automatická kovadlina
+ multimeter: Měření energie
+ gps_setup: Základní GPS nastavení
+ gps_emergency_transmitter: GPS nouzový záchytný bod
+ programmable_androids: Programovatelné androidy
+ android_interfaces: Rozhraní androidu
+ geo_scanner: GEO snímače
+ combustion_reactor: Spalovací reaktor
+ teleporter: Základní komponenty pro teleportér
+ teleporter_activation_plates: Aktivace teleportéru
+ better_solar_generators: Vylepšené solární panely
+ better_gps_transmitters: Vylepšené vysílače
elevator: Výtahy
- energized_solar_generator: 24/7 Solární Energie
- energized_gps_transmitter: Nejlepší Trasmitter
- energy_regulator: Energické Sítě 101
- butcher_androids: Android - Řezník
- organic_food: Organické Jídlo
- auto_breeder: Automatické Krmení
- advanced_android: Pokročilý Androidi
- advanced_butcher_android: Pokročílý Androidi - Řezníci
- advanced_fisherman_android: Pokročílý Androidi - Rybář
- animal_growth_accelerator: Manipulase Růstu Zvýřat
- xp_collector: Zběrač XP
- organic_fertilizer: Organické Hnojivo
- crop_growth_accelerator: Zrychelní Růstu Plodin
- better_crop_growth_accelerator: Vylepšené Zrychelní Růstu Plodin
- reactor_essentials: Důležité Části Reaktoru
- nuclear_reactor: Nuclearní Elektrárna
- freezer: Pan Mražák
- cargo_basics: Základy Carga
- cargo_nodes: Nastavení Carga
- electric_ingot_machines: Electrické Vyrábění Ingotů
- high_tier_electric_ingot_machines: Super Rychlá Vyrábění Ingotů
- automated_crafting_chamber: Automatické Crafťění
- better_food_fabricator: Vylepšené Vyrábění Jídla
- reactor_access_port: Interakce s Reactorem
- fluid_pump: Pumpa
- better_freezer: Vylepšený Mrazák
- boosted_uranium: Nikdy Nekončící Kruh
- trash_can: Odpatky
- advanced_output_node: Vylepšený Výstupní Uzel
- carbon_press: Uhlíkový Lis
- electric_smeltery: Elektrická Huť
- better_electric_furnace: Vylepšená Elektrická Pec
- better_carbon_press: Vylepšený Uhlíkový Lis
- empowered_android: Super-nabití Androidi
- empowered_butcher_android: Super-nabití Androidi - Řezník
- empowered_fisherman_android: Super-nabití Androidi - Rybář
- high_tier_carbon_press: Ultimátní Uhlíkový Lis
- wither_assembler: Automatický Zabíječ Wihera
- better_heated_pressure_chamber: Vylepšená Vyhřívaná Tlaková Komora
- elytra: Elytry
- special_elytras: Speciální Elytry
- electric_crucible: Elekryzovaný Kotel
- better_electric_crucibles: Horké Kotly
- advanced_electric_smeltery: Vylepšená Elekrická Huť
- advanced_farmer_android: Vylepšení Androidi - Farmář
- lava_generator: Generátor Energie z Lávy
- nether_ice: Pekelná-Levodá Chladící Kapalina
- nether_star_reactor: Nether Star Reactor
- blistering_ingots: Žíravá Radioactivita
- automatic_ignition_chamber: Automatická Zápalná Komora
- output_chest: Základní výstup do truhly
- copper_wire: Snížená Vodivost
- radiant_backpack: Zářivý Batoh
- auto_drier: Suchý Den
- diet_cookie: Dientní Sušenka
- storm_staff: Bouřková Hole
- soulbound_rune: Duševně-vázaná Runa
- geo_miner: GEO-Ťežič
- lightning_rune: Runa Blesku
- totem_of_undying: Totem Nesmrtelnosti
+ energized_solar_generator: Nezastavitelná solární energie
+ energized_gps_transmitter: Nejlepší vysílač
+ energy_regulator: Energické sítě 101
+ butcher_androids: Řeznické androidy
+ organic_food: Organické jídlo
+ auto_breeder: Automatické krmení
+ advanced_android: Pokročilé androidy
+ advanced_butcher_android: Pokročilé řeznické androidy
+ advanced_fisherman_android: Pokročilé rybářské androidy
+ animal_growth_accelerator: Manipulace s růstem zvířat
+ xp_collector: Sběrač XP
+ organic_fertilizer: Organické hnojivo
+ crop_growth_accelerator: Urychlovač růstu plodin
+ better_crop_growth_accelerator: Vylepšený urychlovač růstu plodin
+ reactor_essentials: Důležité části reaktoru
+ nuclear_reactor: Jaderná elektrárna
+ freezer: Mrazák
+ cargo_basics: Základy nákladu
+ cargo_nodes: Nastavení nákladu
+ electric_ingot_machines: Elektrická výroba ingotů
+ high_tier_electric_ingot_machines: Super rychlá výroba ingotů
+ automated_crafting_chamber: Automatická výroba
+ better_food_fabricator: Vylepšená výroba jídla
+ reactor_access_port: Interakce s reaktorem
+ fluid_pump: Pumpa tekutin
+ better_freezer: Vylepšený mrazák
+ boosted_uranium: Nekonečný kruh
+ trash_can: Koš
+ advanced_output_node: Vylepšený výstupní uzel
+ carbon_press: Uhlíkový lis
+ electric_smeltery: Elektrická huť
+ better_electric_furnace: Vylepšená elektrická pec
+ better_carbon_press: Vylepšený uhlíkový lis
+ empowered_android: Super nabité androidy
+ empowered_butcher_android: Super nabité řeznické androidy
+ empowered_fisherman_android: Super nabité rybářské androidy
+ high_tier_carbon_press: Ultimátní uhlíkový lis
+ wither_assembler: Automatický zabiják withera
+ better_heated_pressure_chamber: Vylepšená vytápěná tlaková komora
+ elytra: Krovky
+ special_elytras: Speciální krovky
+ electric_crucible: Elektrický kotel
+ better_electric_crucibles: Horké kotle
+ advanced_electric_smeltery: Vylepšená elektrická tavírna
+ advanced_farmer_android: Vylepšené farmářské androidy
+ lava_generator: Generátor energie z lávy
+ nether_ice: Netherová chladící kapalina
+ nether_star_reactor: Netherový hvězdný reaktor
+ blistering_ingots: Sžíravá radioaktivita
+ automatic_ignition_chamber: Automatická zápalná komora
+ output_chest: Výstupní truhla základního zařízení
+ copper_wire: Snížená vodivost
+ radiant_backpack: Zářivý batoh
+ auto_drier: Suchý den
+ diet_cookie: Dientní sušenka
+ storm_staff: Bouřková hole
+ soulbound_rune: Runa spoutaná duší
+ geo_miner: GEO horník
+ lightning_rune: Runa blesku
+ totem_of_undying: Totem nesmrtelnosti
charging_bench: Nabíječka
- nether_gold_pan: Pekelná Zlatá Pánev
- electric_press: Electrický Lis
- magnesium_generator: Energie z Magnézia
- kelp_cookie: Chutná Řasa
+ nether_gold_pan: Netherová rýžovací miska
+ electric_press: Elektrický lis
+ magnesium_generator: Energie z magnézia
+ kelp_cookie: Chutná řasa
+ advanced_industrial_miner: Lepší těžení
+ magical_zombie_pills: Dezombifikace
+ enchantment_rune: Antická očarování
+ climbing_pick: Blokace nájezdníků
+ caveman_talisman: Talisman jeskynního člověka
+ even_higher_tier_capacitors: Kondenzátory 3. stupně
+ elytra_cap: Popraskané brnění
+ energy_connectors: Drátové připojení
+ bee_armor: Včelí zbroj
+ wise_talisman: Talisman moudrosti
+ book_binder: Vázání knihy očarování
+ makeshift_smeltery: Vylepšená tavírna
+ tree_growth_accelerator: Rychlejší stromy
+ lead_clothing: Olověné oblečení
+ tape_measure: Svinovací metr
+ iron_golem_assembler: Automatická farma na železné golemy
+ shulker_shell: Syntetičtí shulkeři
+ villager_rune: Obnova vesnických obchodů
+ industrial_miner: Průmyslové těžení
+ auto_brewer: Průmyslový pivovar
diff --git a/src/main/resources/languages/researches_de.yml b/src/main/resources/languages/researches_de.yml
index e934cddbb..c8f40955e 100644
--- a/src/main/resources/languages/researches_de.yml
+++ b/src/main/resources/languages/researches_de.yml
@@ -249,3 +249,4 @@ slimefun:
energy_connectors: Kupferkabel
bee_armor: Bienen-Rüstung
wise_talisman: Stein der Weisen
+ book_binder: Verzaubertes Bücherbinden
diff --git a/src/main/resources/languages/researches_he.yml b/src/main/resources/languages/researches_he.yml
index d355acc5e..0e1872d80 100644
--- a/src/main/resources/languages/researches_he.yml
+++ b/src/main/resources/languages/researches_he.yml
@@ -3,29 +3,18 @@ slimefun:
walking_sticks: מקלות הליכה
portable_crafter: שולחן מלאכה נייד
fortune_cookie: עוגיית מזל
- ender_armor: שריון אנדר
- magic_eye_of_ender: עין אנדר קסומה
- magic_sugar: סוכר קסום
- slime_armor: שריון רפש
- sword_of_beheading: חרב העריפות
- parachute: מצנח
- bronze: יצירת ברונזה
- reinforced_alloy: סגסוגת מחוזקת
- magic_workbench: שולחן מלאכה קסום
- wind_staff: מטה רוח
- gold_carats: זהב טהור
- fire_staff: מטה אש
- first_aid: עזרה ראשונה
- water_staff: מטה מים
- farmer_shoes: נעלי איכר
- backpacks: תיקי גב
portable_dustbin: פח אשפה נייד
meat_jerky: בשר מלוח
armor_forge: יצירת שריון
glowstone_armor: שריון גלוסטון
lumps: גושים וקסמים
ender_backpack: תיק גב אנדר
+ ender_armor: שריון אנדר
+ magic_eye_of_ender: עין אנדר קסומה
+ magic_sugar: סוכר קסום
monster_jerky: בשר מפלצת מלוח
+ slime_armor: שריון רפש
+ sword_of_beheading: חרב העריפות
basic_circuit_board: לוח מגעים בסיסי
advanced_circuit_board: לוח מגעים מתקדם
smeltery: תנור התכה
@@ -34,6 +23,7 @@ slimefun:
battery: הסוללה הראשונה שלך
steel_plate: ציפוי פלדה
steel_thruster: דוחף פלדה
+ parachute: מצנח
grappling_hook: וו אחיזה
jetpacks: תרמיל רחיפה
multitools: רב כלים
@@ -45,6 +35,7 @@ slimefun:
magical_book_cover: כריכת ספרים קסומה
slimefun_metals: מתכות חדשות
ore_crusher: הכפלת עפרת
+ bronze: יצירת ברונזה
alloys: סגסוגות מתקדמות
compressor_and_carbon: יצירת פחמן
gilded_iron_armor: שריון ברזל מוזהב
@@ -53,10 +44,15 @@ slimefun:
synthetic_sapphire: ספיר סינטטי
damascus_steel: פלדת דמשק
damascus_steel_armor: שריון פלדת דמשק
+ reinforced_alloy: סגסוגת מחוזקת
carbonado: יהלומים שחורים
+ magic_workbench: שולחן מלאכה קסום
+ wind_staff: מטה רוח
reinforced_armor: שריון מחוזק
ore_washer: שוטף עופרת
+ gold_carats: זהב טהור
silicon: עמק הסיליקון
+ fire_staff: מטה אש
smelters_pickaxe: מכוש התכה
common_talisman: קמע נפוץ
anvil_talisman: קמע הסדן
@@ -82,6 +78,7 @@ slimefun:
crushed_ore: טיהור עפרת
redstone_alloy: סגסוגת רדסטון
carbonado_tools: מכונות ברמה עליונה
+ first_aid: עזרה ראשונה
gold_armor: שריון מבריק
night_vision_googles: משקפי ראיית לילה
pickaxe_of_containment: מקוש הכלה
@@ -89,12 +86,15 @@ slimefun:
table_saw: מסור שולחני
slime_steel_armor: שריון פלדה רזה
blade_of_vampires: להב הערפדים
+ water_staff: מטה מים
24k_gold_block: עיר מוזהבת
composter: עפר קומפוסטציה
+ farmer_shoes: נעלי איכר
explosive_tools: כלי נפץ
automated_panning_machine: מסננת אוטומטית
boots_of_the_stomper: מגפי הרוקע
pickaxe_of_the_seeker: מכוש המחפש
+ backpacks: תיקי גב
woven_backpack: תיק גב ארוג
crucible: כור היתוך
gilded_backpack: תיק גב מוזהב
@@ -133,6 +133,7 @@ slimefun:
wither_proof_obsidian: בזלת עמידה לוויד'ר
ancient_runes: רונות אלמנטריות
special_runes: רונות סגולות
+ infernal_bonemeal: אינפרנל בואונמיל
rainbow_blocks: בלוקים צבעוניים
infused_hopper: משפך חדור
wither_proof_glass: זכוכית עמידה לוויד'ר
@@ -247,4 +248,5 @@ slimefun:
elytra_cap: גלגל שיניים מרסק
energy_connectors: חיבור קווי
bee_armor: שריון דבורים
- infernal_bonemeal: אינפרנל בואונמיל
+ wise_talisman: קמע של החכמה
+ book_binder: כריכת ספר קסום
diff --git a/src/main/resources/languages/researches_vi.yml b/src/main/resources/languages/researches_vi.yml
index e6259c773..c920b3499 100644
--- a/src/main/resources/languages/researches_vi.yml
+++ b/src/main/resources/languages/researches_vi.yml
@@ -248,3 +248,5 @@ slimefun:
elytra_cap: Mũ lượn
energy_connectors: Đầu nối
bee_armor: Giáp ong
+ wise_talisman: Bùa ma thuật của sự Tinh Khôn
+ book_binder: Sách phù phép Ràng Buộc
diff --git a/src/main/resources/languages/researches_zh-CN.yml b/src/main/resources/languages/researches_zh-CN.yml
index 12899cf16..302ba9d67 100644
--- a/src/main/resources/languages/researches_zh-CN.yml
+++ b/src/main/resources/languages/researches_zh-CN.yml
@@ -249,3 +249,4 @@ slimefun:
energy_connectors: 有线连接
bee_armor: 蜜蜂服
wise_talisman: 智者的护身符
+ book_binder: 附魔融合
diff --git a/src/main/resources/tags/fungus_soil.json b/src/main/resources/tags/fungus_soil.json
new file mode 100644
index 000000000..b943c9e59
--- /dev/null
+++ b/src/main/resources/tags/fungus_soil.json
@@ -0,0 +1,17 @@
+{
+ "values" : [
+ "#slimefun:dirt_variants",
+ {
+ "id" : "minecraft:soul_soil",
+ "required" : false
+ },
+ {
+ "id" : "minecraft:crimson_nylium",
+ "required" : false
+ },
+ {
+ "id" : "minecraft:warped_nylium",
+ "required" : false
+ }
+ ]
+}
diff --git a/src/main/resources/tags/miner_talisman_triggers.json b/src/main/resources/tags/miner_talisman_triggers.json
new file mode 100644
index 000000000..8dfd56669
--- /dev/null
+++ b/src/main/resources/tags/miner_talisman_triggers.json
@@ -0,0 +1,9 @@
+{
+ "values" : [
+ "#slimefun:fortune_compatible_ores",
+ {
+ "id" : "minecraft:gilded_blackstone",
+ "required" : false
+ }
+ ]
+}
diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java
index 6a715312f..9f4f88bac 100644
--- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java
+++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/researches/TestResearchUnlocking.java
@@ -10,7 +10,6 @@ import org.bukkit.entity.Player;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@@ -54,7 +53,6 @@ class TestResearchUnlocking {
@ParameterizedTest
@DisplayName("Test Unlocking Researches")
- @Disabled(value = "Blocked by a concurrency issue in MockBukkit")
@ValueSource(booleans = { true, false })
void testUnlock(boolean instant) throws InterruptedException {
SlimefunPlugin.getRegistry().setResearchingEnabled(true);
diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java
index bf2b4aa09..4a52485c6 100644
--- a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java
+++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestChargeUtils.java
@@ -1,12 +1,7 @@
package io.github.thebusybiscuit.slimefun4.testing.tests.utils;
-import java.util.Arrays;
import java.util.Collections;
-import be.seeseemelk.mockbukkit.MockBukkit;
-import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
-import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
-import io.github.thebusybiscuit.slimefun4.utils.ChargeUtils;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -17,6 +12,11 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import be.seeseemelk.mockbukkit.MockBukkit;
+import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
+import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.utils.ChargeUtils;
+
class TestChargeUtils {
@BeforeAll
diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestInfiniteBlockGenerators.java b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestInfiniteBlockGenerators.java
new file mode 100644
index 000000000..7c1fa3b93
--- /dev/null
+++ b/src/test/java/io/github/thebusybiscuit/slimefun4/testing/tests/utils/TestInfiniteBlockGenerators.java
@@ -0,0 +1,167 @@
+package io.github.thebusybiscuit.slimefun4.testing.tests.utils;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.event.block.BlockFormEvent;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import be.seeseemelk.mockbukkit.MockBukkit;
+import be.seeseemelk.mockbukkit.ServerMock;
+import be.seeseemelk.mockbukkit.WorldMock;
+import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
+import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator;
+
+class TestInfiniteBlockGenerators {
+
+ private static ServerMock server;
+
+ @BeforeAll
+ public static void load() {
+ server = MockBukkit.mock();
+ MockBukkit.load(SlimefunPlugin.class);
+ }
+
+ @AfterAll
+ public static void unload() {
+ MockBukkit.unmock();
+ }
+
+ @Test
+ @DisplayName("Test if invalid Cobblestone generators are ignored")
+ void testInvalidCobblestoneGenerator() {
+ World world = new WorldMock();
+ Block block = world.getBlockAt(0, 100, 0);
+
+ block.setType(Material.STONE);
+ Assertions.assertFalse(InfiniteBlockGenerator.COBBLESTONE_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+
+ block.setType(Material.COBBLESTONE);
+ Assertions.assertFalse(InfiniteBlockGenerator.COBBLESTONE_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+ }
+
+ @ParameterizedTest
+ @MethodSource(value = "provideFaces")
+ @DisplayName("Test if a Cobblestone Generator can be detected")
+ void testValidCobblestoneGenerator(BlockFace water, BlockFace lava) {
+ InfiniteBlockGenerator generator = InfiniteBlockGenerator.COBBLESTONE_GENERATOR;
+
+ World world = new WorldMock();
+ Block block = world.getBlockAt(0, 100, 0);
+
+ block.setType(Material.COBBLESTONE);
+ block.getRelative(water).setType(Material.WATER);
+ block.getRelative(lava).setType(Material.LAVA);
+
+ Assertions.assertTrue(generator.test(block));
+ Assertions.assertNotNull(generator.callEvent(block));
+
+ server.getPluginManager().assertEventFired(BlockFormEvent.class);
+ server.getPluginManager().clearEvents();
+
+ Assertions.assertEquals(generator, InfiniteBlockGenerator.findAt(block));
+ }
+
+ @Test
+ @DisplayName("Test if invalid Basalt generators are ignored")
+ void testInvalidBasaltGenerator() {
+ World world = new WorldMock();
+ Block block = world.getBlockAt(0, 100, 0);
+
+ block.setType(Material.COBBLESTONE);
+ Assertions.assertFalse(InfiniteBlockGenerator.BASALT_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+
+ block.setType(Material.BASALT);
+ Assertions.assertFalse(InfiniteBlockGenerator.BASALT_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+
+ block.getRelative(BlockFace.DOWN).setType(Material.SOUL_SOIL);
+ Assertions.assertFalse(InfiniteBlockGenerator.BASALT_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+ }
+
+ @ParameterizedTest
+ @MethodSource(value = "provideFaces")
+ @DisplayName("Test if a Basalt Generator can be detected")
+ void testValidBasaltGenerator(BlockFace ice, BlockFace lava) {
+ InfiniteBlockGenerator generator = InfiniteBlockGenerator.BASALT_GENERATOR;
+
+ World world = new WorldMock();
+ Block block = world.getBlockAt(0, 100, 0);
+
+ block.setType(Material.BASALT);
+ block.getRelative(BlockFace.DOWN).setType(Material.SOUL_SOIL);
+ block.getRelative(ice).setType(Material.BLUE_ICE);
+ block.getRelative(lava).setType(Material.LAVA);
+
+ Assertions.assertTrue(generator.test(block));
+ Assertions.assertNotNull(generator.callEvent(block));
+
+ server.getPluginManager().assertEventFired(BlockFormEvent.class);
+ server.getPluginManager().clearEvents();
+
+ Assertions.assertEquals(generator, InfiniteBlockGenerator.findAt(block));
+ }
+
+ @Test
+ @DisplayName("Test if invalid Stone generators are ignored")
+ void testInvalidStoneGenerator() {
+ World world = new WorldMock();
+ Block block = world.getBlockAt(0, 100, 0);
+
+ block.setType(Material.COBBLESTONE);
+ Assertions.assertFalse(InfiniteBlockGenerator.STONE_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+
+ block.setType(Material.STONE);
+ Assertions.assertFalse(InfiniteBlockGenerator.STONE_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+
+ block.getRelative(BlockFace.UP).setType(Material.LAVA);
+ Assertions.assertFalse(InfiniteBlockGenerator.STONE_GENERATOR.test(block));
+ Assertions.assertNull(InfiniteBlockGenerator.findAt(block));
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = BlockFace.class, names = { "NORTH", "EAST", "SOUTH", "WEST" })
+ @DisplayName("Test if a Stone Generator can be detected")
+ void testValidStoneGenerator(BlockFace water) {
+ InfiniteBlockGenerator generator = InfiniteBlockGenerator.STONE_GENERATOR;
+
+ World world = new WorldMock();
+ Block block = world.getBlockAt(0, 100, 0);
+
+ block.setType(Material.STONE);
+ block.getRelative(BlockFace.UP).setType(Material.LAVA);
+ block.getRelative(water).setType(Material.WATER);
+
+ Assertions.assertTrue(generator.test(block));
+ Assertions.assertNotNull(generator.callEvent(block));
+
+ server.getPluginManager().assertEventFired(BlockFormEvent.class);
+ server.getPluginManager().clearEvents();
+
+ Assertions.assertEquals(generator, InfiniteBlockGenerator.findAt(block));
+ }
+
+ private static Stream provideFaces() {
+ BlockFace[] faces = { BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };
+ Stream stream = Arrays.stream(faces);
+ return stream.flatMap(a -> Arrays.stream(faces).filter(b -> a != b).map(b -> Arguments.of(a, b)));
+ }
+}