Fixed crafting, deprecated now-unneeded API

This commit is contained in:
Auxilor
2022-03-01 10:24:38 +00:00
parent 79d6277d94
commit 4cb630d201
10 changed files with 138 additions and 227 deletions

View File

@@ -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.
*

View File

@@ -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

View File

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

View File

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

View File

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

View File

@@ -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),

View File

@@ -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)) {

View File

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

View File

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

View File

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