'(1.16.5) Crafting table with multiple items in one slot
I want to make a crafting table (custom) that will accept any vanilla and modded recipes AND my custom recipes with multiple items in slots (and for the table to recognize it). I've tried extending WorkbenchContainer class (kinda working, but shift click added items to the crafting grid), copying its code and making my own (doesn't do anything).
class CompressorContainer @JvmOverloads constructor(
id: Int, playerInventory: PlayerInventory, private val worldPosCallable: IWorldPosCallable = IWorldPosCallable.DUMMY
) :
RecipeBookContainer<CraftingInventory?>(ContainerType.CRAFTING, id) {
private val craftMatrix = CraftingInventory(this, 3, 3)
private val craftResult = CraftResultInventory()
private val player: PlayerEntity
init {
player = playerInventory.player
addSlot(CraftingResultSlot(playerInventory.player, craftMatrix, craftResult, 0, 124, 35))
for (i in 0..2) {
for (j in 0..2) {
addSlot(Slot(craftMatrix, 1 + j + i * 3, 30 + j * 18, 17 + i * 18))
}
}
for (k in 0..2) {
for (i1 in 0..8) {
addSlot(Slot(playerInventory, i1 + k * 9 + 9, 8 + i1 * 18, 84 + k * 18))
}
}
for (l in 0..8) {
addSlot(Slot(playerInventory, l, 8 + l * 18, 142))
}
}
/**
* Callback for when the crafting matrix is changed.
*/
override fun onCraftMatrixChanged(inventoryIn: IInventory) {
worldPosCallable.consume { world: World, _: BlockPos? ->
updateCraftingResult(
windowId,
world,
player
)
}
}
override fun fillStackedContents(itemHelperIn: RecipeItemHelper) {
craftMatrix.fillStackedContents(itemHelperIn)
}
override fun clear() {
craftMatrix.clear()
craftResult.clear()
}
override fun matches(recipeIn: IRecipe<in CraftingInventory?>): Boolean {
return recipeIn.matches(craftMatrix, player.world)
}
/**
* Called when the container is closed.
*/
override fun onContainerClosed(playerIn: PlayerEntity) {
super.onContainerClosed(playerIn)
worldPosCallable.consume { p_217068_2_: World, _: BlockPos ->
clearContainer(
playerIn,
p_217068_2_,
craftMatrix
)
}
}
/**
* Determines whether supplied player can use this container
*/
override fun canInteractWith(playerIn: PlayerEntity): Boolean {
return isWithinUsableDistance(worldPosCallable, playerIn, Blocks.COMPRESSOR)
}
/**
* Handle when the stack in slot `index` is shift-clicked. Normally this moves the stack between the player
* inventory and the other inventory(s).
*/
override fun transferStackInSlot(playerIn: PlayerEntity, index: Int): ItemStack {
var itemstack = ItemStack.EMPTY
val slot = inventorySlots[index]
if (slot != null && slot.hasStack) {
val itemstack1 = slot.stack
itemstack = itemstack1.copy()
if (index == 0) {
worldPosCallable.consume { p_217067_2_: World, _: BlockPos ->
itemstack1.item.onCreated(itemstack1, p_217067_2_, playerIn)
}
if (!mergeItemStack(itemstack1, 10, 46, true)) {
return ItemStack.EMPTY
}
slot.onSlotChange(itemstack1, itemstack)
} else if (index in 10..45) {
if (!mergeItemStack(itemstack1, 1, 10, false)) {
if (index < 37) {
if (!mergeItemStack(itemstack1, 37, 46, false)) {
return ItemStack.EMPTY
}
} else if (!mergeItemStack(itemstack1, 10, 37, false)) {
return ItemStack.EMPTY
}
}
} else if (!mergeItemStack(itemstack1, 10, 46, false)) {
return ItemStack.EMPTY
}
if (itemstack1.isEmpty) {
slot.putStack(ItemStack.EMPTY)
} else {
slot.onSlotChanged()
}
if (itemstack1.count == itemstack.count) {
return ItemStack.EMPTY
}
val itemstack2 = slot.onTake(playerIn, itemstack1)
if (index == 0) {
playerIn.dropItem(itemstack2, false)
}
}
return itemstack
}
/**
* Called to determine if the current slot is valid for the stack merging (double-click) code. The stack passed in is
* null for the initial slot that was double-clicked.
*/
override fun canMergeSlot(stack: ItemStack, slotIn: Slot): Boolean {
return slotIn.inventory !== craftResult && super.canMergeSlot(stack, slotIn)
}
override fun getOutputSlot(): Int {
return 0
}
override fun getWidth(): Int {
return craftMatrix.width
}
override fun getHeight(): Int {
return craftMatrix.height
}
@OnlyIn(Dist.CLIENT)
override fun getSize(): Int {
return 10
}
@OnlyIn(Dist.CLIENT)
override fun func_241850_m(): RecipeBookCategory {
return RecipeBookCategory.CRAFTING
}
fun updateCraftingResult(
id: Int, world: World, player: PlayerEntity
) {
if (!world.isRemote) {
var itemstack = ItemStack.EMPTY
val spe = player as ServerPlayerEntity
val optional = Skyblock.RECIPE.getRecipe(IRecipeType.CRAFTING, craftMatrix, world)
val c = craftMatrix.contents.sortedByDescending { it.count }
if (optional.isPresent) {
val icraftingrecipe = optional.get()
if (craftResult.canUseRecipe(world, spe, icraftingrecipe)) {
itemstack = icraftingrecipe.getCraftingResult(craftMatrix)
}
} else {
when (c) {
ItemStack(MCItems.DIAMOND, 32) * 5, listOf(
*(ItemStack(
MCItems.DIAMOND,
64
) * 2).toTypedArray(),
ItemStack(MCItems.DIAMOND, 32)
) -> Items.ENCH_DIAMOND
ItemStack(MCItems.GOLD_INGOT, 32) * 5 -> Items.ENCH_GOLD
else -> null
}?.let { it: Item? ->
if (it != null) itemstack = it.provider
}
}
craftResult.setInventorySlotContents(0, itemstack)
spe.connection.sendPacket(SSetSlotPacket(id, 0, itemstack))
}
}
}
val CraftingInventory.contents: List<ItemStack>
get() {
val l = mutableListOf<ItemStack>()
for (i in 0 until width * height) {
l.add(getStackInSlot(i))
}
return l.toList()
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
