Slice container APIs and decouple interface from implementation, container sorting test
This commit is contained in:
parent
67f97dfba6
commit
d4c029f27d
@ -805,6 +805,7 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
|
||||
gui("balance_inputs", "Balance input slots")
|
||||
|
||||
gui("sorting.sort_now", "Sort")
|
||||
gui("sorting.default", "Default sorting")
|
||||
gui("sorting.name", "Sort by name")
|
||||
gui("sorting.id", "Sort by ID")
|
||||
|
@ -805,6 +805,7 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
|
||||
gui("balance_inputs", "Балансировать входные слоты")
|
||||
|
||||
gui("sorting.sort_now", "Отсортировать")
|
||||
gui("sorting.default", "Сортировка по умолчанию")
|
||||
gui("sorting.name", "Сортировка по имени")
|
||||
gui("sorting.id", "Сортировка по ID")
|
||||
|
@ -43,8 +43,6 @@ import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets8
|
||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
||||
import ru.dbotthepony.mc.otm.container.addItem
|
||||
import ru.dbotthepony.mc.otm.container.util.iterator
|
||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||
@ -345,7 +343,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
||||
|
||||
check(residue.size == craftingGrid.containerSize) { "Container and residue list sizes mismatch: ${residue.size} != ${craftingGrid.containerSize}" }
|
||||
|
||||
val combinedInventory = craftingPlayer.matteryPlayer?.combinedInventory
|
||||
val combinedInventory = craftingPlayer.matteryPlayer?.inventoryAndExopack
|
||||
val copy = craftingGrid.iterator(true).map { it.copy() }.toList()
|
||||
|
||||
// удаляем по одному предмету из сетки крафта
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@ -74,7 +75,7 @@ class PlatePressBlockEntity(
|
||||
if (status.job.itemStack.isEmpty)
|
||||
return status.success()
|
||||
|
||||
if (!outputContainer.fullyAddItem(status.job.itemStack, start = id, end = id) && !outputContainer.fullyAddItem(status.job.itemStack))
|
||||
if (!outputContainer.fullyAddItem(status.job.itemStack, slots = IntArrayList.of(id)) && !outputContainer.fullyAddItem(status.job.itemStack))
|
||||
return status.noItem()
|
||||
|
||||
experience = (experience + status.experience).coerceAtMost(100.0)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.capability
|
||||
|
||||
import com.google.common.collect.Streams
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
@ -27,11 +26,11 @@ import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.getMekanismEnergySided
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.mekanismEnergy
|
||||
import ru.dbotthepony.mc.otm.container.util.awareStream
|
||||
import ru.dbotthepony.mc.otm.capability.iterator
|
||||
import ru.dbotthepony.mc.otm.container.util.iterator
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.ContainerItemStackEntry
|
||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||
import ru.dbotthepony.mc.otm.core.collect.emptyIterator
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
@ -217,21 +216,16 @@ fun ICapabilityProvider.getMatteryEnergySided(side: Direction? = null): LazyOpti
|
||||
return LazyOptional.empty()
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT modify returned ItemStacks!
|
||||
*
|
||||
* Contains all items that player might carry
|
||||
*/
|
||||
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
val iterators = ArrayList<Iterator<ItemStack>>()
|
||||
iterators.add(inventory.iterator())
|
||||
val matteryPlayer = matteryPlayer ?: return emptyIterator()
|
||||
|
||||
matteryPlayer?.let {
|
||||
if (it.hasExopack) {
|
||||
iterators.add(it.exopackContainer.iterator())
|
||||
iterators.add(it.exopackEnergy.parent.iterator())
|
||||
iterators.add(it.exopackChargeSlots.iterator())
|
||||
}
|
||||
val iterators = ArrayList<Iterator<ItemStack>>()
|
||||
iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item })
|
||||
|
||||
if (matteryPlayer.hasExopack) {
|
||||
iterators.add(matteryPlayer.exopackContainer.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item })
|
||||
iterators.add(matteryPlayer.exopackEnergy.parent.iterator())
|
||||
iterators.add(matteryPlayer.exopackChargeSlots.iterator())
|
||||
}
|
||||
|
||||
if (isCuriosLoaded) {
|
||||
@ -245,25 +239,12 @@ fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
return concatIterators(iterators)
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT modify returned ItemStacks!
|
||||
*
|
||||
* Contains all items that player might see/access ([itemsStream] + open container's items)
|
||||
*/
|
||||
fun Player.allItems(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
fun Player.trackedItems(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||
if (containerMenu == inventoryMenu || containerMenu == matteryPlayer?.exoPackMenu) {
|
||||
return items(includeCosmetics)
|
||||
}
|
||||
|
||||
val seen = ReferenceOpenHashSet<ItemStack>(containerMenu.slots.size)
|
||||
|
||||
for (slot in containerMenu.slots) {
|
||||
seen.add(slot.item)
|
||||
}
|
||||
|
||||
return concatIterators(
|
||||
items(includeCosmetics).filter { it.isNotEmpty && it !in seen },
|
||||
containerMenu.slots.iterator().map { it.item })
|
||||
return concatIterators(items(includeCosmetics), containerMenu.slots.iterator().map { it.item }.filter { it.isNotEmpty })
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,6 @@ import net.minecraft.client.player.AbstractClientPlayer
|
||||
import net.minecraft.commands.Commands
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.ByteTag
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.IntTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
@ -31,6 +30,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.boss.wither.WitherBoss
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.ProjectileWeaponItem
|
||||
@ -82,7 +82,9 @@ import ru.dbotthepony.mc.otm.config.ExopackConfig
|
||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.capability.iterator
|
||||
import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IContainer
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||
import ru.dbotthepony.mc.otm.container.vanishCursedItems
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
@ -91,7 +93,6 @@ import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||
import ru.dbotthepony.mc.otm.core.math.minus
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getByteList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getIntList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
||||
@ -258,27 +259,23 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
synchronizer.Field(null, ItemValueCodec.nullable)
|
||||
}
|
||||
|
||||
val regularSlotChargeFlag = immutableList(Inventory.INVENTORY_SIZE + 5) {
|
||||
synchronizer.bool()
|
||||
}
|
||||
val slotsChargeFlag by synchronizer.Set(
|
||||
codec = VarIntValueCodec,
|
||||
backingSet = IntAVLTreeSet(),
|
||||
)
|
||||
|
||||
private fun slotChargeToDefault() {
|
||||
// броня
|
||||
regularSlotChargeFlag[36].boolean = true
|
||||
regularSlotChargeFlag[37].boolean = true
|
||||
regularSlotChargeFlag[38].boolean = true
|
||||
regularSlotChargeFlag[39].boolean = true
|
||||
slotsChargeFlag.add(36)
|
||||
slotsChargeFlag.add(37)
|
||||
slotsChargeFlag.add(38)
|
||||
slotsChargeFlag.add(39)
|
||||
}
|
||||
|
||||
init {
|
||||
slotChargeToDefault()
|
||||
}
|
||||
|
||||
val exoPackSlotsChargeFlag by synchronizer.Set(
|
||||
codec = VarIntValueCodec,
|
||||
backingSet = IntAVLTreeSet(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Exopack container, which actually store items inside Exopack
|
||||
*/
|
||||
@ -303,19 +300,60 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
value.addFilterSynchronizer(synchronizer)
|
||||
field = value
|
||||
|
||||
_combinedInventory = CombinedContainer(ply.inventory, exopackContainer)
|
||||
_combinedInventory = CombinedContainer(wrappedInventory, exopackContainer)
|
||||
_combinedInventory2 = CombinedContainer(wrappedItemInventory, exopackContainer)
|
||||
_combinedInventory3 = CombinedContainer.Builder().add(wrappedItemInventory, 9 .. 35).add(exopackContainer).build()
|
||||
}
|
||||
|
||||
private var _combinedInventory: CombinedContainer? = null
|
||||
private var _combinedInventory2: CombinedContainer? = null
|
||||
private var _combinedInventory3: CombinedContainer? = null
|
||||
|
||||
val wrappedInventory: IMatteryContainer = object : IMatteryContainer, IContainer by DynamicallyProxiedContainer(ply::getInventory) {
|
||||
override fun getSlotFilter(slot: Int): Item? {
|
||||
return regularSlotFilters.getOrNull(slot)?.get()
|
||||
}
|
||||
|
||||
override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
||||
regularSlotFilters.getOrNull(slot)?.accept(filter)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setChanged(slot: Int) {
|
||||
ply.inventory.setChanged()
|
||||
}
|
||||
}
|
||||
|
||||
val wrappedItemInventory: IMatteryContainer = object : IMatteryContainer by wrappedInventory {
|
||||
override fun getContainerSize(): Int {
|
||||
return 36
|
||||
}
|
||||
}
|
||||
|
||||
val combinedInventory: CombinedContainer
|
||||
get() {
|
||||
if (_combinedInventory == null)
|
||||
_combinedInventory = CombinedContainer(ply.inventory, exopackContainer)
|
||||
_combinedInventory = CombinedContainer(wrappedInventory, exopackContainer)
|
||||
|
||||
return _combinedInventory!!
|
||||
}
|
||||
|
||||
val inventoryAndExopack: CombinedContainer
|
||||
get() {
|
||||
if (_combinedInventory2 == null)
|
||||
_combinedInventory2 = CombinedContainer(wrappedItemInventory, exopackContainer)
|
||||
|
||||
return _combinedInventory2!!
|
||||
}
|
||||
|
||||
val inventoryAndExopackNoHotbar: CombinedContainer
|
||||
get() {
|
||||
if (_combinedInventory3 == null)
|
||||
_combinedInventory3 = CombinedContainer.Builder().add(wrappedItemInventory, 9 .. 35).add(exopackContainer).build()
|
||||
|
||||
return _combinedInventory3!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever Exopack has 3x3 crafting grid upgrade installed
|
||||
*/
|
||||
@ -914,14 +952,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
}
|
||||
}
|
||||
|
||||
tag["regularSlotChargeFlag"] = ListTag().also {
|
||||
for (flag in regularSlotChargeFlag) {
|
||||
it.add(ByteTag.valueOf(flag.boolean))
|
||||
}
|
||||
}
|
||||
|
||||
tag["exoPackSlotsChargeFlag"] = ListTag().also {
|
||||
for (value in exoPackSlotsChargeFlag) {
|
||||
tag["slotsChargeFlag"] = ListTag().also {
|
||||
for (value in slotsChargeFlag) {
|
||||
it.add(IntTag.valueOf(value))
|
||||
}
|
||||
}
|
||||
@ -945,12 +977,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
filter.value = null
|
||||
}
|
||||
|
||||
for (flag in regularSlotChargeFlag) {
|
||||
flag.boolean = false
|
||||
}
|
||||
|
||||
exoPackSlotsChargeFlag.clear()
|
||||
|
||||
slotsChargeFlag.clear()
|
||||
slotChargeToDefault()
|
||||
|
||||
val regularSlotFilters = tag.getStringList("regularSlotFilters")
|
||||
@ -961,14 +988,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
this.regularSlotFilters[i].value = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(path) ?: continue) ?: Items.AIR
|
||||
}
|
||||
|
||||
val regularSlotChargeFlag = tag.getByteList("regularSlotChargeFlag")
|
||||
|
||||
for (i in 0 until regularSlotChargeFlag.size.coerceAtMost(this.regularSlotChargeFlag.size)) {
|
||||
this.regularSlotChargeFlag[i].boolean = regularSlotChargeFlag[i].asInt > 0
|
||||
}
|
||||
|
||||
for (v in tag.getIntList("exoPackSlotsChargeFlag")) {
|
||||
this.exoPackSlotsChargeFlag.add(v.asInt)
|
||||
for (v in tag.getIntList("slotsChargeFlag")) {
|
||||
this.slotsChargeFlag.add(v.asInt)
|
||||
}
|
||||
|
||||
// iterations
|
||||
@ -1128,25 +1149,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
}
|
||||
|
||||
if (available.isPositive) {
|
||||
for ((i, flag) in regularSlotChargeFlag.withIndex()) {
|
||||
if (flag.boolean) {
|
||||
val item = ply.inventory[i]
|
||||
|
||||
if (item.isNotEmpty) {
|
||||
item.energy?.let {
|
||||
available -= exopackEnergy.extractEnergy(it.receiveEnergy(available, false), false)
|
||||
}
|
||||
|
||||
if (!available.isPositive) break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (available.isPositive) {
|
||||
for (slot in exoPackSlotsChargeFlag) {
|
||||
if (slot in 0 until exopackContainer.containerSize) {
|
||||
val item = exopackContainer[slot]
|
||||
for (slot in slotsChargeFlag) {
|
||||
if (slot in 0 until combinedInventory.containerSize) {
|
||||
val item = combinedInventory[slot]
|
||||
|
||||
if (item.isNotEmpty) {
|
||||
item.energy?.let {
|
||||
@ -1364,127 +1369,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
* This re-implement [Inventory.add] logic (original method is redirected to this)
|
||||
*/
|
||||
fun inventoryAddImpl(stack: ItemStack): Boolean {
|
||||
val items = ply.inventory.items
|
||||
val exoPackContainer = exopackContainer
|
||||
|
||||
if (!stack.isStackable) {
|
||||
// двигаем в отфильтрованные слоты
|
||||
for (i in items.indices) {
|
||||
if (items[i].isEmpty && regularSlotFilters[i].value === stack.item) {
|
||||
items[i] = stack.copy()
|
||||
items[i].popTime = 5
|
||||
stack.count = 0
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until exoPackContainer.containerSize) {
|
||||
if (exoPackContainer[i].isEmpty && exoPackContainer.hasSlotFilter(i) && exoPackContainer.testSlotFilter(i, stack)) {
|
||||
exoPackContainer[i] = stack.copy()
|
||||
exoPackContainer[i].popTime = 5
|
||||
stack.count = 0
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// двигаем в обычные слоты
|
||||
for (i in items.indices) {
|
||||
if (items[i].isEmpty && regularSlotFilters[i].value === null) {
|
||||
items[i] = stack.copy()
|
||||
items[i].popTime = 5
|
||||
stack.count = 0
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until exoPackContainer.containerSize) {
|
||||
if (exoPackContainer[i].isEmpty && !exoPackContainer.hasSlotFilter(i)) {
|
||||
exoPackContainer[i] = stack.copy()
|
||||
exoPackContainer[i].popTime = 5
|
||||
stack.count = 0
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
|
||||
|
||||
if (ply.abilities.instabuild) {
|
||||
stack.count = 0
|
||||
}
|
||||
|
||||
return stack.isEmpty
|
||||
}
|
||||
|
||||
// двигаем в существующие слоты
|
||||
items[ply.inventory.selected].also { stackStacks(it, stack) }
|
||||
if (stack.isEmpty) return true
|
||||
ply.inventory.offhand[0].also { stackStacks(it, stack) }
|
||||
if (stack.isEmpty) return true
|
||||
|
||||
for (i in items.indices) {
|
||||
if (stackStacks(items[i], stack) && stack.isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until exoPackContainer.containerSize) {
|
||||
if (stackStacks(exoPackContainer[i], stack)) {
|
||||
exoPackContainer.setChanged(i)
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// двигаем в пустые слоты
|
||||
|
||||
// двигаем в отфильтрованные слоты
|
||||
for (i in items.indices) {
|
||||
if (items[i].isEmpty && regularSlotFilters[i].value === stack.item) {
|
||||
items[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||
items[i].popTime = 5
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until exoPackContainer.containerSize) {
|
||||
if (exoPackContainer[i].isEmpty && exoPackContainer.hasSlotFilter(i) && exoPackContainer.testSlotFilter(i, stack)) {
|
||||
exoPackContainer[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||
exoPackContainer[i].popTime = 5
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// двигаем в обычные слоты
|
||||
for (i in items.indices) {
|
||||
if (items[i].isEmpty && regularSlotFilters[i].value === null) {
|
||||
items[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||
items[i].popTime = 5
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i in 0 until exoPackContainer.containerSize) {
|
||||
if (exoPackContainer[i].isEmpty && !exoPackContainer.hasSlotFilter(i)) {
|
||||
exoPackContainer[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||
exoPackContainer[i].popTime = 5
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inventoryAndExopack.consumeItem(stack, false, popTime = 5)
|
||||
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
|
||||
|
||||
if (ply.abilities.instabuild) {
|
||||
@ -1587,25 +1472,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
)
|
||||
}
|
||||
|
||||
private fun stackStacks(it: ItemStack, stack: ItemStack): Boolean {
|
||||
if (
|
||||
!it.isEmpty &&
|
||||
it.maxStackSize > it.count &&
|
||||
it.isStackable &&
|
||||
ItemStack.isSameItemSameTags(it, stack)
|
||||
) {
|
||||
val new = (it.count + stack.count).coerceAtMost(it.maxStackSize)
|
||||
val diff = new - it.count
|
||||
it.count = new
|
||||
stack.count -= diff
|
||||
it.popTime = 5
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
init {
|
||||
WitherBoss.TARGETING_CONDITIONS.selector(WitherBoss.TARGETING_CONDITIONS.selector!!.and { it.matteryPlayer?.isAndroid != true })
|
||||
WitherBoss.LIVING_ENTITY_SELECTOR = WitherBoss.LIVING_ENTITY_SELECTOR.and { it.matteryPlayer?.isAndroid != true }
|
||||
|
@ -85,11 +85,11 @@ private fun inventoryLogic(event: ScreenEvent.Init.Post) {
|
||||
val screen = if (eventScreen is AbstractContainerScreen<*> && (eventScreen.menu is InventoryMenu || eventScreen.isCosmeticArmorScreen)) eventScreen else return
|
||||
|
||||
val widget = Panel2Widget(LargeRectangleButtonPanel(screen, null,
|
||||
x = screen.guiLeft + screen.xSize - 2f - LargeRectangleButtonPanel.SIZE,
|
||||
y = screen.guiTop.toFloat() - LargeRectangleButtonPanel.SIZE - 2,
|
||||
skinElement = Widgets18.RETURN_ARROW_LEFT,
|
||||
skinElementWinding = UVWindingOrder.FLOP,
|
||||
onPress = {
|
||||
x = screen.guiLeft + screen.xSize - 2f - LargeRectangleButtonPanel.SIZE,
|
||||
y = screen.guiTop.toFloat() - LargeRectangleButtonPanel.SIZE - 2,
|
||||
icon = Widgets18.RETURN_ARROW_LEFT,
|
||||
iconWinding = UVWindingOrder.FLOP,
|
||||
onPress = {
|
||||
shouldOpenVanillaInventory = false
|
||||
val mouseX = minecraft.mouseHandler.xpos()
|
||||
val mouseY = minecraft.mouseHandler.ypos()
|
||||
|
@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas
|
||||
|
||||
object WidgetLocation {
|
||||
val LARGE_BUTTON = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/large_button.png"), 72f, 18f)
|
||||
val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 54f)
|
||||
val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 72f)
|
||||
val MISC_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/misc18.png"), 72f, 72f)
|
||||
val SLOT_BACKGROUNDS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/slot_backgrounds.png"), 72f, 72f)
|
||||
|
||||
|
@ -37,7 +37,7 @@ object Widgets18 {
|
||||
val BUTTON_DISABLED_STRETCHABLE = makeButton(buttonGrids)
|
||||
val BUTTON_DISABLED = buttonGrids.next()
|
||||
|
||||
private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 3, columns = 5)
|
||||
private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 4, columns = 5)
|
||||
val ARROW_DOWN = storageGrid.next()
|
||||
val ARROW_UP = storageGrid.next()
|
||||
val SORT_DEFAULT = storageGrid.next()
|
||||
@ -53,6 +53,7 @@ object Widgets18 {
|
||||
val PAUSE = storageGrid.next()
|
||||
val PLAY = storageGrid.next()
|
||||
val STOP = storageGrid.next()
|
||||
val SORT_NOW = storageGrid.next()
|
||||
|
||||
private val miscGrid = WidgetLocation.MISC_18.grid(4, 4)
|
||||
|
||||
|
@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.client.render.sprites.sprite
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
||||
@ -243,7 +244,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
|
||||
scrollPanel.dock = Dock.RIGHT
|
||||
scrollPanel.setDockMargin(right = 3f)
|
||||
|
||||
val closeButtonPanel = LargeRectangleButtonPanel(this, frame, x = frame.width - 2f - LargeRectangleButtonPanel.SIZE, y = -LargeRectangleButtonPanel.SIZE - 2f, skinElement = Widgets18.RETURN_ARROW_LEFT, onPress = {
|
||||
val closeButtonPanel = LargeRectangleButtonPanel(this, frame, x = frame.width - 2f - LargeRectangleButtonPanel.SIZE, y = -LargeRectangleButtonPanel.SIZE - 2f, icon = Widgets18.RETURN_ARROW_LEFT, onPress = {
|
||||
shouldOpenVanillaInventory = true
|
||||
val minecraft = minecraft!!
|
||||
|
||||
@ -256,14 +257,28 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
|
||||
}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_back")) }
|
||||
|
||||
if (isCuriosLoaded) {
|
||||
LargeRectangleButtonPanel(this, frame, x = closeButtonPanel.x - 2f - LargeRectangleButtonPanel.SIZE, y = closeButtonPanel.y, skinElement = Widgets18.CURIOS_INVENTORY, onPress = {
|
||||
LargeRectangleButtonPanel(this, frame, x = closeButtonPanel.x - 2f - LargeRectangleButtonPanel.SIZE, y = closeButtonPanel.y, icon = Widgets18.CURIOS_INVENTORY, onPress = {
|
||||
openCuriosScreen(minecraft!!.player!!.containerMenu.carried)
|
||||
}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_curios")) }
|
||||
}
|
||||
|
||||
makeInventoryRowsControls(frame, frame.width + 2f, frame.height.coerceAtMost(95f)) { movePixels ->
|
||||
val controls = DeviceControls(this, frame)
|
||||
|
||||
controls.dockTop = 85f
|
||||
|
||||
controls.addButton(makeInventoryRowsControls(frame) { movePixels ->
|
||||
frame.y += movePixels
|
||||
moveMousePosScaled(y = movePixels)
|
||||
} as EditablePanel<ExopackInventoryScreen>)
|
||||
|
||||
|
||||
if (menu.sortInventoryInput != null) {
|
||||
controls.addButton(LargeRectangleButtonPanel.input(
|
||||
this,
|
||||
controls,
|
||||
menu.sortInventoryInput!!,
|
||||
icon = Widgets18.SORT_NOW
|
||||
).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) })
|
||||
}
|
||||
|
||||
var x = -4f
|
||||
|
@ -22,6 +22,8 @@ import ru.dbotthepony.mc.otm.client.render.WidgetLocation
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
import ru.dbotthepony.mc.otm.client.render.translation
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
||||
@ -157,7 +159,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
inventoryScrollbar.scroll = inventoryScrollbar.scroll
|
||||
}
|
||||
|
||||
protected fun makeInventoryRowsControls(parent: EditablePanel<*>, x: Float, y: Float, callback: (Float) -> Unit): HeightControls<*> {
|
||||
protected fun makeInventoryRowsControls(parent: EditablePanel<*>, x: Float = 0f, y: Float = 0f, callback: (Float) -> Unit): HeightControls<MatteryScreen<*>> {
|
||||
return HeightControls(this, parent, x, y) {
|
||||
inventoryRows += if (it) 1 else -1
|
||||
callback.invoke(if (it) -AbstractSlotPanel.SIZE / 2f else AbstractSlotPanel.SIZE / 2f)
|
||||
@ -206,13 +208,17 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
|
||||
init {
|
||||
if (menu.playerInventorySlots.isNotEmpty() && menu.autoCreateInventoryFrame) {
|
||||
if (menu.playerExoSuitSlots.isEmpty()) {
|
||||
val deviceControls: DeviceControls<MatteryScreen<*>>
|
||||
|
||||
if (menu.playerCombinedInventorySlots.size <= 27) {
|
||||
inventoryFrame = FramePanel<MatteryScreen<*>>(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
|
||||
inventoryFrame!!.makeHelpButton().addSlotFiltersHelp().also {
|
||||
if (menu.player.matteryPlayer?.hasExopack == true)
|
||||
it.tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||
}
|
||||
|
||||
deviceControls = DeviceControls(this, inventoryFrame!!)
|
||||
|
||||
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
|
||||
hotbarStrip.dock = Dock.BOTTOM
|
||||
|
||||
@ -240,6 +246,8 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
it.tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||
}
|
||||
|
||||
deviceControls = DeviceControls(this, inventoryFrame!!)
|
||||
|
||||
inventoryScrollbar = DiscreteScrollBarPanel(this, inventoryFrame, { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) }, {
|
||||
_, old, new ->
|
||||
|
||||
@ -292,11 +300,20 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
}
|
||||
|
||||
makeInventoryRowsControls(inventoryFrame!!, inventoryFrame!!.width + 2f, 0f) { movePixels ->
|
||||
deviceControls.addButton(makeInventoryRowsControls(inventoryFrame!!) { movePixels ->
|
||||
mainFrame?.let { it.y += movePixels }
|
||||
inventoryFrame?.let { it.y += movePixels }
|
||||
moveMousePosScaled(y = movePixels)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (menu.sortInventoryInput != null) {
|
||||
deviceControls.addButton(LargeRectangleButtonPanel.input(
|
||||
this,
|
||||
deviceControls,
|
||||
menu.sortInventoryInput!!,
|
||||
icon = Widgets18.SORT_NOW
|
||||
).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) })
|
||||
}
|
||||
|
||||
if (menu.exopackChargeSlots.isNotEmpty()) {
|
||||
|
@ -2,11 +2,15 @@ package ru.dbotthepony.mc.otm.client.screen.decorative
|
||||
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||
|
||||
class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen<CargoCrateMenu>(menu, inventory, title) {
|
||||
@ -22,6 +26,10 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
|
||||
for (slot in menu.storageSlots)
|
||||
UserFilteredSlotPanel.of(this, grid, slot)
|
||||
|
||||
val controls = DeviceControls(this, frame)
|
||||
|
||||
controls.addButton(LargeRectangleButtonPanel.input(this, frame, menu.sort, icon = Widgets18.SORT_NOW).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) })
|
||||
|
||||
return frame
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
|
||||
buttons.clear()
|
||||
|
||||
for (recipe in menu.possibleRecipes) {
|
||||
object : LargeRectangleButtonPanel<PainterScreen>(this@PainterScreen, canvas.canvas, skinElement = ItemStackIcon(recipe.output, 14f, 14f).fixed()) {
|
||||
object : LargeRectangleButtonPanel<PainterScreen>(this@PainterScreen, canvas.canvas, icon = ItemStackIcon(recipe.output, 14f, 14f).fixed()) {
|
||||
init {
|
||||
buttons.add(this)
|
||||
dockRight = 1f
|
||||
|
@ -77,7 +77,7 @@ class MatterPanelScreen(
|
||||
LargeRectangleButtonPanel(
|
||||
this,
|
||||
frame,
|
||||
skinElement = Widgets18.STOP,
|
||||
icon = Widgets18.STOP,
|
||||
onPress = {
|
||||
frame.queryUser(
|
||||
TranslatableComponent("otm.gui.matter_panel.cancel_all"),
|
||||
|
@ -386,7 +386,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
if (upgrades != null) {
|
||||
upgradesButton = addButton(object : LargeRectangleButtonPanel<S>(
|
||||
screen, this@DeviceControls,
|
||||
skinElement = Widgets18.UPGRADES
|
||||
icon = Widgets18.UPGRADES
|
||||
) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.upgrades"))
|
||||
@ -473,7 +473,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
}
|
||||
|
||||
if (itemConfig != null) {
|
||||
itemConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, skinElement = Widgets18.ITEMS_CONFIGURATION) {
|
||||
itemConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, icon = Widgets18.ITEMS_CONFIGURATION) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.sides.item_config"))
|
||||
}
|
||||
@ -492,7 +492,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
}
|
||||
|
||||
if (energyConfig != null) {
|
||||
energyConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, y = nextY, skinElement = Widgets18.ENERGY_CONFIGURATION) {
|
||||
energyConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, y = nextY, icon = Widgets18.ENERGY_CONFIGURATION) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.sides.energy_config"))
|
||||
}
|
||||
@ -511,7 +511,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
}
|
||||
|
||||
if (fluidConfig != null) {
|
||||
fluidConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, y = nextY, skinElement = Widgets18.FLUID_CONFIGURATION) {
|
||||
fluidConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, y = nextY, icon = Widgets18.FLUID_CONFIGURATION) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.sides.fluid_config"))
|
||||
}
|
||||
@ -530,10 +530,28 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
x = (parent?.width ?: 0f) + 3f
|
||||
y = dockTop
|
||||
}
|
||||
|
||||
override fun tickInner() {
|
||||
super.tickInner()
|
||||
x = (parent?.width ?: 0f) + 3f
|
||||
y = 0f
|
||||
y = dockTop
|
||||
}
|
||||
|
||||
// не съедаем ввод мыши
|
||||
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseDraggedInner(x: Double, y: Double, button: Int, xDelta: Double, yDelta: Double): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -2,10 +2,12 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button
|
||||
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
|
||||
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
|
||||
open class LargeRectangleButtonPanel<out S : Screen>(
|
||||
screen: S,
|
||||
@ -15,8 +17,8 @@ open class LargeRectangleButtonPanel<out S : Screen>(
|
||||
width: Float = SIZE,
|
||||
height: Float = SIZE,
|
||||
onPress: ((clickButton: Int) -> Unit)? = null,
|
||||
var skinElement: IGUIRenderable? = null,
|
||||
var skinElementWinding: UVWindingOrder? = null,
|
||||
var icon: IGUIRenderable? = null,
|
||||
var iconWinding: UVWindingOrder? = null,
|
||||
) : RectangleButtonPanel<S>(screen, parent, x, y, width, height, onPress) {
|
||||
final override val IDLE = Widgets18.BUTTON_IDLE
|
||||
final override val HOVERED = Widgets18.BUTTON_HOVERED
|
||||
@ -26,14 +28,36 @@ open class LargeRectangleButtonPanel<out S : Screen>(
|
||||
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
super.innerRender(graphics, mouseX, mouseY, partialTick)
|
||||
|
||||
if (skinElementWinding != null) {
|
||||
skinElement?.render(graphics, width = width, height = height, winding = skinElementWinding!!)
|
||||
if (iconWinding != null) {
|
||||
icon?.render(graphics, width = width, height = height, winding = iconWinding!!)
|
||||
} else {
|
||||
skinElement?.render(graphics, width = width, height = height)
|
||||
icon?.render(graphics, width = width, height = height)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SIZE = 18f
|
||||
|
||||
fun <S : Screen> input(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>?,
|
||||
input: MatteryMenu.PlayerInput<Nothing?>,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = SIZE,
|
||||
height: Float = SIZE,
|
||||
icon: IGUIRenderable? = null,
|
||||
iconWinding: UVWindingOrder? = null,
|
||||
): LargeRectangleButtonPanel<S> {
|
||||
return object : LargeRectangleButtonPanel<S>(screen, parent, x, y, width, height, null, icon, iconWinding) {
|
||||
override fun onClick(mouseButton: Int) {
|
||||
input.accept(null)
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !input.test(minecraft.player)
|
||||
set(value) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
outputs.dockResize = DockResizeMode.NONE
|
||||
outputs.dockMargin = DockProperty(bottom = 3f)
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_1) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, icon = STORE_1) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.store", 1))
|
||||
@ -108,7 +108,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_10) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, icon = STORE_10) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.store", 10))
|
||||
@ -123,7 +123,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_ALL) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, icon = STORE_ALL) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.store_all"))
|
||||
@ -138,7 +138,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_1) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, icon = DISPENSE_1) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", 1))
|
||||
@ -153,7 +153,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_10) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, icon = DISPENSE_10) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", 10))
|
||||
@ -168,7 +168,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_ALL) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, icon = DISPENSE_ALL) {
|
||||
init {
|
||||
dockRight = 3f
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense_all"))
|
||||
@ -186,7 +186,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
val customBar = HorizontalStripPanel(this, frame, height = 18f)
|
||||
customBar.dock = Dock.TOP
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = STORE_CUSTOM) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, icon = STORE_CUSTOM) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.store", customDispense))
|
||||
}
|
||||
@ -227,7 +227,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = DISPENSE_CUSTOM) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, icon = DISPENSE_CUSTOM) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", customDispense))
|
||||
}
|
||||
@ -241,7 +241,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = SET_EXACT) {
|
||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, icon = SET_EXACT) {
|
||||
init {
|
||||
tooltips.add(TranslatableComponent("otm.gui.experience.set_exact", customDispense))
|
||||
dock = Dock.RIGHT
|
||||
|
@ -4,17 +4,18 @@ import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import it.unimi.dsi.fastutil.ints.IntSet
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.Slot
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.container.util.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.IIterableContainer
|
||||
import ru.dbotthepony.mc.otm.container.util.containerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.iterator
|
||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.flatMap
|
||||
@ -24,21 +25,34 @@ import ru.dbotthepony.mc.otm.core.stream
|
||||
import java.util.LinkedList
|
||||
import java.util.stream.Stream
|
||||
|
||||
class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Container, IIterableContainer {
|
||||
constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize).iterator() })
|
||||
constructor(containers: Collection<Container>) : this(containers.stream().map { it to (0 until it.containerSize).iterator() })
|
||||
class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IMatteryContainer {
|
||||
constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||
constructor(containers: Collection<Container>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||
|
||||
private val slots: List<ContainerSlot>
|
||||
private val slotsMap: Map<Container, List<ContainerSlot>>
|
||||
private inner class Slot(override val slot: Int, val outer: IContainerSlot) : IContainerSlot by outer {
|
||||
override val container: Container
|
||||
get() = this@CombinedContainer
|
||||
|
||||
override fun component1(): Int {
|
||||
return super.component1()
|
||||
}
|
||||
|
||||
override fun component2(): ItemStack {
|
||||
return super.component2()
|
||||
}
|
||||
}
|
||||
|
||||
private val slots: List<Slot>
|
||||
private val slotsMap: Map<Container, List<IContainerSlot>>
|
||||
private val containers: Set<Container>
|
||||
private val fullCoverage: List<Container>
|
||||
private val notFullCoverage: Map<Container, List<ContainerSlot>>
|
||||
private val notFullCoverage: Map<Container, List<IContainerSlot>>
|
||||
|
||||
init {
|
||||
val list = ImmutableList.Builder<ContainerSlot>()
|
||||
val list = ImmutableList.Builder<Slot>()
|
||||
var i = 0
|
||||
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
|
||||
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<ContainerSlot>>()
|
||||
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<IContainerSlot>>()
|
||||
|
||||
for ((container, slots) in containers) {
|
||||
val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntAVLTreeSet() })
|
||||
@ -46,9 +60,8 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Co
|
||||
|
||||
for (slot in slots) {
|
||||
if (validator.add(slot)) {
|
||||
i++
|
||||
val slotObj = ContainerSlot(slot, container)
|
||||
list.add(slotObj)
|
||||
val slotObj = container.containerSlot(slot)
|
||||
list.add(Slot(i++, slotObj))
|
||||
slotList.add(slotObj)
|
||||
} else {
|
||||
throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot")
|
||||
@ -107,27 +120,23 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Co
|
||||
return true
|
||||
}
|
||||
|
||||
fun slotAt(index: Int): ContainerSlot {
|
||||
return slots[index]
|
||||
}
|
||||
|
||||
override fun getItem(index: Int): ItemStack {
|
||||
override fun getItem(slot: Int): ItemStack {
|
||||
// do not violate contract of getItem not throwing exceptions when index is invalid
|
||||
return slots.getOrNull(index)?.item ?: ItemStack.EMPTY
|
||||
return slots.getOrNull(slot)?.item ?: ItemStack.EMPTY
|
||||
}
|
||||
|
||||
override fun removeItem(index: Int, count: Int): ItemStack {
|
||||
val data = slots.getOrNull(index) ?: return ItemStack.EMPTY
|
||||
return data.container.removeItem(data.slot, count)
|
||||
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||
val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY
|
||||
return data.outer.container.removeItem(data.outer.slot, amount)
|
||||
}
|
||||
|
||||
override fun removeItemNoUpdate(index: Int): ItemStack {
|
||||
val data = slots.getOrNull(index) ?: return ItemStack.EMPTY
|
||||
return data.container.removeItemNoUpdate(data.slot)
|
||||
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||
val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY
|
||||
return data.outer.container.removeItemNoUpdate(data.outer.slot)
|
||||
}
|
||||
|
||||
override fun setItem(index: Int, value: ItemStack) {
|
||||
slots.getOrNull(index)?.item = value
|
||||
override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||
slots.getOrNull(slot)?.item = itemStack
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
@ -136,16 +145,6 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Co
|
||||
}
|
||||
}
|
||||
|
||||
fun setChanged(index: Int) {
|
||||
val data = slots.getOrNull(index) ?: return
|
||||
|
||||
if (data.container is MatteryContainer) {
|
||||
data.container.setChanged(data.slot)
|
||||
} else {
|
||||
data.container.setChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player): Boolean {
|
||||
for (container in containers)
|
||||
if (!container.stillValid(player))
|
||||
@ -168,33 +167,64 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Co
|
||||
return slots.iterator()
|
||||
}
|
||||
|
||||
override fun containerSlot(slot: Int): IContainerSlot {
|
||||
return slots[slot]
|
||||
}
|
||||
|
||||
override fun getSlotFilter(slot: Int): Item? {
|
||||
return slots[slot].getFilter()
|
||||
}
|
||||
|
||||
override fun setChanged(slot: Int) {
|
||||
slots[slot].setChanged()
|
||||
}
|
||||
|
||||
override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
||||
return slots[slot].setFilter(filter)
|
||||
}
|
||||
|
||||
class Builder {
|
||||
private var built = false
|
||||
private val values = LinkedList<Pair<Container, Iterator<Int>>>()
|
||||
private val values = ArrayList<Pair<Container, Iterable<Int>>>()
|
||||
|
||||
fun add(container: Container): Builder {
|
||||
check(!built) { "Already built!" }
|
||||
values.add(container to (0 until container.containerSize).iterator())
|
||||
values.add(container to container.slotRange)
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: Container, slots: Iterator<Int>): Builder {
|
||||
check(!built) { "Already built!" }
|
||||
values.add(container to slots)
|
||||
values.add(container to IntArrayList(slots))
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: Container, slot: Int): Builder {
|
||||
values.add(container to intArrayOf(slot).asIterable())
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: Container, from: Int, to: Int): Builder {
|
||||
values.add(container to (from .. to))
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: Container, slots: Iterable<Int>): Builder {
|
||||
check(!built) { "Already built!" }
|
||||
values.add(container to slots.iterator())
|
||||
values.add(container to slots)
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): CombinedContainer {
|
||||
check(!built) { "Already built!" }
|
||||
val value = CombinedContainer(values.stream())
|
||||
values.clear()
|
||||
return value
|
||||
return CombinedContainer(values.stream())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromMenuSlots(slots: Iterator<net.minecraft.world.inventory.Slot>): CombinedContainer {
|
||||
val builder = Builder()
|
||||
|
||||
for (slot in slots) {
|
||||
builder.add(slot.container, slot.slotIndex)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package ru.dbotthepony.mc.otm.container
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
|
||||
class ContainerHandler @JvmOverloads internal constructor(
|
||||
private val container: MatteryContainer,
|
||||
class ContainerHandler(
|
||||
private val container: IMatteryContainer,
|
||||
private val filter: HandlerFilter = HandlerFilter.Both,
|
||||
) : IItemHandler {
|
||||
override fun getSlots() = container.containerSize
|
||||
|
@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.container
|
||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import it.unimi.dsi.fastutil.ints.IntArraySet
|
||||
import it.unimi.dsi.fastutil.ints.IntIterable
|
||||
import it.unimi.dsi.fastutil.ints.IntIterator
|
||||
import it.unimi.dsi.fastutil.ints.IntSet
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
|
||||
@ -11,10 +13,14 @@ import net.minecraft.world.inventory.CraftingContainer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.ItemStackHashStrategy
|
||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||
import ru.dbotthepony.mc.otm.core.addAll
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.map
|
||||
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -27,13 +33,30 @@ inline operator fun Container.get(index: Int): ItemStack = getItem(index)
|
||||
@Suppress("nothing_to_inline")
|
||||
inline operator fun IFluidHandler.get(index: Int) = getFluidInTank(index)
|
||||
|
||||
fun Container.addItem(stack: ItemStack, range: IntRange, simulate: Boolean = false): ItemStack {
|
||||
if (this is MatteryContainer) {
|
||||
return this.addItem(stack, range, simulate)
|
||||
}
|
||||
val Container.slotRange: IntIterable get() {
|
||||
return IntIterable {
|
||||
val i = (0 until containerSize).iterator()
|
||||
|
||||
if (range.last >= containerSize || range.first < 0)
|
||||
throw IllegalArgumentException("Invalid range: $range")
|
||||
object : IntIterator {
|
||||
override fun hasNext(): Boolean {
|
||||
return i.hasNext()
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun nextInt(): Int {
|
||||
return i.nextInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange): ItemStack {
|
||||
if (this is IMatteryContainer) {
|
||||
return this.addItem(stack, simulate, slots)
|
||||
}
|
||||
|
||||
if (stack.isEmpty)
|
||||
return stack
|
||||
@ -41,7 +64,11 @@ fun Container.addItem(stack: ItemStack, range: IntRange, simulate: Boolean = fal
|
||||
val copy = stack.copy()
|
||||
|
||||
// двигаем в одинаковые слоты
|
||||
for (slot in range) {
|
||||
var i = slots.intIterator()
|
||||
|
||||
while (i.hasNext()) {
|
||||
val slot = i.nextInt()
|
||||
|
||||
if (ItemStack.isSameItemSameTags(this[slot], copy)) {
|
||||
val slotStack = this[slot]
|
||||
val slotLimit = maxStackSize.coerceAtMost(slotStack.maxStackSize)
|
||||
@ -65,7 +92,11 @@ fun Container.addItem(stack: ItemStack, range: IntRange, simulate: Boolean = fal
|
||||
}
|
||||
|
||||
// двигаем в пустые слоты
|
||||
for (slot in range) {
|
||||
i = slots.intIterator()
|
||||
|
||||
while (i.hasNext()) {
|
||||
val slot = i.nextInt()
|
||||
|
||||
if (this[slot].isEmpty) {
|
||||
val diff = copy.count.coerceAtMost(maxStackSize.coerceAtMost(copy.maxStackSize))
|
||||
|
||||
@ -87,8 +118,6 @@ fun Container.addItem(stack: ItemStack, range: IntRange, simulate: Boolean = fal
|
||||
return copy
|
||||
}
|
||||
|
||||
fun Container.addItem(stack: ItemStack, simulate: Boolean): ItemStack = addItem(stack, 0 until containerSize, simulate)
|
||||
|
||||
fun Container.vanishCursedItems() {
|
||||
for (slot in slotIterator()) {
|
||||
if (hasVanishingCurse(slot.item)) {
|
||||
@ -258,3 +287,31 @@ operator fun CraftingContainer.get(column: Int, row: Int, flop: Boolean): ItemSt
|
||||
else
|
||||
get(column, row)
|
||||
}
|
||||
|
||||
private object FilteredFirst : Comparator<IContainerSlot> {
|
||||
override fun compare(o1: IContainerSlot, o2: IContainerSlot): Int {
|
||||
if (o1.hasFilter && o2.hasFilter)
|
||||
return 0
|
||||
else if (o2.hasFilter)
|
||||
return -1
|
||||
else if (o1.hasFilter)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
fun Container.sort(comparator: Comparator<ItemStack> = ItemStackSorter.DEFAULT) {
|
||||
if (isEmpty)
|
||||
return
|
||||
|
||||
val slots = slotIterator().filter { !it.isForbiddenForAutomation && it.getMaxStackSize() >= it.item.count }.toList()
|
||||
|
||||
if (slots.isEmpty())
|
||||
return
|
||||
|
||||
slots.sortWith(FilteredFirst.thenComparing(comparator.map(IContainerSlot::item)))
|
||||
val items = slots.map { it.item.copy() }
|
||||
slots.forEach { it.remove() }
|
||||
items.forEach { addItem(it, false) }
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import java.util.function.Predicate
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* because mods tend to do crazy shit
|
||||
*/
|
||||
class DynamicallyProxiedContainer(private val toProxy: Supplier<Container>) : IContainer {
|
||||
override fun clearContent() {
|
||||
return toProxy.get().clearContent()
|
||||
}
|
||||
|
||||
override fun getContainerSize(): Int {
|
||||
return toProxy.get().containerSize
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return toProxy.get().isEmpty
|
||||
}
|
||||
|
||||
override fun getItem(slot: Int): ItemStack {
|
||||
return toProxy.get().getItem(slot)
|
||||
}
|
||||
|
||||
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||
return toProxy.get().removeItem(slot, amount)
|
||||
}
|
||||
|
||||
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||
return toProxy.get().removeItemNoUpdate(slot)
|
||||
}
|
||||
|
||||
override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||
return toProxy.get().setItem(slot, itemStack)
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
return toProxy.get().setChanged()
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player): Boolean {
|
||||
return toProxy.get().stillValid(player)
|
||||
}
|
||||
|
||||
override fun getMaxStackSize(): Int {
|
||||
return toProxy.get().getMaxStackSize()
|
||||
}
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
toProxy.get().startOpen(player)
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
toProxy.get().stopOpen(player)
|
||||
}
|
||||
|
||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return toProxy.get().canPlaceItem(slot, itemStack)
|
||||
}
|
||||
|
||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||
return toProxy.get().canTakeItem(container, slot, itemStack)
|
||||
}
|
||||
|
||||
override fun countItem(item: Item): Int {
|
||||
return toProxy.get().countItem(item)
|
||||
}
|
||||
|
||||
override fun hasAnyOf(items: Set<Item>): Boolean {
|
||||
return toProxy.get().hasAnyOf(items)
|
||||
}
|
||||
|
||||
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
||||
return toProxy.get().hasAnyMatching(predicate)
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import net.minecraft.world.item.ItemStack
|
||||
import java.util.function.Predicate
|
||||
|
||||
// passthrough all default methods to fix Kotlin bug related to implementation delegation not properly working on Java interfaces
|
||||
// and also to give params proper names
|
||||
// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods
|
||||
interface IContainer : Container {
|
||||
override fun getMaxStackSize(): Int {
|
||||
@ -41,6 +42,16 @@ interface IContainer : Container {
|
||||
return super.hasAnyMatching(predicate)
|
||||
}
|
||||
|
||||
override fun clearContent()
|
||||
override fun getContainerSize(): Int
|
||||
override fun isEmpty(): Boolean
|
||||
override fun getItem(slot: Int): ItemStack
|
||||
override fun removeItem(slot: Int, amount: Int): ItemStack
|
||||
override fun removeItemNoUpdate(slot: Int): ItemStack
|
||||
override fun setItem(slot: Int, itemStack: ItemStack)
|
||||
override fun setChanged()
|
||||
|
||||
override fun stillValid(player: Player): Boolean
|
||||
companion object {
|
||||
fun wrap(container: Container): IContainer {
|
||||
if (container is IContainer)
|
||||
|
@ -0,0 +1,217 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntIterable
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
|
||||
interface IMatteryContainer : IContainer, Iterable<ItemStack> {
|
||||
fun getSlotFilter(slot: Int): Item?
|
||||
|
||||
/**
|
||||
* @return whenever the filter was set. Returns false only if container can't be filtered.
|
||||
*/
|
||||
fun setSlotFilter(slot: Int, filter: Item? = null): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
fun setChanged(slot: Int)
|
||||
|
||||
/**
|
||||
* Iterates over non-empty itemstacks of this container
|
||||
*/
|
||||
override fun iterator(): Iterator<ItemStack> {
|
||||
return iterator(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates non-empty slots of this container
|
||||
*/
|
||||
fun slotIterator(): Iterator<IContainerSlot> {
|
||||
return slotIterator(true)
|
||||
}
|
||||
|
||||
fun iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
||||
if (nonEmpty) {
|
||||
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
|
||||
} else {
|
||||
return (0 until containerSize).iterator().map { this[it] }
|
||||
}
|
||||
}
|
||||
|
||||
open class ContainerSlot(override val slot: Int, override val container: IMatteryContainer) : IContainerSlot {
|
||||
override val isForbiddenForAutomation: Boolean
|
||||
get() = container.isSlotForbiddenForAutomation(slot)
|
||||
|
||||
override fun getFilter(): Item? {
|
||||
return container.getSlotFilter(slot)
|
||||
}
|
||||
|
||||
override fun setFilter(filter: Item?): Boolean {
|
||||
return container.setSlotFilter(slot, filter)
|
||||
}
|
||||
|
||||
override fun getMaxStackSize(item: ItemStack): Int {
|
||||
return container.getMaxStackSize(slot, item)
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
container.setChanged(slot)
|
||||
}
|
||||
}
|
||||
|
||||
fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot> {
|
||||
if (nonEmpty) {
|
||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) }
|
||||
} else {
|
||||
return (0 until containerSize).iterator().map { containerSlot(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun containerSlot(slot: Int): IContainerSlot {
|
||||
return ContainerSlot(slot, this)
|
||||
}
|
||||
|
||||
fun hasSlotFilter(slot: Int) = getSlotFilter(slot) !== null
|
||||
fun isSlotForbiddenForAutomation(slot: Int) = getSlotFilter(slot) === Items.AIR
|
||||
|
||||
fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return testSlotFilter(slot, itemStack.item)
|
||||
}
|
||||
|
||||
fun testSlotFilter(slot: Int, item: Item): Boolean {
|
||||
if (getSlotFilter(slot) == null) {
|
||||
return true
|
||||
} else {
|
||||
return getSlotFilter(slot) === item
|
||||
}
|
||||
}
|
||||
|
||||
fun getMaxStackSize(slot: Int, itemStack: ItemStack) = maxStackSize.coerceAtMost(itemStack.maxStackSize)
|
||||
|
||||
private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntIterable, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack {
|
||||
if (stack.isEmpty)
|
||||
return stack
|
||||
|
||||
// двигаем в одинаковые слоты
|
||||
var i = slots.intIterator()
|
||||
|
||||
while (i.hasNext()) {
|
||||
val slot = i.nextInt()
|
||||
|
||||
if (
|
||||
(ignoreFilters || !isSlotForbiddenForAutomation(slot)) &&
|
||||
ItemStack.isSameItemSameTags(getItem(slot), stack) &&
|
||||
(ignoreFilters || !filterPass && !hasSlotFilter(slot) || filterPass && hasSlotFilter(slot) && testSlotFilter(slot, stack))
|
||||
) {
|
||||
val slotStack = getItem(slot)
|
||||
val slotLimit = getMaxStackSize(slot, slotStack)
|
||||
|
||||
if (slotStack.count < slotLimit) {
|
||||
val newCount = (slotStack.count + stack.count).coerceAtMost(slotLimit)
|
||||
val diff = newCount - slotStack.count
|
||||
|
||||
if (!simulate) {
|
||||
slotStack.count = newCount
|
||||
setChanged(slot)
|
||||
|
||||
if (popTime != null) {
|
||||
slotStack.popTime = popTime
|
||||
}
|
||||
}
|
||||
|
||||
stack.shrink(diff)
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return stack
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyIntoExisting) {
|
||||
i = slots.intIterator()
|
||||
|
||||
// двигаем в пустые слоты
|
||||
while (i.hasNext()) {
|
||||
val slot = i.nextInt()
|
||||
|
||||
if (
|
||||
getItem(slot).isEmpty &&
|
||||
(ignoreFilters || !isSlotForbiddenForAutomation(slot)) &&
|
||||
(ignoreFilters || !filterPass && !hasSlotFilter(slot) || filterPass && hasSlotFilter(slot) && testSlotFilter(slot, stack))
|
||||
) {
|
||||
val diff = stack.count.coerceAtMost(getMaxStackSize(slot, stack))
|
||||
|
||||
if (!simulate) {
|
||||
val copyToPut = stack.copy()
|
||||
copyToPut.count = diff
|
||||
setItem(slot, copyToPut)
|
||||
|
||||
if (popTime != null) {
|
||||
copyToPut.popTime = popTime
|
||||
}
|
||||
}
|
||||
|
||||
stack.shrink(diff)
|
||||
|
||||
if (stack.isEmpty) {
|
||||
return stack
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
fun addItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): ItemStack {
|
||||
if (stack.isEmpty)
|
||||
return stack
|
||||
|
||||
if (ignoreFilters) {
|
||||
return addItem(stack.copy(), simulate, true, slots, onlyIntoExisting, popTime, true)
|
||||
} else {
|
||||
var copy = addItem(stack.copy(), simulate, true, slots, onlyIntoExisting, popTime, false)
|
||||
copy = addItem(copy, simulate, false, slots, onlyIntoExisting, popTime, false)
|
||||
return copy
|
||||
}
|
||||
}
|
||||
|
||||
fun handler(filter: HandlerFilter = HandlerFilter.Both): ContainerHandler {
|
||||
return ContainerHandler(this, filter)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike [addItem], modifies original [stack]
|
||||
*
|
||||
* @return Whenever [stack] was modified
|
||||
*/
|
||||
fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean {
|
||||
if (stack.isEmpty)
|
||||
return false
|
||||
|
||||
val result = addItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters)
|
||||
|
||||
if (result.count != stack.count) {
|
||||
if (!simulate) {
|
||||
stack.count = result.count
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun fullyAddItem(stack: ItemStack, slots: IntIterable = slotRange, ignoreFilters: Boolean = false): Boolean {
|
||||
if (!addItem(stack, true, slots, ignoreFilters).isEmpty)
|
||||
return false
|
||||
|
||||
return addItem(stack, false, slots, ignoreFilters).isEmpty
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.jvm.JvmOverloads
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.entity.player.StackedContents
|
||||
import net.minecraft.world.inventory.StackedContentsCompatible
|
||||
@ -19,9 +19,7 @@ import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.container.util.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.util.IIterableContainer
|
||||
import ru.dbotthepony.mc.otm.core.addSorted
|
||||
import ru.dbotthepony.mc.otm.core.collect.any
|
||||
import ru.dbotthepony.mc.otm.core.collect.count
|
||||
@ -44,10 +42,9 @@ import java.util.function.Supplier
|
||||
import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.Iterator
|
||||
|
||||
@Suppress("UNUSED")
|
||||
open class MatteryContainer(protected val watcher: Runnable, private val size: Int) : IContainer, IIterableContainer, Iterable<ItemStack>, INBTSerializable<Tag?>, StackedContentsCompatible {
|
||||
open class MatteryContainer(protected val watcher: Runnable, private val size: Int) : IMatteryContainer, INBTSerializable<Tag?>, StackedContentsCompatible {
|
||||
constructor(size: Int) : this({}, size)
|
||||
|
||||
init {
|
||||
@ -134,7 +131,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
return field
|
||||
}
|
||||
|
||||
fun setSlotFilter(slot: Int, filter: Item? = null) {
|
||||
final override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
||||
if (filters[slot] !== filter) {
|
||||
filters[slot] = filter
|
||||
|
||||
@ -146,17 +143,19 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getSlotFilter(slot: Int) = filters[slot]
|
||||
fun hasSlotFilter(slot: Int) = filters[slot] !== null
|
||||
fun isSlotForbiddenForAutomation(slot: Int) = filters[slot] === Items.AIR
|
||||
final override fun getSlotFilter(slot: Int) = filters[slot]
|
||||
final override fun hasSlotFilter(slot: Int) = filters[slot] !== null
|
||||
final override fun isSlotForbiddenForAutomation(slot: Int) = filters[slot] === Items.AIR
|
||||
|
||||
fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean {
|
||||
final override fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return testSlotFilter(slot, itemStack.item)
|
||||
}
|
||||
|
||||
fun testSlotFilter(slot: Int, item: Item): Boolean {
|
||||
final override fun testSlotFilter(slot: Int, item: Item): Boolean {
|
||||
if (filters[slot] == null) {
|
||||
return true
|
||||
} else {
|
||||
@ -283,137 +282,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
}
|
||||
}
|
||||
|
||||
fun hasEmptySlot(): Boolean {
|
||||
for (i in 0 until size) {
|
||||
if (this[i].isEmpty) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun handler(filter: HandlerFilter = HandlerFilter.Both): ContainerHandler {
|
||||
return ContainerHandler(this, filter)
|
||||
}
|
||||
|
||||
open fun getMaxStackSize(slot: Int, itemStack: ItemStack) = maxStackSize.coerceAtMost(itemStack.maxStackSize)
|
||||
|
||||
/**
|
||||
* @return Leftover [ItemStack]
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun addItem(stack: ItemStack, range: IntRange, simulate: Boolean = false, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack {
|
||||
if (range.last >= size || range.first < 0)
|
||||
throw IllegalArgumentException("Invalid range: $range")
|
||||
|
||||
if (stack.isEmpty)
|
||||
return stack
|
||||
|
||||
val copy = stack.copy()
|
||||
|
||||
// двигаем в одинаковые слоты
|
||||
for (slot in range) {
|
||||
if (ItemStack.isSameItemSameTags(slots[slot], copy)) {
|
||||
val slotStack = slots[slot]
|
||||
val slotLimit = getMaxStackSize(slot, slotStack)
|
||||
|
||||
if (slotStack.count < slotLimit) {
|
||||
val newCount = (slotStack.count + copy.count).coerceAtMost(slotLimit)
|
||||
val diff = newCount - slotStack.count
|
||||
|
||||
if (!simulate) {
|
||||
val old = slotStack.copy()
|
||||
slotStack.count = newCount
|
||||
trackedSlots[slot] = slotStack.copy()
|
||||
changeset++
|
||||
internalSetChanged(slot, slotStack, old)
|
||||
|
||||
if (popTime != null) {
|
||||
slotStack.popTime = popTime
|
||||
}
|
||||
}
|
||||
|
||||
copy.shrink(diff)
|
||||
|
||||
if (copy.isEmpty) {
|
||||
return copy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyIntoExisting) {
|
||||
// двигаем в пустые слоты
|
||||
for (slot in range) {
|
||||
if (slots[slot].isEmpty) {
|
||||
val diff = copy.count.coerceAtMost(getMaxStackSize(slot, copy))
|
||||
|
||||
if (!simulate) {
|
||||
val copyToPut = copy.copy()
|
||||
copyToPut.count = diff
|
||||
slots[slot] = copyToPut
|
||||
trackedSlots[slot] = copyToPut.copy()
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
internalSetChanged(slot, copyToPut, ItemStack.EMPTY)
|
||||
|
||||
if (popTime != null) {
|
||||
copyToPut.popTime = popTime
|
||||
}
|
||||
}
|
||||
|
||||
copy.shrink(diff)
|
||||
|
||||
if (copy.isEmpty) {
|
||||
return copy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copy
|
||||
}
|
||||
|
||||
fun addItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack {
|
||||
return addItem(stack, 0 until size, simulate, onlyIntoExisting = onlyIntoExisting, popTime = popTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike [addItem], modifies original [stack]
|
||||
*
|
||||
* @return Whenever [stack] was modified
|
||||
*/
|
||||
fun consumeItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean {
|
||||
if (stack.isEmpty)
|
||||
return false
|
||||
|
||||
val result = addItem(stack, 0 until size, simulate, onlyIntoExisting = onlyIntoExisting, popTime = popTime)
|
||||
|
||||
if (result.count != stack.count) {
|
||||
if (!simulate) {
|
||||
stack.count = result.count
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun fullyAddItem(stack: ItemStack, start: Int = 0, end: Int = size - 1): Boolean {
|
||||
return fullyAddItem(stack, start .. end)
|
||||
}
|
||||
|
||||
fun fullyAddItem(stack: ItemStack, range: IntRange): Boolean {
|
||||
if (!addItem(stack, range, true).isEmpty)
|
||||
return false
|
||||
|
||||
return addItem(stack, range, false).isEmpty
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
final override fun isEmpty(): Boolean {
|
||||
return nonEmptyIndices.isEmpty
|
||||
}
|
||||
|
||||
@ -484,17 +353,17 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
return old
|
||||
}
|
||||
|
||||
final override fun setItem(slot: Int, stack: ItemStack) {
|
||||
if (slots[slot].isEmpty && stack.isEmpty || stack === slots[slot])
|
||||
final override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||
if (slots[slot].isEmpty && itemStack.isEmpty || itemStack === slots[slot])
|
||||
return
|
||||
|
||||
val old = slots[slot]
|
||||
slots[slot] = if (stack.isEmpty) ItemStack.EMPTY else stack
|
||||
trackedSlots[slot] = if (stack.isEmpty) ItemStack.EMPTY else stack.copy()
|
||||
slots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack
|
||||
trackedSlots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack.copy()
|
||||
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
internalSetChanged(slot, stack, old)
|
||||
internalSetChanged(slot, itemStack, old)
|
||||
}
|
||||
|
||||
final override fun setChanged() {
|
||||
@ -512,7 +381,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
}
|
||||
}
|
||||
|
||||
fun setChanged(slot: Int) {
|
||||
final override fun setChanged(slot: Int) {
|
||||
if (!slots[slot].equals(trackedSlots[slot], false)) {
|
||||
trackedSlots[slot] = slots[slot].copy()
|
||||
updateEmptyFlag(slot)
|
||||
@ -613,22 +482,50 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
}
|
||||
}
|
||||
|
||||
private inner class Slot(override val slot: Int) : IContainerSlot {
|
||||
override val container: Container
|
||||
get() = this@MatteryContainer
|
||||
|
||||
override val isForbiddenForAutomation: Boolean
|
||||
get() = isSlotForbiddenForAutomation(slot)
|
||||
|
||||
override fun getFilter(): Item? {
|
||||
return getSlotFilter(slot)
|
||||
}
|
||||
|
||||
override fun setFilter(filter: Item?): Boolean {
|
||||
return setSlotFilter(slot, filter)
|
||||
}
|
||||
|
||||
override fun getMaxStackSize(item: ItemStack): Int {
|
||||
return getMaxStackSize(slot, item)
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
setChanged(slot)
|
||||
}
|
||||
}
|
||||
|
||||
final override fun slotIterator(): kotlin.collections.Iterator<IContainerSlot> {
|
||||
indicesReferenced = true
|
||||
return nonEmptyIndices.iterator().map { ContainerSlot(it, this) }
|
||||
return nonEmptyIndices.iterator().map { Slot(it) }
|
||||
}
|
||||
|
||||
final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator<IContainerSlot> {
|
||||
if (!nonEmpty) {
|
||||
return (0 until size).iterator().map { ContainerSlot(it, this) }
|
||||
return (0 until size).iterator().map { Slot(it) }
|
||||
} else if (isEmpty) {
|
||||
return emptyIterator()
|
||||
} else {
|
||||
indicesReferenced = true
|
||||
return nonEmptyIndices.iterator().map { ContainerSlot(it, this) }
|
||||
return nonEmptyIndices.iterator().map { Slot(it) }
|
||||
}
|
||||
}
|
||||
|
||||
final override fun containerSlot(slot: Int): IContainerSlot {
|
||||
return Slot(slot)
|
||||
}
|
||||
|
||||
final override fun countItem(item: Item): Int {
|
||||
return iterator().filter { it.item == item }.count().toInt()
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.container.util
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.container.set
|
||||
@ -11,6 +13,10 @@ import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
|
||||
/**
|
||||
* While this somewhat similar to [net.minecraft.world.inventory.Slot], this slot is not meant
|
||||
* for Player interaction.
|
||||
*/
|
||||
interface IContainerSlot : GetterSetter<ItemStack> {
|
||||
val slot: Int
|
||||
val container: Container
|
||||
@ -18,28 +24,23 @@ interface IContainerSlot : GetterSetter<ItemStack> {
|
||||
operator fun component1() = slot
|
||||
operator fun component2() = item
|
||||
|
||||
fun getMaxStackSize(item: ItemStack = this.item): Int {
|
||||
return container.maxStackSize
|
||||
}
|
||||
|
||||
val isForbiddenForAutomation: Boolean get() {
|
||||
val container = container
|
||||
|
||||
if (container is MatteryContainer) {
|
||||
return container.isSlotForbiddenForAutomation(slot)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return getFilter() === Items.AIR
|
||||
}
|
||||
|
||||
val filter: Item? get() {
|
||||
val container = container
|
||||
fun getFilter(): Item?
|
||||
|
||||
if (container is MatteryContainer) {
|
||||
return container.getSlotFilter(slot)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return whenever the filter was set. Returns false only if container can't be filtered.
|
||||
*/
|
||||
fun setFilter(filter: Item? = null): Boolean
|
||||
|
||||
val hasFilter: Boolean
|
||||
get() = filter != null
|
||||
get() = getFilter() != null
|
||||
|
||||
fun remove() {
|
||||
container[slot] = ItemStack.EMPTY
|
||||
@ -54,13 +55,7 @@ interface IContainerSlot : GetterSetter<ItemStack> {
|
||||
}
|
||||
|
||||
fun setChanged() {
|
||||
val container = container
|
||||
|
||||
if (container is MatteryContainer) {
|
||||
container.setChanged(slot)
|
||||
} else {
|
||||
container.setChanged()
|
||||
}
|
||||
container.setChanged()
|
||||
}
|
||||
|
||||
var item: ItemStack
|
||||
@ -78,32 +73,28 @@ class ContainerSlot(override val slot: Int, override val container: Container) :
|
||||
init {
|
||||
require(slot in 0 until container.containerSize) { "Slot out of bounds: $slot (container: $container with size ${container.containerSize})" }
|
||||
}
|
||||
|
||||
override fun getFilter(): Item? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun setFilter(filter: Item?): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
interface IIterableContainer : Iterable<ItemStack> {
|
||||
/**
|
||||
* Iterates over non-empty itemstacks of this container
|
||||
*/
|
||||
override fun iterator(): Iterator<ItemStack> {
|
||||
return iterator(true)
|
||||
fun Container.containerSlot(slot: Int): IContainerSlot {
|
||||
if (this is IMatteryContainer) {
|
||||
return containerSlot(slot)
|
||||
} else {
|
||||
return ContainerSlot(slot, this)
|
||||
}
|
||||
|
||||
fun iterator(nonEmpty: Boolean): Iterator<ItemStack>
|
||||
|
||||
/**
|
||||
* Iterates non-empty slots of this container
|
||||
*/
|
||||
fun slotIterator(): Iterator<IContainerSlot> {
|
||||
return slotIterator(true)
|
||||
}
|
||||
|
||||
fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot>
|
||||
}
|
||||
|
||||
operator fun Container.iterator() = iterator(true)
|
||||
|
||||
fun Container.iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
||||
if (this is IIterableContainer) {
|
||||
if (this is IMatteryContainer) {
|
||||
return iterator(nonEmpty)
|
||||
} else if (nonEmpty) {
|
||||
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
|
||||
@ -113,7 +104,7 @@ fun Container.iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
||||
}
|
||||
|
||||
fun Container.slotIterator(nonEmpty: Boolean = true): Iterator<IContainerSlot> {
|
||||
if (this is IIterableContainer) {
|
||||
if (this is IMatteryContainer) {
|
||||
return slotIterator(nonEmpty)
|
||||
} else if (nonEmpty) {
|
||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { ContainerSlot(it, this) }
|
||||
|
@ -362,17 +362,12 @@ fun <T> Stream<T>.asIterable(): Iterable<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// Kotlin type safety:
|
||||
// since Java generics are invariant,
|
||||
// and can not distinguish between null and non-null type parameters
|
||||
// we need to tell compiler that Comparator.nullsFirst actually has next signature:
|
||||
// fun <T> Comparator.nullsFirst(original: Comparator<in T>): Comparator<in T?>
|
||||
fun <T> Comparator<in T>.nullsFirst(): Comparator<T?> {
|
||||
return Comparator.nullsFirst(this as Comparator<in T?>)
|
||||
fun <T> Comparator<T>.nullsFirst(): Comparator<T> {
|
||||
return Comparator.nullsFirst(this)
|
||||
}
|
||||
|
||||
fun <T> Comparator<in T>.nullsLast(): Comparator<T?> {
|
||||
return Comparator.nullsLast(this as Comparator<in T?>)
|
||||
fun <T> Comparator<T>.nullsLast(): Comparator<T> {
|
||||
return Comparator.nullsLast(this)
|
||||
}
|
||||
|
||||
class MappedComparator<T, O>(private val parent: Comparator<O>, private val mapper: (T) -> O) : Comparator<T> {
|
||||
|
@ -0,0 +1,24 @@
|
||||
package ru.dbotthepony.mc.otm.core.collect
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntIterable
|
||||
import it.unimi.dsi.fastutil.ints.IntIterator
|
||||
|
||||
fun IntRange.asIterable(): IntIterable {
|
||||
return IntIterable {
|
||||
val i = this@asIterable.iterator()
|
||||
|
||||
object : IntIterator {
|
||||
override fun hasNext(): Boolean {
|
||||
return i.hasNext()
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun nextInt(): Int {
|
||||
return i.nextInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -294,8 +294,8 @@ fun <T, A, R> Iterator<T>.collect(collector: Collector<T, A, R>): R {
|
||||
return collector.finisher().apply(instance)
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.toList(): MutableList<T> {
|
||||
val result = ArrayList<T>()
|
||||
fun <T> Iterator<T>.toList(expectedSize: Int = 16): MutableList<T> {
|
||||
val result = ArrayList<T>(expectedSize)
|
||||
result.addAll(this)
|
||||
return result
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ import ru.dbotthepony.mc.otm.matter.MatterManager
|
||||
import ru.dbotthepony.mc.otm.storage.ItemStorageStack
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
|
||||
private fun Comparator<Item?>.stacks(): Comparator<ItemStack?> {
|
||||
return Comparator<ItemStack> { o1, o2 -> this@stacks.compare(o1.item, o2.item) }.nullsFirst()
|
||||
private fun Comparator<Item>.stacks(): Comparator<ItemStack> {
|
||||
return Comparator { o1, o2 -> this@stacks.compare(o1.item, o2.item) }
|
||||
}
|
||||
|
||||
private fun Comparator<Item?>.storage(): Comparator<ItemStorageStack?> {
|
||||
return Comparator<ItemStorageStack> { o1, o2 -> this@storage.compare(o1.item, o2.item) }.nullsFirst()
|
||||
private fun Comparator<Item>.storage(): Comparator<ItemStorageStack> {
|
||||
return Comparator { o1, o2 -> this@storage.compare(o1.item, o2.item) }
|
||||
}
|
||||
|
||||
object CreativeMenuItemComparator : Comparator<Item> {
|
||||
@ -156,7 +156,7 @@ object ItemStorageStackCountComparator : Comparator<ItemStorageStack> {
|
||||
val NullsLast = nullsLast()
|
||||
}
|
||||
|
||||
enum class ItemSorter(comparator: Comparator<Item>, private val sTitle: Component, icon: Lazy<IGUIRenderable>) : Comparator<Item?> by comparator.nullsFirst() {
|
||||
enum class ItemSorter(comparator: Comparator<Item>, private val sTitle: Component, icon: Lazy<IGUIRenderable>) : Comparator<Item> by comparator {
|
||||
DEFAULT(CreativeMenuItemComparator, TranslatableComponent("otm.gui.sorting.default"), lazy { Widgets18.SORT_DEFAULT }),
|
||||
NAME(ItemLocalizedNameComparator.thenComparing(CreativeMenuItemComparator), TranslatableComponent("otm.gui.sorting.name"), lazy { Widgets18.SORT_ALPHABET }),
|
||||
ID(ItemIDComparator.thenComparing(CreativeMenuItemComparator), TranslatableComponent("otm.gui.sorting.id"), lazy { Widgets18.SORT_ID }),
|
||||
@ -167,14 +167,12 @@ enum class ItemSorter(comparator: Comparator<Item>, private val sTitle: Componen
|
||||
|
||||
val icon: IGUIRenderable by icon
|
||||
val title: MutableComponent get() = sTitle.copy()
|
||||
val suppliers = suppliers()
|
||||
val reversed: Comparator<Item?> = reversed()
|
||||
}
|
||||
|
||||
enum class ItemStackSorter(comparator: Comparator<ItemStack?>, private val sTitle: Component, icon: Lazy<IGUIRenderable>) : Comparator<ItemStack?> by comparator {
|
||||
enum class ItemStackSorter(comparator: Comparator<ItemStack>, private val sTitle: Component, icon: Lazy<IGUIRenderable>) : Comparator<ItemStack> by comparator {
|
||||
DEFAULT(ItemSorter.DEFAULT.stacks(), ItemSorter.DEFAULT.title, lazy { Widgets18.SORT_DEFAULT }),
|
||||
COUNT(ItemStackCountComparator.NullsFirst.thenComparing(ItemSorter.DEFAULT.stacks()), TranslatableComponent("otm.gui.sorting.count"), lazy { Widgets18.SORT_COUNT }),
|
||||
NAME(ItemStackNameComparator.NullsFirst.thenComparing(ItemSorter.DEFAULT.stacks()), ItemSorter.NAME.title, lazy { Widgets18.SORT_ALPHABET }),
|
||||
COUNT(ItemStackCountComparator.thenComparing(ItemSorter.DEFAULT.stacks()), TranslatableComponent("otm.gui.sorting.count"), lazy { Widgets18.SORT_COUNT }),
|
||||
NAME(ItemStackNameComparator.thenComparing(ItemSorter.DEFAULT.stacks()), ItemSorter.NAME.title, lazy { Widgets18.SORT_ALPHABET }),
|
||||
ID(ItemSorter.ID.stacks(), ItemSorter.ID.title, lazy { Widgets18.SORT_ID }),
|
||||
MOD(ItemSorter.MOD.stacks(), ItemSorter.MOD.title, lazy { Widgets18.SORT_MODID }),
|
||||
MATTER_VALUE(ItemSorter.MATTER_VALUE.stacks(), ItemSorter.MATTER_VALUE.title, lazy { Widgets18.SORT_MATTER_VALUE }),
|
||||
@ -182,14 +180,12 @@ enum class ItemStackSorter(comparator: Comparator<ItemStack?>, private val sTitl
|
||||
|
||||
val icon: IGUIRenderable by icon
|
||||
val title: MutableComponent get() = sTitle.copy()
|
||||
val suppliers = suppliers()
|
||||
val reversed: Comparator<ItemStack?> = reversed()
|
||||
}
|
||||
|
||||
enum class ItemStorageStackSorter(comparator: Comparator<ItemStorageStack?>, private val sTitle: Component, icon: Lazy<IGUIRenderable>) : Comparator<ItemStorageStack?> by comparator {
|
||||
enum class ItemStorageStackSorter(comparator: Comparator<ItemStorageStack>, private val sTitle: Component, icon: Lazy<IGUIRenderable>) : Comparator<ItemStorageStack> by comparator {
|
||||
DEFAULT(ItemSorter.DEFAULT.storage(), ItemSorter.DEFAULT.title, lazy { Widgets18.SORT_DEFAULT }),
|
||||
COUNT(ItemStorageStackCountComparator.NullsFirst.thenComparing(ItemSorter.DEFAULT.storage()), TranslatableComponent("otm.gui.sorting.count"), lazy { Widgets18.SORT_COUNT }),
|
||||
NAME(ItemStorageStackNameComparator.NullsFirst.thenComparing(ItemSorter.DEFAULT.storage()), ItemSorter.NAME.title, lazy { Widgets18.SORT_ALPHABET }),
|
||||
COUNT(ItemStorageStackCountComparator.thenComparing(ItemSorter.DEFAULT.storage()), TranslatableComponent("otm.gui.sorting.count"), lazy { Widgets18.SORT_COUNT }),
|
||||
NAME(ItemStorageStackNameComparator.thenComparing(ItemSorter.DEFAULT.storage()), ItemSorter.NAME.title, lazy { Widgets18.SORT_ALPHABET }),
|
||||
ID(ItemSorter.ID.storage(), ItemSorter.ID.title, lazy { Widgets18.SORT_ID }),
|
||||
MOD(ItemSorter.MOD.storage(), ItemSorter.MOD.title, lazy { Widgets18.SORT_MODID }),
|
||||
MATTER_VALUE(ItemSorter.MATTER_VALUE.storage(), ItemSorter.MATTER_VALUE.title, lazy { Widgets18.SORT_MATTER_VALUE }),
|
||||
@ -197,6 +193,4 @@ enum class ItemStorageStackSorter(comparator: Comparator<ItemStorageStack?>, pri
|
||||
|
||||
val icon: IGUIRenderable by icon
|
||||
val title: MutableComponent get() = sTitle.copy()
|
||||
val suppliers = suppliers()
|
||||
val reversed: Comparator<ItemStorageStack?> = reversed()
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import net.minecraftforge.network.NetworkEvent
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.allItems
|
||||
import ru.dbotthepony.mc.otm.capability.trackedItems
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.getBarColor
|
||||
import ru.dbotthepony.mc.otm.capability.energy.getBarWidth
|
||||
@ -347,7 +347,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
|
||||
for (ply in event.server.playerList.players) {
|
||||
val networkedChannels = ObjectOpenHashSet<UUID>(0)
|
||||
|
||||
for (item in ply.allItems().filter { it.isNotEmpty && it.item is QuantumBatteryItem }) {
|
||||
for (item in ply.trackedItems().filter { it.isNotEmpty && it.item is QuantumBatteryItem }) {
|
||||
val power = item.getCapability(MatteryCapability.ENERGY).orThrow() as Power
|
||||
power.updateValues()
|
||||
if (power.values.isServer && networkedChannels.add(power.values.uuid)) {
|
||||
|
@ -33,9 +33,10 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots
|
||||
import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
|
||||
import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||
import ru.dbotthepony.mc.otm.container.sort
|
||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
||||
@ -105,8 +106,6 @@ abstract class MatteryMenu(
|
||||
|
||||
private val _playerInventorySlots = ArrayList<InventorySlot>()
|
||||
private val _playerHotbarSlots = ArrayList<InventorySlot>()
|
||||
private val _playerMainSlots = ArrayList<InventorySlot>()
|
||||
private val _playerExoSuitSlots = ArrayList<InventorySlot>()
|
||||
private val _playerCombinedInventorySlots = ArrayList<InventorySlot>()
|
||||
private val _exopackChargeSlots = ArrayList<MatterySlot>()
|
||||
|
||||
@ -189,7 +188,7 @@ abstract class MatteryMenu(
|
||||
fun intInput(allowSpectators: Boolean = false, handler: (Int) -> Unit) = PlayerInput(VarIntValueCodec, allowSpectators, handler)
|
||||
|
||||
/**
|
||||
* hotbar + inventory + exosuit (in this order)
|
||||
* hotbar + inventory + Exopack (in this order)
|
||||
*/
|
||||
val playerInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerInventorySlots)
|
||||
|
||||
@ -199,17 +198,7 @@ abstract class MatteryMenu(
|
||||
val playerHotbarSlots: List<InventorySlot> = Collections.unmodifiableList(_playerHotbarSlots)
|
||||
|
||||
/**
|
||||
* inventory only
|
||||
*/
|
||||
val playerMainSlots: List<InventorySlot> = Collections.unmodifiableList(_playerMainSlots)
|
||||
|
||||
/**
|
||||
* exosuit only
|
||||
*/
|
||||
val playerExoSuitSlots: List<InventorySlot> = Collections.unmodifiableList(_playerExoSuitSlots)
|
||||
|
||||
/**
|
||||
* inventory + exosuit (in this order)
|
||||
* inventory + Exopack (in this order)
|
||||
*/
|
||||
val playerCombinedInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerCombinedInventorySlots)
|
||||
|
||||
@ -217,6 +206,9 @@ abstract class MatteryMenu(
|
||||
|
||||
val exopackPowerLevel = ProfiledLevelGaugeWidget<ProfiledEnergyStorage<*>>(mSynchronizer)
|
||||
|
||||
var sortInventoryInput: PlayerInput<Nothing?>? = null
|
||||
private set
|
||||
|
||||
var offhandSlot: InventorySlot? = null
|
||||
protected set
|
||||
|
||||
@ -267,7 +259,7 @@ abstract class MatteryMenu(
|
||||
return addFilterSlots(slots)
|
||||
}
|
||||
|
||||
open inner class InventorySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : UserFilteredSlot(container, index, x, y) {
|
||||
open inner class InventorySlot(container: Container, index: Int, addFilter: Boolean = false) : UserFilteredSlot(container, index, 0, 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return !isInventorySlotLocked(index) && super.mayPlace(itemStack)
|
||||
}
|
||||
@ -276,61 +268,30 @@ abstract class MatteryMenu(
|
||||
return !isInventorySlotLocked(index) && super.mayPickup(player)
|
||||
}
|
||||
|
||||
override fun isSameInventory(other: Slot): Boolean {
|
||||
if (container === inventory || container === player.matteryPlayer?.exopackContainer)
|
||||
return (other.container === inventory || other.container === player.matteryPlayer?.exopackContainer) && isSameFilter(other)
|
||||
|
||||
return super.isSameInventory(other)
|
||||
}
|
||||
|
||||
var chargeFlag: GetterSetter<Boolean>? = null
|
||||
private set
|
||||
|
||||
init {
|
||||
val mattery = player.matteryPlayer
|
||||
val mattery = player.matteryPlayer!!
|
||||
|
||||
if (mattery != null) {
|
||||
if (container === inventory) {
|
||||
if (slotIndex in mattery.regularSlotFilters.indices) {
|
||||
filter = GetterSetter.of(
|
||||
getter = { mattery.regularSlotFilters[slotIndex].value },
|
||||
setter = nullableItemInput(true) { mattery.regularSlotFilters[slotIndex].value = it }::accept
|
||||
)
|
||||
}
|
||||
if (addFilter) {
|
||||
val mContainer = container as IMatteryContainer
|
||||
|
||||
if (slotIndex in mattery.regularSlotChargeFlag.indices) {
|
||||
val input = booleanInput(true) { mattery.regularSlotChargeFlag[slotIndex].boolean = it }
|
||||
|
||||
chargeFlag = GetterSetter.of(
|
||||
getter = { mattery.regularSlotChargeFlag[slotIndex].boolean },
|
||||
setter = input::accept
|
||||
)
|
||||
}
|
||||
} else if (container === mattery.exopackContainer) {
|
||||
filter = GetterSetter.of(
|
||||
getter = { mattery.exopackContainer.getSlotFilter(slotIndex) },
|
||||
setter = nullableItemInput(true) { mattery.exopackContainer.setSlotFilter(slotIndex, it) }::accept
|
||||
)
|
||||
|
||||
val input = booleanInput(true) { if (it) mattery.exoPackSlotsChargeFlag.add(slotIndex) else mattery.exoPackSlotsChargeFlag.remove(slotIndex) }
|
||||
|
||||
chargeFlag = GetterSetter.of(
|
||||
getter = { slotIndex in mattery.exoPackSlotsChargeFlag },
|
||||
setter = input::accept
|
||||
)
|
||||
} else {
|
||||
filter = null
|
||||
}
|
||||
} else {
|
||||
filter = null
|
||||
filter = GetterSetter.of(
|
||||
getter = { mContainer.getSlotFilter(slotIndex) },
|
||||
setter = nullableItemInput(true) { mContainer.setSlotFilter(slotIndex, it) }::accept
|
||||
)
|
||||
}
|
||||
|
||||
chargeFlag = GetterSetter.of(
|
||||
getter = { slotIndex in mattery.slotsChargeFlag },
|
||||
setter = booleanInput(true) { if (it) mattery.slotsChargeFlag.add(slotIndex) else mattery.slotsChargeFlag.remove(slotIndex) }::accept
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
open inner class EquipmentSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot, x: Int = 0, y: Int = 0) : InventorySlot(container, index, x, y) {
|
||||
constructor(type: net.minecraft.world.entity.EquipmentSlot, x: Int = 0, y: Int = 0) : this(
|
||||
inventory, 34 + type.ordinal, type, x, y
|
||||
)
|
||||
open inner class EquipmentSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot) : InventorySlot(container, index) {
|
||||
constructor(type: net.minecraft.world.entity.EquipmentSlot) : this(inventory, 34 + type.ordinal, type)
|
||||
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return super.mayPlace(itemStack) && itemStack.canEquip(type, inventory.player)
|
||||
@ -351,6 +312,8 @@ abstract class MatteryMenu(
|
||||
|
||||
protected fun addInventorySlots(autoFrame: Boolean = !player.isSpectator) {
|
||||
check(_playerInventorySlots.isEmpty()) { "Already created inventory slots" }
|
||||
val mattery = player.matteryPlayer ?: return
|
||||
|
||||
autoCreateInventoryFrame = autoFrame
|
||||
|
||||
offhandSlot = object : InventorySlot(inventory, 40) {
|
||||
@ -362,11 +325,12 @@ abstract class MatteryMenu(
|
||||
mapQuickMoveToInventory(offhandSlot!!)
|
||||
addSlot(offhandSlot!!)
|
||||
|
||||
for (i in 0 .. 35) {
|
||||
val slot = InventorySlot(inventory, i)
|
||||
for (i in 0 until mattery.combinedInventory.containerSize) {
|
||||
if (i in Inventory.INVENTORY_SIZE .. player.inventory.containerSize) continue
|
||||
|
||||
val slot = InventorySlot(mattery.combinedInventory, i, true)
|
||||
|
||||
_playerInventorySlots.add(slot)
|
||||
_playerMainSlots.add(slot)
|
||||
|
||||
if (i <= 8)
|
||||
_playerHotbarSlots.add(slot)
|
||||
@ -378,21 +342,7 @@ abstract class MatteryMenu(
|
||||
addSlot(slot)
|
||||
}
|
||||
|
||||
val mattery = player.matteryPlayer
|
||||
|
||||
if (mattery != null && mattery.hasExopack) {
|
||||
for (i in 0 until mattery.exopackContainer.containerSize) {
|
||||
val slot = InventorySlot(mattery.exopackContainer, i)
|
||||
|
||||
_playerInventorySlots.add(slot)
|
||||
_playerExoSuitSlots.add(slot)
|
||||
_playerCombinedInventorySlots.add(slot)
|
||||
|
||||
mapQuickMove(slot, equipmentSlots)
|
||||
mapQuickMoveToExternal(slot)
|
||||
addSlot(slot)
|
||||
}
|
||||
|
||||
if (mattery.hasExopack) {
|
||||
_exopackChargeSlots.add(BatterySlot(mattery.exopackEnergy.parent, 0).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) })
|
||||
|
||||
for (i in 0 until mattery.exopackChargeSlots.containerSize)
|
||||
@ -400,6 +350,10 @@ abstract class MatteryMenu(
|
||||
|
||||
exopackPowerLevel.with(mattery.exopackEnergy)
|
||||
}
|
||||
|
||||
sortInventoryInput = PlayerInput(NullValueCodec) {
|
||||
mattery.inventoryAndExopackNoHotbar.sort()
|
||||
}
|
||||
}
|
||||
|
||||
private var broadcastOnce = false
|
||||
@ -471,7 +425,7 @@ abstract class MatteryMenu(
|
||||
val input: PlayerInput<Item?>
|
||||
val field: IField<Item?>
|
||||
|
||||
if (container is MatteryContainer) {
|
||||
if (container is IMatteryContainer) {
|
||||
input = PlayerInput(ItemValueCodec.nullable, handler = { container.setSlotFilter(pSlot.slotIndex, it) })
|
||||
field = mSynchronizer.ComputedField(getter = { container.getSlotFilter(pSlot.slotIndex) }, ItemValueCodec.nullable)
|
||||
} else {
|
||||
|
@ -11,6 +11,8 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.runOnClient
|
||||
@ -44,6 +46,26 @@ open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0)
|
||||
open fun canTakeItemForPickAll(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getMaxStackSize(): Int {
|
||||
val container = container
|
||||
|
||||
if (container is IMatteryContainer) {
|
||||
return container.getMaxStackSize(slotIndex, ItemStack.EMPTY)
|
||||
} else {
|
||||
return super.getMaxStackSize()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMaxStackSize(itemStack: ItemStack): Int {
|
||||
val container = container
|
||||
|
||||
if (container is IMatteryContainer) {
|
||||
return container.getMaxStackSize(slotIndex, itemStack)
|
||||
} else {
|
||||
return super.getMaxStackSize(itemStack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class UserFilteredSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y), Predicate<ItemStack> {
|
||||
|
@ -162,7 +162,7 @@ class NetworkedItemView(val ply: Player, val menu: MatteryMenu, val isRemote: Bo
|
||||
|
||||
val id2tuple = Int2ObjectOpenHashMap<Tuple>()
|
||||
val sortedView = ArrayList<Tuple>()
|
||||
var sorter: Comparator<in ItemStorageStack> = ItemStorageStackSorter.DEFAULT
|
||||
var sorter: Comparator<ItemStorageStack> = ItemStorageStackSorter.DEFAULT
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
|
@ -5,6 +5,8 @@ import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.sort
|
||||
import ru.dbotthepony.mc.otm.core.util.NullValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||
import ru.dbotthepony.mc.otm.menu.UserFilteredSlot
|
||||
@ -16,9 +18,12 @@ class CargoCrateMenu @JvmOverloads constructor(
|
||||
tile: CargoCrateBlockEntity? = null
|
||||
) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory, tile) {
|
||||
val storageSlots: List<UserFilteredSlot>
|
||||
|
||||
private val trackedPlayerOpen = !inventory.player.isSpectator
|
||||
|
||||
val sort = PlayerInput(NullValueCodec) {
|
||||
tile?.container?.sort()
|
||||
}
|
||||
|
||||
init {
|
||||
val container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY)
|
||||
|
||||
|
@ -55,7 +55,7 @@ class DriveViewerMenu(
|
||||
if (isAscending) {
|
||||
networkedItemView.sorter = sorting
|
||||
} else {
|
||||
networkedItemView.sorter = sorting.reversed
|
||||
networkedItemView.sorter = sorting.reversed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ class ItemMonitorMenu(
|
||||
if (ascendingSort) {
|
||||
networkedItemView.sorter = sorting
|
||||
} else {
|
||||
networkedItemView.sorter = sorting.reversed
|
||||
networkedItemView.sorter = sorting.reversed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1020 B After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user