Fixed crafting, deprecated now-unneeded API
This commit is contained in:
@@ -57,6 +57,23 @@ public class GroupedTestableItems implements TestableItem {
|
||||
throw new IllegalStateException("Empty group of children!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matching child for an ItemStack.
|
||||
*
|
||||
* @param itemStack The ItemStack.
|
||||
* @return The matching child, or null if the item matches nothing.
|
||||
*/
|
||||
@Nullable
|
||||
public TestableItem getMatchingChild(@NotNull final ItemStack itemStack) {
|
||||
for (TestableItem child : children) {
|
||||
if (child.matches(itemStack)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the children.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.core.recipe.parts;
|
||||
|
||||
import com.willfp.eco.core.items.Items;
|
||||
import com.willfp.eco.core.items.TestableItem;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Material;
|
||||
@@ -35,7 +36,13 @@ public class MaterialTestableItem implements TestableItem {
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(@Nullable final ItemStack itemStack) {
|
||||
return itemStack != null && itemStack.getType() == material;
|
||||
boolean simpleMatches = itemStack != null && itemStack.getType() == material;
|
||||
|
||||
if (!simpleMatches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Items.isCustomItem(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.willfp.eco.util;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@@ -9,28 +8,16 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Utilities / API methods for blocks.
|
||||
*/
|
||||
public final class BlockUtils {
|
||||
/**
|
||||
* If the meta set function has been set.
|
||||
*/
|
||||
private static boolean initialized = false;
|
||||
|
||||
/**
|
||||
* The block break function.
|
||||
*/
|
||||
private static BiConsumer<Player, Block> blockBreakConsumer = null;
|
||||
|
||||
private static Set<Block> getNearbyBlocks(@NotNull final Block start,
|
||||
@NotNull final List<Material> allowedMaterials,
|
||||
@NotNull final Set<Block> blocks,
|
||||
@@ -75,12 +62,11 @@ public final class BlockUtils {
|
||||
*
|
||||
* @param player The player to break the block as.
|
||||
* @param block The block to break.
|
||||
* @deprecated Added into spigot API in 1.17.1
|
||||
*/
|
||||
@Deprecated(since = "6.26.2", forRemoval = true)
|
||||
public static void breakBlock(@NotNull final Player player,
|
||||
@NotNull final Block block) {
|
||||
Validate.isTrue(initialized, "Must be initialized!");
|
||||
Validate.notNull(blockBreakConsumer, "Must be initialized!");
|
||||
|
||||
Location location = block.getLocation();
|
||||
World world = location.getWorld();
|
||||
assert world != null;
|
||||
@@ -89,7 +75,7 @@ public final class BlockUtils {
|
||||
return;
|
||||
}
|
||||
|
||||
blockBreakConsumer.accept(player, block);
|
||||
player.breakBlock(block);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,20 +93,6 @@ public final class BlockUtils {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the block break function.
|
||||
*
|
||||
* @param function The function.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public static void initialize(@NotNull final BiConsumer<Player, Block> function) {
|
||||
Validate.isTrue(!initialized, "Already initialized!");
|
||||
|
||||
blockBreakConsumer = function;
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private BlockUtils() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
|
||||
|
||||
import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class BlockBreak : BlockBreakProxy {
|
||||
override fun breakBlock(
|
||||
player: Player,
|
||||
block: Block
|
||||
) {
|
||||
player.breakBlock(block)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
|
||||
|
||||
import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class BlockBreak : BlockBreakProxy {
|
||||
override fun breakBlock(
|
||||
player: Player,
|
||||
block: Block
|
||||
) {
|
||||
player.breakBlock(block)
|
||||
}
|
||||
}
|
||||
@@ -106,15 +106,13 @@ import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl
|
||||
import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
|
||||
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
|
||||
import com.willfp.eco.internal.spigot.math.evaluateExpression
|
||||
import com.willfp.eco.internal.spigot.proxy.BlockBreakProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.SkullProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.TPSProxy
|
||||
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
|
||||
import com.willfp.eco.internal.spigot.recipes.StackedRecipeListener
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInEco
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
|
||||
import com.willfp.eco.util.BlockUtils
|
||||
import com.willfp.eco.util.NumberUtils
|
||||
import com.willfp.eco.util.ServerUtils
|
||||
import com.willfp.eco.util.SkullUtils
|
||||
@@ -158,7 +156,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
Entities.registerArgParser(EntityArgParserEquipment())
|
||||
|
||||
ShapedRecipeListener.registerListener(ComplexInComplex())
|
||||
ShapedRecipeListener.registerListener(ComplexInEco())
|
||||
ShapedRecipeListener.registerListener(ComplexInVanilla())
|
||||
|
||||
SegmentParserGroup().register()
|
||||
@@ -170,9 +167,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
{ meta -> skullProxy.getSkullTexture(meta) }
|
||||
)
|
||||
|
||||
val blockBreakProxy = getProxy(BlockBreakProxy::class.java)
|
||||
BlockUtils.initialize { player, block -> blockBreakProxy.breakBlock(player, block) }
|
||||
|
||||
val tpsProxy = getProxy(TPSProxy::class.java)
|
||||
ServerUtils.initialize { tpsProxy.getTPS() }
|
||||
|
||||
@@ -322,6 +316,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
ArmorListener(),
|
||||
EntityDeathByEntityListeners(this),
|
||||
ShapedRecipeListener(),
|
||||
StackedRecipeListener(this),
|
||||
GUIListener(this),
|
||||
ArrowDataListener(this),
|
||||
ArmorChangeEventListeners(this),
|
||||
|
||||
@@ -2,95 +2,14 @@ package com.willfp.eco.internal.spigot.recipes
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.recipe.Recipes
|
||||
import com.willfp.eco.core.recipe.parts.TestableStack
|
||||
import org.bukkit.Keyed
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.inventory.CraftItemEvent
|
||||
import org.bukkit.event.inventory.PrepareItemCraftEvent
|
||||
import org.bukkit.event.player.PlayerRecipeDiscoverEvent
|
||||
import org.bukkit.inventory.ShapedRecipe
|
||||
|
||||
class ShapedRecipeListener : Listener {
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
fun stackedRecipeListener(event: CraftItemEvent) {
|
||||
val recipe = event.recipe as? ShapedRecipe ?: return
|
||||
|
||||
if (!EcoPlugin.getPluginNames().contains(recipe.key.namespace)) {
|
||||
return
|
||||
}
|
||||
|
||||
val matrix = event.inventory.matrix
|
||||
|
||||
val wrapped = WrappedCraftItemEvent(event)
|
||||
|
||||
if (validators.any { it.validate(wrapped) }) {
|
||||
return
|
||||
}
|
||||
|
||||
val matched = Recipes.getMatch(matrix)
|
||||
|
||||
if (matched == null) {
|
||||
wrapped.deny()
|
||||
return
|
||||
}
|
||||
|
||||
var isStackedRecipe = false
|
||||
var upperBound = 64
|
||||
for (i in 0..8) {
|
||||
val inMatrix = event.inventory.matrix.getOrNull(i)
|
||||
val inRecipe = matched.parts[i]
|
||||
|
||||
if (inRecipe is TestableStack) {
|
||||
val max = Math.floorDiv(inMatrix!!.amount, inRecipe.amount)
|
||||
if (max < upperBound) {
|
||||
upperBound = max
|
||||
}
|
||||
isStackedRecipe = true
|
||||
} else if (inMatrix != null) {
|
||||
val max = inMatrix.amount
|
||||
if (max < upperBound) {
|
||||
upperBound = max
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isStackedRecipe) {
|
||||
return
|
||||
}
|
||||
|
||||
val toGivePerRecipe = event.recipe.result.amount
|
||||
val maxStackSize = event.recipe.result.maxStackSize
|
||||
while (toGivePerRecipe * upperBound > maxStackSize) {
|
||||
upperBound--
|
||||
}
|
||||
|
||||
for (i in 0..8) {
|
||||
val inMatrix = event.inventory.matrix[i]
|
||||
val inRecipe = matched.parts[i]
|
||||
|
||||
if (inRecipe is TestableStack) {
|
||||
if (event.isShiftClick) {
|
||||
var amount = inMatrix.amount + 1
|
||||
for (j in 0..upperBound) {
|
||||
amount -= inRecipe.amount
|
||||
}
|
||||
inMatrix.amount = amount
|
||||
} else {
|
||||
inMatrix.amount = inMatrix.amount - (inRecipe.amount - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.isShiftClick) {
|
||||
val result = event.inventory.result ?: return
|
||||
|
||||
result.amount = result.amount * upperBound
|
||||
event.inventory.result = result
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun preventLearningDisplayedRecipes(event: PlayerRecipeDiscoverEvent) {
|
||||
if (!EcoPlugin.getPluginNames().contains(event.recipe.namespace)) {
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.willfp.eco.internal.spigot.recipes
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.recipe.Recipes
|
||||
import com.willfp.eco.core.recipe.parts.GroupedTestableItems
|
||||
import com.willfp.eco.core.recipe.parts.TestableStack
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.inventory.CraftingInventory
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class StackedRecipeListener(
|
||||
private val plugin: EcoPlugin
|
||||
) : Listener {
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
fun handleStacks(event: InventoryClickEvent) {
|
||||
val inventory = event.clickedInventory as? CraftingInventory ?: return
|
||||
if (event.slot != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val matrix = inventory.matrix
|
||||
|
||||
val recipe = Recipes.getMatch(matrix) ?: return
|
||||
|
||||
var isStackedRecipe = false
|
||||
var maxCraftable = Int.MAX_VALUE
|
||||
|
||||
// Start by calculating the maximum number of items to craft
|
||||
for (i in 0..8) {
|
||||
val item = inventory.matrix.getOrNull(i) ?: continue
|
||||
val part = recipe.parts[i].let {
|
||||
if (it is GroupedTestableItems) {
|
||||
it.getMatchingChild(item)
|
||||
} else it
|
||||
} ?: continue
|
||||
|
||||
if (part is TestableStack) {
|
||||
isStackedRecipe = true
|
||||
}
|
||||
|
||||
maxCraftable = min(maxCraftable, Math.floorDiv(item.amount, part.item.amount))
|
||||
}
|
||||
|
||||
if (!isStackedRecipe) {
|
||||
return
|
||||
}
|
||||
|
||||
// Don't allow crafting above the max stack size of the output
|
||||
maxCraftable = min(maxCraftable, Math.floorDiv(recipe.output.maxStackSize, recipe.output.amount))
|
||||
|
||||
Bukkit.getLogger().info("Amount to craft: $maxCraftable")
|
||||
|
||||
// Deduct the correct number of items from the inventory
|
||||
for (i in 0..8) {
|
||||
val item = inventory.matrix.getOrNull(i) ?: continue
|
||||
val part = recipe.parts[i].let {
|
||||
if (it is GroupedTestableItems) {
|
||||
it.getMatchingChild(item)
|
||||
} else it
|
||||
} ?: continue
|
||||
|
||||
val amount = max(
|
||||
if (event.isShiftClick) {
|
||||
item.amount - (part.item.amount * maxCraftable)
|
||||
} else {
|
||||
item.amount - part.item.amount
|
||||
}, 0
|
||||
)
|
||||
|
||||
println("Setting amount of ${item.type} to $amount")
|
||||
|
||||
// Anti-Underflow
|
||||
if (amount == 0) {
|
||||
item.type = Material.AIR
|
||||
}
|
||||
item.amount = amount
|
||||
|
||||
val newItem = item.clone()
|
||||
|
||||
// Do it twice because spigot hates me
|
||||
// Everything has to be cloned because the inventory changes the item
|
||||
inventory.matrix[i] = item // Use un-cloned version first
|
||||
plugin.scheduler.run {
|
||||
println("Setting ${inventory.matrix[i]} to $newItem")
|
||||
inventory.matrix[i] = newItem
|
||||
inventory.setItem(i + 1, newItem)
|
||||
// Just to be safe, modify the instance (safe check) Using ?. causes a warning.
|
||||
if (inventory.matrix[i] != null) {
|
||||
inventory.matrix[i].amount = amount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply the result by the amount to craft if shift-clicking
|
||||
if (event.isShiftClick) {
|
||||
val result = inventory.result ?: return
|
||||
|
||||
result.amount *= maxCraftable
|
||||
inventory.result = result
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.willfp.eco.internal.spigot.recipes.listeners
|
||||
|
||||
import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.core.items.TestableItem
|
||||
import com.willfp.eco.core.recipe.Recipes
|
||||
import com.willfp.eco.core.recipe.parts.GroupedTestableItems
|
||||
import com.willfp.eco.core.recipe.parts.MaterialTestableItem
|
||||
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem
|
||||
import com.willfp.eco.core.recipe.parts.TestableStack
|
||||
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe
|
||||
import com.willfp.eco.internal.spigot.recipes.GenericCraftEvent
|
||||
import com.willfp.eco.internal.spigot.recipes.RecipeListener
|
||||
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class ComplexInEco : RecipeListener {
|
||||
override fun handle(event: GenericCraftEvent) {
|
||||
val craftingRecipe = Recipes.getRecipe(event.recipe.key)
|
||||
|
||||
if (craftingRecipe !is ShapedCraftingRecipe) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ShapedRecipeListener.validators.any { it.validate(event) }) {
|
||||
return
|
||||
}
|
||||
|
||||
for (i in 0..8) {
|
||||
val itemStack = event.inventory.matrix[i] ?: continue
|
||||
val part = craftingRecipe.parts[i]
|
||||
if (part.isCustomWhenShouldNotBe(itemStack)) {
|
||||
event.deny()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestableItem.isCustomWhenShouldNotBe(itemStack: ItemStack): Boolean {
|
||||
when (this) {
|
||||
is MaterialTestableItem -> {
|
||||
if (Items.isCustomItem(itemStack)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
is ModifiedTestableItem -> {
|
||||
if (this.handle is MaterialTestableItem) {
|
||||
if (Items.isCustomItem(itemStack)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
is TestableStack -> {
|
||||
if (this.handle is MaterialTestableItem) {
|
||||
if (Items.isCustomItem(itemStack)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
is GroupedTestableItems -> {
|
||||
// This will fail if and only if there is a complex item grouped with a simple item of the same type
|
||||
if (this.children.any { it.isCustomWhenShouldNotBe(itemStack) && it.matches(itemStack) }) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.willfp.eco.internal.spigot.proxy
|
||||
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
interface BlockBreakProxy {
|
||||
fun breakBlock(
|
||||
player: Player,
|
||||
block: Block
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user