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

Merge branch 'master' into feature/auto-crafters

This commit is contained in:
TheBusyBiscuit 2021-02-10 18:34:34 +01:00 committed by GitHub
commit 2754703f9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 298 additions and 148 deletions

View File

@ -24,6 +24,7 @@ jobs:
chore: '🧹 Chores'
performance: '💡 Performance Optimization'
api: '🔧 API'
compatibility: '🤝 Compatibility'
- uses: thollander/actions-comment-pull-request@1.0.1
name: Leave a comment about the applied label
@ -49,6 +50,7 @@ jobs:
`chore/**` | 🧹 Chores
`api/**` | 🔧 API
`performance/**` | 💡 Performance Optimization
`compatibility/**` | 🤝 Compatibility
<hr>
If your changes do not fall into any of these categories, don't worry.
You can just ignore this message in that case! 👀

View File

@ -36,7 +36,13 @@
#### Fixes
* Fixed #2794
* Fixed #2793
* Fixed #2809
* Fixed a small exception which gets thrown when Slimefun is disabled due to an invalid environment
* Fixed #2810
* Fixed #2804
* Fixed #2817
* Fixed exceptions with inventories not being printed using the logger of the addon that caused it
* Fixed #2818
* Fixed #1161
## Release Candidate 20 (30 Jan 2021)

View File

@ -436,7 +436,7 @@
<dependency>
<groupId>com.github.LoneDev6</groupId>
<artifactId>itemsadder-api</artifactId>
<version>2.1.25</version>
<version>2.1.35</version>
<scope>provided</scope>
<exclusions>
<exclusion>

View File

@ -157,7 +157,8 @@ public class LockedCategory extends Category {
for (Category category : parents) {
for (SlimefunItem item : category.getItems()) {
if (!item.canUse(p, false)) {
// Check if the Player has researched every item (if the item is enabled)
if (!item.isDisabledIn(p.getWorld()) && item.hasResearch() && !profile.hasUnlocked(item.getResearch())) {
return false;
}
}

View File

@ -131,11 +131,23 @@ import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
*/
public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
/**
* Our static instance of {@link SlimefunPlugin}.
* Make sure to clean this up in {@link #onDisable()} !
*/
private static SlimefunPlugin instance;
/**
* Keep track of which {@link MinecraftVersion} we are on.
*/
private MinecraftVersion minecraftVersion = MinecraftVersion.UNKNOWN;
/**
* Keep track of whether this is a fresh install or a regular boot up.
*/
private boolean isNewlyInstalled = false;
// Various things we need
private final SlimefunRegistry registry = new SlimefunRegistry();
private final SlimefunCommand command = new SlimefunCommand(this);
private final TickerTask ticker = new TickerTask();
@ -154,10 +166,12 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this);
private final HologramsService hologramsService = new HologramsService(this);
// Some other things we need
private final IntegrationsManager integrations = new IntegrationsManager(this);
private final SlimefunProfiler profiler = new SlimefunProfiler();
private final GPSNetwork gpsNetwork = new GPSNetwork(this);
// Even more things we need
private NetworkManager networkManager;
private LocalizationService local;
@ -234,6 +248,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private void onPluginStart() {
long timestamp = System.nanoTime();
// Check if Paper (<3) is installed
if (PaperLib.isPaper()) {
getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied.");
} else {
@ -259,6 +274,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
int networkSize = config.getInt("networks.max-size");
// Make sure that the network size is a valid input
if (networkSize < 1) {
getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize);
networkSize = 1;
@ -660,7 +676,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
* This (re)loads every {@link SlimefunTag}.
*/
private void loadTags() {
for (SlimefunTag tag : SlimefunTag.valuesCache) {
for (SlimefunTag tag : SlimefunTag.values()) {
try {
// Only reload "empty" (or unloaded) Tags
if (tag.isEmpty()) {

View File

@ -267,7 +267,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
SlimefunItem sfitem = category.getItems().get(target);
if (Slimefun.isEnabled(p, sfitem, false)) {
if (!sfitem.isDisabledIn(p.getWorld())) {
displaySlimefunItem(menu, category, p, profile, sfitem, page, index);
index++;
}

View File

@ -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;
@ -13,10 +16,10 @@ import org.bukkit.block.Block;
import org.bukkit.block.Dispenser;
import org.bukkit.entity.Player;
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;
@ -47,15 +50,17 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/
public class BlockPlacer extends SlimefunItem {
private final ItemSetting<List<String>> blacklist = new MaterialTagSetting("unplaceable-blocks", SlimefunTag.UNBREAKABLE_MATERIALS);
private final ItemSetting<List<String>> 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);
addItemSetting(unplaceableBlocks);
addItemHandler(onPlace(), onBlockDispense());
}
@Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@ -69,6 +74,7 @@ public class BlockPlacer extends SlimefunItem {
};
}
@Nonnull
private BlockDispenseHandler onBlockDispense() {
return (e, dispenser, facedBlock, machine) -> {
if (!hasPermission(dispenser, facedBlock)) {
@ -79,7 +85,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 +95,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 +103,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 +129,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 +142,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 +173,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);
}
}

View File

@ -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;
@ -143,23 +144,35 @@ public class Talisman extends SlimefunItem {
}
@ParametersAreNonnullByDefault
public static boolean checkFor(Event e, SlimefunItemStack stack) {
return checkFor(e, stack.getItem());
public static boolean trigger(Event e, SlimefunItemStack stack) {
return trigger(e, stack.getItem(), true);
}
@ParametersAreNonnullByDefault
public static boolean checkFor(Event e, SlimefunItem item) {
public static boolean trigger(Event e, SlimefunItemStack stack, boolean sendMessage) {
return trigger(e, stack.getItem(), sendMessage);
}
@ParametersAreNonnullByDefault
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;
}
@ -167,7 +180,7 @@ public class Talisman extends SlimefunItem {
if (SlimefunUtils.containsSimilarItem(p.getInventory(), talismanItem, true)) {
if (talisman.canUse(p, true)) {
activateTalisman(e, p, p.getInventory(), talisman, talismanItem);
activateTalisman(e, p, p.getInventory(), talisman, talismanItem, sendMessage);
return true;
} else {
return false;
@ -177,7 +190,7 @@ public class Talisman extends SlimefunItem {
if (SlimefunUtils.containsSimilarItem(p.getEnderChest(), enderTalisman, true)) {
if (talisman.canUse(p, true)) {
activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman);
activateTalisman(e, p, p.getEnderChest(), talisman, enderTalisman, sendMessage);
return true;
} else {
return false;
@ -189,11 +202,14 @@ 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);
talisman.sendMessage(p);
if (sendMessage) {
talisman.sendMessage(p);
}
}
@ParametersAreNonnullByDefault
@ -242,19 +258,45 @@ public class Talisman extends SlimefunItem {
return suffix;
}
@ParametersAreNonnullByDefault
private void sendMessage(Player p) {
if (!isSilent()) {
String messageKey = "messages.talisman." + getMessageSuffix();
/**
* 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.");
if (SlimefunPlugin.getRegistry().useActionbarForTalismans()) {
SlimefunPlugin.getLocalization().sendActionbarMessage(p, messageKey, false);
} else {
SlimefunPlugin.getLocalization().sendMessage(p, messageKey, true);
// 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 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) {
@ -274,14 +316,4 @@ public class Talisman extends SlimefunItem {
return null;
}
private static boolean pass(@Nonnull Player p, @Nonnull SlimefunItem talisman) {
for (PotionEffect effect : ((Talisman) talisman).getEffects()) {
if (effect != null && p.hasPotionEffect(effect.getType())) {
return false;
}
}
return true;
}
}

View File

@ -96,10 +96,6 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> 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<ItemUseHandler> 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<ItemUseHandler> 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<ItemUseHandler> implements Recip
*
* @return the {@link EntityInteractHandler} of this {@link SlimefunItem}
*/
@Nonnull
public EntityInteractHandler onEntityInteract() {
return (e, item, offHand) -> {
if (!(e.getRightClicked() instanceof ItemFrame)) {

View File

@ -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));
}
}
}

View File

@ -120,11 +120,10 @@ public class SlimefunItemInteractListener implements Listener {
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;
}
}
@ -134,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);
}
}

View File

@ -1,12 +1,15 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.MagicianTalisman;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman;
import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@ -38,14 +41,13 @@ import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.Vector;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.MagicianTalisman;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman;
import io.github.thebusybiscuit.slimefun4.implementation.settings.TalismanEnchantment;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
public class TalismanListener implements Listener {
@ -59,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) {
@ -89,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);
}
@ -141,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<ItemStack> extraDrops = getExtraDrops(e.getEntity(), e.getDrops());
for (ItemStack drop : extraDrops) {
@ -190,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();
@ -223,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);
}
}
@ -236,7 +238,7 @@ public class TalismanListener implements Listener {
MagicianTalisman talisman = (MagicianTalisman) SlimefunItems.TALISMAN_MAGICIAN.getItem();
TalismanEnchantment enchantment = talisman.getRandomEnchantment(e.getItem(), enchantments.keySet());
if (enchantment != null && Talisman.checkFor(e, SlimefunItems.TALISMAN_MAGICIAN)) {
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.
@ -249,7 +251,7 @@ public class TalismanListener implements Listener {
}
// 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<Enchantment, Integer> entry : enchantments.entrySet()) {
if (entry.getValue() > 1 && random.nextInt(100) < 40) {
@ -264,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);
}
@ -272,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<Item> 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));
@ -294,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());
}
}
}
}
@ -305,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);
}
}

View File

@ -22,6 +22,7 @@ import io.github.thebusybiscuit.slimefun4.api.exceptions.TagMisconfigurationExce
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.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;
@ -190,6 +191,11 @@ public enum SlimefunTag implements Tag<Material> {
*/
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.
*/
@ -216,8 +222,16 @@ public enum SlimefunTag implements Tag<Material> {
*/
CAVEMAN_TALISMAN_TRIGGERS;
/**
* Lookup table for tag names.
*/
private static final Map<String, SlimefunTag> 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) {

View File

@ -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}.
@ -258,7 +257,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;
}
}

View File

@ -387,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
@ -1006,7 +1026,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) {

View File

@ -0,0 +1,9 @@
{
"values" : [
"#slimefun:fortune_compatible_ores",
{
"id" : "minecraft:gilded_blackstone",
"required" : false
}
]
}