1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-20 03:35:51 +00:00

Merge branch 'master' into master

This commit is contained in:
Rothes 2021-04-20 12:51:03 +08:00 committed by GitHub
commit df0d36f4f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 1733 additions and 988 deletions

View File

@ -48,6 +48,6 @@ assignees: ''
<!-- Make sure that the screenshot covers the entire output of that command. -->
<!-- If your issue is related to other plugins, make sure to include the versions of these plugins too! -->
- Server Software:
- Minecraft Version:
- Slimefun Version:
- Server software:
- Minecraft version:
- Slimefun version:

View File

@ -1,16 +1,20 @@
## Description
<!-- Please explain what you changed/added and why you did it in detail. -->
<!-- Please explain why you are making this pull request. -->
<!-- Start writing below this line -->
## Changes
<!-- Please list all the changes you have made. -->
## Proposed changes
<!-- Please explain what changes you have made to the code. -->
<!-- Start writing below this line -->
## Related Issues
## Related Issues (if applicable)
<!-- Please tag any Issues related to your Pull Request -->
<!-- Syntax: "Resolves #000" -->
<!-- Start writing below this line -->
## Checklist
<!-- Here is a little checklist you should follow. -->
<!-- You can click those check boxes after you posted your issue. -->
<!-- Here is a little checklist you can follow. -->
<!-- Click on these checkboxes after you created the pull request. -->
<!-- Don't worry, these are not requirements. They only serve as guidance. -->
- [ ] I have fully tested the proposed changes and promise that they will not break everything into chaos.
- [ ] I have also tested the proposed changes in combination with various popular addons and can confirm my changes do not break them.
- [ ] I followed the existing code standards and didn't mess up the formatting.

View File

@ -18,8 +18,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v2.3.4
- name: Set up Java JDK 11
uses: actions/setup-java@v1.4.3
uses: actions/setup-java@v2.0.0
with:
distribution: 'adopt'
java-version: '11'
java-package: jdk
architecture: x64

View File

@ -24,8 +24,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@master
uses: actions/setup-java@v2.0.0
with:
java-version: 1.8
distribution: 'adopt'
java-version: '8'
- name: Build with Maven
run: mvn package --file pom.xml

View File

@ -1,5 +1,6 @@
# Table of contents
- [Release Candidate 22 (TBD)](#release-candidate-22-tbd)
- [Release Candidate 23 (TBD)](#release-candidate-23-tbd)
- [Release Candidate 22 (18 Apr 2021)](#release-candidate-22-18-apr-2021)
- [Release Candidate 21 (14 Mar 2021)](#release-candidate-21-14-mar-2021)
- [Release Candidate 20 (30 Jan 2021)](#release-candidate-20-30-jan-2021)
- [Release Candidate 19 (11 Jan 2021)](#release-candidate-19-11-jan-2021)
@ -22,15 +23,46 @@
- [Release Candidate 2 (29 Sep 2019)](#release-candidate-2-29-sep-2019)
- [Release Candidate 1 (26 Sep 2019)](#release-candidate-1-26-sep-2019)
## Release Candidate 22 (TBD)
## Release Candidate 23 (TBD)
#### Additions
* Added Vanilla Auto Crafter
* Added Enhanced Auto Crafter
* Added "Quartz Block -> 4 Quartz" recipe to Grind Stone
#### Changes
* Renamed "Solar Panel" to "Photovoltaic Cell" to avoid confusions with solar generators
* Photovoltaic Cells can no longer be placed
* (API) Removed deprecated "SlimefunBlockHandler"
#### Fixes
## Release Candidate 22 (18 Apr 2021)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#22
#### Additions
* Added Vanilla Auto-Crafter
* Added Enhanced Auto-Crafter
* Added "Smart-Filling" mode to Cargo Input nodes
* Added "Netherite Ingot -> Netherite Block" recipe to Electric Press
* Added "Slimeballs -> Slime Block" recipe to Electric Press
* Added Armor Forge Auto-Crafter
* Auto-Crafters can now be turned on and off
* Added Produce Collector to automate Milk and Mushroom Stew
* Added a new message when constructing a Multiblock successfully
* Added Crafting Motor
* Block Placers can now place down cake
* Added support for the "FunnyGuilds" plugin
* Added "magma cream -> slime ball" recipe to the Freezer
* Added "2 magma blocks -> slime block" recipe to the Freezer
* Added configurable enchantment level limit for both auto enchanter and auto disenchanter
* (API) Added AutoEnchantEvent
#### Changes
* Changed item order in guide for the Villager Rune and Nether Goo (All runes are now grouped together)
* Ancient Pedestals can now be found under "Magical Gadgets"
* Removed all functionality from the old Automated Crafting Chamber
* Changed Cargo Motor texture
* Lowered "Magma block -> Sulfate" recipe to only require 1 magma block
* Small performance improvements
#### Fixes
* Fixed #1161
@ -41,6 +73,19 @@
* Fixed #2896
* Fixed #2899
* Fixed #2906
* Fixed #2903
* Fixed #2913
* Fixed #2914
* Fixed Auto-Crafters swallowing buckets when crafting cake
* Fixed Multimeter not working on Auto-Crafters
* Fixed #2650
* Fixed Slimefun items applying damage to items with an `unbreakable` tag
* Fixed #2930
* Fixed #2926
* Fixed Grappling Hook vanishing in creative mode
* Fixed #2944
* Fixed #2837
* Fixed #2942
## Release Candidate 21 (14 Mar 2021)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#21

View File

@ -67,7 +67,7 @@ Well, we asked some users on our [Discord server](#discord) to send us some scre
| *Screenshot provided by GalaxyKat11#3816* | *Screenshot provided by TamThan#7987* | *Screenshot provided by Kilaruna#4981* |
## Discord
You can find Slimefun's community on Discord and connect with **over 4000** users of this plugin from all over the world.<br>
You can find Slimefun's community on Discord and connect with **over 5000** users of this plugin from all over the world.<br>
Click the badge down below to join the server for suggestions/questions or other discussions about this plugin.<br>
We are also hosting a community event every so often, join us to find out more.<br>
**Important**: We do **not** accept bug reports on discord, please use our [Issue Tracker](https://github.com/Slimefun/Slimefun4/issues) to submit bug reports!

View File

@ -341,13 +341,13 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.8.0</version>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.16</artifactId>
<version>0.32.1</version>
<version>0.33.0</version>
<scope>test</scope>
<exclusions>
@ -364,7 +364,7 @@
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>CS-CoreLib2</artifactId>
<version>0.30.3</version>
<version>0.30.4</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -420,7 +420,7 @@
<dependency>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.1.182</version>
<version>2.1.194</version>
<scope>provided</scope>
<exclusions>

View File

@ -50,6 +50,18 @@ public class ErrorReport<T extends Throwable> {
private T throwable;
private File file;
/**
* This is the base constructor for an {@link ErrorReport}. It will only
* print the necessary info and provides a {@link Consumer} for any more detailed
* needs.
*
* @param throwable
* The {@link Throwable} which caused this {@link ErrorReport}.
* @param addon
* The {@link SlimefunAddon} responsible.
* @param printer
* A custom {@link Consumer} to add more details.
*/
@ParametersAreNonnullByDefault
public ErrorReport(T throwable, SlimefunAddon addon, Consumer<PrintStream> printer) {
this.throwable = throwable;
@ -58,6 +70,17 @@ public class ErrorReport<T extends Throwable> {
SlimefunPlugin.runSync(() -> print(printer));
}
/**
* This constructs a new {@link ErrorReport} for the given {@link Location} and
* {@link SlimefunItem}.
*
* @param throwable
* The {@link Throwable} which caused this {@link ErrorReport}.
* @param l
* The {@link Location} at which the error was thrown.
* @param item
* The {@link SlimefunItem} responsible.
*/
@ParametersAreNonnullByDefault
public ErrorReport(T throwable, Location l, SlimefunItem item) {
this(throwable, item.getAddon(), stream -> {
@ -91,6 +114,14 @@ public class ErrorReport<T extends Throwable> {
});
}
/**
* This constructs a new {@link ErrorReport} for the given {@link SlimefunItem}.
*
* @param throwable
* The {@link Throwable} which caused this {@link ErrorReport}.
* @param item
* The {@link SlimefunItem} responsible.
*/
@ParametersAreNonnullByDefault
public ErrorReport(T throwable, SlimefunItem item) {
this(throwable, item.getAddon(), stream -> {

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@ -26,7 +27,7 @@ public class AsyncMachineProcessCompleteEvent extends Event {
private final MachineRecipe machineRecipe;
public AsyncMachineProcessCompleteEvent(@Nonnull Location l, @Nullable AContainer container, @Nullable MachineRecipe machineRecipe) {
super(true);
super(!Bukkit.isPrimaryThread());
this.location = l;
this.container = container;

View File

@ -15,6 +15,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines
*
* @author poma123
*
* @see AutoEnchantEvent
*/
public class AutoDisenchantEvent extends Event implements Cancellable {

View File

@ -0,0 +1,63 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
/**
* An {@link Event} that is called whenever an {@link AutoEnchanter} is trying to enchant
* an {@link ItemStack}.
*
* @author WalshyDev
*
* @see AutoDisenchantEvent
*/
public class AutoEnchantEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final ItemStack item;
private boolean cancelled;
public AutoEnchantEvent(@Nonnull ItemStack item) {
super(true);
this.item = item;
}
/**
* This returns the {@link ItemStack} that is being enchanted.
*
* @return The {@link ItemStack} that is being enchanted
*/
@Nonnull
public ItemStack getItem() {
return item;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Nonnull
public static HandlerList getHandlerList() {
return handlers;
}
@Nonnull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -15,10 +15,12 @@ import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
@ -47,6 +49,12 @@ public class ResourceManager {
private final int[] backgroundSlots = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 17, 18, 26, 27, 35, 36, 44, 45, 46, 48, 49, 50, 52, 53 };
private final Config config;
/**
* This will create a new {@link ResourceManager}.
*
* @param plugin
* Our {@link SlimefunPlugin} instance
*/
public ResourceManager(@Nonnull SlimefunPlugin plugin) {
config = new Config(plugin, "resources.yml");
}
@ -95,6 +103,7 @@ public class ResourceManager {
*
* @return An {@link OptionalInt}, either empty or containing the amount of the given {@link GEOResource}
*/
@Nonnull
public OptionalInt getSupplies(@Nonnull GEOResource resource, @Nonnull World world, int x, int z) {
Validate.notNull(resource, "Cannot get supplies for null");
Validate.notNull(world, "World must not be null");
@ -109,6 +118,20 @@ public class ResourceManager {
}
}
/**
* This method will set the supplies in a given {@link Chunk} to the specified value.
*
* @param resource
* The {@link GEOResource}
* @param world
* The {@link World}
* @param x
* The x coordinate of that {@link Chunk}
* @param z
* The z coordinate of that {@link Chunk}
* @param value
* The new supply value
*/
public void setSupplies(@Nonnull GEOResource resource, @Nonnull World world, int x, int z, int value) {
Validate.notNull(resource, "Cannot set supplies for null");
Validate.notNull(world, "World cannot be null");
@ -117,13 +140,42 @@ public class ResourceManager {
BlockStorage.setChunkInfo(world, x, z, key, String.valueOf(value));
}
/**
* This method will generate the default supplies for a given {@link GEOResource} at the
* given {@link Chunk}.
* <p>
* This method will invoke {@link #setSupplies(GEOResource, World, int, int, int)} and also calls a
* {@link GEOResourceGenerationEvent}.
*
* @param resource
* The {@link GEOResource} to generate
* @param world
* The {@link World}
* @param x
* The x coordinate of that {@link Chunk}
* @param z
* The z coordinate of that {@link Chunk}
*
* @return The new supply value
*/
private int generate(@Nonnull GEOResource resource, @Nonnull World world, int x, int z) {
Validate.notNull(resource, "Cannot generate resources for null");
Validate.notNull(world, "World cannot be null");
// Get the corresponding Block (and Biome)
Block block = world.getBlockAt(x << 4, 72, z << 4);
int value = resource.getDefaultSupply(world.getEnvironment(), block.getBiome());
Biome biome = block.getBiome();
/*
* getBiome() is marked as NotNull, but it seems like some servers ignore this entirely.
* We have seen multiple reports on Tuinity where it has indeed returned null.
*/
Validate.notNull(biome, "Biome appears to be null for position: " + new BlockPosition(block));
// Make sure the value is not below zero.
int value = Math.max(0, resource.getDefaultSupply(world.getEnvironment(), biome));
// Check if more than zero units are to be generated.
if (value > 0) {
int max = resource.getMaxDeviation();
@ -134,7 +186,8 @@ public class ResourceManager {
value += ThreadLocalRandom.current().nextInt(max);
}
GEOResourceGenerationEvent event = new GEOResourceGenerationEvent(world, block.getBiome(), x, z, resource, value);
// Fire an event, so that plugins can modify this.
GEOResourceGenerationEvent event = new GEOResourceGenerationEvent(world, biome, x, z, resource, value);
Bukkit.getPluginManager().callEvent(event);
value = event.getValue();
@ -166,7 +219,8 @@ public class ResourceManager {
int x = block.getX() >> 4;
int z = block.getZ() >> 4;
ChestMenu menu = new ChestMenu("&4" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.results"));
String title = "&4" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.results");
ChestMenu menu = new ChestMenu(title);
for (int slot : backgroundSlots) {
menu.addItem(slot, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());

View File

@ -58,6 +58,13 @@ public class GPSNetwork {
private final TeleportationManager teleportation = new TeleportationManager();
private final ResourceManager resourceManager;
/**
* This constructs a new {@link GPSNetwork}.
* Note that this network is per {@link Server} and not per {@link Player}.
*
* @param plugin
* Our {@link SlimefunPlugin} instance
*/
public GPSNetwork(@Nonnull SlimefunPlugin plugin) {
resourceManager = new ResourceManager(plugin);
}
@ -125,6 +132,13 @@ public class GPSNetwork {
return locations == null ? 0 : locations.size();
}
/**
* This method opens the {@link GPSTransmitter} control panel to the given
* {@link Player}.
*
* @param p
* The {@link Player}
*/
public void openTransmitterControlPanel(@Nonnull Player p) {
ChestMenu menu = new ChestMenu(ChatColor.BLUE + SlimefunPlugin.getLocalization().getMessage(p, "machines.GPS_CONTROL_PANEL.title"));

View File

@ -7,6 +7,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.World.Environment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -34,53 +35,103 @@ public class Waypoint {
private final String name;
private final Location location;
/**
* This constructs a new {@link Waypoint} object.
*
* @param profile
* The owning {@link PlayerProfile}
* @param id
* The unique id for this {@link Waypoint}
* @param loc
* The {@link Location} of the {@link Waypoint}
* @param name
* The name of this {@link Waypoint}
*/
@ParametersAreNonnullByDefault
public Waypoint(PlayerProfile profile, String id, Location l, String name) {
public Waypoint(PlayerProfile profile, String id, Location loc, String name) {
Validate.notNull(profile, "Profile must never be null!");
Validate.notNull(id, "id must never be null!");
Validate.notNull(l, "Location must never be null!");
Validate.notNull(loc, "Location must never be null!");
Validate.notNull(name, "Name must never be null!");
this.profile = profile;
this.id = id;
this.location = l;
this.location = loc;
this.name = name;
}
/**
* This returns the owner of the {@link Waypoint}.
*
* @return The corresponding {@link PlayerProfile}
*/
@Nonnull
public PlayerProfile getOwner() {
return profile;
}
/**
* This method returns the unique identifier for this {@link Waypoint}.
*
* @return The {@link Waypoint} id
*/
@Nonnull
public String getId() {
return id;
}
/**
* This returns the name of this {@link Waypoint}.
*
* @return The name of this {@link Waypoint}
*/
@Nonnull
public String getName() {
return name;
}
/**
* This returns the {@link Location} of this {@link Waypoint}
*
* @return The {@link Waypoint} {@link Location}
*/
@Nonnull
public Location getLocation() {
return location;
}
/**
* This method returns whether this {@link Waypoint} is a Deathpoint.
*
* @return Whether this is a Deathpoint
*/
public boolean isDeathpoint() {
return name.startsWith("player:death ");
}
/**
* This method returns the {@link ItemStack} icon for this {@link Waypoint}.
* The icon is dependent on the {@link Environment} the {@link Waypoint} is in
* and whether it is a Deathpoint.
*
* @return The {@link ItemStack} icon for this {@link Waypoint}
*/
@Nonnull
public ItemStack getIcon() {
return SlimefunPlugin.getGPSNetwork().getIcon(name, location.getWorld().getEnvironment());
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hash(profile.getUUID(), id, name, location);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Waypoint)) {

View File

@ -1,44 +0,0 @@
package io.github.thebusybiscuit.slimefun4.api.items;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
public interface ItemRestriction {
/**
* This method represents a check.
* The returned boolean will decide whether to allow the action.
*
* @param profile
* The Player's profile
* @param p
* The Player itself
* @param item
* The SlimefunItem that the {@link ItemStack} represents
* @param itemstack
* The ItemStack that is being tested.
*
* @return Whether the action was allowed
*/
boolean isAllowed(PlayerProfile profile, Player p, SlimefunItem item, ItemStack itemstack);
/**
* This method is executed if an ItemRestriction took affect.
* Override it to send a message to the Player telling them they cannot
* use that item, or do something else in there.
*
* @param profile
* The Player's profile
* @param p
* The Player to warn
* @param item
* The SlimefunItem that the {@link ItemStack} represents
* @param itemstack
* The ItemStack that was prevented from being used
*/
void warnPlayer(PlayerProfile profile, Player p, SlimefunItem item, ItemStack itemstack);
}

View File

@ -471,6 +471,8 @@ public class PlayerProfile {
}
public boolean hasFullProtectionAgainst(@Nonnull ProtectionType type) {
Validate.notNull(type, "ProtectionType must not be null.");
int armorCount = 0;
NamespacedKey setId = null;

View File

@ -36,7 +36,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.BlockInfoConfig;
@ -92,7 +91,6 @@ public final class SlimefunRegistry {
private final Map<String, BlockMenuPreset> blockMenuPresets = new HashMap<>();
private final Map<String, UniversalBlockMenu> universalInventories = new HashMap<>();
private final Map<Class<? extends ItemHandler>, Set<ItemHandler>> globalItemHandlers = new HashMap<>();
private final Map<String, SlimefunBlockHandler> blockHandlers = new HashMap<>();
public void load(@Nonnull SlimefunPlugin plugin, @Nonnull Config cfg) {
Validate.notNull(plugin, "The Plugin cannot be null!");
@ -333,12 +331,6 @@ public final class SlimefunRegistry {
return globalItemHandlers;
}
@Deprecated
@Nonnull
public Map<String, SlimefunBlockHandler> getBlockHandlers() {
return blockHandlers;
}
@Nonnull
public Map<String, BlockStorage> getWorlds() {
return worlds;

View File

@ -3,7 +3,7 @@ package io.github.thebusybiscuit.slimefun4.core.attributes;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.Material;
import io.github.thebusybiscuit.slimefun4.utils.UnbreakingAlgorithm;
import org.bukkit.Sound;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
@ -22,7 +22,10 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
* option that decides whether or not this {@link SlimefunItem} shall be damageable.
*
* @author TheBusyBiscuit
*
* @author RobotHanzo
*
* @see UnbreakingAlgorithm
*
*/
public interface DamageableItem extends ItemAttribute {
@ -47,24 +50,43 @@ public interface DamageableItem extends ItemAttribute {
* The {@link ItemStack} to damage
*/
default void damageItem(@Nonnull Player p, @Nullable ItemStack item) {
if (isDamageable() && item != null && item.getType() != Material.AIR && item.getAmount() > 0) {
if (isDamageable() && item != null && !item.getType().isAir() && item.getAmount() > 0) {
int unbreakingLevel = item.getEnchantmentLevel(Enchantment.DURABILITY);
if (unbreakingLevel > 0 && Math.random() * 100 <= (60 + Math.floorDiv(40, (unbreakingLevel + 1)))) {
if (evaluateUnbreakingEnchantment(unbreakingLevel)) {
return;
}
ItemMeta meta = item.getItemMeta();
Damageable damageable = (Damageable) meta;
if (damageable.getDamage() >= item.getType().getMaxDurability()) {
p.playSound(p.getEyeLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
} else {
damageable.setDamage(damageable.getDamage() + 1);
item.setItemMeta(meta);
if (!meta.isUnbreakable()) {
Damageable damageable = (Damageable) meta;
if (damageable.getDamage() >= item.getType().getMaxDurability()) {
p.playSound(p.getEyeLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
} else {
damageable.setDamage(damageable.getDamage() + 1);
item.setItemMeta(meta);
}
}
}
}
/**
* This method will randomly decide if the item should be damaged or not
* This does not damage the item, it is called by {@link #damageItem(Player, ItemStack)} to randomly generate a
* boolean
* This function should be overridden when the item type is not a tool which is the default value
*
* @param unbreakingLevel
* The {@link Integer} level of the unbreaking {@link Enchantment}
*
* @return Whether to save the item from taking damage
*
*/
default boolean evaluateUnbreakingEnchantment(int unbreakingLevel) {
return UnbreakingAlgorithm.TOOLS.evaluate(unbreakingLevel);
}
}

View File

@ -10,6 +10,7 @@ import java.util.Set;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bukkit.Location;
import org.bukkit.block.Block;
@ -19,6 +20,7 @@ import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
/**
@ -47,10 +49,12 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
protected final Map<Location, Integer> roundRobin = new HashMap<>();
private int tickDelayThreshold = 0;
@Nullable
public static CargoNet getNetworkFromLocation(@Nonnull Location l) {
return SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, CargoNet.class).orElse(null);
}
@Nonnull
public static CargoNet getNetworkFromLocationOrCreate(@Nonnull Location l) {
Optional<CargoNet> cargoNetwork = SlimefunPlugin.getNetworkManager().getNetworkFromLocation(l, CargoNet.class);
@ -145,7 +149,7 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
}
}
public void tick(Block b) {
public void tick(@Nonnull Block b) {
if (!regulator.equals(b.getLocation())) {
updateHologram(b, "&4Multiple Cargo Regulators connected");
return;
@ -186,7 +190,8 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
}
}
private Map<Location, Integer> mapInputNodes(Set<Location> chestTerminalNodes) {
@Nonnull
private Map<Location, Integer> mapInputNodes(@Nonnull Set<Location> chestTerminalNodes) {
Map<Location, Integer> inputs = new HashMap<>();
for (Location node : inputNodes) {
@ -202,7 +207,8 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
return inputs;
}
private Map<Integer, List<Location>> mapOutputNodes(Set<Location> chestTerminalOutputs) {
@Nonnull
private Map<Integer, List<Location>> mapOutputNodes(@Nonnull Set<Location> chestTerminalOutputs) {
Map<Integer, List<Location>> output = new HashMap<>();
List<Location> list = new LinkedList<>();
@ -241,7 +247,7 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
/**
* 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
* Should there be invalid data this method it will fall back to zero in
* order to preserve the integrity of the {@link CargoNet}.
*
* @param node
@ -249,13 +255,16 @@ public class CargoNet extends AbstractItemNetwork implements HologramOwner {
*
* @return The frequency of the given node
*/
private static int getFrequency(Location node) {
try {
String str = BlockStorage.getLocationInfo(node).getString("frequency");
return str == null ? 0 : Integer.parseInt(str);
} catch (Exception x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Error occurred while parsing a Cargo Node Frequency (" + node.getWorld().getName() + " - " + node.getBlockX() + "," + node.getBlockY() + "," + +node.getBlockZ() + ")");
private static int getFrequency(@Nonnull Location node) {
String frequency = BlockStorage.getLocationInfo(node, "frequency");
if (frequency == null) {
return 0;
} else if (!PatternUtils.NUMERIC.matcher(frequency).matches()) {
SlimefunPlugin.logger().log(Level.SEVERE, () -> "Failed to parse a Cargo Node Frequency (" + node.getWorld().getName() + " - " + node.getBlockX() + ',' + node.getBlockY() + ',' + node.getBlockZ() + "): " + frequency);
return 0;
} else {
return Integer.parseInt(frequency);
}
}
}

View File

@ -1,8 +1,10 @@
package io.github.thebusybiscuit.slimefun4.core.networks.cargo;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -158,13 +160,24 @@ class CargoNetworkTask implements Runnable {
private ItemStack distributeItem(ItemStack stack, Location inputNode, List<Location> outputNodes) {
ItemStack item = stack;
Deque<Location> destinations = new LinkedList<>(outputNodes);
Config cfg = BlockStorage.getLocationInfo(inputNode);
boolean roundrobin = Objects.equals(cfg.getString("round-robin"), "true");
boolean smartFill = Objects.equals(cfg.getString("smart-fill"), "true");
Collection<Location> destinations;
if (roundrobin) {
roundRobinSort(inputNode, destinations);
// Use an ArrayDeque to perform round-robin sorting
// Since the impl for roundRobinSort just does Deque.addLast(Deque#removeFirst)
// An ArrayDequeue is preferable as opposed to a LinkedList:
// - The number of elements does not change.
// - ArrayDequeue has better iterative performance
Deque<Location> tempDestinations = new ArrayDeque<>(outputNodes);
roundRobinSort(inputNode, tempDestinations);
destinations = tempDestinations;
} else {
// Using an ArrayList here since we won't need to sort the destinations
// The ArrayList has the best performance for iteration bar a primitive array
destinations = new ArrayList<>(outputNodes);
}
for (Location output : destinations) {

View File

@ -292,6 +292,11 @@ final class CargoUtils {
int maxStackSize = itemInSlot.getType().getMaxStackSize();
int currentAmount = itemInSlot.getAmount();
if (!smartFill && currentAmount == maxStackSize) {
// Skip full stacks - Performance optimization for non-smartfill nodes
continue;
}
if (SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false)) {
if (currentAmount < maxStackSize) {
int amount = currentAmount + stack.getAmount();
@ -339,11 +344,17 @@ final class CargoUtils {
inv.setItem(slot, stack);
return null;
} else {
int currentAmount = itemInSlot.getAmount();
int maxStackSize = itemInSlot.getType().getMaxStackSize();
if (!smartFill && currentAmount == maxStackSize) {
// Skip full stacks - Performance optimization for non-smartfill nodes
continue;
}
if (SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false)) {
if (itemInSlot.getAmount() < maxStackSize) {
int amount = itemInSlot.getAmount() + stack.getAmount();
if (currentAmount < maxStackSize) {
int amount = currentAmount + stack.getAmount();
if (amount > maxStackSize) {
stack.setAmount(amount - maxStackSize);

View File

@ -150,7 +150,7 @@ public class LocalizationService extends SlimefunLocalization {
@Override
public Language getLanguage(@Nonnull Player p) {
Validate.notNull("Player cannot be null!");
Validate.notNull(p, "Player cannot be null!");
PersistentDataContainer container = p.getPersistentDataContainer();
String language = container.get(languageKey, PersistentDataType.STRING);
@ -253,7 +253,7 @@ public class LocalizationService extends SlimefunLocalization {
}
@Nonnull
private Set<String> getKeys(FileConfiguration... files) {
private Set<String> getKeys(@Nonnull FileConfiguration... files) {
Set<String> keys = new HashSet<>();
for (FileConfiguration cfg : files) {

View File

@ -50,8 +50,11 @@ class ContributionsConnector extends GitHubConnector {
* These people are... "special cases".
*/
private void loadConfiguration() {
// Bots and invalid accounts we want to ignore.
ignoredAccounts.add("invalid-email-address");
ignoredAccounts.add("renovate");
ignoredAccounts.add("renovate-bot");
ignoredAccounts.add("renovate[bot]");
ignoredAccounts.add("TheBusyBot");
ignoredAccounts.add("ImgBotApp");
ignoredAccounts.add("imgbot");
@ -61,6 +64,7 @@ class ContributionsConnector extends GitHubConnector {
ignoredAccounts.add("gitlocalize-app[bot]");
ignoredAccounts.add("mt-gitlocalize");
// Known Minecraft aliases.
aliases.put("WalshyDev", "HumanRightsAct");
aliases.put("J3fftw1", "_lagpc_");
aliases.put("ajan-12", "ajan_12");

View File

@ -13,6 +13,8 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang.Validate;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Translators;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -78,10 +80,14 @@ public class GitHubService {
* the usual methods.
*/
private void addDefaultContributors() {
// Artists
addContributor("Fuffles_", "&dArtist");
addContributor("IMS_Art", "&dArtist");
addContributor("IMS_Art", "https://github.com/IAmSorryArt", "&dArtist", 0);
// Addon Jam winners
addContributor("nahkd123", "&aWinner of the 2020 Addon Jam");
// Translators
new Translators(this);
}
@ -94,6 +100,11 @@ public class GitHubService {
@Nonnull
public Contributor addContributor(@Nonnull String minecraftName, @Nonnull String profileURL, @Nonnull String role, int commits) {
Validate.notNull(minecraftName, "Minecraft username must not be null.");
Validate.notNull(profileURL, "GitHub profile url must not be null.");
Validate.notNull(role, "Role should not be null.");
Validate.isTrue(commits >= 0, "Commit count cannot be negative.");;
String username = profileURL.substring(profileURL.lastIndexOf('/') + 1);
Contributor contributor = contributors.computeIfAbsent(username, key -> new Contributor(minecraftName, profileURL));
@ -106,9 +117,10 @@ public class GitHubService {
this.logging = logging;
addDefaultContributors();
// TheBusyBiscuit/Slimefun4 (twice because there may me multiple pages)
// TheBusyBiscuit/Slimefun4 (multiple times because there may me multiple pages)
connectors.add(new ContributionsConnector(this, "code", 1, repository, "developer"));
connectors.add(new ContributionsConnector(this, "code2", 2, repository, "developer"));
connectors.add(new ContributionsConnector(this, "code3", 3, repository, "developer"));
// TheBusyBiscuit/Slimefun4-Wiki
connectors.add(new ContributionsConnector(this, "wiki", 1, "Slimefun/Wiki", "wiki"));
@ -122,6 +134,7 @@ public class GitHubService {
this.pendingPullRequests = pullRequests;
}));
// Forks, star count and last commit date
connectors.add(new GitHubActivityConnector(this, repository, (forks, stars, date) -> {
this.publicForks = forks;
this.stargazers = stars;

View File

@ -160,8 +160,7 @@ public final class Language {
*/
@Nonnull
public String getName(@Nonnull Player p) {
String name = SlimefunPlugin.getLocalization().getMessage(p, "languages." + id);
return name != null ? name : toString();
return SlimefunPlugin.getLocalization().getMessage(p, "languages." + id);
}
/**

View File

@ -1,13 +1,15 @@
package io.github.thebusybiscuit.slimefun4.core.services.localization;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.UnaryOperator;
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.Keyed;
import org.bukkit.NamespacedKey;
@ -33,9 +35,9 @@ import net.md_5.bungee.api.chat.TextComponent;
/**
* This is an abstract parent class of {@link LocalizationService}.
* There is not really much more I can say besides that...
*
*
* @author TheBusyBiscuit
*
*
* @see LocalizationService
*
*/
@ -48,10 +50,10 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
/**
* This method attempts to return the {@link Language} with the given
* language code.
*
*
* @param id
* The language code
*
*
* @return A {@link Language} with the given id or null
*/
@Nullable
@ -59,28 +61,30 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
/**
* This method returns the currently selected {@link Language} of a {@link Player}.
*
*
* @param p
* The {@link Player} to query
*
*
* @return The {@link Language} that was selected by the given {@link Player}
*/
@Nullable
public abstract Language getLanguage(@Nonnull Player p);
/**
* This method returns the default {@link Language} of this {@link Server}
*
*
* @return The default {@link Language}
*/
@Nullable
public abstract Language getDefaultLanguage();
/**
* This returns whether a {@link Language} with the given id exists within
* the project resources.
*
*
* @param id
* The {@link Language} id
*
*
* @return Whether the project contains a {@link Language} with that id
*/
protected abstract boolean hasLanguage(@Nonnull String id);
@ -88,7 +92,7 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
/**
* This method returns a full {@link Collection} of every {@link Language} that was
* found.
*
*
* @return A {@link Collection} that contains every installed {@link Language}
*/
@Nonnull
@ -96,7 +100,7 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
/**
* This method adds a new {@link Language} with the given id and texture.
*
*
* @param id
* The {@link Language} id
* @param texture
@ -117,7 +121,28 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
}
public String getMessage(Player p, String key) {
@Nonnull
@Override
public String getMessage(@Nonnull String key) {
Validate.notNull(key, "Message key must not be null!");
Language language = getDefaultLanguage();
String message = language == null ? null : language.getMessagesFile().getString(key);
if (message == null) {
Language fallback = getLanguage(SupportedLanguage.ENGLISH.getLanguageId());
return fallback.getMessagesFile().getString(key);
}
return message;
}
@Nonnull
public String getMessage(@Nonnull Player p, @Nonnull String key) {
Validate.notNull(p, "Player must not be null!");
Validate.notNull(key, "Message key must not be null!");
Language language = getLanguage(p);
if (language == null) {
@ -134,11 +159,15 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
return message;
}
public List<String> getMessages(Player p, String key) {
@Nonnull
public List<String> getMessages(@Nonnull Player p, @Nonnull String key) {
Validate.notNull(p, "Player should not be null.");
Validate.notNull(key, "Message key cannot be null.");
Language language = getLanguage(p);
if (language == null) {
return Arrays.asList("NO LANGUAGE FOUND");
return Collections.singletonList("NO LANGUAGE FOUND");
}
List<String> messages = language.getMessagesFile().getStringList(key);
@ -151,37 +180,55 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
return messages;
}
@Nonnull
@ParametersAreNonnullByDefault
public List<String> getMessages(Player p, String key, UnaryOperator<String> function) {
Validate.notNull(p, "Player cannot be null.");
Validate.notNull(key, "Message key cannot be null.");
Validate.notNull(function, "Function cannot be null.");
List<String> messages = getMessages(p, key);
messages.replaceAll(function);
return messages;
}
public String getResearchName(Player p, NamespacedKey key) {
@Nullable
public String getResearchName(@Nonnull Player p, @Nonnull NamespacedKey key) {
Validate.notNull(p, "Player must not be null.");
Validate.notNull(key, "NamespacedKey cannot be null.");
Language language = getLanguage(p);
if (language.getResearchesFile() == null) {
if (language == null || language.getResearchesFile() == null) {
return null;
}
return language.getResearchesFile().getString(key.getNamespace() + "." + key.getKey());
return language.getResearchesFile().getString(key.getNamespace() + '.' + key.getKey());
}
public String getCategoryName(Player p, NamespacedKey key) {
@Nullable
public String getCategoryName(@Nonnull Player p, @Nonnull NamespacedKey key) {
Validate.notNull(p, "Player must not be null.");
Validate.notNull(key, "NamespacedKey cannot be null!");
Language language = getLanguage(p);
if (language.getCategoriesFile() == null) {
if (language == null || language.getCategoriesFile() == null) {
return null;
}
return language.getCategoriesFile().getString(key.getNamespace() + "." + key.getKey());
return language.getCategoriesFile().getString(key.getNamespace() + '.' + key.getKey());
}
public String getResourceString(Player p, String key) {
@Nullable
public String getResourceString(@Nonnull Player p, @Nonnull String key) {
Validate.notNull(p, "Player should not be null!");
Validate.notNull(key, "Message key should not be null!");
Language language = getLanguage(p);
String value = language.getResourcesFile() != null ? language.getResourcesFile().getString(key) : null;
String value = language != null && language.getResourcesFile() != null ? language.getResourcesFile().getString(key) : null;
if (value != null) {
return value;
@ -191,16 +238,20 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
}
public ItemStack getRecipeTypeItem(Player p, RecipeType recipeType) {
@Nullable
public ItemStack getRecipeTypeItem(@Nonnull Player p, @Nonnull RecipeType recipeType) {
Validate.notNull(p, "Player cannot be null!");
Validate.notNull(recipeType, "Recipe type cannot be null!");
Language language = getLanguage(p);
ItemStack item = recipeType.toItem();
NamespacedKey key = recipeType.getKey();
if (language.getRecipeTypesFile() == null || !language.getRecipeTypesFile().contains(key.getNamespace() + "." + key.getKey())) {
if (language == null || language.getRecipeTypesFile() == null || !language.getRecipeTypesFile().contains(key.getNamespace() + '.' + key.getKey())) {
language = getLanguage("en");
}
if (!language.getRecipeTypesFile().contains(key.getNamespace() + "." + key.getKey())) {
if (!language.getRecipeTypesFile().contains(key.getNamespace() + '.' + key.getKey())) {
return item;
}
@ -218,7 +269,10 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
@Override
public void sendMessage(CommandSender recipient, String key, boolean addPrefix) {
public void sendMessage(@Nonnull CommandSender recipient, @Nonnull String key, boolean addPrefix) {
Validate.notNull(recipient, "Recipient cannot be null!");
Validate.notNull(key, "Message key cannot be null!");
String prefix = addPrefix ? getPrefix() : "";
if (recipient instanceof Player) {
@ -229,6 +283,9 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
public void sendActionbarMessage(@Nonnull Player player, @Nonnull String key, boolean addPrefix) {
Validate.notNull(player, "Player cannot be null!");
Validate.notNull(key, "Message key cannot be null!");
String prefix = addPrefix ? getPrefix() : "";
String message = ChatColors.color(prefix + getMessage(player, key));
@ -237,15 +294,17 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
@Override
public void sendMessage(CommandSender recipient, String key) {
public void sendMessage(@Nonnull CommandSender recipient, @Nonnull String key) {
sendMessage(recipient, key, true);
}
@ParametersAreNonnullByDefault
public void sendMessage(CommandSender recipient, String key, UnaryOperator<String> function) {
sendMessage(recipient, key, true, function);
}
@Override
@ParametersAreNonnullByDefault
public void sendMessage(CommandSender recipient, String key, boolean addPrefix, UnaryOperator<String> function) {
if (SlimefunPlugin.getMinecraftVersion() == MinecraftVersion.UNIT_TEST) {
return;
@ -261,7 +320,7 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
@Override
public void sendMessages(CommandSender recipient, String key) {
public void sendMessages(@Nonnull CommandSender recipient, @Nonnull String key) {
String prefix = getPrefix();
if (recipient instanceof Player) {
@ -278,6 +337,7 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
@Override
@ParametersAreNonnullByDefault
public void sendMessages(CommandSender recipient, String key, boolean addPrefix, UnaryOperator<String> function) {
String prefix = addPrefix ? getPrefix() : "";
@ -294,8 +354,8 @@ public abstract class SlimefunLocalization extends Localization implements Keyed
}
}
@ParametersAreNonnullByDefault
public void sendMessages(CommandSender recipient, String key, UnaryOperator<String> function) {
sendMessages(recipient, key, true, function);
}
}

View File

@ -404,7 +404,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack PURE_ORE_CLUSTER = new SlimefunItemStack("PURE_ORE_CLUSTER", Material.GUNPOWDER, "&6Pure Ore Cluster");
public static final SlimefunItemStack SMALL_URANIUM = new SlimefunItemStack("SMALL_URANIUM", HeadTexture.URANIUM, "&cSmall Chunk of Uranium", "", LoreBuilder.radioactive(Radioactivity.MODERATE), LoreBuilder.HAZMAT_SUIT_REQUIRED);
public static final SlimefunItemStack TINY_URANIUM = new SlimefunItemStack("TINY_URANIUM", HeadTexture.URANIUM, "&cTiny Pile of Uranium", "", LoreBuilder.radioactive(Radioactivity.LOW));
public static final SlimefunItemStack SOLAR_PANEL = new SlimefunItemStack("SOLAR_PANEL", Material.DAYLIGHT_DETECTOR, "&bSolar Panel", "", "&a&oTransforms Sunlight to Energy");
public static final SlimefunItemStack SOLAR_PANEL = new SlimefunItemStack("SOLAR_PANEL", Material.DAYLIGHT_DETECTOR, "&9Photovoltaic Cell", "", "&7Important component for", "&7crafting a &bSolar Generator");
public static final SlimefunItemStack PLASTIC_SHEET = new SlimefunItemStack("PLASTIC_SHEET", Material.PAPER, "&fPlastic Sheet");
public static final SlimefunItemStack MAGNET = new SlimefunItemStack("MAGNET", HeadTexture.MAGNET, "&cMagnet");
@ -415,7 +415,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack HEATING_COIL = new SlimefunItemStack("HEATING_COIL", HeadTexture.HEATING_COIL, "&cHeating Coil");
public static final SlimefunItemStack COOLING_UNIT = new SlimefunItemStack("COOLING_UNIT", HeadTexture.COOLING_UNIT, "&bCooling Unit");
public static final SlimefunItemStack ELECTRIC_MOTOR = new SlimefunItemStack("ELECTRIC_MOTOR", HeadTexture.MOTOR, "&cElectric Motor");
public static final SlimefunItemStack CARGO_MOTOR = new SlimefunItemStack("CARGO_MOTOR", HeadTexture.MOTOR, "&3Cargo Motor");
public static final SlimefunItemStack CARGO_MOTOR = new SlimefunItemStack("CARGO_MOTOR", HeadTexture.CARGO_MOTOR, "&3Cargo Motor", "", "&7Important ingredient for items", "&7related to Cargo Management");
public static final SlimefunItemStack SCROLL_OF_DIMENSIONAL_TELEPOSITION = new SlimefunItemStack("SCROLL_OF_DIMENSIONAL_TELEPOSITION", Material.PAPER, "&6Scroll of Dimensional Teleposition", "", "&cThis Scroll is capable of creating", "&ca temporary black Hole which pulls", "&cnearby Entities into itself and sends", "&cthem into another Dimension where", "&ceverything is turned around", "", "&fIn other words: Makes Entities turn by 180 Degrees");
public static final SlimefunItemStack TOME_OF_KNOWLEDGE_SHARING = new SlimefunItemStack("TOME_OF_KNOWLEDGE_SHARING", Material.ENCHANTED_BOOK, "&6Tome of Knowledge Sharing", "&7Owner: &bNone", "", "&eRight Click&7 to bind this Tome to yourself", "", "", "&eRight Click&7 to obtain all Researches by", "&7the previously assigned Owner");
public static final SlimefunItemStack HARDENED_GLASS = new SlimefunItemStack("HARDENED_GLASS", Material.LIGHT_GRAY_STAINED_GLASS, "&7Hardened Glass", "", "&fWithstands Explosions");
@ -425,6 +425,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack ANCIENT_PEDESTAL = new SlimefunItemStack("ANCIENT_PEDESTAL", Material.DISPENSER, "&dAncient Pedestal", "", "&5Part of the Ancient Altar");
public static final SlimefunItemStack ANCIENT_ALTAR = new SlimefunItemStack("ANCIENT_ALTAR", Material.ENCHANTING_TABLE, "&dAncient Altar", "", "&5Multi-Block Altar for", "&5magical Crafting Processes");
public static final SlimefunItemStack COPPER_WIRE = new SlimefunItemStack("COPPER_WIRE", Material.STRING, "&6Copper Wire", "", "&6Crucial component in electric modules");
public static final SlimefunItemStack CRAFTING_MOTOR = new SlimefunItemStack("CRAFTING_MOTOR", HeadTexture.CRAFTING_MOTOR, "&6Crafting Motor", "", "&7Important component of Auto-Crafters");
/* Rainbow blocks */
private static final String RAINBOW = "&dCycles through all Colors of the Rainbow!";
@ -782,7 +783,9 @@ public final class SlimefunItems {
public static final SlimefunItemStack CARGO_OUTPUT_NODE = new SlimefunItemStack("CARGO_NODE_OUTPUT", HeadTexture.CARGO_OUTPUT_NODE, "&7Cargo Node &c(Output)", "", "&fCargo Output Pipe");
public static final SlimefunItemStack CARGO_OUTPUT_NODE_2 = new SlimefunItemStack("CARGO_NODE_OUTPUT_ADVANCED", HeadTexture.CARGO_OUTPUT_NODE, "&6Advanced Cargo Node &c(Output)", "", "&fCargo Output Pipe");
// Animal farm
public static final SlimefunItemStack AUTO_BREEDER = new SlimefunItemStack("AUTO_BREEDER", Material.HAY_BLOCK, "&eAuto-Breeder", "", "&fRuns on &aOrganic Food", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), LoreBuilder.powerBuffer(1024), "&8\u21E8 &e\u26A1 &760 J/Animal");
public static final SlimefunItemStack PRODUCE_COLLECTOR = new SlimefunItemStack("PRODUCE_COLLECTOR", Material.HAY_BLOCK, "&bProduce Collector", "", "&fThis machine allows you to", "&fcollect produce from nearby animals.", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), LoreBuilder.powerBuffer(512), LoreBuilder.powerPerSecond(32));
public static final SlimefunItemStack ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD", HeadTexture.FILLED_CAN, "&aOrganic Food", "&7Content: &9???");
public static final SlimefunItemStack WHEAT_ORGANIC_FOOD = new SlimefunItemStack("ORGANIC_FOOD_WHEAT", HeadTexture.FILLED_CAN, ORGANIC_FOOD.getDisplayName(), "&7Content: &9Wheat");
@ -849,6 +852,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack VANILLA_AUTO_CRAFTER = new SlimefunItemStack("VANILLA_AUTO_CRAFTER", HeadTexture.VANILLA_AUTO_CRAFTER, "&2Auto-Crafter &8(Vanilla)", "", "&fPlace this machine on top of a", "&fchest or similar and make it craft", "&fanything that can be crafted using a", "&fnormal &eCrafting Table", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &716 J/Item");
public static final SlimefunItemStack ENHANCED_AUTO_CRAFTER = new SlimefunItemStack("ENHANCED_AUTO_CRAFTER", HeadTexture.ENHANCED_AUTO_CRAFTER, "&2Auto-Crafter &8(Enhanced)", "", "&fPlace this machine on top of a", "&fchest or similar and make it craft", "&fanything that can be crafted using an", "&eEnhanced Crafting Table", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &716 J/Item");
public static final SlimefunItemStack ARMOR_AUTO_CRAFTER = new SlimefunItemStack("ARMOR_AUTO_CRAFTER", HeadTexture.ARMOR_AUTO_CRAFTER, "&2Auto-Crafter &8(Armor Forge)", "", "&fPlace this machine on top of a", "&fchest or similar and make it craft", "&fanything that can be crafted using an", "&eArmor Forge", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &732 J/Item");
public static final SlimefunItemStack IRON_GOLEM_ASSEMBLER = new SlimefunItemStack("IRON_GOLEM_ASSEMBLER", Material.IRON_BLOCK, "&6Iron Golem Assembler", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), "&8\u21E8 &7Cooldown: &b30 Seconds", LoreBuilder.powerBuffer(4096), "&8\u21E8 &e\u26A1 &72048 J/Golem");
public static final SlimefunItemStack WITHER_ASSEMBLER = new SlimefunItemStack("WITHER_ASSEMBLER", Material.OBSIDIAN, "&5Wither Assembler", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), "&8\u21E8 &7Cooldown: &b30 Seconds", LoreBuilder.powerBuffer(4096), "&8\u21E8 &e\u26A1 &74096 J/Wither");

View File

@ -34,6 +34,7 @@ import io.github.thebusybiscuit.cscorelib2.protection.ProtectionManager;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.exceptions.TagMisconfigurationException;
import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource;
import io.github.thebusybiscuit.slimefun4.api.gps.GPSNetwork;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.SlimefunRegistry;
@ -778,6 +779,13 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.items;
}
/**
* This returns our {@link GPSNetwork} instance.
* The {@link GPSNetwork} is responsible for handling any GPS-related
* operations and for managing any {@link GEOResource}.
*
* @return Our {@link GPSNetwork} instance
*/
@Nonnull
public static GPSNetwork getGPSNetwork() {
validateInstance();

View File

@ -153,7 +153,7 @@ public enum Instruction {
* ahead of them.
*/
ATTACK_MOBS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
Predicate<LivingEntity> predicate = e -> e instanceof Monster;
Predicate<LivingEntity> predicate = Monster.class::isInstance;
android.attack(b, face, predicate);
}),
@ -162,7 +162,7 @@ public enum Instruction {
* ahead of them.
*/
ATTACK_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
Predicate<LivingEntity> predicate = e -> e instanceof Animals;
Predicate<LivingEntity> predicate = Animals.class::isInstance;
android.attack(b, face, predicate);
}),

View File

@ -24,6 +24,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Rotatable;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
@ -36,6 +37,7 @@ import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock;
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.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -52,7 +54,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction;
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.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
@ -132,23 +133,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"));
if (allow) {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), 43);
inv.dropItems(b.getLocation(), getOutputSlots());
}
}
return allow;
});
addItemHandler(onPlace());
addItemHandler(onPlace(), onBreak());
}
@Nonnull
@ -178,6 +163,31 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
};
}
@Nonnull
private BlockBreakHandler onBreak() {
return new BlockBreakHandler(false, false) {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
Block b = e.getBlock();
String owner = BlockStorage.getLocationInfo(b.getLocation(), "owner");
if (!e.getPlayer().hasPermission("slimefun.android.bypass") && !e.getPlayer().getUniqueId().toString().equals(owner)) {
// The Player is not allowed to break this android
e.setCancelled(true);
return;
}
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), 43);
inv.dropItems(b.getLocation(), getOutputSlots());
}
}
};
}
/**
* This returns the {@link AndroidType} that is associated with this {@link ProgrammableAndroid}.
*

View File

@ -1,8 +1,10 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import io.github.thebusybiscuit.slimefun4.utils.UnbreakingAlgorithm;
import org.bukkit.GameMode;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
@ -41,12 +43,17 @@ public class ElytraCap extends SlimefunArmorPiece implements DamageableItem, Pro
}
@Override
public void damageItem(Player p, ItemStack item) {
public void damageItem(@Nonnull Player p, @Nullable ItemStack item) {
if (p.getGameMode() != GameMode.CREATIVE) {
DamageableItem.super.damageItem(p, item);
}
}
@Override
public boolean evaluateUnbreakingEnchantment(int unbreakingLevel) {
return UnbreakingAlgorithm.ARMOR.evaluate(unbreakingLevel);
}
@Nonnull
@Override
public ProtectionType[] getProtectionTypes() {

View File

@ -1,6 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
@ -9,7 +11,6 @@ import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@ -27,6 +28,7 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
@ -35,6 +37,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AutoCrafterListener;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import io.papermc.lib.PaperLib;
import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
@ -73,6 +76,11 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
*/
protected final NamespacedKey recipeStorageKey;
/**
* The {@link NamespacedKey} used to determine whether the recipe is enabled.
*/
protected final NamespacedKey recipeEnabledKey;
// @formatter:off
protected final int[] background = {
0, 1, 2, 3, 4, 5, 6, 7, 8,
@ -84,10 +92,11 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
// @formatter:on
@ParametersAreNonnullByDefault
public AbstractAutoCrafter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
protected AbstractAutoCrafter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
recipeStorageKey = new NamespacedKey(SlimefunPlugin.instance(), "recipe_key");
recipeEnabledKey = new NamespacedKey(SlimefunPlugin.instance(), "recipe_enabled");
addItemHandler(new BlockTicker() {
@ -142,19 +151,28 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
}
}
/**
* This method performs one tick for the {@link AbstractAutoCrafter}.
*
* @param b
* The block for this {@link AbstractAutoCrafter}
* @param data
* The data stored on this block
*/
protected void tick(@Nonnull Block b, @Nonnull Config data) {
AbstractRecipe recipe = getSelectedRecipe(b);
if (recipe == null || getCharge(b.getLocation(), data) < getEnergyConsumption()) {
// No valid recipe selected, abort...
if (recipe == null || !recipe.isEnabled() || getCharge(b.getLocation(), data) < getEnergyConsumption()) {
// No recipe / disabled recipe / no energy, abort...
return;
}
Block chest = b.getRelative(BlockFace.DOWN);
// The block below where we would expect our inventory holder.
Block targetBlock = b.getRelative(BlockFace.DOWN);
// Make sure this is a Chest
if (isValidInventory(chest)) {
BlockState state = PaperLib.getBlockState(chest, false).getState();
if (isValidInventory(targetBlock)) {
BlockState state = PaperLib.getBlockState(targetBlock, false).getState();
if (state instanceof InventoryHolder) {
Inventory inv = ((InventoryHolder) state).getInventory();
@ -236,6 +254,9 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
if (recipe == null) {
// Clear the value from persistent data storage
PersistentDataAPI.remove((Skull) state, recipeStorageKey);
// Also remove the "enabled" state since this should be per-recipe.
PersistentDataAPI.remove((Skull) state, recipeEnabledKey);
} else {
// Store the value to persistent data storage
PersistentDataAPI.setString((Skull) state, recipeStorageKey, recipe.toString());
@ -271,14 +292,29 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
ChestMenuUtils.drawBackground(menu, background);
ChestMenuUtils.drawBackground(menu, 45, 46, 47, 48, 50, 51, 52, 53);
menu.addItem(49, new CustomItem(Material.BARRIER, ChatColor.RED + SlimefunPlugin.getLocalization().getMessage(p, "messages.auto-crafting.remove")));
menu.addMenuClickHandler(49, (pl, item, slot, action) -> {
setSelectedRecipe(b, null);
pl.closeInventory();
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SlimefunPlugin.getLocalization().sendMessage(p, "messages.auto-crafting.recipe-removed");
return false;
});
if (recipe.isEnabled()) {
menu.addItem(49, new CustomItem(Material.BARRIER, SlimefunPlugin.getLocalization().getMessages(p, "messages.auto-crafting.tooltips.enabled")));
menu.addMenuClickHandler(49, (pl, item, slot, action) -> {
if (action.isRightClicked()) {
deleteRecipe(pl, b);
} else {
setRecipeEnabled(pl, b, false);
}
return false;
});
} else {
menu.addItem(49, new CustomItem(HeadTexture.EXCLAMATION_MARK.getAsItemStack(), SlimefunPlugin.getLocalization().getMessages(p, "messages.auto-crafting.tooltips.disabled")));
menu.addMenuClickHandler(49, (pl, item, slot, action) -> {
if (action.isRightClicked()) {
deleteRecipe(pl, b);
} else {
setRecipeEnabled(pl, b, true);
}
return false;
});
}
// This makes the slots cycle through different ingredients
AsyncRecipeChoiceTask task = new AsyncRecipeChoiceTask();
@ -293,6 +329,32 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
}
}
@ParametersAreNonnullByDefault
private void setRecipeEnabled(Player p, Block b, boolean enabled) {
p.closeInventory();
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
BlockState state = PaperLib.getBlockState(b, false).getState();
// Make sure the block is still a Skull
if (state instanceof Skull) {
if (enabled) {
PersistentDataAPI.remove((Skull) state, recipeEnabledKey);
SlimefunPlugin.getLocalization().sendMessage(p, "messages.auto-crafting.re-enabled");
} else {
PersistentDataAPI.setByte((Skull) state, recipeEnabledKey, (byte) 1);
SlimefunPlugin.getLocalization().sendMessage(p, "messages.auto-crafting.temporarily-disabled");
}
}
}
@ParametersAreNonnullByDefault
private void deleteRecipe(Player p, Block b) {
setSelectedRecipe(b, null);
p.closeInventory();
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SlimefunPlugin.getLocalization().sendMessage(p, "messages.auto-crafting.recipe-removed");
}
/**
* This method checks whether the given {@link Predicate} matches the provided {@link ItemStack}.
*
@ -347,6 +409,11 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
Validate.notNull(inv, "The Inventory must not be null");
Validate.notNull(recipe, "The Recipe shall not be null");
// Make sure that the Recipe is actually enabled
if (!recipe.isEnabled()) {
return false;
}
// Check if we have an empty slot
if (inv.firstEmpty() != -1) {
Map<Integer, Integer> itemQuantities = new HashMap<>();
@ -358,23 +425,79 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
}
}
List<ItemStack> leftoverItems = new ArrayList<>();
// Remove ingredients
for (Map.Entry<Integer, Integer> entry : itemQuantities.entrySet()) {
ItemStack item = inv.getItem(entry.getKey());
// Double-check to be extra safe
if (item != null) {
// Handle leftovers
ItemStack leftover = getLeftoverItem(item);
if (leftover != null) {
// Account for the amount of removed items
leftover.setAmount(item.getAmount() - entry.getValue());
leftoverItems.add(leftover);
}
// Update the item amount
item.setAmount(entry.getValue());
}
}
// All Predicates have found a match
return inv.addItem(recipe.getResult().clone()).isEmpty();
boolean success = inv.addItem(recipe.getResult().clone()).isEmpty();
if (success) {
// Fixes #2926 - Push leftover items to the inventory.
for (ItemStack leftoverItem : leftoverItems) {
inv.addItem(leftoverItem);
}
}
return success;
}
return false;
}
/**
* This method returns the "leftovers" from a crafting operation.
* The method functions very similarly to {@link Material#getCraftingRemainingItem()}.
* However we cannot use this method as it is only available in the latest 1.16 snapshots
* of Spigot, not even on earlier 1.16 builds...
* But this gives us more control over the leftovers anyway!
*
* @param item
* The {@link ItemStack} that is being consumed
*
* @return The leftover item or null if the item is fully consumed
*/
@Nullable
private ItemStack getLeftoverItem(@Nonnull ItemStack item) {
Material type = item.getType();
switch (type) {
case WATER_BUCKET:
case LAVA_BUCKET:
case MILK_BUCKET:
return new ItemStack(Material.BUCKET);
case DRAGON_BREATH:
case POTION:
return new ItemStack(Material.GLASS_BOTTLE);
default:
MinecraftVersion minecraftVersion = SlimefunPlugin.getMinecraftVersion();
// Honey does not exist in 1.14
if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15) && type == Material.HONEY_BOTTLE) {
return new ItemStack(Material.GLASS_BOTTLE);
} else {
return null;
}
}
}
/**
* This method returns the max amount of electricity this machine can hold.
*

View File

@ -44,6 +44,11 @@ public abstract class AbstractRecipe {
*/
private final ItemStack result;
/**
* Whether this recipe is enabled.
*/
private boolean enabled = true;
/**
* Protected constructor. For implementation classes only.
*
@ -83,6 +88,27 @@ public abstract class AbstractRecipe {
return result;
}
/**
* This returns whether or not this recipe has been enabled.
* A disabled recipe will not be crafted.
*
* @return Whether this recipe is enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* This method enables or disables this recipe.
* A disabled recipe will not be crafted.
*
* @param enabled
* Whether this recipe is enabled
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* This will visually represent this {@link AbstractRecipe} in the given {@link ChestMenu}.
* Any {@link MaterialChoice} will be cycled through using the {@link AsyncRecipeChoiceTask}.

View File

@ -0,0 +1,31 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.ArmorForge;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link ArmorAutoCrafter} is an implementation of the {@link AbstractAutoCrafter}.
* It can craft items that are crafted using the {@link ArmorForge}.
*
* @author TheBusyBiscuit
*
* @see ArmorForge
* @see AbstractAutoCrafter
* @see SlimefunAutoCrafter
* @see SlimefunItemRecipe
*
*/
public class ArmorAutoCrafter extends SlimefunAutoCrafter {
@ParametersAreNonnullByDefault
public ArmorAutoCrafter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe, RecipeType.ARMOR_FORGE);
}
}

View File

@ -13,8 +13,9 @@ import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
@ -60,11 +61,15 @@ public class SlimefunAutoCrafter extends AbstractAutoCrafter {
if (state instanceof Skull) {
// Read the stored value from persistent data storage
String value = PersistentDataAPI.getString((Skull) state, recipeStorageKey);
PersistentDataContainer container = ((Skull) state).getPersistentDataContainer();
String value = container.get(recipeStorageKey, PersistentDataType.STRING);
SlimefunItem item = SlimefunItem.getByID(value);
if (item != null) {
return AbstractRecipe.of(item, targetRecipeType);
boolean enabled = !container.has(recipeEnabledKey, PersistentDataType.BYTE);
AbstractRecipe recipe = AbstractRecipe.of(item, targetRecipeType);
recipe.setEnabled(enabled);
return recipe;
}
}

View File

@ -9,7 +9,6 @@ import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@ -22,9 +21,11 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.services.MinecraftRecipeService;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -58,16 +59,12 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
@Override
@Nullable
public AbstractRecipe getSelectedRecipe(@Nonnull Block b) {
return AbstractRecipe.of(getRecipe(b));
}
@Nullable
private Recipe getRecipe(@Nonnull Block b) {
BlockState state = PaperLib.getBlockState(b, false).getState();
if (state instanceof Skull) {
// Read the stored value from persistent data storage
String value = PersistentDataAPI.getString((Skull) state, recipeStorageKey);
PersistentDataContainer container = ((Skull) state).getPersistentDataContainer();
String value = container.get(recipeStorageKey, PersistentDataType.STRING);
if (value != null) {
String[] values = PatternUtils.COLON.split(value);
@ -79,8 +76,15 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
*/
@SuppressWarnings("deprecation")
NamespacedKey key = new NamespacedKey(values[0], values[1]);
Recipe keyedRecipe = SlimefunPlugin.getMinecraftRecipeService().getRecipe(key);
return SlimefunPlugin.getMinecraftRecipeService().getRecipe(key);
if (keyedRecipe != null) {
boolean enabled = !container.has(recipeEnabledKey, PersistentDataType.BYTE);
AbstractRecipe recipe = AbstractRecipe.of(keyedRecipe);
recipe.setEnabled(enabled);
return recipe;
}
}
}
@ -169,7 +173,10 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
private List<Recipe> getRecipesFor(@Nonnull ItemStack item) {
List<Recipe> recipes = new ArrayList<>();
for (Recipe recipe : Bukkit.getRecipesFor(item)) {
// Fixes #2913 - Bukkit.getRecipesFor() only checks for Materials
MinecraftRecipeService recipeService = SlimefunPlugin.getMinecraftRecipeService();
for (Recipe recipe : recipeService.getRecipesFor(item)) {
if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) {
recipes.add(recipe);
}

View File

@ -13,6 +13,7 @@ import org.bukkit.Material;
import org.bukkit.Nameable;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Dispenser;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockPlaceEvent;
@ -97,16 +98,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.
*/
return;
}
if (facedBlock.isEmpty() && isAllowed(material) && dispenser.getInventory().getViewers().isEmpty()) {
if (facedBlock.isEmpty() && dispenser.getInventory().getViewers().isEmpty() && isAllowed(facedBlock, material)) {
SlimefunItem item = SlimefunItem.getByItem(e.getItem());
if (item != null) {
@ -158,14 +150,33 @@ public class BlockPlacer extends SlimefunItem {
*
* @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 false;
private boolean isAllowed(@Nonnull Block facedBlock, @Nonnull Material type) {
if (!type.isBlock()) {
// Make sure the material is actually a block.
return false;
} else if (type == Material.CAKE) {
/*
* Special case for cakes.
* Cakes are a lie but I really want the Block Placer to place them down!!!
*/
return !facedBlock.getRelative(BlockFace.DOWN).isPassable();
} else if (SlimefunTag.BLOCK_PLACER_IGNORED_MATERIALS.isTagged(type)) {
/*
* 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.
*/
return false;
} else {
// Check for all unplaceable block
for (String blockType : unplaceableBlocks.getValue()) {
if (type.toString().equals(blockType)) {
return false;
}
}
}
return true;
return true;
}
}
@ParametersAreNonnullByDefault

View File

@ -188,7 +188,8 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
private void placeLiquid(@Nonnull Block block, boolean water) {
if (block.getType() == Material.AIR || block.getType() == Material.CAVE_AIR || block.getType() == Material.VOID_AIR) {
block.setType(water ? Material.WATER : Material.LAVA);
// Fixes #2903 - Cancel physics update to resolve weird overlapping
block.setType(water ? Material.WATER : Material.LAVA, false);
} else {
if (water && block.getBlockData() instanceof Waterlogged) {
Waterlogged wl = (Waterlogged) block.getBlockData();

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
@ -31,7 +32,7 @@ public class UnplaceableBlock extends SimpleSlimefunItem<ItemUseHandler> impleme
}
@ParametersAreNonnullByDefault
public UnplaceableBlock(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
public UnplaceableBlock(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
}

View File

@ -3,6 +3,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine
import java.util.ArrayList;
import java.util.List;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.inventory.ItemStack;
@ -27,6 +29,7 @@ public class AutoDrier extends AContainer implements RecipeDisplayItem, NotHoppe
private List<ItemStack> recipeList;
@ParametersAreNonnullByDefault
public AutoDrier(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}

View File

@ -3,9 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.ParametersAreNonnullByDefault;
@ -21,21 +19,18 @@ 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.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.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.EnhancedCraftingTable;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters.AbstractAutoCrafter;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.Item.CustomItemSerializer;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.Item.CustomItemSerializer.ItemFlag;
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;
@ -44,10 +39,9 @@ import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
/**
* This class needs to be rewritten VERY BADLY.
* But we should focus on rewriting the recipe system first.
* This machine is disabled and has been replaced by Auto Crafters.
*
* @deprecated This is horribly done. Someone needs to rewrite this.
* @deprecated This has been replaced by the {@link AbstractAutoCrafter}.
*
* @author TheBusyBiscuit
*
@ -58,13 +52,11 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
private final int[] inputBorder = { 9, 10, 11, 12, 13, 18, 22, 27, 31, 36, 40, 45, 46, 47, 48, 49 };
private final int[] outputBorder = { 23, 24, 25, 26, 32, 35, 41, 42, 43, 44 };
private final Map<String, ItemStack> craftingRecipes = new HashMap<>();
@ParametersAreNonnullByDefault
public AutomatedCraftingChamber(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
new BlockMenuPreset(getId(), "&4Deprecated item. Do not use.") {
new BlockMenuPreset(getId(), "&4Machine is disabled.") {
@Override
public void init() {
@ -88,17 +80,11 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
return false;
});
}
menu.replaceExistingItem(7, new CustomItem(Material.CRAFTING_TABLE, "&7Craft Last", "", "&e> Click to craft the last shaped recipe", "&cOnly works with the last one"));
menu.addMenuClickHandler(7, (p, slot, item, action) -> {
tick(b, true);
return false;
});
}
@Override
public boolean canOpen(Block b, Player p) {
p.sendMessage(ChatColor.DARK_RED + "This item has been deprecated. It will be removed soon!");
p.sendMessage(ChatColor.DARK_RED + "This item has been disabled and will be removed soon. Please switch over to the new Auto Crafters in the Cargo Category.");
return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.INTERACT_BLOCK);
}
@ -132,17 +118,7 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
}
};
addItemHandler(onPlace());
registerBlockHandler(getId(), (p, b, stack, reason) -> {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
return true;
});
addItemHandler(onPlace(), onBreak());
}
private BlockPlaceHandler onPlace() {
@ -150,7 +126,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!");
e.getPlayer().sendMessage(ChatColor.DARK_RED + "This item has been disabled and will be removed soon. Please switch over to the new Auto Crafters in the Cargo Category.");
BlockStorage.addBlockInfo(e.getBlock(), "enabled", String.valueOf(false));
}
@ -161,6 +137,21 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
};
}
private BlockBreakHandler onBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
}
};
}
private Comparator<Integer> compareSlots(DirtyChestMenu menu) {
return (slot1, slot2) -> menu.getItemInSlot(slot1).getAmount() - menu.getItemInSlot(slot2).getAmount();
}
@ -212,106 +203,4 @@ public abstract class AutomatedCraftingChamber extends SlimefunItem implements I
public EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.CONSUMER;
}
@Override
public void preRegister() {
addItemHandler(new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
AutomatedCraftingChamber.this.tick(b, false);
}
@Override
public boolean isSynchronized() {
return false;
}
});
}
protected void tick(Block block, boolean craftLast) {
if (!craftLast && BlockStorage.getLocationInfo(block.getLocation(), "enabled").equals(String.valueOf(false))) {
return;
}
if (getCharge(block.getLocation()) < getEnergyConsumption()) {
return;
}
String input = getSerializedInput(block, craftLast);
testInputAgainstRecipes(block, input);
}
private String getSerializedInput(Block block, boolean craftLast) {
BlockMenu menu = BlockStorage.getInventory(block);
StringBuilder builder = new StringBuilder();
int i = 0;
boolean lastIteration = false;
for (int j = 0; j < 9; j++) {
if (i > 0) {
builder.append(" </slot> ");
}
ItemStack item = menu.getItemInSlot(getInputSlots()[j]);
if (item != null && item.getAmount() == 1) {
if (craftLast) {
lastIteration = true;
} else {
return "";
}
}
builder.append(CustomItemSerializer.serialize(item, ItemFlag.MATERIAL, ItemFlag.ITEMMETA_DISPLAY_NAME, ItemFlag.ITEMMETA_LORE));
i++;
}
// we're only executing the last possible shaped recipe
// we don't want to allow this to be pressed instead of the default timer-based
// execution to prevent abuse and auto clickers
if (craftLast && !lastIteration) {
return "";
}
return builder.toString();
}
private void testInputAgainstRecipes(Block block, String input) {
BlockMenu menu = BlockStorage.getInventory(block);
ItemStack output = craftingRecipes.get(input);
if (output != null && menu.fits(output, getOutputSlots())) {
menu.pushItem(output.clone(), getOutputSlots());
removeCharge(block.getLocation(), getEnergyConsumption());
for (int j = 0; j < 9; j++) {
if (menu.getItemInSlot(getInputSlots()[j]) != null) {
menu.consumeItem(getInputSlots()[j]);
}
}
}
}
public void loadRecipes() {
EnhancedCraftingTable machine = (EnhancedCraftingTable) SlimefunItems.ENHANCED_CRAFTING_TABLE.getItem();
for (ItemStack[] inputs : RecipeType.getRecipeInputList(machine)) {
StringBuilder builder = new StringBuilder();
int i = 0;
for (ItemStack item : inputs) {
if (i > 0) {
builder.append(" </slot> ");
}
builder.append(CustomItemSerializer.serialize(item, ItemFlag.MATERIAL, ItemFlag.ITEMMETA_DISPLAY_NAME, ItemFlag.ITEMMETA_LORE));
i++;
}
craftingRecipes.put(builder.toString(), RecipeType.getRecipeOutputList(machine, inputs));
}
}
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@ -13,6 +15,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class CarbonPress extends AContainer implements RecipeDisplayItem {
@ParametersAreNonnullByDefault
public CarbonPress(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}

View File

@ -6,8 +6,10 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
@ -34,6 +36,7 @@ public class ElectricPress extends AContainer implements RecipeDisplayItem {
addRecipe(5, new ItemStack(Material.GLASS), new ItemStack(Material.GLASS_PANE, 3));
addRecipe(4, new ItemStack(Material.SNOWBALL, 4), new ItemStack(Material.SNOW_BLOCK));
addRecipe(4, new ItemStack(Material.MAGMA_CREAM, 4), new ItemStack(Material.MAGMA_BLOCK));
addRecipe(4, new ItemStack(Material.SLIME_BALL, 9), new ItemStack(Material.SLIME_BLOCK));
addRecipe(3, new ItemStack(Material.DRIED_KELP, 9), new ItemStack(Material.DRIED_KELP_BLOCK));
addRecipe(3, new ItemStack(Material.BONE_MEAL, 9), new ItemStack(Material.BONE_BLOCK));
@ -70,6 +73,10 @@ public class ElectricPress extends AContainer implements RecipeDisplayItem {
addRecipe(8, new ItemStack(Material.EMERALD, 9), new ItemStack(Material.EMERALD_BLOCK));
addRecipe(8, new ItemStack(Material.DIAMOND, 9), new ItemStack(Material.DIAMOND_BLOCK));
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
addRecipe(16, new ItemStack(Material.NETHERITE_INGOT, 9), new ItemStack(Material.NETHERITE_BLOCK));
}
}
@ParametersAreNonnullByDefault

View File

@ -186,13 +186,15 @@ public class FluidPump extends SimpleSlimefunItem<BlockTicker> implements Invent
@Nonnull
private ItemStack getFilledBucket(@Nonnull Block fluid) {
if (fluid.getType() == Material.LAVA) {
return new ItemStack(Material.LAVA_BUCKET);
} else if (fluid.getType() == Material.WATER || fluid.getType() == Material.BUBBLE_COLUMN) {
return new ItemStack(Material.WATER_BUCKET);
} else {
// Fallback for any new liquids
return new ItemStack(Material.BUCKET);
switch (fluid.getType()) {
case LAVA:
return new ItemStack(Material.LAVA_BUCKET);
case WATER:
case BUBBLE_COLUMN:
return new ItemStack(Material.WATER_BUCKET);
default:
// Fallback for any new liquids
return new ItemStack(Material.BUCKET);
}
}
@ -214,6 +216,7 @@ public class FluidPump extends SimpleSlimefunItem<BlockTicker> implements Invent
return levelled.getLevel() == 0;
}
}
return false;
}

View File

@ -28,6 +28,8 @@ public class Freezer extends AContainer implements RecipeDisplayItem {
registerRecipe(6, new ItemStack[] { new ItemStack(Material.PACKED_ICE) }, new ItemStack[] { new ItemStack(Material.BLUE_ICE) });
registerRecipe(8, new ItemStack[] { new ItemStack(Material.BLUE_ICE) }, new ItemStack[] { SlimefunItems.REACTOR_COOLANT_CELL });
registerRecipe(6, new ItemStack[] { new ItemStack(Material.SNOW_BLOCK, 2) }, new ItemStack[] { new ItemStack(Material.ICE) });
registerRecipe(6, new ItemStack[] { new ItemStack(Material.MAGMA_CREAM) }, new ItemStack[] { new ItemStack(Material.SLIME_BALL) });
registerRecipe(6, new ItemStack[] { new ItemStack(Material.MAGMA_BLOCK, 2) }, new ItemStack[] { new ItemStack(Material.SLIME_BLOCK) });
}
@Override

View File

@ -110,48 +110,25 @@ public class BookBinder extends AContainer {
@ParametersAreNonnullByDefault
private Map<Enchantment, Integer> combineEnchantments(Map<Enchantment, Integer> ech1, Map<Enchantment, Integer> ech2) {
Map<Enchantment, Integer> enchantments = new HashMap<>();
boolean conflicts = false;
enchantments.putAll(ech1);
boolean hasConflicts = false;
for (Map.Entry<Enchantment, Integer> entry : ech2.entrySet()) {
for (Map.Entry<Enchantment, Integer> conflictsWith : enchantments.entrySet()) {
// Check if entry enchantment and conflictsWith enchantment conflict, and confirm that the enchantsments
// aren't the exact same.
/*
* 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;
hasConflicts = true;
}
}
if (!conflicts) {
if (!hasConflicts) {
enchantments.merge(entry.getKey(), entry.getValue(), (a, b) -> {
int enchantMaxLevel = entry.getKey().getMaxLevel();
if (a.intValue() == b.intValue()) {
// 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;
}
} else {
int highestLevel = Math.max(a, b);
// 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;
}
}
int maxLevel = entry.getKey().getMaxLevel();
return combineEnchantmentLevels(maxLevel, a, b);
});
}
}
@ -159,4 +136,35 @@ public class BookBinder extends AContainer {
return enchantments;
}
private int combineEnchantmentLevels(int maxLevel, int lvl1, int lvl2) {
if (lvl1 == lvl2) {
/*
* Confirm the entry's enchant level doesn't go over the maximum
* unless it uses bypass-vanilla-max-level
*/
if (maxLevel <= lvl1 && !bypassVanillaMaxLevel.getValue()) {
return maxLevel;
} else if (hasCustomMaxLevel.getValue()) {
return lvl1 + 1 > customMaxLevel.getValue() ? customMaxLevel.getValue() : lvl1 + 1;
} else {
return lvl1 + 1;
}
} else {
int highestLevel = Math.max(lvl1, lvl2);
/*
* Confirm the entry's enchant level doesn't go over the maximum
* unless it uses bypass-vanilla-max-level
*/
if (maxLevel <= highestLevel && !bypassVanillaMaxLevel.getValue()) {
return maxLevel;
} else if (hasCustomMaxLevel.getValue()) {
return highestLevel > customMaxLevel.getValue() ? customMaxLevel.getValue() : highestLevel;
} else {
return highestLevel;
}
}
}
}

View File

@ -1,11 +1,17 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
@ -14,6 +20,7 @@ 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.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;
@ -25,7 +32,6 @@ 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.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
@ -59,7 +65,8 @@ public abstract class AbstractEntityAssembler<T extends Entity> extends SimpleSl
private int lifetime = 0;
public AbstractEntityAssembler(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
@ParametersAreNonnullByDefault
protected AbstractEntityAssembler(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
new BlockMenuPreset(getId(), item.getImmutableMeta().getDisplayName().orElse("Entity Assembler")) {
@ -108,23 +115,10 @@ public abstract class AbstractEntityAssembler<T extends Entity> extends SimpleSl
}
};
addItemHandler(onPlace());
registerBlockHandler(getId(), (p, b, stack, reason) -> {
if (reason == UnregisterReason.EXPLODE) {
return false;
}
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), headSlots);
inv.dropItems(b.getLocation(), bodySlots);
}
return true;
});
addItemHandler(onPlace(), onBreak());
}
@Nonnull
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(true) {
@ -145,6 +139,23 @@ public abstract class AbstractEntityAssembler<T extends Entity> extends SimpleSl
};
}
@Nonnull
private BlockBreakHandler onBreak() {
return new BlockBreakHandler(false, false) {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List<ItemStack> drops) {
Block b = e.getBlock();
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), headSlots);
inv.dropItems(b.getLocation(), bodySlots);
}
}
};
}
private void updateBlockInventory(BlockMenu menu, Block b) {
if (!BlockStorage.hasBlockInfo(b) || BlockStorage.getLocationInfo(b.getLocation(), KEY_ENABLED) == null || BlockStorage.getLocationInfo(b.getLocation(), KEY_ENABLED).equals(String.valueOf(false))) {
menu.replaceExistingItem(22, new CustomItem(Material.GUNPOWDER, "&7Enabled: &4\u2718", "", "&e> Click to enable this Machine"));

View File

@ -0,0 +1,39 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
/**
* An {@link AnimalProduce} can be obtained via the {@link ProduceCollector}.
*
* @author TheBusyBiscuit
*
* @see ProduceCollector
*
*/
public class AnimalProduce extends MachineRecipe implements Predicate<LivingEntity> {
private final Predicate<LivingEntity> predicate;
@ParametersAreNonnullByDefault
public AnimalProduce(ItemStack input, ItemStack result, Predicate<LivingEntity> predicate) {
super(5, new ItemStack[] { input }, new ItemStack[] { result });
Validate.notNull(predicate, "The Predicate must not be null");
this.predicate = predicate;
}
@Override
public boolean test(@Nonnull LivingEntity entity) {
return predicate.test(entity);
}
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@ -0,0 +1,164 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Cow;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.MushroomCow;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
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.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
/**
* The {@link ProduceCollector} allows you to collect produce from animals.
* Providing it with a bucket and a nearby {@link Cow} will allow you to obtain milk.
*
* @author TheBusyBiscuit
*
*/
public class ProduceCollector extends AContainer implements RecipeDisplayItem {
private final ItemSetting<Integer> range = new IntRangeSetting(this, "range", 1, 2, 32);
private final Set<AnimalProduce> animalProduces = new HashSet<>();
@ParametersAreNonnullByDefault
public ProduceCollector(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
addItemSetting(range);
}
@Override
protected void registerDefaultRecipes() {
// Milk from adult cows
addProduce(new AnimalProduce(new ItemStack(Material.BUCKET), new ItemStack(Material.MILK_BUCKET), n -> {
if (n instanceof Cow) {
return ((Cow) n).isAdult();
} else {
return false;
}
}));
// Mushroom Stew from Mooshrooms
addProduce(new AnimalProduce(new ItemStack(Material.BOWL), new ItemStack(Material.MUSHROOM_STEW), n -> {
if (n instanceof MushroomCow) {
return ((MushroomCow) n).isAdult();
} else {
return false;
}
}));
}
/**
* This method adds a new {@link AnimalProduce} to this machine.
*
* @param produce
* The {@link AnimalProduce} to add
*/
public void addProduce(@Nonnull AnimalProduce produce) {
Validate.notNull(produce, "A produce cannot be null");
this.animalProduces.add(produce);
}
@Override
public void preRegister() {
addItemHandler(new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
ProduceCollector.this.tick(b);
}
@Override
public boolean isSynchronized() {
// We override the preRegister() method to override the sync setting here
return true;
}
});
}
@Override
public List<ItemStack> getDisplayRecipes() {
List<ItemStack> displayRecipes = new ArrayList<>();
displayRecipes.add(new CustomItem(Material.BUCKET, null, "&fRequires &bCow &fnearby"));
displayRecipes.add(new ItemStack(Material.MILK_BUCKET));
displayRecipes.add(new CustomItem(Material.BOWL, null, "&fRequires &bMooshroom &fnearby"));
displayRecipes.add(new ItemStack(Material.MUSHROOM_STEW));
return displayRecipes;
}
@Override
protected MachineRecipe findNextRecipe(@Nonnull BlockMenu inv) {
for (int slot : getInputSlots()) {
for (AnimalProduce produce : animalProduces) {
ItemStack item = inv.getItemInSlot(slot);
if (!SlimefunUtils.isItemSimilar(item, produce.getInput()[0], true) || !InvUtils.fits(inv.toInventory(), produce.getOutput()[0], getOutputSlots())) {
continue;
}
if (isAnimalNearby(inv.getBlock(), produce::test)) {
inv.consumeItem(slot);
return produce;
}
}
}
return null;
}
@ParametersAreNonnullByDefault
private boolean isAnimalNearby(Block b, Predicate<LivingEntity> predicate) {
int radius = range.getValue();
return !b.getWorld().getNearbyEntities(b.getLocation(), radius, radius, radius, n -> isValidAnimal(n, predicate)).isEmpty();
}
@ParametersAreNonnullByDefault
private boolean isValidAnimal(Entity n, Predicate<LivingEntity> predicate) {
if (n instanceof LivingEntity) {
return predicate.test((LivingEntity) n);
} else {
return false;
}
}
@Override
public String getMachineIdentifier() {
return "PRODUCE_COLLECTOR";
}
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.SHEARS);
}
}

View File

@ -1,146 +0,0 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities;
import java.util.Iterator;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.event.block.BlockPlaceEvent;
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.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
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 class XPCollector 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) {
super(category, item, recipeType, recipe);
createPreset(this, this::constructMenu);
addItemHandler(onPlace());
registerBlockHandler(getId(), (p, b, stack, reason) -> {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getOutputSlots());
}
return true;
});
}
private BlockPlaceHandler onPlace() {
return new BlockPlaceHandler(false) {
@Override
public void onPlayerPlace(BlockPlaceEvent e) {
BlockStorage.addBlockInfo(e.getBlock(), "owner", e.getPlayer().getUniqueId().toString());
}
};
}
@Override
public int[] getInputSlots() {
return new int[0];
}
@Override
public int[] getOutputSlots() {
return new int[] { 12, 13, 14 };
}
@Override
public EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.CONSUMER;
}
@Override
public int getCapacity() {
return 1024;
}
protected void constructMenu(BlockMenuPreset preset) {
for (int slot : border) {
preset.addItem(slot, new CustomItem(Material.PURPLE_STAINED_GLASS_PANE, " "), (p, s, item, action) -> false);
}
}
@Override
public void preRegister() {
addItemHandler(new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
XPCollector.this.tick(b);
}
@Override
public boolean isSynchronized() {
return true;
}
});
}
protected void tick(Block b) {
Iterator<Entity> iterator = b.getWorld().getNearbyEntities(b.getLocation(), 4.0, 4.0, 4.0, n -> n instanceof ExperienceOrb && n.isValid()).iterator();
int experiencePoints = 0;
while (iterator.hasNext() && experiencePoints == 0) {
Entity entity = iterator.next();
if (getCharge(b.getLocation()) < ENERGY_CONSUMPTION) {
return;
}
experiencePoints = getStoredExperience(b) + ((ExperienceOrb) entity).getExperience();
removeCharge(b.getLocation(), ENERGY_CONSUMPTION);
entity.remove();
int withdrawn = 0;
BlockMenu menu = BlockStorage.getInventory(b);
for (int level = 0; level < getStoredExperience(b); level = level + 10) {
if (menu.fits(SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE, getOutputSlots())) {
withdrawn = withdrawn + 10;
menu.pushItem(SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE.clone(), getOutputSlots());
}
}
BlockStorage.addBlockInfo(b, DATA_KEY, String.valueOf(experiencePoints - withdrawn));
}
}
private int getStoredExperience(Block b) {
Config cfg = BlockStorage.getLocationInfo(b.getLocation());
String value = cfg.getString(DATA_KEY);
if (value != null) {
return Integer.parseInt(value);
} else {
BlockStorage.addBlockInfo(b, DATA_KEY, "0");
return 0;
}
}
}

View File

@ -53,7 +53,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramO
public GEOMiner(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
addItemHandler(onPlace(), onBreak());
addItemHandler(onPlace());
}
@Nonnull
@ -68,7 +68,8 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramO
}
@Nonnull
private BlockBreakHandler onBreak() {
@Override
protected BlockBreakHandler onBlockBreak() {
return new SimpleBlockBreakHandler() {
@Override
@ -87,26 +88,31 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramO
};
}
@Nonnull
@Override
public String getMachineIdentifier() {
return "GEO_MINER";
}
@Nonnull
@Override
public ItemStack getProgressBar() {
return new ItemStack(Material.DIAMOND_PICKAXE);
}
@Nonnull
@Override
public int[] getInputSlots() {
return new int[0];
}
@Nonnull
@Override
public int[] getOutputSlots() {
return OUTPUT_SLOTS;
}
@Nonnull
@Override
public List<ItemStack> getDisplayRecipes() {
List<ItemStack> displayRecipes = new LinkedList<>();
@ -120,13 +126,14 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramO
return displayRecipes;
}
@Nonnull
@Override
public String getLabelLocalPath() {
return "guide.tooltips.recipes.miner";
}
@Override
protected void constructMenu(BlockMenuPreset preset) {
protected void constructMenu(@Nonnull BlockMenuPreset preset) {
for (int i : BORDER) {
preset.addItem(i, new CustomItem(Material.GRAY_STAINED_GLASS_PANE, " "), (p, slot, item, action) -> false);
}
@ -154,7 +161,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramO
}
@Override
protected void tick(Block b) {
protected void tick(@Nonnull Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
if (isProcessing(b)) {
@ -183,7 +190,7 @@ public class GEOMiner extends AContainer implements RecipeDisplayItem, HologramO
}
}
private void start(Block b, BlockMenu inv) {
private void start(@Nonnull Block b, @Nonnull BlockMenu inv) {
for (GEOResource resource : SlimefunPlugin.getRegistry().getGEOResources().values()) {
if (resource.isObtainableFromGEOMiner()) {
OptionalInt optional = SlimefunPlugin.getGPSNetwork().getResourceManager().getSupplies(resource, b.getWorld(), b.getX() >> 4, b.getZ() >> 4);

View File

@ -0,0 +1,60 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.misc;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.Smeltery;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link GoldIngot} from Slimefun is a simple resource which is divided into different
* levels of carat ratings.
* <p>
* It can be obtained via gold dust and other gold ingots in a {@link Smeltery}.
*
* @author TheBusyBiscuit
*
* @see Smeltery
*
*/
public class GoldIngot extends SlimefunItem {
/**
* The carat rating.
*/
private final int caratRating;
@ParametersAreNonnullByDefault
public GoldIngot(Category category, int caratRating, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
Validate.isTrue(caratRating > 0, "Carat rating must be above zero.");
Validate.isTrue(caratRating <= 24, "Carat rating cannot go above 24.");
this.caratRating = caratRating;
}
/**
* This returns the carat rating of this {@link GoldIngot}.
* <p>
* The purity of the {@link GoldIngot} is measured in carat (1-24).
*
* <pre>
* 24k = 100% gold.
* 18k = 75% gold.
* 12k = 50% gold.
* </pre>
*
* and so on...
*
* @return The carat rating of this {@link GoldIngot}
*/
public int getCaratRating() {
return caratRating;
}
}

View File

@ -51,7 +51,11 @@ public class ArmorForge extends AbstractCraftingTable {
}
}
SlimefunPlugin.getLocalization().sendMessage(p, "machines.pattern-not-found", true);
if (inv.isEmpty()) {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.inventory-empty", true);
} else {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.pattern-not-found", true);
}
}
}

View File

@ -50,7 +50,11 @@ public class EnhancedCraftingTable extends AbstractCraftingTable {
}
}
SlimefunPlugin.getLocalization().sendMessage(p, "machines.pattern-not-found", true);
if (inv.isEmpty()) {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.inventory-empty", true);
} else {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.pattern-not-found", true);
}
}
}

View File

@ -76,6 +76,9 @@ public class GrindStone extends MultiBlockMachine {
recipes.add(new ItemStack(Material.NETHER_WART_BLOCK));
recipes.add(new ItemStack(Material.NETHER_WART, 9));
recipes.add(new ItemStack(Material.QUARTZ_BLOCK));
recipes.add(new ItemStack(Material.QUARTZ, 4));
}
@Override

View File

@ -57,7 +57,11 @@ public class MagicWorkbench extends AbstractCraftingTable {
}
}
SlimefunPlugin.getLocalization().sendMessage(p, "machines.pattern-not-found", true);
if (inv.isEmpty()) {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.inventory-empty", true);
} else {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.pattern-not-found", true);
}
}
}

View File

@ -89,7 +89,7 @@ public class OreCrusher extends MultiBlockMachine {
recipes.add(new ItemStack(Material.GRAVEL));
recipes.add(new ItemStack(Material.SAND));
recipes.add(new ItemStack(Material.MAGMA_BLOCK, 4));
recipes.add(new ItemStack(Material.MAGMA_BLOCK));
recipes.add(SlimefunItems.SULFATE);
recipes.add(SlimefunItems.CARBON);

View File

@ -11,6 +11,7 @@ import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
@ -235,7 +236,7 @@ public class ClimbingPick extends SimpleSlimefunItem<ItemUseHandler> implements
}
@Override
public void damageItem(Player p, ItemStack item) {
public void damageItem(@Nonnull Player p, @Nullable ItemStack item) {
if (p.getGameMode() != GameMode.CREATIVE) {
DamageableItem.super.damageItem(p, item);
}

View File

@ -12,6 +12,7 @@ import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.inventory.ItemStack;
@ -20,15 +21,14 @@ import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEve
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
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.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
@ -64,12 +64,12 @@ public class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 0.2F, 1F);
List<Block> blocks = findBlocks(b);
breakBlocks(p, tool, b, blocks, drops);
breakBlocks(e, p, tool, b, blocks, drops);
};
}
@ParametersAreNonnullByDefault
private void breakBlocks(Player p, ItemStack item, Block b, List<Block> blocks, List<ItemStack> drops) {
private void breakBlocks(BlockBreakEvent e, Player p, ItemStack item, Block b, List<Block> blocks, List<ItemStack> drops) {
List<Block> blocksToDestroy = new ArrayList<>();
if (callExplosionEvent.getValue().booleanValue()) {
@ -96,7 +96,7 @@ public class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements
if (!event.isCancelled()) {
for (Block block : blocksToDestroy) {
breakBlock(p, item, block, drops);
breakBlock(e, p, item, block, drops);
}
}
}
@ -141,7 +141,7 @@ public class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements
}
@ParametersAreNonnullByDefault
private void breakBlock(Player p, ItemStack item, Block b, List<ItemStack> drops) {
private void breakBlock(BlockBreakEvent e, Player p, ItemStack item, Block b, List<ItemStack> drops) {
SlimefunPlugin.getProtectionManager().logAction(p, b, ProtectableAction.BREAK_BLOCK);
Material material = b.getType();
@ -149,10 +149,8 @@ public class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements
SlimefunItem sfItem = BlockStorage.check(b);
if (sfItem != null && !sfItem.useVanillaBlockBreaking()) {
SlimefunBlockHandler handler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getId());
if (handler != null && !handler.onBreak(p, b, sfItem, UnregisterReason.PLAYER_BREAK)) {
drops.add(BlockStorage.retrieve(b));
if (!sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(e, item, drops))) {
drops.addAll(sfItem.getDrops(p));
}
} else {
b.breakNaturally(item);

View File

@ -4,6 +4,7 @@ import java.util.UUID;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Bat;
@ -54,7 +55,7 @@ public class GrapplingHook extends SimpleSlimefunItem<ItemUseHandler> {
return e -> {
Player p = e.getPlayer();
UUID uuid = p.getUniqueId();
boolean isConsumed = consumeOnUse.getValue();
boolean isConsumed = consumeOnUse.getValue() && p.getGameMode() != GameMode.CREATIVE;
if (!e.getClickedBlock().isPresent() && !SlimefunPlugin.getGrapplingHookListener().isGrappling(uuid)) {
e.cancel();

View File

@ -14,6 +14,7 @@ import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters.AbstractAutoCrafter;
import io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters.EnhancedAutoCrafter;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.Multimeter;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
@ -50,6 +51,13 @@ public class AutoCrafterListener implements Listener {
SlimefunItem block = slimefunBlock.get();
if (block instanceof AbstractAutoCrafter) {
Optional<SlimefunItem> slimefunItem = e.getSlimefunItem();
if (!e.getPlayer().isSneaking() && slimefunItem.isPresent() && slimefunItem.get() instanceof Multimeter) {
// Allow Multimeters to pass through and do their job
return;
}
// Prevent blocks from being placed, food from being eaten, etc...
e.cancel();

View File

@ -21,6 +21,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
@ -29,9 +30,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
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;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@ -156,22 +155,10 @@ public class BlockListener implements Listener {
}
if (sfItem != null && !sfItem.useVanillaBlockBreaking()) {
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getId());
sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(e, item, drops));
if (blockHandler != null) {
try {
if (!blockHandler.onBreak(e.getPlayer(), e.getBlock(), sfItem, UnregisterReason.PLAYER_BREAK)) {
e.setCancelled(true);
return;
}
} catch (Exception | LinkageError x) {
sfItem.error("Something went wrong while triggering a BlockHandler", x);
}
} else {
sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(e, item, drops));
if (e.isCancelled()) {
return;
}
if (e.isCancelled()) {
return;
}
drops.addAll(sfItem.getDrops());
@ -191,6 +178,7 @@ public class BlockListener implements Listener {
e.setDropItems(false);
for (ItemStack drop : drops) {
// Prevent null or air from being dropped
if (drop != null && drop.getType() != Material.AIR) {
e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), drop);
}
@ -217,33 +205,27 @@ public class BlockListener implements Listener {
SlimefunItem sfItem = BlockStorage.check(blockAbove);
if (sfItem != null && !sfItem.useVanillaBlockBreaking()) {
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(sfItem.getId());
/*
* 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<ItemStack> drops = new ArrayList<>();
drops.addAll(sfItem.getDrops(e.getPlayer()));
if (blockHandler != null) {
if (blockHandler.onBreak(e.getPlayer(), blockAbove, sfItem, UnregisterReason.PLAYER_BREAK)) {
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), BlockStorage.retrieve(blockAbove));
blockAbove.setType(Material.AIR);
}
} else {
/*
* 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<ItemStack> drops = new ArrayList<>();
drops.addAll(sfItem.getDrops(e.getPlayer()));
sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));
blockAbove.setType(Material.AIR);
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);
}
if (!dummyEvent.isCancelled() && dummyEvent.isDropItems()) {
for (ItemStack drop : drops) {
if (drop != null && !drop.getType().isAir()) {
blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), drop);
}
}
}
// Fixes #2944 - Don't forget to clear the Block Data
BlockStorage.clearBlockInfo(blockAbove);
}
}
}
@ -251,10 +233,17 @@ public class BlockListener implements Listener {
private int getBonusDropsWithFortune(@Nullable ItemStack item, @Nonnull Block b) {
int amount = 1;
if (item != null) {
int fortuneLevel = item.getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS);
if (item != null && !item.getType().isAir() && item.hasItemMeta()) {
/*
* Small performance optimization:
* ItemStack#getEnchantmentLevel() calls ItemStack#getItemMeta(), so if
* we are handling more than one Enchantment, we should access the ItemMeta
* directly and re use it.
*/
ItemMeta meta = item.getItemMeta();
int fortuneLevel = meta.getEnchantLevel(Enchantment.LOOT_BONUS_BLOCKS);
if (fortuneLevel > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) {
if (fortuneLevel > 0 && !meta.hasEnchant(Enchantment.SILK_TOUCH)) {
Random random = ThreadLocalRandom.current();
amount = Math.max(1, random.nextInt(fortuneLevel + 2) - 1);

View File

@ -5,6 +5,7 @@ import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -18,9 +19,7 @@ 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;
/**
@ -58,36 +57,26 @@ public class ExplosionsListener implements Listener {
if (item != null) {
blocks.remove();
if (!(item instanceof WitherProof)) {
SlimefunBlockHandler blockHandler = SlimefunPlugin.getRegistry().getBlockHandlers().get(item.getId());
boolean success = true;
if (!(item instanceof WitherProof) && !item.callItemHandler(BlockBreakHandler.class, handler -> handleExplosion(handler, block))) {
BlockStorage.clearBlockInfo(block);
block.setType(Material.AIR);
}
}
}
}
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);
@ParametersAreNonnullByDefault
private void handleExplosion(BlockBreakHandler handler, Block block) {
if (handler.isExplosionAllowed(block)) {
BlockStorage.clearBlockInfo(block);
block.setType(Material.AIR);
List<ItemStack> drops = new ArrayList<>();
handler.onExplode(block, drops);
List<ItemStack> 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) {
BlockStorage.clearBlockInfo(block);
block.setType(Material.AIR);
}
for (ItemStack drop : drops) {
if (drop != null && !drop.getType().isAir()) {
block.getWorld().dropItemNaturally(block.getLocation(), drop);
}
}
}

View File

@ -1,7 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
@ -43,7 +42,7 @@ public class SoulboundListener implements Listener {
ItemStack item = p.getInventory().getItem(slot);
// Store soulbound items for later retrieval
if (SlimefunUtils.isSoulbound(item)) {
if (SlimefunUtils.isSoulbound(item, p.getWorld())) {
items.put(slot, item);
}
}
@ -58,14 +57,7 @@ public class SoulboundListener implements Listener {
}
// Remove soulbound items from our drops
Iterator<ItemStack> drops = e.getDrops().iterator();
while (drops.hasNext()) {
ItemStack item = drops.next();
if (SlimefunUtils.isSoulbound(item)) {
drops.remove();
}
}
e.getDrops().removeIf(itemStack -> SlimefunUtils.isSoulbound(itemStack, p.getWorld()));
}
@EventHandler

View File

@ -278,7 +278,14 @@ public class TalismanListener implements Listener {
ItemStack item = e.getPlayer().getInventory().getItemInMainHand();
// We are going to ignore Silk Touch here
if (item.getType() != Material.AIR && item.getAmount() > 0 && !item.containsEnchantment(Enchantment.SILK_TOUCH)) {
if (item.getType() != Material.AIR && item.getAmount() > 0) {
ItemMeta meta = item.getItemMeta();
// Ignore Silk Touch Enchantment
if (meta.hasEnchant(Enchantment.SILK_TOUCH)) {
return;
}
Material type = e.getBlockState().getType();
// We only want to double ores
@ -286,7 +293,7 @@ public class TalismanListener implements Listener {
Collection<Item> drops = e.getItems();
if (Talisman.trigger(e, SlimefunItems.TALISMAN_MINER, false)) {
int dropAmount = getAmountWithFortune(type, item.getEnchantmentLevel(Enchantment.LOOT_BONUS_BLOCKS));
int dropAmount = getAmountWithFortune(type, meta.getEnchantLevel(Enchantment.LOOT_BONUS_BLOCKS));
// Keep track of whether we actually doubled the drops or not
boolean doubledDrops = false;

View File

@ -27,7 +27,6 @@ import com.google.gson.JsonParser;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutomatedCraftingChamber;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.GrindStone;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.MakeshiftSmeltery;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.OreCrusher;
@ -78,7 +77,6 @@ public final class PostSetup {
}
}
loadAutomaticCraftingChamber();
loadOreGrinderRecipes();
loadSmelteryRecipes();
@ -128,14 +126,6 @@ public final class PostSetup {
// @formatter:on
}
private static void loadAutomaticCraftingChamber() {
AutomatedCraftingChamber crafter = (AutomatedCraftingChamber) SlimefunItems.AUTOMATED_CRAFTING_CHAMBER.getItem();
if (crafter != null) {
crafter.loadRecipes();
}
}
private static void loadOreGrinderRecipes() {
List<ItemStack[]> grinderRecipes = new ArrayList<>();

View File

@ -181,7 +181,7 @@ public final class ResearchSetup {
register("electric_furnaces", 170, "Powered Furnace", 15, SlimefunItems.ELECTRIC_FURNACE);
register("electric_ore_grinding", 171, "Crushing and Grinding", 20, SlimefunItems.ELECTRIC_ORE_GRINDER, SlimefunItems.ELECTRIC_INGOT_PULVERIZER);
register("heated_pressure_chamber", 172, "Heated Pressure Chamber", 22, SlimefunItems.HEATED_PRESSURE_CHAMBER);
register("coal_generator", 173, "Coal Generator", 18, SlimefunItems.COAL_GENERATOR);
register("coal_generator", 173, "Coal Generator", 14, SlimefunItems.COAL_GENERATOR);
register("bio_reactor", 173, "Bio-Reactor", 18, SlimefunItems.BIO_REACTOR);
register("auto_enchanting", 174, "Automatic Enchanting and Disenchanting", 24, SlimefunItems.AUTO_ENCHANTER, SlimefunItems.AUTO_DISENCHANTER);
register("auto_anvil", 175, "Automatic Anvil", 34, SlimefunItems.AUTO_ANVIL, SlimefunItems.AUTO_ANVIL_2);
@ -217,7 +217,8 @@ public final class ResearchSetup {
register("cargo_basics", 205, "Cargo Basics", 30, SlimefunItems.CARGO_MOTOR, SlimefunItems.CARGO_MANAGER, SlimefunItems.CARGO_CONNECTOR_NODE);
register("cargo_nodes", 206, "Cargo Setup", 30, SlimefunItems.CARGO_INPUT_NODE, SlimefunItems.CARGO_OUTPUT_NODE);
register("electric_ingot_machines", 207, "Electric Ingot Fabrication", 18, SlimefunItems.ELECTRIC_GOLD_PAN, SlimefunItems.ELECTRIC_DUST_WASHER, SlimefunItems.ELECTRIC_INGOT_FACTORY);
register("high_tier_electric_ingot_machines", 209, "Super Fast Ingot Fabrication", 32, SlimefunItems.ELECTRIC_GOLD_PAN_3, SlimefunItems.ELECTRIC_DUST_WASHER_3, SlimefunItems.ELECTRIC_INGOT_FACTORY_3, SlimefunItems.ELECTRIC_ORE_GRINDER_2, SlimefunItems.ELECTRIC_ORE_GRINDER_3);
register("medium_tier_electric_ingot_machines", 208, "Fast Ingot Fabrication", 25, SlimefunItems.ELECTRIC_GOLD_PAN_2, SlimefunItems.ELECTRIC_DUST_WASHER_2, SlimefunItems.ELECTRIC_INGOT_FACTORY_2, SlimefunItems.ELECTRIC_ORE_GRINDER_2);
register("high_tier_electric_ingot_machines", 209, "Super Fast Ingot Fabrication", 32, SlimefunItems.ELECTRIC_GOLD_PAN_3, SlimefunItems.ELECTRIC_DUST_WASHER_3, SlimefunItems.ELECTRIC_INGOT_FACTORY_3, SlimefunItems.ELECTRIC_ORE_GRINDER_3);
register("automated_crafting_chamber", 210, "Automated Crafting", 20, SlimefunItems.AUTOMATED_CRAFTING_CHAMBER);
register("better_food_fabricator", 211, "Upgraded Food Fabrication", 28, SlimefunItems.FOOD_FABRICATOR_2, SlimefunItems.FOOD_COMPOSTER_2);
register("reactor_access_port", 212, "Reactor Interaction", 18, SlimefunItems.REACTOR_ACCESS_PORT);
@ -242,7 +243,7 @@ public final class ResearchSetup {
register("better_electric_crucibles", 231, "Hot Crucibles", 30, SlimefunItems.ELECTRIFIED_CRUCIBLE_2, SlimefunItems.ELECTRIFIED_CRUCIBLE_3);
register("advanced_electric_smeltery", 232, "Advanced Electric Smeltery", 28, SlimefunItems.ELECTRIC_SMELTERY_2);
register("advanced_farmer_android", 233, "Advanced Androids - Farmer", 30, SlimefunItems.PROGRAMMABLE_ANDROID_2_FARMER);
register("lava_generator", 234, "Lava Generator", 38, SlimefunItems.LAVA_GENERATOR);
register("lava_generator", 234, "Lava Generator", 16, SlimefunItems.LAVA_GENERATOR);
register("nether_ice", 235, "Nether Ice Coolant", 45, SlimefunItems.NETHER_ICE, SlimefunItems.ENRICHED_NETHER_ICE, SlimefunItems.NETHER_ICE_COOLANT_CELL);
register("nether_star_reactor", 236, "Nether Star Reactor", 60, SlimefunItems.NETHER_STAR_REACTOR);
register("blistering_ingots", 237, "Blistering Radioactivity", 38, SlimefunItems.BLISTERING_INGOT, SlimefunItems.BLISTERING_INGOT_2, SlimefunItems.BLISTERING_INGOT_3);
@ -282,7 +283,10 @@ public final class ResearchSetup {
register("bee_armor", 270, "Bee Armor", 24, SlimefunItems.BEE_HELMET, SlimefunItems.BEE_WINGS, SlimefunItems.BEE_LEGGINGS, SlimefunItems.BEE_BOOTS);
register("wise_talisman", 271, "Talisman of the Wise", 20, SlimefunItems.TALISMAN_WISE);
register("book_binder", 272, "Enchantment Book Binding", 26, SlimefunItems.BOOK_BINDER);
register("auto_crafting", 273, "Automatic Crafting", 30, SlimefunItems.VANILLA_AUTO_CRAFTER, SlimefunItems.ENHANCED_AUTO_CRAFTER);
register("auto_crafting", 273, "Automatic Crafting", 30, SlimefunItems.CRAFTING_MOTOR, SlimefunItems.VANILLA_AUTO_CRAFTER, SlimefunItems.ENHANCED_AUTO_CRAFTER, SlimefunItems.ARMOR_AUTO_CRAFTER);
register("produce_collector", 274, "Automatic Milking", 20, SlimefunItems.PRODUCE_COLLECTOR);
register("improved_generators", 275, "Improved Generators", 24, SlimefunItems.COAL_GENERATOR_2, SlimefunItems.LAVA_GENERATOR_2);
register("ingredients_and_cheese", 276, "Slimefun Cuisine", 5, SlimefunItems.SALT, SlimefunItems.WHEAT_FLOUR, SlimefunItems.HEAVY_CREAM, SlimefunItems.CHEESE, SlimefunItems.BUTTER);
}
@ParametersAreNonnullByDefault

View File

@ -40,6 +40,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.armor.LongFallBoo
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.Parachute;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.StomperBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters.ArmorAutoCrafter;
import io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters.EnhancedAutoCrafter;
import io.github.thebusybiscuit.slimefun4.implementation.items.autocrafters.VanillaAutoCrafter;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
@ -82,7 +83,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.generato
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.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.AutoDrier;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutomatedCraftingChamber;
@ -109,9 +109,11 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines
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.AutoBreeder;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.ExpCollector;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.IronGolemAssembler;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.ProduceCollector;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.entities.WitherAssembler;
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;
@ -157,6 +159,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.medical.Splint;
import io.github.thebusybiscuit.slimefun4.implementation.items.medical.Vitamins;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.BasicCircuitBoard;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.CoolantCell;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.GoldIngot;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.OrganicFertilizer;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.OrganicFood;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.SteelThruster;
@ -715,47 +718,47 @@ public final class SlimefunItemSetup {
new OreWasher(categories.basicMachines, SlimefunItems.ORE_WASHER).register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_24K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 24, SlimefunItems.GOLD_24K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_22K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_22K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 22, SlimefunItems.GOLD_22K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_20K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_20K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 20, SlimefunItems.GOLD_20K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_18K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_18K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 18, SlimefunItems.GOLD_18K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_16K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_16K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 16, SlimefunItems.GOLD_16K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_14K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_14K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 14, SlimefunItems.GOLD_14K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_12K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_12K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 12, SlimefunItems.GOLD_12K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_10K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_10K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 10, SlimefunItems.GOLD_10K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_8K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_8K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 8, SlimefunItems.GOLD_8K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_6K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_6K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 6, SlimefunItems.GOLD_6K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, SlimefunItems.GOLD_4K, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.resources, SlimefunItems.GOLD_4K, RecipeType.SMELTERY,
new GoldIngot(categories.resources, 4, SlimefunItems.GOLD_4K, RecipeType.SMELTERY,
new ItemStack[] {SlimefunItems.GOLD_DUST, null, null, null, null, null, null, null, null})
.setUseableInWorkbench(true)
.register(plugin);
@ -768,7 +771,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {new ItemStack(Material.QUARTZ_BLOCK), null, null, null, null, null, null, null, null})
.register(plugin);
new SlimefunItem(categories.technicalComponents, SlimefunItems.SOLAR_PANEL, RecipeType.ENHANCED_CRAFTING_TABLE,
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.SOLAR_PANEL, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {new ItemStack(Material.GLASS), new ItemStack(Material.GLASS), new ItemStack(Material.GLASS), SlimefunItems.SILICON, SlimefunItems.SILICON, SlimefunItems.SILICON, SlimefunItems.FERROSILICON, SlimefunItems.FERROSILICON, SlimefunItems.FERROSILICON})
.register(plugin);
@ -1481,7 +1484,7 @@ public final class SlimefunItemSetup {
new SlimefunItemStack(SlimefunItems.WITHER_PROOF_OBSIDIAN, 4))
.register(plugin);
new AncientPedestal(categories.magicalResources, SlimefunItems.ANCIENT_PEDESTAL, RecipeType.MAGIC_WORKBENCH,
new AncientPedestal(categories.magicalGadgets, SlimefunItems.ANCIENT_PEDESTAL, RecipeType.MAGIC_WORKBENCH,
new ItemStack[] {new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN), null, new ItemStack(Material.STONE), null, new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN)},
new SlimefunItemStack(SlimefunItems.ANCIENT_PEDESTAL, 4))
.register(plugin);
@ -2476,7 +2479,7 @@ public final class SlimefunItemSetup {
.register(plugin);
new AutomatedCraftingChamber(categories.electricity, SlimefunItems.AUTOMATED_CRAFTING_CHAMBER, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, new ItemStack(Material.CRAFTING_TABLE), null, SlimefunItems.CARGO_MOTOR, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.CARGO_MOTOR, null, SlimefunItems.ELECTRIC_MOTOR, null}) {
new ItemStack[] {null, null, null, null, new CustomItem(Material.BARRIER, "&4This Item has been disabled.", "&cIt will soon be removed!", "&cPlease switch over to the new", "&cAuto-Crafters from the Cargo Category."), null, null, null, null}) {
@Override
public int getEnergyConsumption() {
@ -2584,19 +2587,37 @@ public final class SlimefunItemSetup {
new ElytraCap(categories.magicalArmor, SlimefunItems.ELYTRA_CAP, RecipeType.ARMOR_FORGE,
new ItemStack[] {new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), SlimefunItems.ELYTRA_SCALE, SlimefunItems.ELYTRA_SCALE, SlimefunItems.ELYTRA_SCALE, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.LEATHER_HELMET), new ItemStack(Material.SLIME_BALL)})
.register(plugin);
new UnplaceableBlock(categories.cargo, SlimefunItems.CRAFTING_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.BLISTERING_INGOT_3, new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.REDSTONE_ALLOY, SlimefunItems.CARGO_MOTOR, SlimefunItems.REDSTONE_ALLOY, new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.BLISTERING_INGOT_3, new ItemStack(Material.CRAFTING_TABLE)},
new SlimefunItemStack(SlimefunItems.CRAFTING_MOTOR, 2))
.register(plugin);
new VanillaAutoCrafter(categories.cargo, SlimefunItems.VANILLA_AUTO_CRAFTER, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, SlimefunItems.BLISTERING_INGOT_3, null, new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.CARGO_MOTOR, new ItemStack(Material.CRAFTING_TABLE), null, SlimefunItems.ELECTRIC_MOTOR, null})
new ItemStack[] {null, SlimefunItems.CARGO_MOTOR, null, new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.CRAFTING_MOTOR, new ItemStack(Material.CRAFTING_TABLE), null, SlimefunItems.ELECTRIC_MOTOR, null})
.setCapacity(256)
.setEnergyConsumption(16)
.register(plugin);
new EnhancedAutoCrafter(categories.cargo, SlimefunItems.ENHANCED_AUTO_CRAFTER, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, SlimefunItems.VANILLA_AUTO_CRAFTER, null, new ItemStack(Material.CRAFTING_TABLE), new ItemStack(Material.DISPENSER), new ItemStack(Material.CRAFTING_TABLE), null, SlimefunItems.CARGO_MOTOR, null})
new ItemStack[] {null, SlimefunItems.CRAFTING_MOTOR, null, new ItemStack(Material.CRAFTING_TABLE), new ItemStack(Material.DISPENSER), new ItemStack(Material.CRAFTING_TABLE), null, SlimefunItems.CARGO_MOTOR, null})
.setCapacity(256)
.setEnergyConsumption(16)
.register(plugin);
new ArmorAutoCrafter(categories.cargo, SlimefunItems.ARMOR_AUTO_CRAFTER, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, SlimefunItems.CRAFTING_MOTOR, null, new ItemStack(Material.DISPENSER), new ItemStack(Material.ANVIL), new ItemStack(Material.DISPENSER), new ItemStack(Material.CRAFTING_TABLE), SlimefunItems.ELECTRIC_MOTOR, new ItemStack(Material.CRAFTING_TABLE)})
.setCapacity(256)
.setEnergyConsumption(32)
.register(plugin);
new ProduceCollector(categories.electricity, SlimefunItems.PRODUCE_COLLECTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, new ItemStack(Material.HAY_BLOCK), null, new ItemStack(Material.BUCKET), SlimefunItems.MEDIUM_CAPACITOR, new ItemStack(Material.BUCKET), SlimefunItems.ALUMINUM_BRASS_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_BRASS_INGOT})
.setCapacity(256)
.setProcessingSpeed(1)
.setEnergyConsumption(16)
.register(plugin);
// @formatter:on
}

View File

@ -114,7 +114,11 @@ public enum HeadTexture {
PIGLIN_HEAD("2882af1294a74023e6919a31d1a027310f2e142afb4667d230d155e7f21dbb41"),
NECROTIC_SKULL("7953b6c68448e7e6b6bf8fb273d7203acd8e1be19e81481ead51f45de59a8"),
VANILLA_AUTO_CRAFTER("80a4334f6a61e40c0c63deb665fa7b581e6eb259f7a3207ced7a1ff8bdc8a9f9"),
ENHANCED_AUTO_CRAFTER("5038298306a5e28584df39e88896917c38d40a326226d8c83070723c95798b24");
ENHANCED_AUTO_CRAFTER("5038298306a5e28584df39e88896917c38d40a326226d8c83070723c95798b24"),
ARMOR_AUTO_CRAFTER("5cbd9f5ec1ed007259996491e69ff649a3106cf920227b1bb3a71ee7a89863f"),
EXCLAMATION_MARK("2e3f50ba62cbda3ecf5479b62fedebd61d76589771cc19286bf2745cd71e47c6"),
CARGO_MOTOR("8e47f99abcd645a3ef1122c9d850a981979f431ba293255c1680e91ab117ed35"),
CRAFTING_MOTOR("1003620899f1afa271e8e521ecbee2977a06c8529d3f389e8cc04af06d8c7940");
private final String texture;
private final UUID uuid;

View File

@ -14,6 +14,7 @@ import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
@ -79,15 +80,29 @@ public final class SlimefunUtils {
/**
* This method checks whether the given {@link ItemStack} is considered {@link Soulbound}.
*
*
* @param item
* The {@link ItemStack} to check for
* @return Whether the given item is soulbound
*/
public static boolean isSoulbound(@Nullable ItemStack item) {
if (item == null || item.getType() == Material.AIR) {
return false;
} else {
return isSoulbound(item, null);
}
/**
* This method checks whether the given {@link ItemStack} is considered {@link Soulbound}.
* If the provided item is a {@link SlimefunItem} then this method will also check that the item
* is enabled in the provided {@link World}.
*
* @param item
* The {@link ItemStack} to check for
* @param world
* The {@link World} to check if the {@link SlimefunItem} is enabled in if applicable.
* If {@code null} then this will not do a world check.
* @return Whether the given item is soulbound
*/
public static boolean isSoulbound(@Nullable ItemStack item, @Nullable World world) {
if (item != null && item.getType() != Material.AIR) {
ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : null;
if (hasSoulboundFlag(meta)) {
@ -97,13 +112,17 @@ public final class SlimefunUtils {
SlimefunItem sfItem = SlimefunItem.getByItem(item);
if (sfItem instanceof Soulbound) {
return !sfItem.isDisabled();
if (world != null) {
return !sfItem.isDisabledIn(world);
} else {
return !sfItem.isDisabled();
}
} else if (meta != null) {
return meta.hasLore() && meta.getLore().contains(SOULBOUND_LORE);
}
return false;
}
return false;
}
private static boolean hasSoulboundFlag(@Nullable ItemMeta meta) {
@ -111,9 +130,7 @@ public final class SlimefunUtils {
PersistentDataContainer container = meta.getPersistentDataContainer();
NamespacedKey key = SlimefunPlugin.getRegistry().getSoulboundDataKey();
if (container.has(key, PersistentDataType.BYTE)) {
return true;
}
return container.has(key, PersistentDataType.BYTE);
}
return false;

View File

@ -0,0 +1,56 @@
package io.github.thebusybiscuit.slimefun4.utils;
import java.util.function.IntFunction;
import javax.annotation.Nonnull;
import org.bukkit.enchantments.Enchantment;
import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem;
/**
* This a enum evaluating and indicating a {@link DamageableItem} 's chance to be damaged
* depending if it is a tool or an armor
*
* @author RobotHanzo
*
* @see DamageableItem
*/
public enum UnbreakingAlgorithm {
/**
* For armor sets, unbreaking is capped at max. 40% effectiveness.
*/
ARMOR(lvl -> Math.random() >= 0.6 + (0.4 / (lvl + 1))),
/**
* For tools, unbreaking is calculated like this.
* The effect increases indefinitely.
*/
TOOLS(lvl -> Math.random() >= 1.0 / (lvl + 1));
private final IntFunction<Boolean> function;
UnbreakingAlgorithm(@Nonnull IntFunction<Boolean> function) {
this.function = function;
}
/**
* This method will randomly decide if the item should be damaged or not
* based on the internal formula of this {@link UnbreakingAlgorithm}.
* If this method returns true, the item should not take damage.
*
* @param unbreakingLevel
* The {@link Integer} level of the unbreaking {@link Enchantment}
*
* @return Whether to save the item from taking damage
*
*/
public boolean evaluate(int unbreakingLevel) {
if (unbreakingLevel > 0) {
return function.apply(unbreakingLevel);
} else {
return false;
}
}
}

View File

@ -1,117 +0,0 @@
package me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.Item;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
/**
* An old remnant of CS-CoreLib.
* This will be removed once we updated everything.
* Don't look at the code, it will be gone soon, don't worry.
*
* @deprecated This was a horrible idea. Don't use it.
*
*/
@Deprecated
public class CustomItemSerializer {
public enum ItemFlag {
MATERIAL(0),
DATA(1),
AMOUNT(2),
DURABILITY(3),
ENCHANTMENTS(4),
ITEMMETA_DISPLAY_NAME(5),
ITEMMETA_LORE(6);
private int weight;
ItemFlag(int weight) {
this.weight = weight;
}
public int getWeight() {
return this.weight;
}
}
private static ItemFlagComparator comparator = new ItemFlagComparator();
public static String serialize(ItemStack item, ItemFlag... flags) {
if (item == null)
return "NULL";
List<ItemFlag> flaglist = Arrays.asList(flags);
Collections.sort(flaglist, comparator);
StringBuilder builder = new StringBuilder();
int i = 0;
for (ItemFlag flag : flags) {
if (i > 0)
builder.append(" </sep> ");
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");
}
}
break;
case ITEMMETA_DISPLAY_NAME: {
if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
builder.append(item.getItemMeta().getDisplayName().replaceAll("\\u00a7", "&"));
} else {
builder.append("NONE");
}
break;
}
case ITEMMETA_LORE: {
if (item.hasItemMeta() && item.getItemMeta().hasLore()) {
builder.append(item.getItemMeta().getLore().toString().replaceAll("\\u00a7", "&"));
} else {
builder.append("NONE");
}
break;
}
case MATERIAL: {
builder.append(item.getType().toString());
break;
}
default:
break;
}
i++;
}
return builder.toString();
}
public static boolean equals(ItemStack stack1, ItemStack stack2, ItemFlag... flags) {
return serialize(stack1, flags).equals(serialize(stack2, flags));
}
}

View File

@ -1,23 +0,0 @@
package me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.Item;
import java.util.Comparator;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.Item.CustomItemSerializer.ItemFlag;
/**
* An old remnant of CS-CoreLib.
* This will be removed once we updated everything.
* Don't look at the code, it will be gone soon, don't worry.
*
* @deprecated This was a horrible idea. Don't use it.
*
*/
@Deprecated
public class ItemFlagComparator implements Comparator<ItemFlag> {
@Override
public int compare(ItemFlag flag1, ItemFlag flag2) {
return flag1.getWeight() - flag2.getWeight();
}
}

View File

@ -1,42 +0,0 @@
package me.mrCookieSlime.Slimefun.Objects;
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;
/**
* A {@link SlimefunBlockHandler} handles breaking and placing of blocks.
* You can use this class to initialize block data but also to correctly
* destroy blocks.
*
* {@code SlimefunItem.registerBlockHandler(String, SlimefunBlockHandler); }
*
* @author TheBusyBiscuit
*
* @deprecated Please use the {@link BlockBreakHandler} instead.
*
*/
@Deprecated
@FunctionalInterface
public interface SlimefunBlockHandler {
/**
* This method gets called when the {@link Block} is broken.
* The {@link Player} will be null if the {@link Block} exploded
*
* @param p
* The {@link Player} who broke the {@link Block}
* @param b
* The {@link Block} that was broken
* @param item
* The {@link SlimefunItem} that was stored in that {@link Block}
* @param reason
* The reason for the {@link Block} breaking
* @return Whether the {@link Event} should be cancelled
*/
boolean onBreak(Player p, Block b, SlimefunItem item, UnregisterReason reason);
}

View File

@ -40,7 +40,6 @@ 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;
@ -805,14 +804,13 @@ public class SlimefunItem implements Placeable {
Validate.notEmpty(handlers, "You cannot add zero handlers...");
Validate.noNullElements(handlers, "You cannot add any 'null' ItemHandler!");
// Make sure they are added before the item was registered.
if (state != ItemState.UNREGISTERED) {
throw new UnsupportedOperationException("You cannot add an ItemHandler after the SlimefunItem was registered.");
}
for (ItemHandler handler : handlers) {
if (itemhandlers.put(handler.getIdentifier(), handler).isPresent()) {
warn("ItemHandler \"" + handler.getIdentifier().getSimpleName() + "\" has already been assigned to this item. It was overridden.");
}
itemhandlers.put(handler.getIdentifier(), handler);
// Tickers are a special case (at the moment at least)
if (handler instanceof BlockTicker) {
@ -1196,19 +1194,4 @@ public class SlimefunItem implements Placeable {
return SlimefunPlugin.getRegistry().getPublicItemHandlers().computeIfAbsent(identifier, c -> new HashSet<>());
}
/**
* 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);
}
}

View File

@ -1,36 +0,0 @@
package me.mrCookieSlime.Slimefun.Objects.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
/**
* Defines how a block handled by Slimefun is being unregistered.
* <p>
* It is notably used by
* {@link me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler#onBreak(org.bukkit.entity.Player, org.bukkit.block.Block, SlimefunItem, UnregisterReason)}.
*
* @author TheBusyBiscuit
*
* @deprecated This enum is no longer needed
*
* @see SlimefunBlockHandler
*
*/
@Deprecated
public enum UnregisterReason {
/**
* An explosion destroys the block.
*/
EXPLODE,
/**
* A player breaks the block.
*/
PLAYER_BREAK,
/**
* An android miner breaks the block.
*/
ANDROID_DIG
}

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
@ -24,7 +25,9 @@ import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.events.AsyncMachineProcessCompleteEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
@ -47,8 +50,9 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock,
private static final int[] BORDER_IN = { 9, 10, 11, 12, 18, 21, 27, 28, 29, 30 };
private static final int[] BORDER_OUT = { 14, 15, 16, 17, 23, 26, 32, 33, 34, 35 };
public static Map<Block, MachineRecipe> processing = new HashMap<>();
public static Map<Block, Integer> progress = new HashMap<>();
// These will be replaced by proper recipe handler
public static Map<Block, MachineRecipe> processing = new ConcurrentHashMap<>();
public static Map<Block, Integer> progress = new ConcurrentHashMap<>();
protected final List<MachineRecipe> recipes = new ArrayList<>();
@ -57,27 +61,35 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock,
private int processingSpeed = -1;
@ParametersAreNonnullByDefault
public AContainer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
protected AContainer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
createPreset(this, getInventoryTitle(), this::constructMenu);
registerBlockHandler(item.getItemId(), (p, b, tool, reason) -> {
BlockMenu inv = BlockStorage.getInventory(b);
addItemHandler(onBlockBreak());
}
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
@Nonnull
protected BlockBreakHandler onBlockBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
progress.remove(b);
processing.remove(b);
}
progress.remove(b);
processing.remove(b);
return true;
});
};
}
@ParametersAreNonnullByDefault
public AContainer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
protected AContainer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
this(category, item, recipeType, recipe);
this.recipeOutput = recipeOutput;
}

View File

@ -21,8 +21,10 @@ import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.events.AsyncGeneratorProcessCompleteEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
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.AbstractEnergyProvider;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
@ -76,22 +78,29 @@ public abstract class AGenerator extends AbstractEnergyProvider {
}
};
registerBlockHandler(item.getItemId(), (p, b, tool, reason) -> {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
progress.remove(b.getLocation());
processing.remove(b.getLocation());
return true;
});
addItemHandler(onBlockBreak());
registerDefaultFuelTypes();
}
@Nonnull
protected BlockBreakHandler onBlockBreak() {
return new SimpleBlockBreakHandler() {
@Override
public void onBlockBreak(Block b) {
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
inv.dropItems(b.getLocation(), getInputSlots());
inv.dropItems(b.getLocation(), getOutputSlots());
}
progress.remove(b.getLocation());
processing.remove(b.getLocation());
}
};
}
private void constructMenu(BlockMenuPreset preset) {
for (int i : border) {
preset.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());

View File

@ -38,7 +38,7 @@ placeholderapi:
guide:
locked: 'LOCKED'
work-in-progress: 'This feature is not fully finished yet!'
locked-category:
- 'To unlock this category you will'
- 'need to unlock all items from the'
@ -64,11 +64,11 @@ guide:
cheat:
no-multiblocks: '&4You cannot cheat in Multiblocks, you have to build them!'
pages:
previous: 'Previous page'
next: 'Next page'
back:
title: 'Back'
guide: 'Go back to the Slimefun Guide'
@ -86,11 +86,11 @@ guide:
- '&7the language in which Slimefun'
- '&7will be presented to you. Items'
- '&7cannot be translated for now.'
translations:
name: '&aIs something missing?'
lore: 'Click to add your own translation'
title:
main: 'Slimefun Guide'
settings: 'Settings & Info'
@ -101,7 +101,7 @@ guide:
bugs: 'Bug Reports'
source: 'Source Code'
versions: 'Installed versions'
credits:
commit: 'Commit'
commits: 'Commits'
@ -151,9 +151,22 @@ messages:
recipe-set: '&aYou have successfully set the recipe for this machine.'
recipe-removed: '&eYou have successfully removed the recipe from this machine. You can set a new recipe at any time!'
no-recipes: '&cWe could not find any valid recipes for the item you are holding.'
missing-chest: '&cMissing chest! Auto Crafters need to be placed above a chest.'
missing-chest: '&cMissing chest! Auto-Crafters need to be placed above a chest.'
select: 'Select this recipe'
remove: 'Remove this recipe'
temporarily-disabled: '&eThis Auto-Crafter was temporarily disabled. You can re-enable it at any time!'
re-enabled: '&eThis Auto-Crafter was re-enabled!'
tooltips:
enabled:
- '&aThis recipe is currently enabled'
- ''
- '&eLeft Click &7to temporarily disable the recipe'
- '&eRight Click &7to remove this recipe'
disabled:
- '&cThis recipe is currently disabled'
- ''
- '&eLeft Click &7to re-enable this recipe'
- '&eRight Click &7to remove this recipe'
talisman:
anvil: '&a&oYour Talisman saved your tool from breaking'
@ -180,17 +193,17 @@ messages:
fail: '&cYou cannot enchant this item.'
no-enchantment: '&cCouldn''t find any applicable enchantment for this item.'
success: '&aYou have successfully applied a random applicable enchantment to this item.'
research:
start: '&7The Ancient Spirits whisper mysterious words into your ear!'
progress: '&7You start to wonder about &b%research% &e(%progress%)'
tape-measure:
no-anchor: '&cYou need to set an anchor before you can start to measure!'
wrong-world: '&cYour anchor seems to be in a different world!'
distance: '&7Measurement taken. &eDistance: %distance%'
anchor-set: '&aSuccessfully set the anchor:&e %anchor%'
climbing-pick:
dual-wielding: '&4You need to hold Climbing Picks in both hands to use them!'
wrong-material: '&cYou cannot climb this surface. Check your Slimefun Guide for more info!'
@ -204,7 +217,7 @@ messages:
no-iron-golem-heal: '&cThat is not an Iron Ingot. You cannot use this to heal Iron Golems!'
link-prompt: '&eClick here:'
diet-cookie: '&eYou are starting to feel very light...'
fortune-cookie:
- '&7Help me, I am trapped in a Fortune Cookie Factory!'
- '&7You will die tomorrow... by a Creeper'
@ -230,6 +243,7 @@ machines:
full-inventory: '&eSorry, my inventory is too full!'
in-use: '&cThis Block''s inventory is currently opened by a different Player.'
ignition-chamber-no-flint: '&cIgnition Chamber is missing Flint and Steel.'
inventory-empty: '&6You have successfully constructed this Multiblock. Proceed by placing items inside the dispenser and click me again to craft the item you want!'
ANCIENT_ALTAR:
not-enough-pedestals: '&4The Altar is not surrounded by the needed amount of Pedestals &c(%pedestals% / 8)'
@ -242,7 +256,7 @@ machines:
HOLOGRAM_PROJECTOR:
enter-text: '&7Please enter your desired Hologram Text into your Chat. &r(Color Codes are supported!)'
inventory-title: 'Hologram Editor'
ELEVATOR:
no-destinations: '&4No destinations found'
pick-a-floor: '&3- Pick a floor -'
@ -250,26 +264,26 @@ machines:
click-to-teleport: '&eClick &7to teleport to this floor:'
enter-name: '&7Please enter your desired floor name into your Chat. &r(Color Codes are supported!)'
named: '&2Successfully named this floor: &r%floor%'
TELEPORTER:
teleporting: '&3Teleporting...'
teleported: '&3Teleported!'
cancelled: '&4Teleportation cancelled!'
invulnerability: '&b&lYou have been given 30 seconds of Invulnerability!'
gui:
title: 'Your waypoints'
tooltip: 'Click to teleport'
time: 'Estimated time'
GPS_CONTROL_PANEL:
title: 'GPS - Control Panel'
transmitters: 'Transmitter Overview'
waypoints: 'Waypoint Overview'
CARGO_NODES:
must-be-placed: '&4Must be placed onto a chest or machine!'
INDUSTRIAL_MINER:
no-fuel: '&cYour Industrial Miner ran out of fuel! Put your fuel into the chest above.'
piston-facing: '&cYour Industrial Miner requires pistons to face upwards!'
@ -279,7 +293,7 @@ machines:
full-chest: '&cThe Chest of your Industrial Miner is full!'
no-permission: '&4You do not seem to have permission to operate an Industrial Miner here!'
finished: '&eYour Industrial Miner has finished! It obtained a total of %ores% ore(s)!'
anvil:
not-working: '&4You cannot use Slimefun items in an anvil!'
mcmmo-salvaging: '&4You cannot salvage Slimefun items!'
@ -325,12 +339,12 @@ inventory:
android:
started: '&7Your Android resumed running its script'
stopped: '&7Your Android has paused its script'
scripts:
already-uploaded: '&4This script has already been uploaded.'
editor: 'Script Editor'
too-long: '&cThe script is too long to edit!'
instructions:
START: '&2Start Script'
REPEAT: '&9Repeat Script'

View File

@ -188,6 +188,7 @@ slimefun:
cargo_basics: Cargo Basics
cargo_nodes: Cargo Setup
electric_ingot_machines: Electric Ingot Fabrication
medium_tier_electric_ingot_machines: Fast Ingot Fabrication
high_tier_electric_ingot_machines: Super Fast Ingot Fabrication
automated_crafting_chamber: Automated Crafting
better_food_fabricator: Upgraded Food Fabrication
@ -250,3 +251,6 @@ slimefun:
bee_armor: Bee Armor
book_binder: Enchantment Book Binding
auto_crafting: Automatic Crafting
produce_collector: Automatic Milking
improved_generators: Improved Generators
ingredients_and_cheese: Slimefun Cuisine

View File

@ -0,0 +1,34 @@
package io.github.thebusybiscuit.slimefun4.testing.mocks;
import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
public class DamageableMock extends SlimefunItem implements DamageableItem {
private final boolean itemDamageable;
@ParametersAreNonnullByDefault
public DamageableMock(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, boolean damageable) {
super(category, item, recipeType, recipe);
itemDamageable = damageable;
}
@Override
public boolean isDamageable() {
return itemDamageable;
}
@Override
public void damageItem(@Nonnull Player p, @Nullable ItemStack item) {
DamageableItem.super.damageItem(p, item);
}
}

View File

@ -0,0 +1,101 @@
package io.github.thebusybiscuit.slimefun4.testing.tests.items;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.testing.TestUtilities;
import io.github.thebusybiscuit.slimefun4.testing.mocks.DamageableMock;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
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 javax.annotation.Nullable;
class TestDamageableItem {
private static SlimefunPlugin plugin;
private static ServerMock server;
@BeforeAll
public static void load() {
server = MockBukkit.mock();
plugin = MockBukkit.load(SlimefunPlugin.class);
}
@AfterAll
public static void unload() {
MockBukkit.unmock();
}
public static DamageableMock getDummyItem(String id, boolean damageable, @Nullable Enchantment enchantment, @Nullable Integer enchantmentLevel) {
Category category = TestUtilities.getCategory(plugin, "damageable_item_test");
SlimefunItemStack stack = new SlimefunItemStack("DAMAGEABLE_PICKAXE_" + id, Material.DIAMOND_PICKAXE, "&4This pickaxe can break", "&6It appears, it breaks, but most importantly, it tests.");
if (enchantment != null && enchantmentLevel != null) {
ItemMeta im = stack.getItemMeta();
im.addEnchant(enchantment, enchantmentLevel, true);
stack.setItemMeta(im);
}
DamageableMock item = new DamageableMock(category, stack, RecipeType.NULL, new ItemStack[9], damageable);
item.register(plugin);
return item;
}
@Test
@DisplayName("Test DamageableItem actually damages")
void testDamageableItemDamagesItem() {
DamageableMock unDamageableItem = getDummyItem("UDM", false, null, null);
// Check if damageable is successfully registered
Assertions.assertFalse(unDamageableItem.isDamageable());
Player player = server.addPlayer();
ItemStack unDamageableDummy = unDamageableItem.getItem().clone();
unDamageableItem.damageItem(player, unDamageableDummy);
Assertions.assertTrue(unDamageableDummy.hasItemMeta());
// Check if the item is not damaged as we intended it to not be
Assertions.assertEquals(((Damageable) unDamageableDummy.getItemMeta()).getDamage(), 0);
DamageableMock damageableItem = getDummyItem("DM", true, null, null);
// Check if damageable is successfully registered
Assertions.assertTrue(damageableItem.isDamageable());
ItemStack damageableDummy = damageableItem.getItem().clone();
damageableItem.damageItem(player, damageableDummy);
Assertions.assertTrue(damageableDummy.hasItemMeta());
// Check if the item is damaged as we intended it to not be
Assertions.assertEquals(((Damageable) damageableDummy.getItemMeta()).getDamage(), 1);
}
@Test
@DisplayName("Test if DamageableItem cares about unbreaking levels")
void testDamageableItemCaresUnbreaking() {
DamageableMock noUnbreakingItem = getDummyItem("NU", true, null, null);
DamageableMock iiiUnbreakingItem = getDummyItem("IIIU", true, Enchantment.DURABILITY, 3);
DamageableMock xUnbreakingItem = getDummyItem("XU", true, Enchantment.DURABILITY, 10);
ItemStack noUnbreakingItemIS = noUnbreakingItem.getItem().clone();
ItemStack iiiUnbreakingItemIS = iiiUnbreakingItem.getItem().clone();
ItemStack xUnbreakingItemIS = xUnbreakingItem.getItem().clone();
Player player = server.addPlayer();
for (int i = 0; i < 500; ++i) {
noUnbreakingItem.damageItem(player, noUnbreakingItemIS);
noUnbreakingItem.damageItem(player, iiiUnbreakingItemIS);
noUnbreakingItem.damageItem(player, xUnbreakingItemIS);
}
Assertions.assertTrue(noUnbreakingItemIS.hasItemMeta());
Assertions.assertTrue(iiiUnbreakingItemIS.hasItemMeta());
Assertions.assertTrue(xUnbreakingItemIS.hasItemMeta());
Assertions.assertTrue(((Damageable) xUnbreakingItemIS.getItemMeta()).getDamage() < ((Damageable) iiiUnbreakingItemIS.getItemMeta()).getDamage());
Assertions.assertTrue(((Damageable) iiiUnbreakingItemIS.getItemMeta()).getDamage() < ((Damageable) noUnbreakingItemIS.getItemMeta()).getDamage());
}
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.testing.tests.items.auto_crafters;
package io.github.thebusybiscuit.slimefun4.testing.tests.items.autocrafters;
import java.util.Arrays;
import java.util.HashSet;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.testing.tests.items.auto_crafters;
package io.github.thebusybiscuit.slimefun4.testing.tests.items.autocrafters;
import javax.annotation.Nonnull;
@ -69,6 +69,58 @@ class TestAutoCrafter {
Assertions.assertTrue(inv.containsAtLeast(result, 1));
}
@Test
@DisplayName("Test crafting a valid ShapelessRecipe")
void testDisabledRecipe() {
NamespacedKey key = new NamespacedKey(plugin, "disabled_recipe_test");
ItemStack result = new CustomItem(Material.DIAMOND, "&bAmazing Diamond :o");
ShapelessRecipe recipe = new ShapelessRecipe(key, result);
recipe.addIngredient(new MaterialChoice(Material.GOLD_NUGGET));
AbstractRecipe abstractRecipe = AbstractRecipe.of(recipe);
AbstractAutoCrafter crafter = getVanillaAutoCrafter();
InventoryMock inv = new ChestInventoryMock(null, 9);
// Test enabled Recipe
abstractRecipe.setEnabled(true);
inv.addItem(new ItemStack(Material.GOLD_NUGGET));
Assertions.assertTrue(crafter.craft(inv, abstractRecipe));
Assertions.assertFalse(inv.contains(Material.GOLD_NUGGET, 1));
Assertions.assertTrue(inv.containsAtLeast(result, 1));
inv.clear();
// Test disabled Recipe
abstractRecipe.setEnabled(false);
inv.addItem(new ItemStack(Material.GOLD_NUGGET));
Assertions.assertFalse(crafter.craft(inv, abstractRecipe));
Assertions.assertTrue(inv.contains(Material.GOLD_NUGGET, 1));
Assertions.assertFalse(inv.containsAtLeast(result, 1));
}
@Test
@DisplayName("Test resource leftovers when crafting")
void testResourceLeftovers() {
NamespacedKey key = new NamespacedKey(plugin, "resource_leftovers_test");
ItemStack result = new CustomItem(Material.DIAMOND, "&9Diamond. Nuff said.");
ShapelessRecipe recipe = new ShapelessRecipe(key, result);
recipe.addIngredient(new MaterialChoice(Material.HONEY_BOTTLE));
recipe.addIngredient(new MaterialChoice(Material.HONEY_BOTTLE));
AbstractRecipe abstractRecipe = AbstractRecipe.of(recipe);
AbstractAutoCrafter crafter = getVanillaAutoCrafter();
InventoryMock inv = new ChestInventoryMock(null, 9);
inv.addItem(new ItemStack(Material.HONEY_BOTTLE, 2));
Assertions.assertTrue(crafter.craft(inv, abstractRecipe));
Assertions.assertFalse(inv.contains(Material.HONEY_BOTTLE, 2));
Assertions.assertTrue(inv.containsAtLeast(result, 1));
// Check for leftovers
Assertions.assertTrue(inv.contains(Material.GLASS_BOTTLE, 2));
}
@Test
@DisplayName("Test crafting an invalid ShapelessRecipe")
void testInvalidShapelessRecipe() {

View File

@ -1,11 +1,16 @@
package io.github.thebusybiscuit.slimefun4.testing.tests.listeners;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundItem;
import io.github.thebusybiscuit.slimefun4.testing.TestUtilities;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import org.bukkit.Material;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -17,7 +22,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SoulboundListener;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
public class TestSoulboundListener {
class TestSoulboundListener {
private static SlimefunPlugin plugin;
private static ServerMock server;
@ -36,7 +41,8 @@ public class TestSoulboundListener {
@ParameterizedTest
@ValueSource(booleans = { true, false })
public void testItemDrop(boolean soulbound) {
@DisplayName("Test if the soulbound item is dropped or not")
void testItemDrop(boolean soulbound) {
PlayerMock player = server.addPlayer();
ItemStack item = new CustomItem(Material.DIAMOND_SWORD, "&4Cool Sword");
SlimefunUtils.setSoulbound(item, soulbound);
@ -50,7 +56,32 @@ public class TestSoulboundListener {
@ParameterizedTest
@ValueSource(booleans = { true, false })
public void testItemRecover(boolean soulbound) {
@DisplayName("Test if soulbound item is dropped if disabled")
void testItemDropIfItemDisabled(boolean enabled) {
PlayerMock player = server.addPlayer();
SlimefunItemStack item = new SlimefunItemStack("SOULBOUND_ITEM_" + (enabled ? "ENABLED" : "DISABLED"), Material.DIAMOND_SWORD, "&5Soulbound Sword");
SoulboundItem soulboundItem = new SoulboundItem(TestUtilities.getCategory(plugin, "soulbound"), item, RecipeType.NULL, new ItemStack[9]);
soulboundItem.register(plugin);
if (!enabled) {
SlimefunPlugin.getWorldSettingsService().setEnabled(player.getWorld(), soulboundItem, false);
}
player.getInventory().setItem(0, item);
player.setHealth(0);
server.getPluginManager().assertEventFired(EntityDeathEvent.class, event -> {
// If the item is enabled, we don't want it to drop.
return enabled == !event.getDrops().contains(item);
});
SlimefunPlugin.getRegistry().getEnabledSlimefunItems().remove(soulboundItem);
}
@ParameterizedTest
@ValueSource(booleans = { true, false })
@DisplayName("Test if soulbound item is returned to player")
void testItemRecover(boolean soulbound) {
PlayerMock player = server.addPlayer();
ItemStack item = new CustomItem(Material.DIAMOND_SWORD, "&4Cool Sword");
SlimefunUtils.setSoulbound(item, soulbound);