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("balance_inputs", "Balance input slots")
|
||||||
|
|
||||||
|
gui("sorting.sort_now", "Sort")
|
||||||
gui("sorting.default", "Default sorting")
|
gui("sorting.default", "Default sorting")
|
||||||
gui("sorting.name", "Sort by name")
|
gui("sorting.name", "Sort by name")
|
||||||
gui("sorting.id", "Sort by ID")
|
gui("sorting.id", "Sort by ID")
|
||||||
|
@ -805,6 +805,7 @@ private fun gui(provider: MatteryLanguageProvider) {
|
|||||||
|
|
||||||
gui("balance_inputs", "Балансировать входные слоты")
|
gui("balance_inputs", "Балансировать входные слоты")
|
||||||
|
|
||||||
|
gui("sorting.sort_now", "Отсортировать")
|
||||||
gui("sorting.default", "Сортировка по умолчанию")
|
gui("sorting.default", "Сортировка по умолчанию")
|
||||||
gui("sorting.name", "Сортировка по имени")
|
gui("sorting.name", "Сортировка по имени")
|
||||||
gui("sorting.id", "Сортировка по ID")
|
gui("sorting.id", "Сортировка по ID")
|
||||||
|
@ -43,8 +43,6 @@ import java.util.*
|
|||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
import ru.dbotthepony.mc.otm.client.render.Widgets8
|
import ru.dbotthepony.mc.otm.client.render.Widgets8
|
||||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
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.container.util.slotIterator
|
||||||
import ru.dbotthepony.mc.otm.core.collect.map
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
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}" }
|
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()
|
val copy = craftingGrid.iterator(true).map { it.copy() }.toList()
|
||||||
|
|
||||||
// удаляем по одному предмету из сетки крафта
|
// удаляем по одному предмету из сетки крафта
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.server.level.ServerLevel
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
@ -74,7 +75,7 @@ class PlatePressBlockEntity(
|
|||||||
if (status.job.itemStack.isEmpty)
|
if (status.job.itemStack.isEmpty)
|
||||||
return status.success()
|
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()
|
return status.noItem()
|
||||||
|
|
||||||
experience = (experience + status.experience).coerceAtMost(100.0)
|
experience = (experience + status.experience).coerceAtMost(100.0)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.capability
|
package ru.dbotthepony.mc.otm.capability
|
||||||
|
|
||||||
import com.google.common.collect.Streams
|
import com.google.common.collect.Streams
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.network.chat.Component
|
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.getMekanismEnergySided
|
||||||
import ru.dbotthepony.mc.otm.compat.mekanism.mekanismEnergy
|
import ru.dbotthepony.mc.otm.compat.mekanism.mekanismEnergy
|
||||||
import ru.dbotthepony.mc.otm.container.util.awareStream
|
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.container.util.iterator
|
||||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ContainerItemStackEntry
|
import ru.dbotthepony.mc.otm.core.collect.ContainerItemStackEntry
|
||||||
import ru.dbotthepony.mc.otm.core.collect.concatIterators
|
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.filter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.map
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
@ -217,21 +216,16 @@ fun ICapabilityProvider.getMatteryEnergySided(side: Direction? = null): LazyOpti
|
|||||||
return LazyOptional.empty()
|
return LazyOptional.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DO NOT modify returned ItemStacks!
|
|
||||||
*
|
|
||||||
* Contains all items that player might carry
|
|
||||||
*/
|
|
||||||
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||||
val iterators = ArrayList<Iterator<ItemStack>>()
|
val matteryPlayer = matteryPlayer ?: return emptyIterator()
|
||||||
iterators.add(inventory.iterator())
|
|
||||||
|
|
||||||
matteryPlayer?.let {
|
val iterators = ArrayList<Iterator<ItemStack>>()
|
||||||
if (it.hasExopack) {
|
iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item })
|
||||||
iterators.add(it.exopackContainer.iterator())
|
|
||||||
iterators.add(it.exopackEnergy.parent.iterator())
|
if (matteryPlayer.hasExopack) {
|
||||||
iterators.add(it.exopackChargeSlots.iterator())
|
iterators.add(matteryPlayer.exopackContainer.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item })
|
||||||
}
|
iterators.add(matteryPlayer.exopackEnergy.parent.iterator())
|
||||||
|
iterators.add(matteryPlayer.exopackChargeSlots.iterator())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCuriosLoaded) {
|
if (isCuriosLoaded) {
|
||||||
@ -245,25 +239,12 @@ fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
|||||||
return concatIterators(iterators)
|
return concatIterators(iterators)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun Player.trackedItems(includeCosmetics: Boolean = true): Iterator<ItemStack> {
|
||||||
* 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> {
|
|
||||||
if (containerMenu == inventoryMenu || containerMenu == matteryPlayer?.exoPackMenu) {
|
if (containerMenu == inventoryMenu || containerMenu == matteryPlayer?.exoPackMenu) {
|
||||||
return items(includeCosmetics)
|
return items(includeCosmetics)
|
||||||
}
|
}
|
||||||
|
|
||||||
val seen = ReferenceOpenHashSet<ItemStack>(containerMenu.slots.size)
|
return concatIterators(items(includeCosmetics), containerMenu.slots.iterator().map { it.item }.filter { it.isNotEmpty })
|
||||||
|
|
||||||
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 })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +10,6 @@ import net.minecraft.client.player.AbstractClientPlayer
|
|||||||
import net.minecraft.commands.Commands
|
import net.minecraft.commands.Commands
|
||||||
import net.minecraft.commands.arguments.EntityArgument
|
import net.minecraft.commands.arguments.EntityArgument
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.nbt.ByteTag
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.nbt.IntTag
|
import net.minecraft.nbt.IntTag
|
||||||
import net.minecraft.nbt.ListTag
|
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.boss.wither.WitherBoss
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.item.ProjectileWeaponItem
|
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.CombinedContainer
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.container.get
|
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.util.slotIterator
|
||||||
import ru.dbotthepony.mc.otm.container.vanishCursedItems
|
import ru.dbotthepony.mc.otm.container.vanishCursedItems
|
||||||
import ru.dbotthepony.mc.otm.core.*
|
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.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||||
import ru.dbotthepony.mc.otm.core.math.minus
|
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.getCompoundList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.getIntList
|
import ru.dbotthepony.mc.otm.core.nbt.getIntList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
||||||
@ -258,27 +259,23 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
synchronizer.Field(null, ItemValueCodec.nullable)
|
synchronizer.Field(null, ItemValueCodec.nullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
val regularSlotChargeFlag = immutableList(Inventory.INVENTORY_SIZE + 5) {
|
val slotsChargeFlag by synchronizer.Set(
|
||||||
synchronizer.bool()
|
codec = VarIntValueCodec,
|
||||||
}
|
backingSet = IntAVLTreeSet(),
|
||||||
|
)
|
||||||
|
|
||||||
private fun slotChargeToDefault() {
|
private fun slotChargeToDefault() {
|
||||||
// броня
|
// броня
|
||||||
regularSlotChargeFlag[36].boolean = true
|
slotsChargeFlag.add(36)
|
||||||
regularSlotChargeFlag[37].boolean = true
|
slotsChargeFlag.add(37)
|
||||||
regularSlotChargeFlag[38].boolean = true
|
slotsChargeFlag.add(38)
|
||||||
regularSlotChargeFlag[39].boolean = true
|
slotsChargeFlag.add(39)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
slotChargeToDefault()
|
slotChargeToDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
val exoPackSlotsChargeFlag by synchronizer.Set(
|
|
||||||
codec = VarIntValueCodec,
|
|
||||||
backingSet = IntAVLTreeSet(),
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exopack container, which actually store items inside Exopack
|
* Exopack container, which actually store items inside Exopack
|
||||||
*/
|
*/
|
||||||
@ -303,19 +300,60 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
value.addFilterSynchronizer(synchronizer)
|
value.addFilterSynchronizer(synchronizer)
|
||||||
field = value
|
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 _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
|
val combinedInventory: CombinedContainer
|
||||||
get() {
|
get() {
|
||||||
if (_combinedInventory == null)
|
if (_combinedInventory == null)
|
||||||
_combinedInventory = CombinedContainer(ply.inventory, exopackContainer)
|
_combinedInventory = CombinedContainer(wrappedInventory, exopackContainer)
|
||||||
|
|
||||||
return _combinedInventory!!
|
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
|
* Whenever Exopack has 3x3 crafting grid upgrade installed
|
||||||
*/
|
*/
|
||||||
@ -914,14 +952,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tag["regularSlotChargeFlag"] = ListTag().also {
|
tag["slotsChargeFlag"] = ListTag().also {
|
||||||
for (flag in regularSlotChargeFlag) {
|
for (value in slotsChargeFlag) {
|
||||||
it.add(ByteTag.valueOf(flag.boolean))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tag["exoPackSlotsChargeFlag"] = ListTag().also {
|
|
||||||
for (value in exoPackSlotsChargeFlag) {
|
|
||||||
it.add(IntTag.valueOf(value))
|
it.add(IntTag.valueOf(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -945,12 +977,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
filter.value = null
|
filter.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
for (flag in regularSlotChargeFlag) {
|
slotsChargeFlag.clear()
|
||||||
flag.boolean = false
|
|
||||||
}
|
|
||||||
|
|
||||||
exoPackSlotsChargeFlag.clear()
|
|
||||||
|
|
||||||
slotChargeToDefault()
|
slotChargeToDefault()
|
||||||
|
|
||||||
val regularSlotFilters = tag.getStringList("regularSlotFilters")
|
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
|
this.regularSlotFilters[i].value = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(path) ?: continue) ?: Items.AIR
|
||||||
}
|
}
|
||||||
|
|
||||||
val regularSlotChargeFlag = tag.getByteList("regularSlotChargeFlag")
|
for (v in tag.getIntList("slotsChargeFlag")) {
|
||||||
|
this.slotsChargeFlag.add(v.asInt)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterations
|
// iterations
|
||||||
@ -1128,25 +1149,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (available.isPositive) {
|
if (available.isPositive) {
|
||||||
for ((i, flag) in regularSlotChargeFlag.withIndex()) {
|
for (slot in slotsChargeFlag) {
|
||||||
if (flag.boolean) {
|
if (slot in 0 until combinedInventory.containerSize) {
|
||||||
val item = ply.inventory[i]
|
val item = combinedInventory[slot]
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
if (item.isNotEmpty) {
|
if (item.isNotEmpty) {
|
||||||
item.energy?.let {
|
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)
|
* This re-implement [Inventory.add] logic (original method is redirected to this)
|
||||||
*/
|
*/
|
||||||
fun inventoryAddImpl(stack: ItemStack): Boolean {
|
fun inventoryAddImpl(stack: ItemStack): Boolean {
|
||||||
val items = ply.inventory.items
|
inventoryAndExopack.consumeItem(stack, false, popTime = 5)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
|
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
|
||||||
|
|
||||||
if (ply.abilities.instabuild) {
|
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 {
|
init {
|
||||||
WitherBoss.TARGETING_CONDITIONS.selector(WitherBoss.TARGETING_CONDITIONS.selector!!.and { it.matteryPlayer?.isAndroid != true })
|
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 }
|
WitherBoss.LIVING_ENTITY_SELECTOR = WitherBoss.LIVING_ENTITY_SELECTOR.and { it.matteryPlayer?.isAndroid != true }
|
||||||
|
@ -87,8 +87,8 @@ private fun inventoryLogic(event: ScreenEvent.Init.Post) {
|
|||||||
val widget = Panel2Widget(LargeRectangleButtonPanel(screen, null,
|
val widget = Panel2Widget(LargeRectangleButtonPanel(screen, null,
|
||||||
x = screen.guiLeft + screen.xSize - 2f - LargeRectangleButtonPanel.SIZE,
|
x = screen.guiLeft + screen.xSize - 2f - LargeRectangleButtonPanel.SIZE,
|
||||||
y = screen.guiTop.toFloat() - LargeRectangleButtonPanel.SIZE - 2,
|
y = screen.guiTop.toFloat() - LargeRectangleButtonPanel.SIZE - 2,
|
||||||
skinElement = Widgets18.RETURN_ARROW_LEFT,
|
icon = Widgets18.RETURN_ARROW_LEFT,
|
||||||
skinElementWinding = UVWindingOrder.FLOP,
|
iconWinding = UVWindingOrder.FLOP,
|
||||||
onPress = {
|
onPress = {
|
||||||
shouldOpenVanillaInventory = false
|
shouldOpenVanillaInventory = false
|
||||||
val mouseX = minecraft.mouseHandler.xpos()
|
val mouseX = minecraft.mouseHandler.xpos()
|
||||||
|
@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas
|
|||||||
|
|
||||||
object WidgetLocation {
|
object WidgetLocation {
|
||||||
val LARGE_BUTTON = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/large_button.png"), 72f, 18f)
|
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 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)
|
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_STRETCHABLE = makeButton(buttonGrids)
|
||||||
val BUTTON_DISABLED = buttonGrids.next()
|
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_DOWN = storageGrid.next()
|
||||||
val ARROW_UP = storageGrid.next()
|
val ARROW_UP = storageGrid.next()
|
||||||
val SORT_DEFAULT = storageGrid.next()
|
val SORT_DEFAULT = storageGrid.next()
|
||||||
@ -53,6 +53,7 @@ object Widgets18 {
|
|||||||
val PAUSE = storageGrid.next()
|
val PAUSE = storageGrid.next()
|
||||||
val PLAY = storageGrid.next()
|
val PLAY = storageGrid.next()
|
||||||
val STOP = storageGrid.next()
|
val STOP = storageGrid.next()
|
||||||
|
val SORT_NOW = storageGrid.next()
|
||||||
|
|
||||||
private val miscGrid = WidgetLocation.MISC_18.grid(4, 4)
|
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.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.client.render.sprites.sprite
|
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.*
|
||||||
|
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.button.LargeRectangleButtonPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
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.dock = Dock.RIGHT
|
||||||
scrollPanel.setDockMargin(right = 3f)
|
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
|
shouldOpenVanillaInventory = true
|
||||||
val minecraft = minecraft!!
|
val minecraft = minecraft!!
|
||||||
|
|
||||||
@ -256,14 +257,28 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
|
|||||||
}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_back")) }
|
}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_back")) }
|
||||||
|
|
||||||
if (isCuriosLoaded) {
|
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)
|
openCuriosScreen(minecraft!!.player!!.containerMenu.carried)
|
||||||
}).also { it.tooltips.add(TranslatableComponent("otm.gui.exopack.go_curios")) }
|
}).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
|
frame.y += movePixels
|
||||||
moveMousePosScaled(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
|
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.Widgets18
|
||||||
import ru.dbotthepony.mc.otm.client.render.translation
|
import ru.dbotthepony.mc.otm.client.render.translation
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
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.AbstractSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
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
|
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) {
|
return HeightControls(this, parent, x, y) {
|
||||||
inventoryRows += if (it) 1 else -1
|
inventoryRows += if (it) 1 else -1
|
||||||
callback.invoke(if (it) -AbstractSlotPanel.SIZE / 2f else AbstractSlotPanel.SIZE / 2f)
|
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 {
|
init {
|
||||||
if (menu.playerInventorySlots.isNotEmpty() && menu.autoCreateInventoryFrame) {
|
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 = FramePanel<MatteryScreen<*>>(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
|
||||||
inventoryFrame!!.makeHelpButton().addSlotFiltersHelp().also {
|
inventoryFrame!!.makeHelpButton().addSlotFiltersHelp().also {
|
||||||
if (menu.player.matteryPlayer?.hasExopack == true)
|
if (menu.player.matteryPlayer?.hasExopack == true)
|
||||||
it.tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
it.tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceControls = DeviceControls(this, inventoryFrame!!)
|
||||||
|
|
||||||
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
|
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
|
||||||
hotbarStrip.dock = Dock.BOTTOM
|
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"))
|
it.tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deviceControls = DeviceControls(this, inventoryFrame!!)
|
||||||
|
|
||||||
inventoryScrollbar = DiscreteScrollBarPanel(this, inventoryFrame, { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) }, {
|
inventoryScrollbar = DiscreteScrollBarPanel(this, inventoryFrame, { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) }, {
|
||||||
_, old, new ->
|
_, 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 }
|
mainFrame?.let { it.y += movePixels }
|
||||||
inventoryFrame?.let { it.y += movePixels }
|
inventoryFrame?.let { it.y += movePixels }
|
||||||
moveMousePosScaled(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()) {
|
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.network.chat.Component
|
||||||
import net.minecraft.world.entity.player.Inventory
|
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.MatteryScreen
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
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.util.GridPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
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.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||||
|
|
||||||
class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen<CargoCrateMenu>(menu, inventory, title) {
|
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)
|
for (slot in menu.storageSlots)
|
||||||
UserFilteredSlotPanel.of(this, grid, slot)
|
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
|
return frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ class PainterScreen(menu: PainterMenu, inventory: Inventory, title: Component) :
|
|||||||
buttons.clear()
|
buttons.clear()
|
||||||
|
|
||||||
for (recipe in menu.possibleRecipes) {
|
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 {
|
init {
|
||||||
buttons.add(this)
|
buttons.add(this)
|
||||||
dockRight = 1f
|
dockRight = 1f
|
||||||
|
@ -77,7 +77,7 @@ class MatterPanelScreen(
|
|||||||
LargeRectangleButtonPanel(
|
LargeRectangleButtonPanel(
|
||||||
this,
|
this,
|
||||||
frame,
|
frame,
|
||||||
skinElement = Widgets18.STOP,
|
icon = Widgets18.STOP,
|
||||||
onPress = {
|
onPress = {
|
||||||
frame.queryUser(
|
frame.queryUser(
|
||||||
TranslatableComponent("otm.gui.matter_panel.cancel_all"),
|
TranslatableComponent("otm.gui.matter_panel.cancel_all"),
|
||||||
|
@ -386,7 +386,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
if (upgrades != null) {
|
if (upgrades != null) {
|
||||||
upgradesButton = addButton(object : LargeRectangleButtonPanel<S>(
|
upgradesButton = addButton(object : LargeRectangleButtonPanel<S>(
|
||||||
screen, this@DeviceControls,
|
screen, this@DeviceControls,
|
||||||
skinElement = Widgets18.UPGRADES
|
icon = Widgets18.UPGRADES
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.upgrades"))
|
tooltips.add(TranslatableComponent("otm.gui.upgrades"))
|
||||||
@ -473,7 +473,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (itemConfig != null) {
|
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 {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sides.item_config"))
|
tooltips.add(TranslatableComponent("otm.gui.sides.item_config"))
|
||||||
}
|
}
|
||||||
@ -492,7 +492,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (energyConfig != null) {
|
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 {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sides.energy_config"))
|
tooltips.add(TranslatableComponent("otm.gui.sides.energy_config"))
|
||||||
}
|
}
|
||||||
@ -511,7 +511,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fluidConfig != null) {
|
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 {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sides.fluid_config"))
|
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() {
|
override fun tickInner() {
|
||||||
super.tickInner()
|
super.tickInner()
|
||||||
x = (parent?.width ?: 0f) + 3f
|
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 {
|
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.GuiGraphics
|
||||||
import net.minecraft.client.gui.screens.Screen
|
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.IGUIRenderable
|
||||||
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
||||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
|
|
||||||
open class LargeRectangleButtonPanel<out S : Screen>(
|
open class LargeRectangleButtonPanel<out S : Screen>(
|
||||||
screen: S,
|
screen: S,
|
||||||
@ -15,8 +17,8 @@ open class LargeRectangleButtonPanel<out S : Screen>(
|
|||||||
width: Float = SIZE,
|
width: Float = SIZE,
|
||||||
height: Float = SIZE,
|
height: Float = SIZE,
|
||||||
onPress: ((clickButton: Int) -> Unit)? = null,
|
onPress: ((clickButton: Int) -> Unit)? = null,
|
||||||
var skinElement: IGUIRenderable? = null,
|
var icon: IGUIRenderable? = null,
|
||||||
var skinElementWinding: UVWindingOrder? = null,
|
var iconWinding: UVWindingOrder? = null,
|
||||||
) : RectangleButtonPanel<S>(screen, parent, x, y, width, height, onPress) {
|
) : RectangleButtonPanel<S>(screen, parent, x, y, width, height, onPress) {
|
||||||
final override val IDLE = Widgets18.BUTTON_IDLE
|
final override val IDLE = Widgets18.BUTTON_IDLE
|
||||||
final override val HOVERED = Widgets18.BUTTON_HOVERED
|
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) {
|
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
super.innerRender(graphics, mouseX, mouseY, partialTick)
|
super.innerRender(graphics, mouseX, mouseY, partialTick)
|
||||||
|
|
||||||
if (skinElementWinding != null) {
|
if (iconWinding != null) {
|
||||||
skinElement?.render(graphics, width = width, height = height, winding = skinElementWinding!!)
|
icon?.render(graphics, width = width, height = height, winding = iconWinding!!)
|
||||||
} else {
|
} else {
|
||||||
skinElement?.render(graphics, width = width, height = height)
|
icon?.render(graphics, width = width, height = height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SIZE = 18f
|
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.dockResize = DockResizeMode.NONE
|
||||||
outputs.dockMargin = DockProperty(bottom = 3f)
|
outputs.dockMargin = DockProperty(bottom = 3f)
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_1) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, icon = STORE_1) {
|
||||||
init {
|
init {
|
||||||
dockRight = 3f
|
dockRight = 3f
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.store", 1))
|
tooltips.add(TranslatableComponent("otm.gui.experience.store", 1))
|
||||||
@ -108,7 +108,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_10) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, icon = STORE_10) {
|
||||||
init {
|
init {
|
||||||
dockRight = 3f
|
dockRight = 3f
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.store", 10))
|
tooltips.add(TranslatableComponent("otm.gui.experience.store", 10))
|
||||||
@ -123,7 +123,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, skinElement = STORE_ALL) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, inputs, icon = STORE_ALL) {
|
||||||
init {
|
init {
|
||||||
dockRight = 3f
|
dockRight = 3f
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.store_all"))
|
tooltips.add(TranslatableComponent("otm.gui.experience.store_all"))
|
||||||
@ -138,7 +138,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_1) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, icon = DISPENSE_1) {
|
||||||
init {
|
init {
|
||||||
dockRight = 3f
|
dockRight = 3f
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", 1))
|
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", 1))
|
||||||
@ -153,7 +153,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_10) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, icon = DISPENSE_10) {
|
||||||
init {
|
init {
|
||||||
dockRight = 3f
|
dockRight = 3f
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", 10))
|
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", 10))
|
||||||
@ -168,7 +168,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, skinElement = DISPENSE_ALL) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, outputs, icon = DISPENSE_ALL) {
|
||||||
init {
|
init {
|
||||||
dockRight = 3f
|
dockRight = 3f
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense_all"))
|
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)
|
val customBar = HorizontalStripPanel(this, frame, height = 18f)
|
||||||
customBar.dock = Dock.TOP
|
customBar.dock = Dock.TOP
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = STORE_CUSTOM) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, icon = STORE_CUSTOM) {
|
||||||
init {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.store", customDispense))
|
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 {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", customDispense))
|
tooltips.add(TranslatableComponent("otm.gui.experience.dispense", customDispense))
|
||||||
}
|
}
|
||||||
@ -241,7 +241,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title
|
|||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, skinElement = SET_EXACT) {
|
object : LargeRectangleButtonPanel<EssenceStorageScreen>(this@EssenceStorageScreen, customBar, icon = SET_EXACT) {
|
||||||
init {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.experience.set_exact", customDispense))
|
tooltips.add(TranslatableComponent("otm.gui.experience.set_exact", customDispense))
|
||||||
dock = Dock.RIGHT
|
dock = Dock.RIGHT
|
||||||
|
@ -4,17 +4,18 @@ import com.google.common.collect.ImmutableList
|
|||||||
import com.google.common.collect.ImmutableMap
|
import com.google.common.collect.ImmutableMap
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
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.ints.IntSet
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.entity.player.Player
|
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 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.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.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.concatIterators
|
||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.flatMap
|
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.LinkedList
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Container, IIterableContainer {
|
class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IMatteryContainer {
|
||||||
constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize).iterator() })
|
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).iterator() })
|
constructor(containers: Collection<Container>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||||
|
|
||||||
private val slots: List<ContainerSlot>
|
private inner class Slot(override val slot: Int, val outer: IContainerSlot) : IContainerSlot by outer {
|
||||||
private val slotsMap: Map<Container, List<ContainerSlot>>
|
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 containers: Set<Container>
|
||||||
private val fullCoverage: List<Container>
|
private val fullCoverage: List<Container>
|
||||||
private val notFullCoverage: Map<Container, List<ContainerSlot>>
|
private val notFullCoverage: Map<Container, List<IContainerSlot>>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val list = ImmutableList.Builder<ContainerSlot>()
|
val list = ImmutableList.Builder<Slot>()
|
||||||
var i = 0
|
var i = 0
|
||||||
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
|
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
|
||||||
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<ContainerSlot>>()
|
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<IContainerSlot>>()
|
||||||
|
|
||||||
for ((container, slots) in containers) {
|
for ((container, slots) in containers) {
|
||||||
val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntAVLTreeSet() })
|
val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntAVLTreeSet() })
|
||||||
@ -46,9 +60,8 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Co
|
|||||||
|
|
||||||
for (slot in slots) {
|
for (slot in slots) {
|
||||||
if (validator.add(slot)) {
|
if (validator.add(slot)) {
|
||||||
i++
|
val slotObj = container.containerSlot(slot)
|
||||||
val slotObj = ContainerSlot(slot, container)
|
list.add(Slot(i++, slotObj))
|
||||||
list.add(slotObj)
|
|
||||||
slotList.add(slotObj)
|
slotList.add(slotObj)
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot")
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun slotAt(index: Int): ContainerSlot {
|
override fun getItem(slot: Int): ItemStack {
|
||||||
return slots[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItem(index: Int): ItemStack {
|
|
||||||
// do not violate contract of getItem not throwing exceptions when index is invalid
|
// 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 {
|
override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||||
val data = slots.getOrNull(index) ?: return ItemStack.EMPTY
|
val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY
|
||||||
return data.container.removeItem(data.slot, count)
|
return data.outer.container.removeItem(data.outer.slot, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeItemNoUpdate(index: Int): ItemStack {
|
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||||
val data = slots.getOrNull(index) ?: return ItemStack.EMPTY
|
val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY
|
||||||
return data.container.removeItemNoUpdate(data.slot)
|
return data.outer.container.removeItemNoUpdate(data.outer.slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setItem(index: Int, value: ItemStack) {
|
override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||||
slots.getOrNull(index)?.item = value
|
slots.getOrNull(slot)?.item = itemStack
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChanged() {
|
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 {
|
override fun stillValid(player: Player): Boolean {
|
||||||
for (container in containers)
|
for (container in containers)
|
||||||
if (!container.stillValid(player))
|
if (!container.stillValid(player))
|
||||||
@ -168,33 +167,64 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterator<Int>>>) : Co
|
|||||||
return slots.iterator()
|
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 {
|
class Builder {
|
||||||
private var built = false
|
private val values = ArrayList<Pair<Container, Iterable<Int>>>()
|
||||||
private val values = LinkedList<Pair<Container, Iterator<Int>>>()
|
|
||||||
|
|
||||||
fun add(container: Container): Builder {
|
fun add(container: Container): Builder {
|
||||||
check(!built) { "Already built!" }
|
values.add(container to container.slotRange)
|
||||||
values.add(container to (0 until container.containerSize).iterator())
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(container: Container, slots: Iterator<Int>): Builder {
|
fun add(container: Container, slots: Iterator<Int>): Builder {
|
||||||
check(!built) { "Already built!" }
|
values.add(container to IntArrayList(slots))
|
||||||
values.add(container to 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
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(container: Container, slots: Iterable<Int>): Builder {
|
fun add(container: Container, slots: Iterable<Int>): Builder {
|
||||||
check(!built) { "Already built!" }
|
values.add(container to slots)
|
||||||
values.add(container to slots.iterator())
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): CombinedContainer {
|
fun build(): CombinedContainer {
|
||||||
check(!built) { "Already built!" }
|
return CombinedContainer(values.stream())
|
||||||
val value = CombinedContainer(values.stream())
|
}
|
||||||
values.clear()
|
}
|
||||||
return value
|
|
||||||
|
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.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.items.IItemHandler
|
import net.minecraftforge.items.IItemHandler
|
||||||
|
|
||||||
class ContainerHandler @JvmOverloads internal constructor(
|
class ContainerHandler(
|
||||||
private val container: MatteryContainer,
|
private val container: IMatteryContainer,
|
||||||
private val filter: HandlerFilter = HandlerFilter.Both,
|
private val filter: HandlerFilter = HandlerFilter.Both,
|
||||||
) : IItemHandler {
|
) : IItemHandler {
|
||||||
override fun getSlots() = container.containerSize
|
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.IntAVLTreeSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import it.unimi.dsi.fastutil.ints.IntArraySet
|
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.ints.IntSet
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
|
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.ItemStack
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
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.ItemStackHashStrategy
|
||||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||||
import ru.dbotthepony.mc.otm.core.addAll
|
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.isNotEmpty
|
||||||
|
import ru.dbotthepony.mc.otm.core.map
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -27,13 +33,30 @@ inline operator fun Container.get(index: Int): ItemStack = getItem(index)
|
|||||||
@Suppress("nothing_to_inline")
|
@Suppress("nothing_to_inline")
|
||||||
inline operator fun IFluidHandler.get(index: Int) = getFluidInTank(index)
|
inline operator fun IFluidHandler.get(index: Int) = getFluidInTank(index)
|
||||||
|
|
||||||
fun Container.addItem(stack: ItemStack, range: IntRange, simulate: Boolean = false): ItemStack {
|
val Container.slotRange: IntIterable get() {
|
||||||
if (this is MatteryContainer) {
|
return IntIterable {
|
||||||
return this.addItem(stack, range, simulate)
|
val i = (0 until containerSize).iterator()
|
||||||
|
|
||||||
|
object : IntIterator {
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return i.hasNext()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range.last >= containerSize || range.first < 0)
|
override fun remove() {
|
||||||
throw IllegalArgumentException("Invalid range: $range")
|
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)
|
if (stack.isEmpty)
|
||||||
return stack
|
return stack
|
||||||
@ -41,7 +64,11 @@ fun Container.addItem(stack: ItemStack, range: IntRange, simulate: Boolean = fal
|
|||||||
val copy = stack.copy()
|
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)) {
|
if (ItemStack.isSameItemSameTags(this[slot], copy)) {
|
||||||
val slotStack = this[slot]
|
val slotStack = this[slot]
|
||||||
val slotLimit = maxStackSize.coerceAtMost(slotStack.maxStackSize)
|
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) {
|
if (this[slot].isEmpty) {
|
||||||
val diff = copy.count.coerceAtMost(maxStackSize.coerceAtMost(copy.maxStackSize))
|
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
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Container.addItem(stack: ItemStack, simulate: Boolean): ItemStack = addItem(stack, 0 until containerSize, simulate)
|
|
||||||
|
|
||||||
fun Container.vanishCursedItems() {
|
fun Container.vanishCursedItems() {
|
||||||
for (slot in slotIterator()) {
|
for (slot in slotIterator()) {
|
||||||
if (hasVanishingCurse(slot.item)) {
|
if (hasVanishingCurse(slot.item)) {
|
||||||
@ -258,3 +287,31 @@ operator fun CraftingContainer.get(column: Int, row: Int, flop: Boolean): ItemSt
|
|||||||
else
|
else
|
||||||
get(column, row)
|
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
|
import java.util.function.Predicate
|
||||||
|
|
||||||
// passthrough all default methods to fix Kotlin bug related to implementation delegation not properly working on Java interfaces
|
// 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
|
// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods
|
||||||
interface IContainer : Container {
|
interface IContainer : Container {
|
||||||
override fun getMaxStackSize(): Int {
|
override fun getMaxStackSize(): Int {
|
||||||
@ -41,6 +42,16 @@ interface IContainer : Container {
|
|||||||
return super.hasAnyMatching(predicate)
|
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 {
|
companion object {
|
||||||
fun wrap(container: Container): IContainer {
|
fun wrap(container: Container): IContainer {
|
||||||
if (container is 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.ListTag
|
||||||
import net.minecraft.nbt.Tag
|
import net.minecraft.nbt.Tag
|
||||||
import net.minecraft.resources.ResourceLocation
|
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.Player
|
||||||
import net.minecraft.world.entity.player.StackedContents
|
import net.minecraft.world.entity.player.StackedContents
|
||||||
import net.minecraft.world.inventory.StackedContentsCompatible
|
import net.minecraft.world.inventory.StackedContentsCompatible
|
||||||
@ -19,9 +19,7 @@ import net.minecraft.world.item.Item
|
|||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraftforge.common.util.INBTSerializable
|
import net.minecraftforge.common.util.INBTSerializable
|
||||||
import net.minecraftforge.registries.ForgeRegistries
|
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.IContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.util.IIterableContainer
|
|
||||||
import ru.dbotthepony.mc.otm.core.addSorted
|
import ru.dbotthepony.mc.otm.core.addSorted
|
||||||
import ru.dbotthepony.mc.otm.core.collect.any
|
import ru.dbotthepony.mc.otm.core.collect.any
|
||||||
import ru.dbotthepony.mc.otm.core.collect.count
|
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.Stream
|
||||||
import java.util.stream.StreamSupport
|
import java.util.stream.StreamSupport
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.Iterator
|
|
||||||
|
|
||||||
@Suppress("UNUSED")
|
@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)
|
constructor(size: Int) : this({}, size)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -134,7 +131,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
|||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSlotFilter(slot: Int, filter: Item? = null) {
|
final override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
||||||
if (filters[slot] !== filter) {
|
if (filters[slot] !== filter) {
|
||||||
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]
|
final override fun getSlotFilter(slot: Int) = filters[slot]
|
||||||
fun hasSlotFilter(slot: Int) = filters[slot] !== null
|
final override fun hasSlotFilter(slot: Int) = filters[slot] !== null
|
||||||
fun isSlotForbiddenForAutomation(slot: Int) = filters[slot] === Items.AIR
|
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)
|
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) {
|
if (filters[slot] == null) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@ -283,137 +282,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasEmptySlot(): Boolean {
|
final override fun isEmpty(): 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 {
|
|
||||||
return nonEmptyIndices.isEmpty
|
return nonEmptyIndices.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,17 +353,17 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
|||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
final override fun setItem(slot: Int, stack: ItemStack) {
|
final override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||||
if (slots[slot].isEmpty && stack.isEmpty || stack === slots[slot])
|
if (slots[slot].isEmpty && itemStack.isEmpty || itemStack === slots[slot])
|
||||||
return
|
return
|
||||||
|
|
||||||
val old = slots[slot]
|
val old = slots[slot]
|
||||||
slots[slot] = if (stack.isEmpty) ItemStack.EMPTY else stack
|
slots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack
|
||||||
trackedSlots[slot] = if (stack.isEmpty) ItemStack.EMPTY else stack.copy()
|
trackedSlots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack.copy()
|
||||||
|
|
||||||
updateEmptyFlag(slot)
|
updateEmptyFlag(slot)
|
||||||
changeset++
|
changeset++
|
||||||
internalSetChanged(slot, stack, old)
|
internalSetChanged(slot, itemStack, old)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override fun setChanged() {
|
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)) {
|
if (!slots[slot].equals(trackedSlots[slot], false)) {
|
||||||
trackedSlots[slot] = slots[slot].copy()
|
trackedSlots[slot] = slots[slot].copy()
|
||||||
updateEmptyFlag(slot)
|
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> {
|
final override fun slotIterator(): kotlin.collections.Iterator<IContainerSlot> {
|
||||||
indicesReferenced = true
|
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> {
|
final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator<IContainerSlot> {
|
||||||
if (!nonEmpty) {
|
if (!nonEmpty) {
|
||||||
return (0 until size).iterator().map { ContainerSlot(it, this) }
|
return (0 until size).iterator().map { Slot(it) }
|
||||||
} else if (isEmpty) {
|
} else if (isEmpty) {
|
||||||
return emptyIterator()
|
return emptyIterator()
|
||||||
} else {
|
} else {
|
||||||
indicesReferenced = true
|
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 {
|
final override fun countItem(item: Item): Int {
|
||||||
return iterator().filter { it.item == item }.count().toInt()
|
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.Container
|
||||||
import net.minecraft.world.item.Item
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
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.MatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.container.get
|
import ru.dbotthepony.mc.otm.container.get
|
||||||
import ru.dbotthepony.mc.otm.container.set
|
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.collect.map
|
||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
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> {
|
interface IContainerSlot : GetterSetter<ItemStack> {
|
||||||
val slot: Int
|
val slot: Int
|
||||||
val container: Container
|
val container: Container
|
||||||
@ -18,28 +24,23 @@ interface IContainerSlot : GetterSetter<ItemStack> {
|
|||||||
operator fun component1() = slot
|
operator fun component1() = slot
|
||||||
operator fun component2() = item
|
operator fun component2() = item
|
||||||
|
|
||||||
|
fun getMaxStackSize(item: ItemStack = this.item): Int {
|
||||||
|
return container.maxStackSize
|
||||||
|
}
|
||||||
|
|
||||||
val isForbiddenForAutomation: Boolean get() {
|
val isForbiddenForAutomation: Boolean get() {
|
||||||
val container = container
|
return getFilter() === Items.AIR
|
||||||
|
|
||||||
if (container is MatteryContainer) {
|
|
||||||
return container.isSlotForbiddenForAutomation(slot)
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val filter: Item? get() {
|
fun getFilter(): Item?
|
||||||
val container = container
|
|
||||||
|
|
||||||
if (container is MatteryContainer) {
|
/**
|
||||||
return container.getSlotFilter(slot)
|
* @return whenever the filter was set. Returns false only if container can't be filtered.
|
||||||
} else {
|
*/
|
||||||
return null
|
fun setFilter(filter: Item? = null): Boolean
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasFilter: Boolean
|
val hasFilter: Boolean
|
||||||
get() = filter != null
|
get() = getFilter() != null
|
||||||
|
|
||||||
fun remove() {
|
fun remove() {
|
||||||
container[slot] = ItemStack.EMPTY
|
container[slot] = ItemStack.EMPTY
|
||||||
@ -54,14 +55,8 @@ interface IContainerSlot : GetterSetter<ItemStack> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setChanged() {
|
fun setChanged() {
|
||||||
val container = container
|
|
||||||
|
|
||||||
if (container is MatteryContainer) {
|
|
||||||
container.setChanged(slot)
|
|
||||||
} else {
|
|
||||||
container.setChanged()
|
container.setChanged()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var item: ItemStack
|
var item: ItemStack
|
||||||
get() = container[slot]
|
get() = container[slot]
|
||||||
@ -78,32 +73,28 @@ class ContainerSlot(override val slot: Int, override val container: Container) :
|
|||||||
init {
|
init {
|
||||||
require(slot in 0 until container.containerSize) { "Slot out of bounds: $slot (container: $container with size ${container.containerSize})" }
|
require(slot in 0 until container.containerSize) { "Slot out of bounds: $slot (container: $container with size ${container.containerSize})" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getFilter(): Item? {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IIterableContainer : Iterable<ItemStack> {
|
override fun setFilter(filter: Item?): Boolean {
|
||||||
/**
|
return false
|
||||||
* Iterates over non-empty itemstacks of this container
|
}
|
||||||
*/
|
|
||||||
override fun iterator(): Iterator<ItemStack> {
|
|
||||||
return iterator(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun iterator(nonEmpty: Boolean): Iterator<ItemStack>
|
fun Container.containerSlot(slot: Int): IContainerSlot {
|
||||||
|
if (this is IMatteryContainer) {
|
||||||
/**
|
return containerSlot(slot)
|
||||||
* Iterates non-empty slots of this container
|
} else {
|
||||||
*/
|
return ContainerSlot(slot, this)
|
||||||
fun slotIterator(): Iterator<IContainerSlot> {
|
|
||||||
return slotIterator(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun Container.iterator() = iterator(true)
|
operator fun Container.iterator() = iterator(true)
|
||||||
|
|
||||||
fun Container.iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
fun Container.iterator(nonEmpty: Boolean): Iterator<ItemStack> {
|
||||||
if (this is IIterableContainer) {
|
if (this is IMatteryContainer) {
|
||||||
return iterator(nonEmpty)
|
return iterator(nonEmpty)
|
||||||
} else if (nonEmpty) {
|
} else if (nonEmpty) {
|
||||||
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
|
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> {
|
fun Container.slotIterator(nonEmpty: Boolean = true): Iterator<IContainerSlot> {
|
||||||
if (this is IIterableContainer) {
|
if (this is IMatteryContainer) {
|
||||||
return slotIterator(nonEmpty)
|
return slotIterator(nonEmpty)
|
||||||
} else if (nonEmpty) {
|
} else if (nonEmpty) {
|
||||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { ContainerSlot(it, this) }
|
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:
|
fun <T> Comparator<T>.nullsFirst(): Comparator<T> {
|
||||||
// since Java generics are invariant,
|
return Comparator.nullsFirst(this)
|
||||||
// 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<in T>.nullsLast(): Comparator<T?> {
|
fun <T> Comparator<T>.nullsLast(): Comparator<T> {
|
||||||
return Comparator.nullsLast(this as Comparator<in T?>)
|
return Comparator.nullsLast(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
class MappedComparator<T, O>(private val parent: Comparator<O>, private val mapper: (T) -> O) : Comparator<T> {
|
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)
|
return collector.finisher().apply(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Iterator<T>.toList(): MutableList<T> {
|
fun <T> Iterator<T>.toList(expectedSize: Int = 16): MutableList<T> {
|
||||||
val result = ArrayList<T>()
|
val result = ArrayList<T>(expectedSize)
|
||||||
result.addAll(this)
|
result.addAll(this)
|
||||||
return result
|
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.storage.ItemStorageStack
|
||||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
|
|
||||||
private fun Comparator<Item?>.stacks(): Comparator<ItemStack?> {
|
private fun Comparator<Item>.stacks(): Comparator<ItemStack> {
|
||||||
return Comparator<ItemStack> { o1, o2 -> this@stacks.compare(o1.item, o2.item) }.nullsFirst()
|
return Comparator { o1, o2 -> this@stacks.compare(o1.item, o2.item) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Comparator<Item?>.storage(): Comparator<ItemStorageStack?> {
|
private fun Comparator<Item>.storage(): Comparator<ItemStorageStack> {
|
||||||
return Comparator<ItemStorageStack> { o1, o2 -> this@storage.compare(o1.item, o2.item) }.nullsFirst()
|
return Comparator { o1, o2 -> this@storage.compare(o1.item, o2.item) }
|
||||||
}
|
}
|
||||||
|
|
||||||
object CreativeMenuItemComparator : Comparator<Item> {
|
object CreativeMenuItemComparator : Comparator<Item> {
|
||||||
@ -156,7 +156,7 @@ object ItemStorageStackCountComparator : Comparator<ItemStorageStack> {
|
|||||||
val NullsLast = nullsLast()
|
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 }),
|
DEFAULT(CreativeMenuItemComparator, TranslatableComponent("otm.gui.sorting.default"), lazy { Widgets18.SORT_DEFAULT }),
|
||||||
NAME(ItemLocalizedNameComparator.thenComparing(CreativeMenuItemComparator), TranslatableComponent("otm.gui.sorting.name"), lazy { Widgets18.SORT_ALPHABET }),
|
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 }),
|
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 icon: IGUIRenderable by icon
|
||||||
val title: MutableComponent get() = sTitle.copy()
|
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 }),
|
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 }),
|
COUNT(ItemStackCountComparator.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 }),
|
NAME(ItemStackNameComparator.thenComparing(ItemSorter.DEFAULT.stacks()), ItemSorter.NAME.title, lazy { Widgets18.SORT_ALPHABET }),
|
||||||
ID(ItemSorter.ID.stacks(), ItemSorter.ID.title, lazy { Widgets18.SORT_ID }),
|
ID(ItemSorter.ID.stacks(), ItemSorter.ID.title, lazy { Widgets18.SORT_ID }),
|
||||||
MOD(ItemSorter.MOD.stacks(), ItemSorter.MOD.title, lazy { Widgets18.SORT_MODID }),
|
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 }),
|
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 icon: IGUIRenderable by icon
|
||||||
val title: MutableComponent get() = sTitle.copy()
|
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 }),
|
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 }),
|
COUNT(ItemStorageStackCountComparator.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 }),
|
NAME(ItemStorageStackNameComparator.thenComparing(ItemSorter.DEFAULT.storage()), ItemSorter.NAME.title, lazy { Widgets18.SORT_ALPHABET }),
|
||||||
ID(ItemSorter.ID.storage(), ItemSorter.ID.title, lazy { Widgets18.SORT_ID }),
|
ID(ItemSorter.ID.storage(), ItemSorter.ID.title, lazy { Widgets18.SORT_ID }),
|
||||||
MOD(ItemSorter.MOD.storage(), ItemSorter.MOD.title, lazy { Widgets18.SORT_MODID }),
|
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 }),
|
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 icon: IGUIRenderable by icon
|
||||||
val title: MutableComponent get() = sTitle.copy()
|
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 net.minecraftforge.registries.ForgeRegistries
|
||||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
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.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.getBarColor
|
import ru.dbotthepony.mc.otm.capability.energy.getBarColor
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.getBarWidth
|
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) {
|
for (ply in event.server.playerList.players) {
|
||||||
val networkedChannels = ObjectOpenHashSet<UUID>(0)
|
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
|
val power = item.getCapability(MatteryCapability.ENERGY).orThrow() as Power
|
||||||
power.updateValues()
|
power.updateValues()
|
||||||
if (power.values.isServer && networkedChannels.add(power.values.uuid)) {
|
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.cos.cosmeticArmorSlots
|
||||||
import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
|
import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
|
||||||
import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot
|
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.ItemFilter
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
|
||||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
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.GetterSetter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
||||||
@ -105,8 +106,6 @@ abstract class MatteryMenu(
|
|||||||
|
|
||||||
private val _playerInventorySlots = ArrayList<InventorySlot>()
|
private val _playerInventorySlots = ArrayList<InventorySlot>()
|
||||||
private val _playerHotbarSlots = ArrayList<InventorySlot>()
|
private val _playerHotbarSlots = ArrayList<InventorySlot>()
|
||||||
private val _playerMainSlots = ArrayList<InventorySlot>()
|
|
||||||
private val _playerExoSuitSlots = ArrayList<InventorySlot>()
|
|
||||||
private val _playerCombinedInventorySlots = ArrayList<InventorySlot>()
|
private val _playerCombinedInventorySlots = ArrayList<InventorySlot>()
|
||||||
private val _exopackChargeSlots = ArrayList<MatterySlot>()
|
private val _exopackChargeSlots = ArrayList<MatterySlot>()
|
||||||
|
|
||||||
@ -189,7 +188,7 @@ abstract class MatteryMenu(
|
|||||||
fun intInput(allowSpectators: Boolean = false, handler: (Int) -> Unit) = PlayerInput(VarIntValueCodec, allowSpectators, handler)
|
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)
|
val playerInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerInventorySlots)
|
||||||
|
|
||||||
@ -199,17 +198,7 @@ abstract class MatteryMenu(
|
|||||||
val playerHotbarSlots: List<InventorySlot> = Collections.unmodifiableList(_playerHotbarSlots)
|
val playerHotbarSlots: List<InventorySlot> = Collections.unmodifiableList(_playerHotbarSlots)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inventory only
|
* inventory + Exopack (in this order)
|
||||||
*/
|
|
||||||
val playerMainSlots: List<InventorySlot> = Collections.unmodifiableList(_playerMainSlots)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* exosuit only
|
|
||||||
*/
|
|
||||||
val playerExoSuitSlots: List<InventorySlot> = Collections.unmodifiableList(_playerExoSuitSlots)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inventory + exosuit (in this order)
|
|
||||||
*/
|
*/
|
||||||
val playerCombinedInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerCombinedInventorySlots)
|
val playerCombinedInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerCombinedInventorySlots)
|
||||||
|
|
||||||
@ -217,6 +206,9 @@ abstract class MatteryMenu(
|
|||||||
|
|
||||||
val exopackPowerLevel = ProfiledLevelGaugeWidget<ProfiledEnergyStorage<*>>(mSynchronizer)
|
val exopackPowerLevel = ProfiledLevelGaugeWidget<ProfiledEnergyStorage<*>>(mSynchronizer)
|
||||||
|
|
||||||
|
var sortInventoryInput: PlayerInput<Nothing?>? = null
|
||||||
|
private set
|
||||||
|
|
||||||
var offhandSlot: InventorySlot? = null
|
var offhandSlot: InventorySlot? = null
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
@ -267,7 +259,7 @@ abstract class MatteryMenu(
|
|||||||
return addFilterSlots(slots)
|
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 {
|
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||||
return !isInventorySlotLocked(index) && super.mayPlace(itemStack)
|
return !isInventorySlotLocked(index) && super.mayPlace(itemStack)
|
||||||
}
|
}
|
||||||
@ -276,61 +268,30 @@ abstract class MatteryMenu(
|
|||||||
return !isInventorySlotLocked(index) && super.mayPickup(player)
|
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
|
var chargeFlag: GetterSetter<Boolean>? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val mattery = player.matteryPlayer
|
val mattery = player.matteryPlayer!!
|
||||||
|
|
||||||
|
if (addFilter) {
|
||||||
|
val mContainer = container as IMatteryContainer
|
||||||
|
|
||||||
if (mattery != null) {
|
|
||||||
if (container === inventory) {
|
|
||||||
if (slotIndex in mattery.regularSlotFilters.indices) {
|
|
||||||
filter = GetterSetter.of(
|
filter = GetterSetter.of(
|
||||||
getter = { mattery.regularSlotFilters[slotIndex].value },
|
getter = { mContainer.getSlotFilter(slotIndex) },
|
||||||
setter = nullableItemInput(true) { mattery.regularSlotFilters[slotIndex].value = it }::accept
|
setter = nullableItemInput(true) { mContainer.setSlotFilter(slotIndex, it) }::accept
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slotIndex in mattery.regularSlotChargeFlag.indices) {
|
|
||||||
val input = booleanInput(true) { mattery.regularSlotChargeFlag[slotIndex].boolean = it }
|
|
||||||
|
|
||||||
chargeFlag = GetterSetter.of(
|
chargeFlag = GetterSetter.of(
|
||||||
getter = { mattery.regularSlotChargeFlag[slotIndex].boolean },
|
getter = { slotIndex in mattery.slotsChargeFlag },
|
||||||
setter = input::accept
|
setter = booleanInput(true) { if (it) mattery.slotsChargeFlag.add(slotIndex) else mattery.slotsChargeFlag.remove(slotIndex) }::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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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, x: Int = 0, y: Int = 0) : this(
|
constructor(type: net.minecraft.world.entity.EquipmentSlot) : this(inventory, 34 + type.ordinal, type)
|
||||||
inventory, 34 + type.ordinal, type, x, y
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||||
return super.mayPlace(itemStack) && itemStack.canEquip(type, inventory.player)
|
return super.mayPlace(itemStack) && itemStack.canEquip(type, inventory.player)
|
||||||
@ -351,6 +312,8 @@ abstract class MatteryMenu(
|
|||||||
|
|
||||||
protected fun addInventorySlots(autoFrame: Boolean = !player.isSpectator) {
|
protected fun addInventorySlots(autoFrame: Boolean = !player.isSpectator) {
|
||||||
check(_playerInventorySlots.isEmpty()) { "Already created inventory slots" }
|
check(_playerInventorySlots.isEmpty()) { "Already created inventory slots" }
|
||||||
|
val mattery = player.matteryPlayer ?: return
|
||||||
|
|
||||||
autoCreateInventoryFrame = autoFrame
|
autoCreateInventoryFrame = autoFrame
|
||||||
|
|
||||||
offhandSlot = object : InventorySlot(inventory, 40) {
|
offhandSlot = object : InventorySlot(inventory, 40) {
|
||||||
@ -362,11 +325,12 @@ abstract class MatteryMenu(
|
|||||||
mapQuickMoveToInventory(offhandSlot!!)
|
mapQuickMoveToInventory(offhandSlot!!)
|
||||||
addSlot(offhandSlot!!)
|
addSlot(offhandSlot!!)
|
||||||
|
|
||||||
for (i in 0 .. 35) {
|
for (i in 0 until mattery.combinedInventory.containerSize) {
|
||||||
val slot = InventorySlot(inventory, i)
|
if (i in Inventory.INVENTORY_SIZE .. player.inventory.containerSize) continue
|
||||||
|
|
||||||
|
val slot = InventorySlot(mattery.combinedInventory, i, true)
|
||||||
|
|
||||||
_playerInventorySlots.add(slot)
|
_playerInventorySlots.add(slot)
|
||||||
_playerMainSlots.add(slot)
|
|
||||||
|
|
||||||
if (i <= 8)
|
if (i <= 8)
|
||||||
_playerHotbarSlots.add(slot)
|
_playerHotbarSlots.add(slot)
|
||||||
@ -378,21 +342,7 @@ abstract class MatteryMenu(
|
|||||||
addSlot(slot)
|
addSlot(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
val mattery = player.matteryPlayer
|
if (mattery.hasExopack) {
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
_exopackChargeSlots.add(BatterySlot(mattery.exopackEnergy.parent, 0).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) })
|
_exopackChargeSlots.add(BatterySlot(mattery.exopackEnergy.parent, 0).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) })
|
||||||
|
|
||||||
for (i in 0 until mattery.exopackChargeSlots.containerSize)
|
for (i in 0 until mattery.exopackChargeSlots.containerSize)
|
||||||
@ -400,6 +350,10 @@ abstract class MatteryMenu(
|
|||||||
|
|
||||||
exopackPowerLevel.with(mattery.exopackEnergy)
|
exopackPowerLevel.with(mattery.exopackEnergy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sortInventoryInput = PlayerInput(NullValueCodec) {
|
||||||
|
mattery.inventoryAndExopackNoHotbar.sort()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var broadcastOnce = false
|
private var broadcastOnce = false
|
||||||
@ -471,7 +425,7 @@ abstract class MatteryMenu(
|
|||||||
val input: PlayerInput<Item?>
|
val input: PlayerInput<Item?>
|
||||||
val field: IField<Item?>
|
val field: IField<Item?>
|
||||||
|
|
||||||
if (container is MatteryContainer) {
|
if (container is IMatteryContainer) {
|
||||||
input = PlayerInput(ItemValueCodec.nullable, handler = { container.setSlotFilter(pSlot.slotIndex, it) })
|
input = PlayerInput(ItemValueCodec.nullable, handler = { container.setSlotFilter(pSlot.slotIndex, it) })
|
||||||
field = mSynchronizer.ComputedField(getter = { container.getSlotFilter(pSlot.slotIndex) }, ItemValueCodec.nullable)
|
field = mSynchronizer.ComputedField(getter = { container.getSlotFilter(pSlot.slotIndex) }, ItemValueCodec.nullable)
|
||||||
} else {
|
} 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.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.energy
|
import ru.dbotthepony.mc.otm.capability.energy
|
||||||
import ru.dbotthepony.mc.otm.client.minecraft
|
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.GetterSetter
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
import ru.dbotthepony.mc.otm.runOnClient
|
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 {
|
open fun canTakeItemForPickAll(): Boolean {
|
||||||
return true
|
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> {
|
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 id2tuple = Int2ObjectOpenHashMap<Tuple>()
|
||||||
val sortedView = ArrayList<Tuple>()
|
val sortedView = ArrayList<Tuple>()
|
||||||
var sorter: Comparator<in ItemStorageStack> = ItemStorageStackSorter.DEFAULT
|
var sorter: Comparator<ItemStorageStack> = ItemStorageStackSorter.DEFAULT
|
||||||
set(value) {
|
set(value) {
|
||||||
if (field != value) {
|
if (field != value) {
|
||||||
field = value
|
field = value
|
||||||
|
@ -5,6 +5,8 @@ import net.minecraft.world.entity.player.Inventory
|
|||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
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.MatteryMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||||
import ru.dbotthepony.mc.otm.menu.UserFilteredSlot
|
import ru.dbotthepony.mc.otm.menu.UserFilteredSlot
|
||||||
@ -16,9 +18,12 @@ class CargoCrateMenu @JvmOverloads constructor(
|
|||||||
tile: CargoCrateBlockEntity? = null
|
tile: CargoCrateBlockEntity? = null
|
||||||
) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory, tile) {
|
) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory, tile) {
|
||||||
val storageSlots: List<UserFilteredSlot>
|
val storageSlots: List<UserFilteredSlot>
|
||||||
|
|
||||||
private val trackedPlayerOpen = !inventory.player.isSpectator
|
private val trackedPlayerOpen = !inventory.player.isSpectator
|
||||||
|
|
||||||
|
val sort = PlayerInput(NullValueCodec) {
|
||||||
|
tile?.container?.sort()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY)
|
val container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY)
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class DriveViewerMenu(
|
|||||||
if (isAscending) {
|
if (isAscending) {
|
||||||
networkedItemView.sorter = sorting
|
networkedItemView.sorter = sorting
|
||||||
} else {
|
} else {
|
||||||
networkedItemView.sorter = sorting.reversed
|
networkedItemView.sorter = sorting.reversed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ class ItemMonitorMenu(
|
|||||||
if (ascendingSort) {
|
if (ascendingSort) {
|
||||||
networkedItemView.sorter = sorting
|
networkedItemView.sorter = sorting
|
||||||
} else {
|
} 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