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

Refactoring and general improvements

This commit is contained in:
TheBusyBiscuit 2020-06-19 13:22:52 +02:00
parent e0a6042619
commit 7059ad216c
39 changed files with 594 additions and 306 deletions

View File

@ -21,8 +21,12 @@
## Release Candidate 14 (TBD)
#### Additions
* Added a starting sound for the Ancient Altar
#### Changes
* Coolant Cells now last twice as long
* Small performance improvements
#### Fixes
* Fixed #2005

View File

@ -36,7 +36,7 @@ Here is a full summary of the differences between the two different versions of
| **Bug Reports** | :heavy_check_mark: | :x: |
| **testing before release** | :x: | :heavy_check_mark: |
| **change logs** | :x: | :memo: **[change log](https://github.com/TheBusyBiscuit/Slimefun4/blob/master/CHANGELOG.md)** |
| **Download link** | :package: **[download latest](https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/master/)** | :package: **[download "stable"](https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/)** |
| **Download link** | :floppy_disk: **[download latest](https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/master/)** | :floppy_disk: **[download "stable"](https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/)** |
**:exclamation: We wholeheartedly recommend you to use _development builds_, they are the most recent version of Slimefun and also receive the most frequent updates!**
<details>

View File

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
@ -68,7 +69,18 @@ public abstract class Network {
protected final Set<Location> connectorNodes = new HashSet<>();
protected final Set<Location> terminusNodes = new HashSet<>();
/**
* This constructs a new {@link Network} at the given {@link Location}.
*
* @param manager
* The {@link NetworkManager} instance
* @param regulator
* The {@link Location} marking the regulator of this {@link Network}.
*/
protected Network(NetworkManager manager, Location regulator) {
Validate.notNull(manager, "A NetworkManager must be provided");
Validate.notNull(regulator, "No regulator was specified");
this.manager = manager;
this.regulator = regulator;

View File

@ -59,6 +59,11 @@ public class NetworkManager {
}
public <T extends Network> Optional<T> getNetworkFromLocation(Location l, Class<T> type) {
if (l == null) {
return Optional.empty();
}
Validate.notNull(type, "Type must not be null");
for (Network network : networks) {
if (type.isInstance(network) && network.connectsTo(l)) {
return Optional.of(type.cast(network));
@ -69,6 +74,12 @@ public class NetworkManager {
}
public <T extends Network> List<T> getNetworksFromLocation(Location l, Class<T> type) {
if (l == null) {
// No networks here, if the location does not even exist
return new ArrayList<>();
}
Validate.notNull(type, "Type must not be null");
List<T> list = new ArrayList<>();
for (Network network : networks) {
@ -80,17 +91,38 @@ public class NetworkManager {
return list;
}
public void registerNetwork(Network n) {
networks.add(n);
/**
* This registers a given {@link Network}.
*
* @param network
* The {@link Network} to register
*/
public void registerNetwork(Network network) {
Validate.notNull(network, "Cannot register a null Network");
networks.add(network);
}
public void unregisterNetwork(Network n) {
networks.remove(n);
/**
* This removes a {@link Network} from the network system.
*
* @param network
* The {@link Network} to remove
*/
public void unregisterNetwork(Network network) {
Validate.notNull(network, "Cannot unregister a null Network");
networks.remove(network);
}
public void handleAllNetworkLocationUpdate(Location l) {
for (Network n : getNetworksFromLocation(l, Network.class)) {
n.markDirty(l);
/**
* This method updates every {@link Network} found at the given {@link Location}.
* More precisely, {@link Network#markDirty(Location)} will be called.
*
* @param l
* The {@link Location} to update
*/
public void updateAllNetworks(Location l) {
for (Network network : getNetworksFromLocation(l, Network.class)) {
network.markDirty(l);
}
}

View File

@ -17,6 +17,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
@ -25,6 +26,21 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
/**
* The {@link CargoNet} is a type of {@link Network} which deals with {@link ItemStack} transportation.
* It is also an extension of {@link ChestTerminalNetwork} which provides methods to deal
* with the addon ChestTerminal.
*
* @author meiamsome
* @author Poslovitch
* @author John000708
* @author BigBadE
* @author SoSeDiK
* @author TheBusyBiscuit
* @author Walshy
* @author DNx5
*
*/
public class CargoNet extends ChestTerminalNetwork {
private static final int RANGE = 5;
@ -53,6 +69,12 @@ public class CargoNet extends ChestTerminalNetwork {
}
}
/**
* This constructs a new {@link CargoNet} at the given {@link Location}.
*
* @param l
* The {@link Location} marking the manager of this {@link Network}.
*/
protected CargoNet(Location l) {
super(l);
}
@ -137,7 +159,9 @@ public class CargoNet extends ChestTerminalNetwork {
Set<Location> destinations = new HashSet<>();
List<Location> output16 = output.get(16);
if (output16 != null) destinations.addAll(output16);
if (output16 != null) {
destinations.addAll(output16);
}
Slimefun.runSync(() -> run(b, destinations, output));
}
@ -312,7 +336,7 @@ public class CargoNet extends ChestTerminalNetwork {
/**
* This method returns the frequency a given node is set to.
* Should there be an {@link Exception} to this method it will fall back to zero in
* order to protect the integrity of the {@link CargoNet}.
* order to preserve the integrity of the {@link CargoNet}.
*
* @param node
* The {@link Location} of our cargo node
@ -322,7 +346,7 @@ public class CargoNet extends ChestTerminalNetwork {
private static int getFrequency(Location node) {
try {
String str = BlockStorage.getLocationInfo(node).getString("frequency");
return Integer.parseInt(str);
return str == null ? 0 : Integer.parseInt(str);
}
catch (Exception x) {
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while parsing a Cargo Node Frequency (" + node.getWorld().getName() + " - " + node.getBlockX() + "," + node.getBlockY() + "," + +node.getBlockZ() + ")");

View File

@ -44,6 +44,7 @@ final class CargoUtils {
*/
static boolean hasInventory(Block block) {
if (block == null) {
// No block, no inventory
return false;
}

View File

@ -8,6 +8,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import org.bukkit.Location;
@ -53,7 +54,8 @@ abstract class ChestTerminalNetwork extends Network {
protected final Set<Location> imports = new HashSet<>();
protected final Set<Location> exports = new HashSet<>();
private final Set<ItemRequest> itemRequests = new HashSet<>();
// This represents a Queue of requests to handle
private final Queue<ItemRequest> itemRequests = new LinkedList<>();
protected ChestTerminalNetwork(Location regulator) {
super(SlimefunPlugin.getNetworkManager(), regulator);
@ -213,7 +215,9 @@ abstract class ChestTerminalNetwork extends Network {
int index = Integer.parseInt(BlockStorage.getLocationInfo(bus, "index"));
index++;
if (index > (items.size() - 1)) index = 0;
if (index > (items.size() - 1)) {
index = 0;
}
BlockStorage.addBlockInfo(bus, "index", String.valueOf(index));
itemRequests.add(new ItemRequest(bus, 17, items.get(index), ItemTransportFlow.WITHDRAW));
@ -233,11 +237,18 @@ abstract class ChestTerminalNetwork extends Network {
}
}
/**
* This method updates every terminal on the network with {@link ItemStack ItemStacks}
* found in any provider of the network.
*
* @param providers
* A {@link Set} of providers to this {@link ChestTerminalNetwork}
*/
protected void updateTerminals(Set<Location> providers) {
List<ItemStackAndInteger> items = findAvailableItems(providers);
for (Location l : terminals) {
BlockMenu menu = BlockStorage.getInventory(l);
BlockMenu terminal = BlockStorage.getInventory(l);
int page = Integer.parseInt(BlockStorage.getLocationInfo(l, "page"));
if (!items.isEmpty() && items.size() < (page - 1) * TERMINAL_SLOTS.length + 1) {
@ -247,42 +258,52 @@ abstract class ChestTerminalNetwork extends Network {
for (int i = 0; i < TERMINAL_SLOTS.length; i++) {
int slot = TERMINAL_SLOTS[i];
if (items.size() > i + (TERMINAL_SLOTS.length * (page - 1))) {
ItemStackAndInteger item = items.get(i + (TERMINAL_SLOTS.length * (page - 1)));
ItemStack stack = item.getItem().clone();
ItemMeta im = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("");
lore.add(ChatColors.color("&7Stored Items: &r" + DoubleHandler.getFancyDouble(item.getInt())));
if (stack.getMaxStackSize() > 1) lore.add(ChatColors.color("&7<Left Click: Request 1 | Right Click: Request " + (item.getInt() > stack.getMaxStackSize() ? stack.getMaxStackSize() : item.getInt()) + ">"));
else lore.add(ChatColors.color("&7<Left Click: Request 1>"));
lore.add("");
if (im.hasLore()) {
lore.addAll(im.getLore());
}
im.setLore(lore);
stack.setItemMeta(im);
menu.replaceExistingItem(slot, stack);
menu.addMenuClickHandler(slot, (p, sl, is, action) -> {
int amount = item.getInt() > item.getItem().getMaxStackSize() ? item.getItem().getMaxStackSize() : item.getInt();
itemRequests.add(new ItemRequest(l, 44, new CustomItem(item.getItem(), action.isRightClicked() ? amount : 1), ItemTransportFlow.WITHDRAW));
return false;
});
}
else {
menu.replaceExistingItem(slot, terminalPlaceholderItem);
menu.addMenuClickHandler(slot, ChestMenuUtils.getEmptyClickHandler());
}
int index = i + (TERMINAL_SLOTS.length * (page - 1));
updateTerminal(l, terminal, slot, index, items);
}
}
}
private void updateTerminal(Location l, BlockMenu terminal, int slot, int index, List<ItemStackAndInteger> items) {
if (items.size() > index) {
ItemStackAndInteger item = items.get(index);
ItemStack stack = item.getItem().clone();
ItemMeta im = stack.getItemMeta();
List<String> lore = new ArrayList<>();
lore.add("");
lore.add(ChatColors.color("&7Stored Items: &r" + DoubleHandler.getFancyDouble(item.getInt())));
if (stack.getMaxStackSize() > 1) {
int amount = item.getInt() > stack.getMaxStackSize() ? stack.getMaxStackSize() : item.getInt();
lore.add(ChatColors.color("&7<Left Click: Request 1 | Right Click: Request " + amount + ">"));
}
else {
lore.add(ChatColors.color("&7<Left Click: Request 1>"));
}
lore.add("");
if (im.hasLore()) {
lore.addAll(im.getLore());
}
im.setLore(lore);
stack.setItemMeta(im);
terminal.replaceExistingItem(slot, stack);
terminal.addMenuClickHandler(slot, (p, sl, is, action) -> {
int amount = item.getInt() > item.getItem().getMaxStackSize() ? item.getItem().getMaxStackSize() : item.getInt();
itemRequests.add(new ItemRequest(l, 44, new CustomItem(item.getItem(), action.isRightClicked() ? amount : 1), ItemTransportFlow.WITHDRAW));
return false;
});
}
else {
terminal.replaceExistingItem(slot, terminalPlaceholderItem);
terminal.addMenuClickHandler(slot, ChestMenuUtils.getEmptyClickHandler());
}
}
private List<ItemStackAndInteger> findAvailableItems(Set<Location> providers) {
List<ItemStackAndInteger> items = new LinkedList<>();

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.networks.cargo;
import java.util.Objects;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
@ -35,4 +37,20 @@ class ItemRequest {
return slot;
}
@Override
public int hashCode() {
return Objects.hash(item, slot, flow, terminal);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ItemRequest) {
ItemRequest request = (ItemRequest) obj;
return Objects.equals(item, request.item) && Objects.equals(terminal, request.terminal) && slot == request.slot && flow == request.flow;
}
else {
return false;
}
}
}

View File

@ -196,7 +196,9 @@ public class EnergyNet extends Network {
available = 0;
}
}
else ChargableBlock.setUnsafeCharge(source, 0, false);
else {
ChargableBlock.setUnsafeCharge(source, 0, false);
}
}
}
@ -240,7 +242,7 @@ public class EnergyNet extends Network {
item.warn("This Item was marked as a 'GENERATOR' but has no 'GeneratorTicker' attached to it! This must be fixed.");
}
}
catch (Throwable t) {
catch (Exception | LinkageError t) {
exploded.add(source);
new ErrorReport(t, source, item);
}

View File

@ -61,7 +61,7 @@ public class ThirdPartyPluginService {
Class.forName("com.sk89q.worldedit.extent.Extent");
new WorldEditHook();
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
String version = plugin.getServer().getPluginManager().getPlugin("WorldEdit").getDescription().getVersion();
Slimefun.getLogger().log(Level.WARNING, "Maybe consider updating WorldEdit or Slimefun?");

View File

@ -90,7 +90,10 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void openMainMenu(PlayerProfile profile, int page) {
Player p = profile.getPlayer();
if (p == null) return;
if (p == null) {
return;
}
List<ChatComponent> lines = new LinkedList<>();
int tier = 0;
@ -143,7 +146,10 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void openCategory(PlayerProfile profile, Category category, int page) {
Player p = profile.getPlayer();
if (p == null) return;
if (p == null) {
return;
}
if (category instanceof FlexCategory) {
((FlexCategory) category).open(p, profile, getLayout());

View File

@ -95,7 +95,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void openMainMenu(PlayerProfile profile, int page) {
Player p = profile.getPlayer();
if (p == null) return;
if (p == null) {
return;
}
if (isSurvivalMode()) {
profile.getGuideHistory().clear();
@ -167,7 +170,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void openCategory(PlayerProfile profile, Category category, int page) {
Player p = profile.getPlayer();
if (p == null) return;
if (p == null) {
return;
}
if (category instanceof FlexCategory) {
((FlexCategory) category).open(p, profile, getLayout());
@ -258,7 +264,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
}
}
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
printErrorMessage(pl, x);
}
@ -276,7 +282,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void openSearch(PlayerProfile profile, String input, boolean addToHistory) {
Player p = profile.getPlayer();
if (p == null) return;
if (p == null) {
return;
}
ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocal().getMessage(p, "guide.search.inventory").replace("%item%", ChatUtils.crop(ChatColor.RESET, input)));
String searchTerm = input.toLowerCase(Locale.ROOT);
@ -294,7 +303,9 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
for (SlimefunItem item : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) {
String itemName = ChatColor.stripColor(item.getItemName()).toLowerCase(Locale.ROOT);
if (index == 44) break;
if (index == 44) {
break;
}
if (!itemName.isEmpty() && (itemName.equals(searchTerm) || itemName.contains(searchTerm))) {
ItemStack itemstack = new CustomItem(item.getItem(), meta -> {
@ -303,6 +314,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
if (category != null) {
ItemStack categoryItem = category.getItem(p);
if (categoryItem != null && categoryItem.hasItemMeta() && categoryItem.getItemMeta().hasDisplayName()) {
lore = Arrays.asList("", ChatColor.DARK_GRAY + "\u21E8 " + ChatColor.RESET + categoryItem.getItemMeta().getDisplayName());
}
@ -322,7 +334,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
displayItem(profile, item, true);
}
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
printErrorMessage(pl, x);
}
@ -339,9 +351,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void displayItem(PlayerProfile profile, ItemStack item, int index, boolean addToHistory) {
Player p = profile.getPlayer();
if (p == null) return;
if (item == null || item.getType() == Material.AIR) return;
if (p == null || item == null || item.getType() == Material.AIR) {
return;
}
SlimefunItem sfItem = SlimefunItem.getByItem(item);
@ -488,7 +501,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
displayItem(profile, itemstack, 0, true);
}
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
printErrorMessage(pl, x);
}
return false;
@ -530,8 +543,8 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
menu.addItem(7, ChestMenuUtils.getSearchButton(p));
menu.addMenuClickHandler(7, (pl, slot, item, action) -> {
pl.closeInventory();
SlimefunPlugin.getLocal().sendMessage(pl, "guide.search.message");
SlimefunPlugin.getLocal().sendMessage(pl, "guide.search.message");
ChatInput.waitForPlayer(SlimefunPlugin.instance, pl, msg -> SlimefunGuide.openSearch(profile, msg, isSurvivalMode(), isSurvivalMode()));
return false;
@ -571,7 +584,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
private static ItemStack getDisplayItem(Player p, boolean isSlimefunRecipe, ItemStack item) {
if (isSlimefunRecipe) {
SlimefunItem slimefunItem = SlimefunItem.getByItem(item);
if (slimefunItem == null) return item;
if (slimefunItem == null) {
return item;
}
String lore = Slimefun.hasPermission(p, slimefunItem, false) ? "&rNeeds to be unlocked elsewhere" : "&rNo Permission";
return Slimefun.hasUnlocked(p, slimefunItem, false) ? item : new CustomItem(Material.BARRIER, ItemUtils.getItemName(item), "&4&l" + SlimefunPlugin.getLocal().getMessage(p, "guide.locked"), "", lore);
@ -642,7 +658,9 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
// We want to clone this item to avoid corrupting the original
// but we wanna make sure no stupid addon creator sneaked some nulls in here
if (item != null) item = item.clone();
if (item != null) {
item = item.clone();
}
menu.replaceExistingItem(slot, item);

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.guide;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Tag;
@ -26,25 +27,39 @@ import me.mrCookieSlime.Slimefun.SlimefunPlugin;
*/
class RecipeChoiceTask implements Runnable {
private static final int UPDATE_INTERVAL = 15;
private static final int UPDATE_INTERVAL = 14;
private Inventory inventory;
private int id;
private Map<Integer, LoopIterator<Material>> iterators = new HashMap<>();
/**
* This will start this task for the given {@link Inventory}.
*
* @param inv
* The {@link Inventory} to start this task for
*/
public void start(Inventory inv) {
Validate.notNull(inv, "Inventory must not be null");
inventory = inv;
id = Bukkit.getScheduler().runTaskTimerAsynchronously(SlimefunPlugin.instance, this, 0, UPDATE_INTERVAL).getTaskId();
}
public void add(int slot, MaterialChoice choice) {
Validate.notNull(choice, "Cannot add a null RecipeChoice");
iterators.put(slot, new LoopIterator<>(choice.getChoices()));
}
public void add(int slot, Tag<Material> tag) {
Validate.notNull(tag, "Cannot add a null Tag");
iterators.put(slot, new LoopIterator<>(tag.getValues()));
}
/**
* This method checks if there are any slots that need to be updated.
*
* @return Whether this task has nothing to do
*/
public boolean isEmpty() {
return iterators.isEmpty();
}

View File

@ -6,6 +6,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import org.apache.commons.lang.Validate;
@ -30,11 +31,15 @@ public final class Script {
this.config = config;
this.name = config.getString("name");
this.code = config.getString("code");
String author = config.getString("author");
Validate.notNull(name);
Validate.notNull(code);
Validate.notNull(author);
Validate.notNull(config.getStringList("rating.positive"));
Validate.notNull(config.getStringList("rating.negative"));
OfflinePlayer player = Bukkit.getOfflinePlayer(config.getUUID("author"));
OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(author));
this.author = player.getName() != null ? player.getName() : config.getString("author_name");
}

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
@ -14,11 +15,18 @@ public class SlimefunArmorPiece extends SlimefunItem {
public SlimefunArmorPiece(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, PotionEffect[] effects) {
super(category, item, recipeType, recipe);
this.effects = effects;
this.effects = effects == null ? new PotionEffect[0] : effects;
}
/**
* An Array of {@link PotionEffect PotionEffects} which get applied to a {@link Player} wearing
* this {@link SlimefunArmorPiece}.
*
* @return An array of effects
*/
public PotionEffect[] getPotionEffects() {
return this.effects;
return effects;
}
}

View File

@ -42,9 +42,9 @@ public class BlockPlacer extends SimpleSlimefunItem<BlockDispenseHandler> {
@Override
public BlockDispenseHandler getItemHandler() {
return (e, dispenser, facedBlock, machine) -> {
// Since vanilla Dispensers can already place Shulker boxes, we simply fallback
// to the vanilla behaviour.
if (isShulkerBox(e.getItem().getType())) {
// Since vanilla Dispensers can already place Shulker boxes, we
// simply fallback to the vanilla behaviour.
return;
}

View File

@ -61,8 +61,12 @@ public abstract class OilPump extends AContainer implements RecipeDisplayItem {
@Override
public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) {
if (flow == ItemTransportFlow.INSERT) return getInputSlots();
else return getOutputSlots();
if (flow == ItemTransportFlow.INSERT) {
return getInputSlots();
}
else {
return getOutputSlots();
}
}
};
}
@ -97,9 +101,11 @@ public abstract class OilPump extends AContainer implements RecipeDisplayItem {
if (timeleft > 0) {
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(b).getTicks(), getProgressBar());
if (ChargableBlock.getCharge(b) < getEnergyConsumption()) return;
ChargableBlock.addCharge(b, -getEnergyConsumption());
if (ChargableBlock.getCharge(b) < getEnergyConsumption()) {
return;
}
ChargableBlock.addCharge(b, -getEnergyConsumption());
progress.put(b, timeleft - 1);
}
else {
@ -112,7 +118,7 @@ public abstract class OilPump extends AContainer implements RecipeDisplayItem {
}
else if (inv.fits(SlimefunItems.OIL_BUCKET, getOutputSlots())) {
for (int slot : getInputSlots()) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(Material.BUCKET), true)) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(Material.BUCKET), true, false)) {
OptionalInt supplies = SlimefunPlugin.getGPSNetwork().getResourceManager().getSupplies(oil, b.getWorld(), b.getX() >> 4, b.getZ() >> 4);
if (supplies.isPresent() && supplies.getAsInt() > 0) {

View File

@ -9,9 +9,17 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemUseHandler;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link KnowledgeFlask} is a magical {@link SlimefunItem} which allows you to store
* experience levels in a bottle when you right click.
*
* @author TheBusyBiscuit
*
*/
public class KnowledgeFlask extends SimpleSlimefunItem<ItemUseHandler> {
public KnowledgeFlask(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {

View File

@ -1,16 +1,15 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
@ -29,6 +28,8 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* {@link SoulboundItem}. It is also one of the very few utilisations of {@link ItemDropHandler}.
*
* @author Linox
* @author Walshy
* @author TheBusyBiscuit
*
* @see ItemDropHandler
* @see Soulbound
@ -36,65 +37,22 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/
public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
private static final double RANGE = 1.5;
public SoulboundRune(Category category, SlimefunItemStack item, RecipeType type, ItemStack[] recipe) {
super(category, item, type, recipe);
}
@Override
public ItemDropHandler getItemHandler() {
return (e, p, droppedItem) -> {
ItemStack item = droppedItem.getItemStack();
if (isItem(item)) {
return (e, p, item) -> {
if (isItem(item.getItemStack())) {
if (!Slimefun.hasUnlocked(p, SlimefunItems.SOULBOUND_RUNE, true)) {
return true;
}
Slimefun.runSync(() -> {
// Being sure the entity is still valid and not picked up or whatsoever.
if (!droppedItem.isValid()) {
return;
}
Location l = droppedItem.getLocation();
Collection<Entity> entites = l.getWorld().getNearbyEntities(l, 1.5, 1.5, 1.5, this::findCompatibleItem);
if (entites.isEmpty()) {
return;
}
Entity entity = entites.stream().findFirst().get();
ItemStack target = ((Item) entity).getItemStack();
Item targetItem = (Item) entity;
SlimefunUtils.setSoulbound(target, true);
if (target.getAmount() == 1) {
e.setCancelled(true);
// This lightning is just an effect, it deals no damage.
l.getWorld().strikeLightningEffect(l);
Slimefun.runSync(() -> {
// Being sure entities are still valid and not picked up or whatsoever.
if (droppedItem.isValid() && targetItem.isValid() && target.getAmount() == 1) {
l.getWorld().createExplosion(l, 0.0F);
l.getWorld().playSound(l, Sound.ENTITY_GENERIC_EXPLODE, 0.3F, 1F);
targetItem.remove();
droppedItem.remove();
l.getWorld().dropItemNaturally(l, target);
SlimefunPlugin.getLocal().sendMessage(p, "messages.soulbound-rune.success", true);
}
}, 10L);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "messages.soulbound-rune.fail", true);
}
}, 20L);
Slimefun.runSync(() -> activate(p, e, item), 20L);
return true;
}
@ -102,20 +60,47 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
};
}
/**
* This method applies the {@link Soulbound} effect onto a given {@link ItemStack}.
*
* @param item
* The {@link ItemStack} to apply this effect to
*/
public void apply(ItemStack item) {
// Should rather use PersistentData here
ItemMeta meta = item.getItemMeta();
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
lore.add(ChatColor.GRAY + "Soulbound");
private void activate(Player p, PlayerDropItemEvent e, Item item) {
// Being sure the entity is still valid and not picked up or whatsoever.
if (!item.isValid()) {
return;
}
meta.setLore(lore);
item.setItemMeta(meta);
Location l = item.getLocation();
Collection<Entity> entites = l.getWorld().getNearbyEntities(l, RANGE, RANGE, RANGE, this::findCompatibleItem);
Optional<Entity> optional = entites.stream().findFirst();
if (optional.isPresent()) {
Item entity = (Item) optional.get();
ItemStack target = entity.getItemStack();
SlimefunUtils.setSoulbound(target, true);
if (target.getAmount() == 1) {
e.setCancelled(true);
// This lightning is just an effect, it deals no damage.
l.getWorld().strikeLightningEffect(l);
Slimefun.runSync(() -> {
// Being sure entities are still valid and not picked up or whatsoever.
if (item.isValid() && entity.isValid() && target.getAmount() == 1) {
l.getWorld().createExplosion(l, 0);
l.getWorld().playSound(l, Sound.ENTITY_GENERIC_EXPLODE, 0.3F, 1);
entity.remove();
item.remove();
l.getWorld().dropItemNaturally(l, target);
SlimefunPlugin.getLocal().sendMessage(p, "messages.soulbound-rune.success", true);
}
}, 10L);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "messages.soulbound-rune.fail", true);
}
}
}
private boolean findCompatibleItem(Entity n) {

View File

@ -31,13 +31,14 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* Unlike the other Staves, it has a limited amount of uses.
*
* @author Linox
* @author Walshy
* @author TheBusyBiscuit
*
*/
public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
public static final int MAX_USES = 8;
private static final NamespacedKey usageKey = new NamespacedKey(SlimefunPlugin.instance, "stormstaff_usage");
public static final int MAX_USES = 8;
public StormStaff(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe, getCraftedOutput());
@ -58,63 +59,62 @@ public class StormStaff extends SimpleSlimefunItem<ItemUseHandler> {
@Override
public ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
ItemStack item = e.getItem();
if (!item.hasItemMeta()) return;
ItemMeta itemMeta = item.getItemMeta();
if (!itemMeta.hasLore()) return;
List<String> itemLore = itemMeta.getLore();
if (p.getFoodLevel() >= 4 || p.getGameMode() == GameMode.CREATIVE) {
// Get a target block with max. 30 blocks of distance
Location loc = p.getTargetBlock(null, 30).getLocation();
ItemStack sfItem = getItem();
ItemMeta sfItemMeta = sfItem.getItemMeta();
List<String> sfItemLore = sfItemMeta.getLore();
Player p = e.getPlayer();
// Index 1 and 3 in SlimefunItems.STAFF_STORM has lores with words and stuff so we check for them.
if (itemLore.size() < 6 && itemLore.get(1).equals(sfItemLore.get(1)) && itemLore.get(3).equals(sfItemLore.get(3))) {
if (p.getFoodLevel() >= 4 || p.getGameMode() == GameMode.CREATIVE) {
// Get a target block with max. 30 blocks of distance
Location loc = p.getTargetBlock(null, 30).getLocation();
if (loc.getWorld() != null && loc.getChunk().isLoaded()) {
if (loc.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, loc, ProtectableAction.PVP)) {
loc.getWorld().strikeLightning(loc);
if (p.getInventory().getItemInMainHand().getType() != Material.SHEARS && p.getGameMode() != GameMode.CREATIVE) {
FoodLevelChangeEvent event = new FoodLevelChangeEvent(p, p.getFoodLevel() - 4);
Bukkit.getPluginManager().callEvent(event);
p.setFoodLevel(event.getFoodLevel());
}
int currentUses = itemMeta.getPersistentDataContainer().getOrDefault(usageKey, PersistentDataType.INTEGER, MAX_USES);
e.cancel();
if (currentUses == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
}
else {
currentUses--;
itemMeta.getPersistentDataContainer().set(usageKey, PersistentDataType.INTEGER, currentUses);
itemLore.set(4, ChatColors.color("&e" + currentUses + ' ' + (currentUses > 1 ? "Uses" : "Use") + " &7left"));
itemMeta.setLore(itemLore);
item.setItemMeta(itemMeta);
}
return;
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "messages.no-pvp", true);
}
if (loc.getWorld() != null && loc.getChunk().isLoaded()) {
if (loc.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, loc, ProtectableAction.PVP)) {
e.cancel();
useItem(p, item, loc);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "messages.no-pvp", true);
}
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "messages.hungry", true);
}
return;
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "messages.hungry", true);
}
};
}
private void useItem(Player p, ItemStack item, Location loc) {
loc.getWorld().strikeLightning(loc);
if (p.getInventory().getItemInMainHand().getType() == Material.SHEARS) {
return;
}
if (p.getGameMode() != GameMode.CREATIVE) {
FoodLevelChangeEvent event = new FoodLevelChangeEvent(p, p.getFoodLevel() - 4);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
p.setFoodLevel(event.getFoodLevel());
}
}
ItemMeta meta = item.getItemMeta();
int usesLeft = meta.getPersistentDataContainer().getOrDefault(usageKey, PersistentDataType.INTEGER, MAX_USES);
if (usesLeft == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
}
else {
usesLeft--;
meta.getPersistentDataContainer().set(usageKey, PersistentDataType.INTEGER, usesLeft);
List<String> lore = meta.getLore();
lore.set(4, ChatColors.color("&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left"));
meta.setLore(lore);
item.setItemMeta(meta);
}
}
}

View File

@ -49,7 +49,9 @@ abstract class AbstractSmeltery extends MultiBlockMachine {
if (outputInv != null) {
craft(p, b, inv, inputs.get(i), output, outputInv);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
else {
SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
}
}
return;

View File

@ -2,7 +2,6 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
@ -49,8 +48,11 @@ public class ArmorForge extends MultiBlockMachine {
if (outputInv != null) {
craft(p, output, inv, outputInv);
}
else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
else {
SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true);
}
}
return;
}
}
@ -71,6 +73,7 @@ public class ArmorForge extends MultiBlockMachine {
private void craft(Player p, ItemStack output, Inventory inv, Inventory outputInv) {
for (int j = 0; j < 9; j++) {
ItemStack item = inv.getContents()[j];
if (item != null && item.getType() != Material.AIR) {
ItemUtils.consumeItem(item, true);
}
@ -79,7 +82,7 @@ public class ArmorForge extends MultiBlockMachine {
for (int j = 0; j < 4; j++) {
int current = j;
Bukkit.getScheduler().runTaskLater(SlimefunPlugin.instance, () -> {
Slimefun.runSync(() -> {
if (current < 3) {
p.getWorld().playSound(p.getLocation(), Sound.BLOCK_ANVIL_USE, 1F, 2F);
}

View File

@ -3,7 +3,6 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
@ -20,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
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 Compressor extends MultiBlockMachine {
@ -75,7 +75,7 @@ public class Compressor extends MultiBlockMachine {
for (int i = 0; i < 4; i++) {
int j = i;
Bukkit.getScheduler().runTaskLater(SlimefunPlugin.instance, () -> {
Slimefun.runSync(() -> {
if (j < 3) {
p.getWorld().playSound(p.getLocation(), j == 1 ? Sound.BLOCK_PISTON_CONTRACT : Sound.BLOCK_PISTON_EXTEND, 1F, j == 0 ? 1F : 2F);
}

View File

@ -36,6 +36,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAlta
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AncientAltarTask;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
@ -108,8 +109,8 @@ public class AncientAltarListener implements Listener {
e.cancel();
usePedestal(b, e.getPlayer());
}
else if (id.equals("ANCIENT_ALTAR")) {
if (!Slimefun.hasUnlocked(e.getPlayer(), SlimefunItems.ANCIENT_ALTAR, true) || altarsInUse.contains(b.getLocation())) {
else if (id.equals(SlimefunItems.ANCIENT_ALTAR.getItemId())) {
if (!Slimefun.hasUnlocked(e.getPlayer(), SlimefunItems.ANCIENT_ALTAR.getItem(), true) || altarsInUse.contains(b.getLocation())) {
e.cancel();
return;
}
@ -175,9 +176,9 @@ public class AncientAltarListener implements Listener {
}
}
ItemStack result = getRecipeOutput(catalyst, input);
if (result != null) {
if (Slimefun.hasUnlocked(p, result, true)) {
Optional<ItemStack> result = getRecipeOutput(catalyst, input);
if (result.isPresent()) {
if (Slimefun.hasUnlocked(p, result.get(), true)) {
List<ItemStack> consumed = new ArrayList<>();
consumed.add(catalyst);
@ -185,7 +186,8 @@ public class AncientAltarListener implements Listener {
ItemUtils.consumeItem(p.getInventory().getItemInMainHand(), false);
}
Slimefun.runSync(new AncientAltarTask(b, altar.getSpeed(), result, pedestals, consumed, p), 10L);
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1);
Slimefun.runSync(new AncientAltarTask(b, altar.getSpeed(), result.get(), pedestals, consumed, p), 10L);
}
else {
altars.remove(b);
@ -325,25 +327,30 @@ public class AncientAltarListener implements Listener {
return list;
}
public ItemStack getRecipeOutput(ItemStack catalyst, List<ItemStack> input) {
if (input.size() != 8) return null;
public Optional<ItemStack> getRecipeOutput(ItemStack catalyst, List<ItemStack> input) {
if (input.size() != 8) {
return Optional.empty();
}
if (SlimefunUtils.isItemSimilar(catalyst, SlimefunItems.BROKEN_SPAWNER, false)) {
if (checkRecipe(SlimefunItems.BROKEN_SPAWNER, input) == null) {
return null;
ItemStackWrapper wrapper = new ItemStackWrapper(catalyst);
List<ItemStackWrapper> items = ItemStackWrapper.wrapList(input);
if (SlimefunUtils.isItemSimilar(wrapper, SlimefunItems.BROKEN_SPAWNER, false)) {
if (!checkRecipe(SlimefunItems.BROKEN_SPAWNER, items).isPresent()) {
return Optional.empty();
}
ItemStack spawner = SlimefunItems.REPAIRED_SPAWNER.clone();
ItemMeta im = spawner.getItemMeta();
im.setLore(Arrays.asList(catalyst.getItemMeta().getLore().get(0)));
im.setLore(Arrays.asList(wrapper.getItemMeta().getLore().get(0)));
spawner.setItemMeta(im);
return spawner;
return Optional.of(spawner);
}
return checkRecipe(catalyst, input);
return checkRecipe(wrapper, items);
}
private ItemStack checkRecipe(ItemStack catalyst, List<ItemStack> items) {
private Optional<ItemStack> checkRecipe(ItemStack catalyst, List<ItemStackWrapper> items) {
for (AltarRecipe recipe : altarRecipes) {
if (SlimefunUtils.isItemSimilar(catalyst, recipe.getCatalyst(), true)) {
for (int i = 0; i < 8; i++) {
@ -353,7 +360,7 @@ public class AncientAltarListener implements Listener {
break;
}
else if (j == 7) {
return recipe.getOutput();
return Optional.of(recipe.getOutput());
}
}
}
@ -361,7 +368,7 @@ public class AncientAltarListener implements Listener {
}
}
return null;
return Optional.empty();
}
}

View File

@ -31,18 +31,21 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*/
public class ButcherAndroidListener implements Listener {
private static final String METADATA_KEY = "android_killer";
public ButcherAndroidListener(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onDeath(EntityDeathEvent e) {
if (e.getEntity().hasMetadata("android_killer")) {
AndroidInstance obj = (AndroidInstance) e.getEntity().getMetadata("android_killer").get(0).value();
if (e.getEntity().hasMetadata(METADATA_KEY)) {
AndroidInstance obj = (AndroidInstance) e.getEntity().getMetadata(METADATA_KEY).get(0).value();
Slimefun.runSync(() -> {
List<ItemStack> items = new ArrayList<>();
// Collect any nearby dropped items
for (Entity n : e.getEntity().getNearbyEntities(0.5D, 0.5D, 0.5D)) {
if (n instanceof Item && n.isValid() && !SlimefunUtils.hasNoPickupFlag((Item) n)) {
items.add(((Item) n).getItemStack());
@ -56,19 +59,30 @@ public class ButcherAndroidListener implements Listener {
ExperienceOrb exp = (ExperienceOrb) e.getEntity().getWorld().spawnEntity(e.getEntity().getLocation(), EntityType.EXPERIENCE_ORB);
exp.setExperience(1 + ThreadLocalRandom.current().nextInt(6));
}, 1L);
e.getEntity().removeMetadata("android_killer", SlimefunPlugin.instance);
// Removing metadata to prevent memory leaks
e.getEntity().removeMetadata(METADATA_KEY, SlimefunPlugin.instance);
}
}
private void addExtraDrops(List<ItemStack> items, EntityType entityType) {
/**
* Some items are not dropped by default. Wither Skeleton Skulls but for some weird reason
* even Blaze rods...
*
* @param drops
* The {@link List} of item drops
* @param entityType
* The {@link EntityType} of the killed entity
*/
private void addExtraDrops(List<ItemStack> drops, EntityType entityType) {
Random random = ThreadLocalRandom.current();
if (entityType == EntityType.WITHER_SKELETON && random.nextInt(250) < 2) {
items.add(new ItemStack(Material.WITHER_SKELETON_SKULL));
drops.add(new ItemStack(Material.WITHER_SKELETON_SKULL));
}
if (entityType == EntityType.BLAZE) {
items.add(new ItemStack(Material.BLAZE_ROD, 1 + random.nextInt(1)));
drops.add(new ItemStack(Material.BLAZE_ROD, 1 + random.nextInt(1)));
}
}
}

View File

@ -50,11 +50,7 @@ public class CoolerListener implements Listener {
for (ItemStack item : p.getInventory().getContents()) {
if (cooler.isItem(item)) {
if (Slimefun.hasUnlocked(p, cooler, true)) {
PlayerProfile.getBackpack(item, backpack -> {
if (backpack != null) {
Slimefun.runSync(() -> consumeJuice(p, backpack));
}
});
takeJuiceFromCooler(p, item);
}
else {
return;
@ -64,6 +60,23 @@ public class CoolerListener implements Listener {
}
}
/**
* This takes a {@link Juice} from the given {@link Cooler} and consumes it in order
* to restore hunger for the given {@link Player}.
*
* @param p
* The {@link Player}
* @param cooler
* The {@link Cooler} {@link ItemStack} to take the {@link Juice} from
*/
private void takeJuiceFromCooler(Player p, ItemStack cooler) {
PlayerProfile.getBackpack(cooler, backpack -> {
if (backpack != null) {
Slimefun.runSync(() -> consumeJuice(p, backpack));
}
});
}
private boolean consumeJuice(Player p, PlayerBackpack backpack) {
Inventory inv = backpack.getInventory();
int slot = -1;

View File

@ -33,7 +33,7 @@ public class MobDropListener implements Listener {
if (customDrops != null && !customDrops.isEmpty()) {
for (ItemStack drop : customDrops) {
if (Slimefun.hasUnlocked(p, drop, true)) {
if (SlimefunUtils.isItemSimilar(drop, SlimefunItems.BASIC_CIRCUIT_BOARD, true) && !((BasicCircuitBoard) SlimefunItem.getByID("BASIC_CIRCUIT_BOARD")).isDroppedFromGolems()) {
if (SlimefunUtils.isItemSimilar(drop, SlimefunItems.BASIC_CIRCUIT_BOARD, true) && !((BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem()).isDroppedFromGolems()) {
continue;
}

View File

@ -30,11 +30,11 @@ public class NetworkListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
manager.handleAllNetworkLocationUpdate(e.getBlock().getLocation());
manager.updateAllNetworks(e.getBlock().getLocation());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
manager.handleAllNetworkLocationUpdate(e.getBlock().getLocation());
manager.updateAllNetworks(e.getBlock().getLocation());
}
}

View File

@ -112,13 +112,16 @@ public class SlimefunBootsListener implements Listener {
@EventHandler
public void onTrample(PlayerInteractEvent e) {
if (e.getAction() != Action.PHYSICAL) return;
if (e.getClickedBlock() == null) return;
if (e.getClickedBlock().getType() != Material.FARMLAND) return;
if (e.getAction() == Action.PHYSICAL) {
Block b = e.getClickedBlock();
ItemStack boots = e.getPlayer().getInventory().getBoots();
if (SlimefunUtils.isItemSimilar(boots, SlimefunItems.FARMER_SHOES, true) && Slimefun.hasUnlocked(e.getPlayer(), boots, true)) {
e.setCancelled(true);
if (b != null && b.getType() == Material.FARMLAND) {
ItemStack boots = e.getPlayer().getInventory().getBoots();
if (SlimefunUtils.isItemSimilar(boots, SlimefunItems.FARMER_SHOES, true) && Slimefun.hasUnlocked(e.getPlayer(), boots, true)) {
e.setCancelled(true);
}
}
}
}
}

View File

@ -47,64 +47,11 @@ public class SlimefunItemListener implements Listener {
boolean itemUsed = e.getHand() == EquipmentSlot.OFF_HAND;
if (event.useItem() != Result.DENY) {
Optional<SlimefunItem> optional = event.getSlimefunItem();
if (optional.isPresent()) {
if (Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) {
itemUsed = optional.get().callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(event));
}
else {
event.setUseItem(Result.DENY);
}
}
rightClickItem(e, event, itemUsed);
}
if (!itemUsed && event.useBlock() != Result.DENY) {
Optional<SlimefunItem> optional = event.getSlimefunBlock();
if (optional.isPresent()) {
if (!Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) {
e.setCancelled(true);
return;
}
boolean interactable = optional.get().callItemHandler(BlockUseHandler.class, handler -> handler.onRightClick(event));
if (!interactable) {
String id = optional.get().getID();
Player p = e.getPlayer();
if (BlockMenuPreset.isInventory(id)) {
if (!p.isSneaking() || Material.AIR == event.getItem().getType()) {
e.setCancelled(true);
if (BlockStorage.hasUniversalInventory(id)) {
UniversalBlockMenu menu = BlockStorage.getUniversalInventory(id);
if (menu.canOpen(e.getClickedBlock(), p)) {
menu.open(p);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "inventory.no-access", true);
}
}
else if (BlockStorage.getStorage(e.getClickedBlock().getWorld()).hasInventory(e.getClickedBlock().getLocation())) {
BlockMenu menu = BlockStorage.getInventory(e.getClickedBlock().getLocation());
if (menu.canOpen(e.getClickedBlock(), p)) {
menu.open(p);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "inventory.no-access", true);
}
}
}
return;
}
}
}
if (!itemUsed && event.useBlock() != Result.DENY && !rightClickBlock(e, event)) {
return;
}
if (e.useInteractedBlock() != Result.DENY) {
@ -117,6 +64,73 @@ public class SlimefunItemListener implements Listener {
}
}
private boolean rightClickItem(PlayerInteractEvent e, PlayerRightClickEvent event, boolean defaultValue) {
Optional<SlimefunItem> optional = event.getSlimefunItem();
if (optional.isPresent()) {
if (Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) {
return optional.get().callItemHandler(ItemUseHandler.class, handler -> handler.onRightClick(event));
}
else {
event.setUseItem(Result.DENY);
}
}
return defaultValue;
}
private boolean rightClickBlock(PlayerInteractEvent e, PlayerRightClickEvent event) {
Optional<SlimefunItem> optional = event.getSlimefunBlock();
if (optional.isPresent()) {
if (!Slimefun.hasUnlocked(e.getPlayer(), optional.get(), true)) {
e.setCancelled(true);
return false;
}
boolean interactable = optional.get().callItemHandler(BlockUseHandler.class, handler -> handler.onRightClick(event));
if (!interactable) {
String id = optional.get().getID();
Player p = e.getPlayer();
if (BlockMenuPreset.isInventory(id)) {
openInventory(p, id, e, event);
return false;
}
}
}
return true;
}
private void openInventory(Player p, String id, PlayerInteractEvent e, PlayerRightClickEvent event) {
if (!p.isSneaking() || Material.AIR == event.getItem().getType()) {
e.setCancelled(true);
if (BlockStorage.hasUniversalInventory(id)) {
UniversalBlockMenu menu = BlockStorage.getUniversalInventory(id);
if (menu.canOpen(e.getClickedBlock(), p)) {
menu.open(p);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "inventory.no-access", true);
}
}
else if (BlockStorage.getStorage(e.getClickedBlock().getWorld()).hasInventory(e.getClickedBlock().getLocation())) {
BlockMenu menu = BlockStorage.getInventory(e.getClickedBlock().getLocation());
if (menu.canOpen(e.getClickedBlock(), p)) {
menu.open(p);
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "inventory.no-access", true);
}
}
}
}
@EventHandler
public void onItemDrop(PlayerDropItemEvent e) {
for (ItemHandler handler : SlimefunItem.getPublicItemHandlers(ItemDropHandler.class)) {

View File

@ -10,6 +10,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.ElevatorPlate;
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.Teleporter;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
@ -26,12 +27,16 @@ public class TeleporterListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPressurePlateEnter(PlayerInteractEvent e) {
if (e.getAction() != Action.PHYSICAL || e.getClickedBlock() == null) return;
if (e.getAction() != Action.PHYSICAL || e.getClickedBlock() == null) {
return;
}
String id = BlockStorage.checkID(e.getClickedBlock());
if (id == null) return;
if (id == null) {
return;
}
if (id.equals("GPS_ACTIVATION_DEVICE_SHARED") || (id.equals("GPS_ACTIVATION_DEVICE_PERSONAL") && BlockStorage.getLocationInfo(e.getClickedBlock().getLocation(), "owner").equals(e.getPlayer().getUniqueId().toString()))) {
if (isTeleporterPad(id, e.getClickedBlock(), e.getPlayer().getUniqueId())) {
SlimefunItem teleporter = BlockStorage.check(e.getClickedBlock().getRelative(BlockFace.DOWN));
if (teleporter instanceof Teleporter && checkForPylons(e.getClickedBlock().getRelative(BlockFace.DOWN))) {
@ -40,14 +45,18 @@ public class TeleporterListener implements Listener {
SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI(e.getPlayer(), owner, block, SlimefunPlugin.getGPSNetwork().getNetworkComplexity(owner));
}
}
else if (id.equals("ELEVATOR_PLATE")) {
((ElevatorPlate) SlimefunItem.getByID("ELEVATOR_PLATE")).open(e.getPlayer(), e.getClickedBlock());
else if (id.equals(SlimefunItems.ELEVATOR_PLATE.getItemId())) {
((ElevatorPlate) SlimefunItems.ELEVATOR_PLATE.getItem()).open(e.getPlayer(), e.getClickedBlock());
}
}
private boolean isTeleporterPad(String id, Block b, UUID uuid) {
return id.equals(SlimefunItems.GPS_ACTIVATION_DEVICE_SHARED.getItemId()) || (id.equals(SlimefunItems.GPS_ACTIVATION_DEVICE_PERSONAL.getItemId()) && BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(uuid.toString()));
}
private boolean checkForPylons(Block teleporter) {
for (BlockFace face : faces) {
if (!BlockStorage.check(teleporter.getRelative(face), "GPS_TELEPORTER_PYLON")) {
if (!BlockStorage.check(teleporter.getRelative(face), SlimefunItems.GPS_TELEPORTER_PYLON.getItemId())) {
return false;
}
}

View File

@ -354,7 +354,7 @@ public class TickerTask implements Runnable {
try {
run();
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
plugin.getLogger().log(Level.SEVERE, x, () -> "An Exception was caught while ticking the Block Tickers Task for Slimefun v" + SlimefunPlugin.getVersion());
abortTick();
}

View File

@ -1,5 +1,8 @@
package io.github.thebusybiscuit.slimefun4.utils.itemstack;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@ -116,4 +119,28 @@ public final class ItemStackWrapper extends ItemStack {
return array;
}
/**
* This creates an {@link ItemStackWrapper} {@link List} from a given {@link ItemStack} {@link List} *
*
* @param items
* The {@link List} of {@link ItemStack ItemStacks} to transform
*
* @return An {@link ItemStackWrapper} array
*/
public static List<ItemStackWrapper> wrapList(List<ItemStack> items) {
Validate.notNull(items, "The list must not be null!");
List<ItemStackWrapper> list = new ArrayList<>(items.size());
for (ItemStack item : items) {
if (item != null) {
list.add(new ItemStackWrapper(item));
}
else {
list.add(null);
}
}
return list;
}
}

View File

@ -711,7 +711,7 @@ public class SlimefunItem implements Placeable {
try {
callable.accept(c.cast(handler.get()));
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
error("Could not pass \"" + c.getSimpleName() + "\" for " + toString(), x);
}

View File

@ -449,7 +449,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
try {
SlimefunItemSetup.setup(this);
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
getLogger().log(Level.SEVERE, x, () -> "An Error occured while initializing SlimefunItems for Slimefun " + getVersion());
}
}
@ -458,7 +458,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
try {
ResearchSetup.setupResearches();
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
getLogger().log(Level.SEVERE, x, () -> "An Error occured while initializing Slimefun Researches for Slimefun " + getVersion());
}
}

View File

@ -18,9 +18,11 @@ import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* Provides a few convenience methods.
* Provides a few static convenience methods.
*
* @since 4.0
* @author TheBusyBiscuit
* @author Walshy
* @author Poslovitch
*/
public final class Slimefun {

View File

@ -172,7 +172,8 @@ public class SlimefunItemStack extends CustomItem {
}
/**
* Gets the {@link SlimefunItem} associated for this {@link SlimefunItemStack}. Null if no item is found.
* Gets the {@link SlimefunItem} associated for this {@link SlimefunItemStack}.
* Null if no item is found.
*
* @return The {@link SlimefunItem} for this {@link SlimefunItemStack}, null if not found.
*/
@ -180,6 +181,25 @@ public class SlimefunItemStack extends CustomItem {
return SlimefunItem.getByID(id);
}
/**
* This method returns the associated {@link SlimefunItem} and casts it to the provided
* {@link Class}.
*
* If no item was found or the found {@link SlimefunItem} is not of the requested type,
* the method will return null.
*
* @param <T>
* The type of {@link SlimefunItem} to cast this to
* @param type
* The {@link Class} of the target {@link SlimefunItem}
*
* @return The {@link SlimefunItem} this {@link SlimefunItem} represents, casted to the given type
*/
public <T extends SlimefunItem> T getItem(Class<T> type) {
SlimefunItem item = getItem();
return type.isInstance(item) ? type.cast(item) : null;
}
public ImmutableItemMeta getImmutableMeta() {
return immutableMeta;
}

View File

@ -195,7 +195,7 @@ public abstract class BlockMenuPreset extends ChestMenu {
try {
newInstance(menu, l.getBlock());
}
catch (Throwable x) {
catch (Exception | LinkageError x) {
getSlimefunItem().error("An eror occured while trying to create a BlockMenu", x);
}
});

View File

@ -2,6 +2,7 @@ package me.mrCookieSlime.Slimefun.api.inventory;
import java.util.ArrayList;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
@ -10,6 +11,7 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
public class DirtyChestMenu extends ChestMenu {
@ -65,16 +67,23 @@ public class DirtyChestMenu extends ChestMenu {
}
public boolean fits(ItemStack item, int... slots) {
return InvUtils.fits(toInventory(), item, slots);
return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots);
}
public ItemStack pushItem(ItemStack item, int... slots) {
if (item == null || item.getType() == Material.AIR) {
throw new IllegalArgumentException("Cannot push null or AIR");
}
int amount = item.getAmount();
for (int slot : slots) {
if (amount <= 0) break;
if (amount <= 0) {
break;
}
ItemStack stack = getItemInSlot(slot);
if (stack == null) {
replaceExistingItem(slot, item);
return null;