Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ class InteractSim internal constructor(simInfo: InteractSimInfo)
countEmptyAsOne()
alwaysWholeStacks()
item?.let { isItem(it) }
(targetState as? TargetState.Stack)?.let { target ->
sortedWith { compareByDescending { it.stack === target.itemStack } }
}
sortedWith { compareByDescending { it.slot?.index == player.inventory.selectedSlot } }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ abstract class Container(

open val isAccessed get() = true

open fun slotIdentity(index: Int): SlotIdentity? = null

context(_: SafeContext)
fun descriptionAndStock(selection: StackSelection) =
buildText {
Expand Down Expand Up @@ -114,7 +116,7 @@ abstract class Container(

fun scanStacksForNestedContainers() {
stacks.forEachIndexed { index, stack ->
if (stack.item in SHULKER_BOXES) {
if (stack.item in SHULKER_BOXES && slotIdentity(index) != null) {
storedContainers[index] =
ShulkerBoxContainer(
stack.name.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ abstract class NestedContainer(type: ContainerType) : Container(type), ExternalC
abstract val containedIn: Container
abstract val index: Int

val slotIdentity get() = containedIn.slotIdentity(index)

override val dimension get() = containedIn.dimension

context(_: Automated)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import com.lambda.task.Task.Ta5kBuilder
import com.lambda.task.tasks.wrappers.actionTask

interface OpenedContainerContext {
val container: Container? get() = null

@Ta5kBuilder
context(automated: Automated)
fun close(): Task<*>?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ abstract class PlacedContainer(
) : Container(type), ExternalContainer {
abstract val pos: BlockPos
abstract val stash: StashContainer?
open val positions: Set<BlockPos> = setOf(pos)
open val positions: Set<BlockPos> get() = setOf(pos)

override fun slotIdentity(index: Int) = SlotIdentity.Placed(positions, index)
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ sealed interface SlotIdentity {
if (live.isEmpty || stack.isEmpty) return false
return live.item == stack.item && live.name.string == stack.name.string
}

context(safeContext: SafeContext)
fun isEmpty() = resolve()?.stack?.isEmpty == true
}

fun Slot.identity(): SlotIdentity? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.lambda.interaction.container.containers
import com.lambda.Lambda.mc
import com.lambda.interaction.container.Container
import com.lambda.interaction.container.ContainerType
import com.lambda.interaction.container.SlotIdentity
import com.lambda.util.player.SlotUtils.armorSlots
import com.lambda.util.player.SlotUtils.armorStacks
import com.lambda.util.text.buildText
Expand All @@ -37,4 +38,6 @@ object ArmorContainer : Container(ContainerType.Armor) {
override val description = buildText { literal("Armor") }

override val isAccessed get() = mc.player?.currentScreenHandler?.syncId == 0

override fun slotIdentity(index: Int) = SlotIdentity.Player(index)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.lambda.Lambda.mc
import com.lambda.context.SafeContext
import com.lambda.interaction.container.Container
import com.lambda.interaction.container.ContainerType
import com.lambda.interaction.container.SlotIdentity
import com.lambda.interaction.manager.managers.inventory.InvRequestBuilder
import com.lambda.util.player.SlotUtils.hotbarSlots
import com.lambda.util.player.SlotUtils.hotbarStacks
Expand All @@ -39,6 +40,8 @@ object HotbarContainer : Container(ContainerType.Hotbar) {

override val description = buildText { literal("Hotbar") }

override fun slotIdentity(index: Int) = SlotIdentity.Player(index)

context(safeContext: SafeContext)
override fun InvRequestBuilder.swap(fromHere: Slot, toSlot: Slot) {
swapWithHotbar(toSlot.id, safeContext.player.hotbarSlots.indexOf(fromHere))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.lambda.interaction.container.containers
import com.lambda.Lambda.mc
import com.lambda.interaction.container.Container
import com.lambda.interaction.container.ContainerType
import com.lambda.interaction.container.SlotIdentity
import com.lambda.util.player.SlotUtils.inventorySlots
import com.lambda.util.player.SlotUtils.inventoryStacks
import com.lambda.util.text.buildText
Expand All @@ -35,4 +36,6 @@ object InventoryContainer : Container(ContainerType.Inventory) {
set(_) {}

override val description = buildText { literal("Inventory") }

override fun slotIdentity(index: Int) = SlotIdentity.Player(index)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.lambda.Lambda.mc
import com.lambda.context.SafeContext
import com.lambda.interaction.container.Container
import com.lambda.interaction.container.ContainerType
import com.lambda.interaction.container.SlotIdentity
import com.lambda.interaction.manager.managers.inventory.InvRequestBuilder
import com.lambda.util.player.SlotUtils.offHandSlots
import com.lambda.util.text.buildText
Expand All @@ -39,6 +40,8 @@ object OffhandContainer : Container(ContainerType.OffHand) {

override val description = buildText { literal("OffHand") }

override fun slotIdentity(index: Int) = SlotIdentity.Player(index)

context(_: SafeContext)
override fun InvRequestBuilder.swap(fromHere: Slot, toSlot: Slot) {
swapWithHotbar(toSlot.id, 40)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ data class ChestContainer(
automated: Automated
) : OpenContainerTask<OpenedContainerContext>(description), Automated by automated {
override fun SafeContext.onStart() {
openContainer(pos)
openContainer<ChestContainer>(pos)
.onSuccess { success(BasicOpenedContainerContext(::isAccessed)) }
.start()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ data class DoubleChestContainer(
val rightDist = rightPos distSq player.pos
val closestPos = if (leftDist <= rightDist) leftPos else rightPos
val farthestPos = if (leftDist > rightDist) leftPos else rightPos
openContainer(closestPos)
.withRecovery { openContainer(farthestPos) }
openContainer<DoubleChestContainer>(closestPos)
.withRecovery { openContainer<DoubleChestContainer>(farthestPos) }
.onSuccess { success(BasicOpenedContainerContext(::isAccessed)) }
.start()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.lambda.interaction.container.ContainerType
import com.lambda.interaction.container.ExternalContainer
import com.lambda.interaction.container.OpenContainerTask
import com.lambda.interaction.container.OpenedContainerContext
import com.lambda.interaction.container.SlotIdentity
import com.lambda.interaction.container.containers.HotbarContainer
import com.lambda.interaction.container.selection.select
import com.lambda.interaction.handler.handlers.ContainerHandler.findSlot
Expand Down Expand Up @@ -67,6 +68,8 @@ object EnderChestContainer : Container(ContainerType.EnderChest), ExternalContai
mc.player?.currentScreenHandler?.typeSafe == ScreenHandlerType.GENERIC_9X3
} ?: false

override fun slotIdentity(index: Int) = SlotIdentity.Ender(index)

@Ta5kBuilder
context(automated: Automated)
override fun access() =
Expand All @@ -79,15 +82,15 @@ object EnderChestContainer : Container(ContainerType.EnderChest), ExternalContai
override fun SafeContext.onStart() {
findBlock(Blocks.ENDER_CHEST, inventoryConfig.enderChestSearchRadius).withBranch(
onSuccess = { pos ->
openContainer(pos).onSuccess {
openContainer<EnderChestContainer>(pos).onSuccess {
success(OpenedEnderChestContext(null))
}
},
onFailure = {
acquireStack(Items.ENDER_CHEST.select())
.then { placeContainer(findSlot(it, HotbarContainer.select())) }
.then { pos ->
openContainer(pos).onSuccess {
openContainer<EnderChestContainer>(pos).onSuccess {
success(OpenedEnderChestContext(pos))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class PlacedShulkerBoxContainer(
automated: Automated
) : OpenContainerTask<BasicOpenedContainerContext>(description), Automated by automated {
override fun SafeContext.onStart() {
openContainer(pos)
openContainer<PlacedShulkerBoxContainer>(pos)
.onSuccess { success(BasicOpenedContainerContext(::isAccessed)) }
.start()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import com.lambda.interaction.container.NestedContainer
import com.lambda.interaction.container.OpenContainerTask
import com.lambda.interaction.container.OpenedContainerContext
import com.lambda.interaction.container.containers.HotbarContainer
import com.lambda.interaction.container.identity
import com.lambda.interaction.container.selection.ContainerSelection
import com.lambda.interaction.container.selection.mutate
import com.lambda.interaction.container.selection.select
import com.lambda.interaction.container.selection.stackSelection
import com.lambda.interaction.handler.handlers.ContainerHandler.findSlot
Expand All @@ -40,16 +40,17 @@ import com.lambda.task.tasks.openContainer
import com.lambda.task.tasks.placeContainer
import com.lambda.task.tasks.transfer
import com.lambda.task.tasks.wrappers.actionTask
import com.lambda.task.tasks.wrappers.softFail
import com.lambda.task.tasks.wrappers.taskOrNull
import com.lambda.task.tasks.wrappers.then
import com.lambda.task.tasks.wrappers.thenOrNull
import com.lambda.util.extension.containerSlots
import com.lambda.util.text.buildText
import com.lambda.util.text.highlighted
import com.lambda.util.text.literal
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.screen.slot.Slot
import net.minecraft.util.math.BlockPos
import java.util.Objects.hash

data class ShulkerBoxContainer(
Expand Down Expand Up @@ -82,67 +83,64 @@ data class ShulkerBoxContainer(
automated: Automated
) : OpenContainerTask<OpenedShulkerBoxContext>(description), Automated by automated {
override fun SafeContext.onStart() {
transfer(
stackSelection {
sortedWith { compareByDescending { it.slot?.index == index } }
isItem(shulkerItem)
withName(itemName)
sortedByBestContentMatch(stacks)
},
containedIn.select(ContainerSearchScope.Loaded),
HotbarContainer.select()
).then { result ->
placeContainer(
findSlot(
result.stackSelection.mutate {
sortedByRecentChange()
},
result.containerSelection
)
)
val selection = stackSelection {
isItem(shulkerItem)
withName(itemName)
slotIdentity?.let { sortedBySlotMatch(it) }
sortedByBestContentMatch(stacks)
}
taskOrNull {
if (containedIn == HotbarContainer) null
else selection.transfer(containedIn.select(ContainerSearchScope.Loaded), HotbarContainer.select())
}.then { result ->
placeContainer(findSlot(result?.stackSelection ?: selection, HotbarContainer.select()))
}.then { pos ->
openContainer(pos).onSuccess {
success(OpenedShulkerBoxContext(pos))
openContainer<PlacedShulkerBoxContainer>(pos).onSuccess {
success(OpenedShulkerBoxContext(it))
}
}.start()
}
}

inner class OpenedShulkerBoxContext(
val blockPos: BlockPos,
override val container: PlacedShulkerBoxContainer,
) : OpenedContainerContext {
context(automated: Automated)
override fun close(): Task<*> {
return taskOrNull {
if (!isAccessed) null
if (!container.isAccessed) null
else actionTask { player.closeHandledScreen() }
}.then { breakAndCollect(blockPos) }
.then { outcome ->
val pickedUp = outcome.pickups
.asSequence()
.filter { it.stack.item == shulkerItem && it.stack.name.string == itemName }
.firstNotNullOfOrNull { it.slot }
}.then {
breakAndCollect(container.pos)
}.thenOrNull { outcome ->
val ownSlot = slotIdentity ?: return@thenOrNull null
val pickedUp = outcome.pickups
.asSequence()
.filter { it.stack.item == shulkerItem && it.stack.name.string == itemName }
.firstNotNullOfOrNull { it.slot }
val inContainer = pickedUp != null && containedIn.slots.any { it.identity() == pickedUp }
if (inContainer && !ownSlot.isEmpty()) return@thenOrNull null

stackSelection {
isItem(shulkerItem)
withName(itemName)
if (pickedUp != null) predicate { _, slot -> slot?.identity() == pickedUp }
sortedByBestContentMatch(container.stacks)
sortedByRecentChange()
}.transfer(
ContainerSelection.HOTBAR_AND_INVENTORY,
containedIn.select(ContainerSearchScope.Loaded),
stackSelection {
isItem(shulkerItem)
withName(itemName)
if (pickedUp != null) sortedBySlotMatch(pickedUp)
sortedByBestContentMatch(stacks)
sortedByRecentChange()
}.transfer(
ContainerSelection.HOTBAR_AND_INVENTORY,
containedIn.select(ContainerSearchScope.Loaded),
stackSelection {
sortedByMatches {
stackSelection {
predicate { _, slot -> slot?.index == index }
isEmpty()
}
isEmpty()
sortedByMatches {
stackSelection {
predicate { _, slot -> slot?.identity() == ownSlot }
}
},
allowQuickMove = false
)
}
}
},
allowQuickMove = false
).softFail()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class StackSelection @ContainerDslMarker internal constructor(
val shulkerBoxScope: ShulkerBoxScope = ShulkerBoxScope.Both,
val countEmptyAsOne: Boolean = false,
val alwaysWholeStacks: Boolean = false,
val comparator: Comparator<StackAndSlot<*>> = compareBy { it.stack.count },
val comparator: Comparator<StackAndSlot<*>>? = null,
Comment thread
blocksimus marked this conversation as resolved.
val selector: (ItemStack, Slot?) -> Boolean,
) {
val optimalStack = itemStack ?: item?.let { ItemStack(it, count) }
Expand Down Expand Up @@ -127,7 +127,7 @@ class StackSelection @ContainerDslMarker internal constructor(
.asSequence()
.filter(::matches)
.let {
if (sorted)
if (sorted && comparator != null)
it.map { StackAndSlot(it, null) }
.sortedWith(comparator)
.map { it.stack }
Expand All @@ -149,7 +149,7 @@ class StackSelection @ContainerDslMarker internal constructor(
.filter { it.identity() !in blacklistedSlots }
.filter(::matches)
.let {
if (sorted)
if (sorted && comparator != null)
it.map { StackAndSlot(it.stack, it) }
.sortedWith(comparator)
.map { it.slot }
Expand All @@ -171,7 +171,7 @@ class StackSelection @ContainerDslMarker internal constructor(
.filter { it.slot?.identity() !in blacklistedSlots }
.filter(::matches)
.let {
if (sorted) it.sortedWith(comparator)
if (sorted && comparator != null) it.sortedWith(comparator)
else it
}
.toList()
Expand Down Expand Up @@ -485,6 +485,11 @@ class StackSelectionBuilder @ContainerDslMarker internal constructor(
sortedWith(comparatorSupplier())
}

fun sortedFirstWith(comparatorSupplier: () -> Comparator<StackAndSlot<*>>) {
val newComparator = comparatorSupplier()
comparator = comparator?.let { newComparator.thenComparing(it) } ?: newComparator
}

fun sortedByMatches(stackSelection: StackSelection) {
sortedWith {
compareByDescending { stackSelection.matches(it) }
Expand Down Expand Up @@ -605,7 +610,7 @@ class StackSelectionBuilder @ContainerDslMarker internal constructor(
shulkerBoxScope,
countEmptyAsOne,
alwaysWholeStacks,
comparator ?: compareBy { it.stack.count },
comparator,
selector
)

Expand Down
Loading