Compare commits
12 Commits
305ddbd0d4
...
c43be6eb62
Author | SHA1 | Date | |
---|---|---|---|
c43be6eb62 | |||
59eab74b44 | |||
bdeb740df0 | |||
621661c9fe | |||
d0904da1db | |||
05bdff6a37 | |||
b076d29560 | |||
a2263c5725 | |||
d57371ca13 | |||
579445fbbe | |||
80ff50b937 | |||
ca37b4959f |
@ -29,7 +29,6 @@ import net.minecraft.world.phys.Vec3
|
||||
import net.neoforged.neoforge.capabilities.Capabilities
|
||||
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
|
@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler
|
||||
import ru.dbotthepony.mc.otm.capability.moveFluid
|
||||
import ru.dbotthepony.mc.otm.config.ItemsConfig
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
|
@ -19,7 +19,6 @@ import net.neoforged.neoforge.fluids.FluidStack
|
||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
|
@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
|
@ -17,7 +17,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
|
||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
|
@ -22,7 +22,6 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
|
||||
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||
|
@ -26,7 +26,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
|
@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.matter.PatternState
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
|
@ -14,7 +14,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
|
||||
|
@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.core.get
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
|
||||
@ -30,7 +29,7 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
||||
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
|
||||
val energyConfig = ConfigurableEnergy(energy)
|
||||
|
||||
val container: EnhancedContainer = object : EnhancedContainer(1) {
|
||||
val container: EnhancedContainer.Simple = object : EnhancedContainer.Simple(1) {
|
||||
override fun notifySlotChanged(slot: Int, old: ItemStack) {
|
||||
super.notifySlotChanged(slot, old)
|
||||
markDirtyFast()
|
||||
|
@ -31,7 +31,6 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
|
||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
@ -219,7 +218,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
||||
fun howMuchPlayerCrafted(ply: Player): Int = craftingAmount.getInt(ply)
|
||||
fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply]
|
||||
|
||||
val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.withListener(3 * 3) {
|
||||
val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.WithListener(3 * 3) {
|
||||
markDirtyFast()
|
||||
|
||||
if (!inProcessOfCraft) {
|
||||
|
@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.capability.matteryEnergy
|
||||
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
||||
import ru.dbotthepony.mc.otm.capability.transcieveEnergy
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
|
@ -12,7 +12,6 @@ import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
|
@ -11,7 +11,6 @@ import ru.dbotthepony.mc.otm.block.entity.ItemJob
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.JobStatus
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
|
@ -17,7 +17,6 @@ import ru.dbotthepony.mc.otm.capability.moveEnergy
|
||||
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
|
@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
|
@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.extractEnergy
|
||||
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
||||
import ru.dbotthepony.mc.otm.capability.moveEnergy
|
||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||
|
@ -25,7 +25,6 @@ import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
@ -71,7 +70,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
|
||||
}
|
||||
|
||||
val capsuleContainer = SlottedContainer.simple(1, ::CapsuleSlot, ::markDirtyFast)
|
||||
val servoContainer = EnhancedContainer.withListener(1, ::markDirtyFast)
|
||||
val servoContainer = EnhancedContainer.WithListener(1, ::markDirtyFast)
|
||||
val mendingContainer = SlottedContainer.simple(1, ::MendingSlot, ::markDirtyFast).also(::addDroppableContainer)
|
||||
|
||||
private var mending: Holder<Enchantment>? = null
|
||||
|
@ -10,7 +10,6 @@ import net.neoforged.neoforge.capabilities.Capabilities
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
|
||||
|
@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
|
||||
import ru.dbotthepony.mc.otm.capability.moveMatter
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
|
@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.UpgradeType
|
||||
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.balance
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
|
@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.capability.item
|
||||
import com.google.common.collect.ImmutableList
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.neoforged.neoforge.items.IItemHandler
|
||||
import ru.dbotthepony.mc.otm.container.ContainerHandler
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import java.util.stream.Stream
|
||||
|
||||
@ -12,7 +11,7 @@ class CombinedItemHandler(val handlers: ImmutableList<IItemHandler>) : IItemHand
|
||||
constructor(handlers: Collection<IItemHandler>) : this(ImmutableList.copyOf(handlers))
|
||||
constructor(vararg handlers: IItemHandler) : this(ImmutableList.copyOf(handlers))
|
||||
|
||||
private val needsChecking = handlers.any { it !is ContainerHandler && it !is SlottedContainer }
|
||||
private val needsChecking = handlers.any { it !is SlottedContainer }
|
||||
private val lastSizes = IntArray(this.handlers.size)
|
||||
private var totalSize = 0
|
||||
private val mappings = ArrayList<Mapping>()
|
||||
|
@ -11,7 +11,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||
class MatteryChestMenu(
|
||||
type: MenuType<*>, containerId: Int,
|
||||
inventory: Inventory, override val rows: Int, override val columns: Int,
|
||||
container: Container = EnhancedContainer(rows * columns)
|
||||
container: Container = EnhancedContainer.Simple(rows * columns)
|
||||
) : AbstractVanillaChestMenu(type, containerId, inventory, container) {
|
||||
override val containerSlots = makeSlots(container, ::MatteryMenuSlot)
|
||||
|
||||
|
@ -10,7 +10,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||
class MatteryShulkerBoxMenu(
|
||||
containerId: Int,
|
||||
inventory: Inventory,
|
||||
container: Container = EnhancedContainer(27)
|
||||
container: Container = EnhancedContainer.Simple(27)
|
||||
) : AbstractVanillaChestMenu(VanillaMenuTypes.SHULKER_BOX, containerId, inventory, container) {
|
||||
override val containerSlots = makeSlots(container, ::Slot)
|
||||
override val rows: Int
|
||||
|
@ -16,11 +16,11 @@ object PlayerConfig : AbstractConfig("player") {
|
||||
|
||||
val REGENERATE_ENERGY_EFFICIENCY_FOOD: Double by builder
|
||||
.comment("How much % of food points to convert to energy")
|
||||
.defineInRange("REGENERATE_ENERGY_EFFICIENCY_FOOD", 0.75, 0.0)
|
||||
.defineInRange("REGENERATE_ENERGY_EFFICIENCY_FOOD", 0.4, 0.0)
|
||||
|
||||
val REGENERATE_ENERGY_EFFICIENCY_SATURATION: Double by builder
|
||||
.comment("How much % of food saturation points to convert to energy")
|
||||
.defineInRange("REGENERATE_ENERGY_EFFICIENCY_SATURATION", 0.4, 0.0)
|
||||
.defineInRange("REGENERATE_ENERGY_EFFICIENCY_SATURATION", 0.2, 0.0)
|
||||
|
||||
val REGENERATE_ENERGY_IN_PEACEFUL: Boolean by builder
|
||||
.comment("Regenerate energy while in peaceful")
|
||||
@ -39,6 +39,28 @@ object PlayerConfig : AbstractConfig("player") {
|
||||
.comment("for android players, since 'hunger' (for compatibility) is managed by mod in such case")
|
||||
.defineInRange("TIME_BETWEEN_NATURAL_REGENERATION", 120, 0, Int.MAX_VALUE)
|
||||
|
||||
val ANDROID_ENERGY_PER_HUNGER_POINT by builder.defineDecimal("energyPerHunger", Decimal(2000), Decimal.ZERO)
|
||||
val ANDROID_MAX_ENERGY by builder
|
||||
.comment("Internal battery of every android has this much storage")
|
||||
.comment("Keep in mind that already existing players won't get their value changed since it is", "stored inside their savedata")
|
||||
.defineDecimal("capacity", Decimal(80_000), Decimal.ZERO)
|
||||
|
||||
val NIGHT_VISION_POWER_DRAW by builder.defineDecimal("nightVisionPowerDraw", Decimal(8), Decimal.ZERO)
|
||||
|
||||
val FALL_DAMAGE_REDUCTION_PER_LEVEL_P: Double by builder
|
||||
.comment("In percent. Level of feature is multiplied by this")
|
||||
.comment("First, fall damage is reduced by flat resistance, then reduced by percentage resistance (this)")
|
||||
.defineInRange("FALL_DAMAGE_REDUCTION_PER_LEVEL_P", 0.2, 0.01, 1.0)
|
||||
|
||||
val FALL_DAMAGE_REDUCTION_PER_LEVEL_F: Double by builder
|
||||
.comment("In flat half of hearts. Level of feature is multiplied by this")
|
||||
.comment("First, fall damage is reduced by flat resistance (this), then reduced by percentage resistance")
|
||||
.defineInRange("FALL_DAMAGE_REDUCTION_PER_LEVEL_F", 1.5, 0.0, Float.MAX_VALUE.toDouble())
|
||||
|
||||
val SWIM_BOOSTERS: Double by builder
|
||||
.comment("Increase per level")
|
||||
.defineInRange("SWIM_BOOSTERS", 0.25, 0.0, Float.MAX_VALUE.toDouble())
|
||||
|
||||
init {
|
||||
builder.pop()
|
||||
}
|
||||
@ -71,27 +93,6 @@ object PlayerConfig : AbstractConfig("player") {
|
||||
}
|
||||
}
|
||||
|
||||
val ANDROID_ENERGY_PER_HUNGER_POINT by builder.defineDecimal("energyPerHunger", Decimal(2000), Decimal.ZERO)
|
||||
val ANDROID_MAX_ENERGY by builder
|
||||
.comment("Internal battery of every android has this much storage")
|
||||
.comment("Keep in mind that already existing players won't get their value changed since it is", "stored inside their savedata")
|
||||
.defineDecimal("capacity", Decimal(80_000), Decimal.ZERO)
|
||||
val NIGHT_VISION_POWER_DRAW by builder.defineDecimal("nightVisionPowerDraw", Decimal(8), Decimal.ZERO)
|
||||
|
||||
val FALL_DAMAGE_REDUCTION_PER_LEVEL_P: Double by builder
|
||||
.comment("In percent. Level of feature is multiplied by this")
|
||||
.comment("First, fall damage is reduced by flat resistance, then reduced by percentage resistance (this)")
|
||||
.defineInRange("FALL_DAMAGE_REDUCTION_PER_LEVEL_P", 0.2, 0.01, 1.0)
|
||||
|
||||
val FALL_DAMAGE_REDUCTION_PER_LEVEL_F: Double by builder
|
||||
.comment("In flat half of hearts. Level of feature is multiplied by this")
|
||||
.comment("First, fall damage is reduced by flat resistance (this), then reduced by percentage resistance")
|
||||
.defineInRange("FALL_DAMAGE_REDUCTION_PER_LEVEL_F", 1.5, 0.0, Float.MAX_VALUE.toDouble())
|
||||
|
||||
val SWIM_BOOSTERS: Double by builder
|
||||
.comment("Increase per level")
|
||||
.defineInRange("SWIM_BOOSTERS", 0.25, 0.0, Float.MAX_VALUE.toDouble())
|
||||
|
||||
object EnderTeleporter {
|
||||
init {
|
||||
builder.comment("Ender Teleporter ability").push("EnderTeleporter")
|
||||
|
@ -23,9 +23,9 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.stream
|
||||
import java.util.stream.Stream
|
||||
|
||||
class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int>>>) : ISlottedContainer, IMatteryContainer {
|
||||
constructor(vararg containers: IEnhancedContainer) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||
constructor(containers: Collection<IEnhancedContainer>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||
class CombinedContainer(containers: Stream<Pair<IEnhancedContainer<*>, Iterable<Int>>>) : ISlottedContainer<IContainerSlot> {
|
||||
constructor(vararg containers: IEnhancedContainer<*>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||
constructor(containers: Collection<IEnhancedContainer<*>>) : this(containers.stream().map { it to (0 until it.containerSize) })
|
||||
|
||||
private val slots: ImmutableList<IContainerSlot>
|
||||
private val slotsMap: ImmutableMap<Container, List<IContainerSlot>>
|
||||
@ -116,28 +116,12 @@ class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int
|
||||
)
|
||||
}
|
||||
|
||||
override fun slotIterator(): Iterator<IFilteredContainerSlot> {
|
||||
return slots.iterator().map {
|
||||
if (it is IFilteredContainerSlot) it else IFilteredContainerSlot.Dummy(it)
|
||||
}
|
||||
override fun slotIterator(): Iterator<IContainerSlot> {
|
||||
return slots.iterator()
|
||||
}
|
||||
|
||||
override fun containerSlot(slot: Int): IFilteredContainerSlot {
|
||||
val getSlot = slots[slot]
|
||||
if (getSlot is IFilteredContainerSlot) return getSlot
|
||||
return IFilteredContainerSlot.Dummy(getSlot)
|
||||
}
|
||||
|
||||
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
|
||||
return super<ISlottedContainer>.getMaxStackSize(slot, itemStack)
|
||||
}
|
||||
|
||||
override fun getSlotFilter(slot: Int): Item? {
|
||||
return containerSlot(slot).filter
|
||||
}
|
||||
|
||||
override fun clearSlotFilters() {
|
||||
|
||||
override fun containerSlot(slot: Int): IContainerSlot {
|
||||
return slots[slot]
|
||||
}
|
||||
|
||||
override fun setChanged(slot: Int) {
|
||||
@ -145,7 +129,7 @@ class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int
|
||||
}
|
||||
|
||||
class Builder {
|
||||
private val values = ArrayList<Pair<IEnhancedContainer, Iterable<Int>>>()
|
||||
private val values = ArrayList<Pair<IEnhancedContainer<*>, Iterable<Int>>>()
|
||||
|
||||
fun add(container: Container): Builder {
|
||||
return add(IEnhancedContainer.wrap(container))
|
||||
@ -167,27 +151,27 @@ class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int
|
||||
return add(IEnhancedContainer.wrap(container), slots)
|
||||
}
|
||||
|
||||
fun add(container: IEnhancedContainer): Builder {
|
||||
fun add(container: IEnhancedContainer<*>): Builder {
|
||||
values.add(container to container.slotRange)
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: IEnhancedContainer, slots: Iterator<Int>): Builder {
|
||||
fun add(container: IEnhancedContainer<*>, slots: Iterator<Int>): Builder {
|
||||
values.add(container to IntArrayList(slots))
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: IEnhancedContainer, slot: Int): Builder {
|
||||
fun add(container: IEnhancedContainer<*>, slot: Int): Builder {
|
||||
values.add(container to intArrayOf(slot).asIterable())
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: IEnhancedContainer, from: Int, to: Int): Builder {
|
||||
fun add(container: IEnhancedContainer<*>, from: Int, to: Int): Builder {
|
||||
values.add(container to (from .. to))
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(container: IEnhancedContainer, slots: Iterable<Int>): Builder {
|
||||
fun add(container: IEnhancedContainer<*>, slots: Iterable<Int>): Builder {
|
||||
values.add(container to slots)
|
||||
return this
|
||||
}
|
||||
|
@ -1,89 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.neoforged.neoforge.items.IItemHandler
|
||||
|
||||
class ContainerHandler(
|
||||
private val container: IMatteryContainer,
|
||||
private val filter: HandlerFilter = HandlerFilter.Both,
|
||||
) : IItemHandler {
|
||||
override fun getSlots() = container.containerSize
|
||||
override fun getStackInSlot(slot: Int) = container[slot]
|
||||
|
||||
override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
|
||||
if (!container.testSlotFilter(slot, stack) || !filter.canInsert(slot, stack))
|
||||
return stack
|
||||
|
||||
filter.preInsert(slot, stack, simulate)
|
||||
|
||||
val localStack = container[slot]
|
||||
var amount = filter.modifyInsertCount(slot, stack, localStack, simulate)
|
||||
|
||||
if (amount <= 0)
|
||||
return stack
|
||||
|
||||
if (localStack.isEmpty) {
|
||||
amount = stack.count.coerceAtMost(container.getMaxStackSize(slot, stack)).coerceAtMost(amount)
|
||||
|
||||
if (!simulate) {
|
||||
container.setItem(slot, stack.copyWithCount(amount))
|
||||
}
|
||||
|
||||
if (stack.count <= amount) {
|
||||
return ItemStack.EMPTY
|
||||
} else {
|
||||
return stack.copyWithCount(stack.count - amount)
|
||||
}
|
||||
} else if (localStack.isStackable && container.getMaxStackSize(slot, localStack) > localStack.count && ItemStack.isSameItemSameComponents(localStack, stack)) {
|
||||
val newCount = container.getMaxStackSize(slot, localStack).coerceAtMost(localStack.count + stack.count.coerceAtMost(amount))
|
||||
val diff = newCount - localStack.count
|
||||
|
||||
if (diff != 0) {
|
||||
if (!simulate) {
|
||||
localStack.grow(diff)
|
||||
container.setChanged(slot)
|
||||
}
|
||||
|
||||
val copy = stack.copy()
|
||||
copy.shrink(diff)
|
||||
return copy
|
||||
}
|
||||
}
|
||||
|
||||
return stack
|
||||
}
|
||||
|
||||
override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack {
|
||||
if (amount <= 0 || container.isSlotForbiddenForAutomation(slot))
|
||||
return ItemStack.EMPTY
|
||||
|
||||
val localStack = container.getItem(slot)
|
||||
if (localStack.isEmpty) return ItemStack.EMPTY
|
||||
|
||||
@Suppress("name_shadowing")
|
||||
val amount = filter.modifyExtractCount(slot, amount, simulate)
|
||||
if (amount <= 0) return ItemStack.EMPTY
|
||||
if (!filter.canExtract(slot, amount, localStack)) return ItemStack.EMPTY
|
||||
|
||||
filter.preExtract(slot, amount, simulate)
|
||||
|
||||
val minimal = amount.coerceAtMost(localStack.count)
|
||||
val copy = localStack.copy()
|
||||
copy.count = minimal
|
||||
|
||||
if (!simulate) {
|
||||
localStack.shrink(minimal)
|
||||
container.setChanged(slot)
|
||||
}
|
||||
|
||||
return copy
|
||||
}
|
||||
|
||||
override fun getSlotLimit(slot: Int): Int {
|
||||
return container.maxStackSize
|
||||
}
|
||||
|
||||
override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
|
||||
return container.testSlotFilter(slot, stack) && filter.canInsert(slot, stack)
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
@ -23,15 +23,9 @@ import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
* This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features
|
||||
* and improved performance (inside [IEnhancedContainer] defined methods).
|
||||
*/
|
||||
open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable<CompoundTag> {
|
||||
abstract class EnhancedContainer<S : IContainerSlot>(private val size: Int) : IEnhancedContainer<S>, INBTSerializable<CompoundTag> {
|
||||
private val items = Array(size) { ItemStack.EMPTY }
|
||||
private val observedItems = Array(size) { ItemStack.EMPTY }
|
||||
private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } }
|
||||
|
||||
// can be safely overridden in subclasses, very little memory will be wasted
|
||||
override fun containerSlot(slot: Int): IContainerSlot {
|
||||
return slots[slot]
|
||||
}
|
||||
|
||||
protected open fun notifySlotChanged(slot: Int, old: ItemStack) {}
|
||||
|
||||
@ -184,16 +178,22 @@ open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSe
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
open class Simple(size: Int) : EnhancedContainer<IContainerSlot>(size) {
|
||||
private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } }
|
||||
|
||||
fun withListener(slots: Int, listener: Runnable): EnhancedContainer {
|
||||
return object : EnhancedContainer(slots) {
|
||||
override fun notifySlotChanged(slot: Int, old: ItemStack) {
|
||||
super.notifySlotChanged(slot, old)
|
||||
listener.run()
|
||||
}
|
||||
}
|
||||
override fun containerSlot(slot: Int): IContainerSlot {
|
||||
return slots[slot]
|
||||
}
|
||||
}
|
||||
|
||||
open class WithListener(size: Int, private val listener: Runnable) : Simple(size) {
|
||||
override fun notifySlotChanged(slot: Int, old: ItemStack) {
|
||||
super.notifySlotChanged(slot, old)
|
||||
listener.run()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,7 @@ import net.neoforged.neoforge.items.IItemHandlerModifiable
|
||||
* Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which
|
||||
* subsequently allow this container to implement [IItemHandler]
|
||||
*/
|
||||
interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable {
|
||||
override fun containerSlot(slot: Int): IAutomatedContainerSlot
|
||||
|
||||
interface IAutomatedContainer<S : IAutomatedContainerSlot> : ISlottedContainer<S>, IItemHandlerModifiable {
|
||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return containerSlot(slot).canAutomationPlaceItem(itemStack)
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
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
|
||||
|
||||
// passthrough all default methods to fix Kotlin bug related to implementation delegation not properly working on Java interfaces
|
||||
// and also to give params proper names
|
||||
// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods
|
||||
interface IContainer : Container {
|
||||
override fun getMaxStackSize(): Int {
|
||||
return super.getMaxStackSize()
|
||||
}
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
super.startOpen(player)
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
super.stopOpen(player)
|
||||
}
|
||||
|
||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return super.canPlaceItem(slot, itemStack)
|
||||
}
|
||||
|
||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||
return super.canTakeItem(container, slot, itemStack)
|
||||
}
|
||||
|
||||
override fun countItem(item: Item): Int {
|
||||
return super.countItem(item)
|
||||
}
|
||||
|
||||
override fun hasAnyOf(items: Set<Item>): Boolean {
|
||||
return super.hasAnyOf(items)
|
||||
}
|
||||
|
||||
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
||||
return super.hasAnyMatching(predicate)
|
||||
}
|
||||
|
||||
override fun clearContent()
|
||||
override fun getContainerSize(): Int
|
||||
override fun isEmpty(): Boolean
|
||||
override fun getItem(slot: Int): ItemStack
|
||||
override fun removeItem(slot: Int, amount: Int): ItemStack
|
||||
override fun removeItemNoUpdate(slot: Int): ItemStack
|
||||
override fun setItem(slot: Int, itemStack: ItemStack)
|
||||
override fun setChanged()
|
||||
|
||||
override fun stillValid(player: Player): Boolean
|
||||
companion object {
|
||||
fun wrap(container: Container): IContainer {
|
||||
if (container is IContainer)
|
||||
return container
|
||||
else
|
||||
return object : IContainer, Container by container {
|
||||
override fun getMaxStackSize(): Int {
|
||||
return container.getMaxStackSize()
|
||||
}
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
container.startOpen(player)
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
container.stopOpen(player)
|
||||
}
|
||||
|
||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return container.canPlaceItem(slot, itemStack)
|
||||
}
|
||||
|
||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||
return container.canTakeItem(container, slot, itemStack)
|
||||
}
|
||||
|
||||
override fun countItem(item: Item): Int {
|
||||
return container.countItem(item)
|
||||
}
|
||||
|
||||
override fun hasAnyOf(items: Set<Item>): Boolean {
|
||||
return container.hasAnyOf(items)
|
||||
}
|
||||
|
||||
override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
||||
return container.hasAnyMatching(predicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,12 +19,41 @@ import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
|
||||
/**
|
||||
* "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [IContainer] ([Container]) code
|
||||
* "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [Container] code
|
||||
*
|
||||
* This is useful because it allows to interact with actually enhanced and regular containers through unified interface,
|
||||
* and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones.
|
||||
*/
|
||||
interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, StackedContentsCompatible {
|
||||
interface IEnhancedContainer<S : IContainerSlot> : Container, RecipeInput, Iterable<ItemStack>, StackedContentsCompatible {
|
||||
// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods
|
||||
override fun getMaxStackSize(): Int {
|
||||
return super.getMaxStackSize()
|
||||
}
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
super.startOpen(player)
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
super.stopOpen(player)
|
||||
}
|
||||
|
||||
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return super.canPlaceItem(slot, itemStack)
|
||||
}
|
||||
|
||||
override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean {
|
||||
return super.canTakeItem(container, slot, itemStack)
|
||||
}
|
||||
|
||||
override fun clearContent()
|
||||
override fun getContainerSize(): Int
|
||||
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()
|
||||
|
||||
// provide non-ambiguous get and set operators
|
||||
operator fun get(slot: Int): ItemStack {
|
||||
return getItem(slot)
|
||||
@ -34,9 +63,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
|
||||
setItem(slot, value)
|
||||
}
|
||||
|
||||
fun containerSlot(slot: Int): IContainerSlot {
|
||||
return IContainerSlot.Simple(slot, this)
|
||||
}
|
||||
fun containerSlot(slot: Int): S
|
||||
|
||||
override fun fillStackedContents(contents: StackedContents) {
|
||||
forEach { contents.accountStack(it) }
|
||||
@ -45,11 +72,11 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
|
||||
/**
|
||||
* Returns iterator over **all** slots this container has
|
||||
*/
|
||||
fun slotIterator(): Iterator<IContainerSlot> {
|
||||
fun slotIterator(): Iterator<S> {
|
||||
return (0 until containerSize).iterator().map { containerSlot(it) }
|
||||
}
|
||||
|
||||
fun nonEmptySlotIterator(): Iterator<IContainerSlot> {
|
||||
fun nonEmptySlotIterator(): Iterator<S> {
|
||||
return slotIterator().filter { it.isNotEmpty }
|
||||
}
|
||||
|
||||
@ -307,7 +334,11 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
|
||||
return StreamSupport.stream(spliterator(), false)
|
||||
}
|
||||
|
||||
private class Wrapper(private val parent: Container) : IEnhancedContainer {
|
||||
private class Wrapper(private val parent: Container) : IEnhancedContainer<IContainerSlot> {
|
||||
override fun containerSlot(slot: Int): IContainerSlot {
|
||||
return IContainerSlot.Simple(slot, parent)
|
||||
}
|
||||
|
||||
override fun clearContent() {
|
||||
return parent.clearContent()
|
||||
}
|
||||
@ -378,8 +409,8 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun wrap(other: Container): IEnhancedContainer {
|
||||
if (other is IEnhancedContainer)
|
||||
fun wrap(other: Container): IEnhancedContainer<*> {
|
||||
if (other is IEnhancedContainer<*>)
|
||||
return other
|
||||
|
||||
return Wrapper(other)
|
||||
|
@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.StackedContents
|
||||
import net.minecraft.world.inventory.CraftingContainer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer {
|
||||
interface IEnhancedCraftingContainer<S : IContainerSlot> : IEnhancedContainer<S>, CraftingContainer {
|
||||
override fun getItems(): MutableList<ItemStack> {
|
||||
return toList()
|
||||
}
|
||||
@ -13,7 +13,7 @@ interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer {
|
||||
forEach { contents.accountSimpleStack(it) }
|
||||
}
|
||||
|
||||
class Wrapper<C : IEnhancedContainer>(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer, IEnhancedContainer by parent {
|
||||
class Wrapper<C : IEnhancedContainer<S>, S : IContainerSlot>(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer<S>, IEnhancedContainer<S> by parent {
|
||||
init {
|
||||
require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" }
|
||||
}
|
||||
|
@ -1,203 +0,0 @@
|
||||
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 net.minecraft.world.item.crafting.RecipeInput
|
||||
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 : IEnhancedContainer {
|
||||
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 clearSlotFilters()
|
||||
|
||||
override fun isEmpty(): Boolean
|
||||
|
||||
override fun size(): Int {
|
||||
return containerSize
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over non-empty itemstacks of this container
|
||||
*/
|
||||
override fun iterator(): Iterator<ItemStack> {
|
||||
return iterator(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates non-empty slots of this container
|
||||
*/
|
||||
override fun slotIterator(): Iterator<IFilteredContainerSlot> {
|
||||
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] }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates either non-empty slots of container or all slots of container
|
||||
*/
|
||||
fun slotIterator(nonEmpty: Boolean): Iterator<IFilteredContainerSlot> {
|
||||
if (nonEmpty) {
|
||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) }
|
||||
} else {
|
||||
return (0 until containerSize).iterator().map { containerSlot(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun containerSlot(slot: Int): IFilteredContainerSlot
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
override 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.isSameItemSameComponents(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
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import ru.dbotthepony.kommons.collect.any
|
||||
/**
|
||||
* Skeletal implementation for containers which revolve around [IContainerSlot]
|
||||
*/
|
||||
interface ISlottedContainer : IEnhancedContainer {
|
||||
interface ISlottedContainer<S : IContainerSlot> : IEnhancedContainer<S> {
|
||||
override fun setChanged(slot: Int) {
|
||||
containerSlot(slot).setChanged()
|
||||
}
|
||||
|
@ -1,498 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||
import it.unimi.dsi.fastutil.ints.IntComparators
|
||||
import it.unimi.dsi.fastutil.ints.IntSpliterator
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSpliterators
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.entity.player.StackedContents
|
||||
import net.minecraft.world.inventory.StackedContentsCompatible
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Items
|
||||
import net.neoforged.neoforge.common.util.INBTSerializable
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kommons.util.Delegate
|
||||
import ru.dbotthepony.mc.otm.core.addSorted
|
||||
import ru.dbotthepony.mc.otm.core.collect.any
|
||||
import ru.dbotthepony.mc.otm.core.collect.count
|
||||
import ru.dbotthepony.mc.otm.core.collect.emptyIterator
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||
import ru.dbotthepony.mc.otm.network.StreamCodecs
|
||||
import ru.dbotthepony.mc.otm.network.syncher.ISynchable
|
||||
import ru.dbotthepony.mc.otm.network.syncher.SynchableObservedDelegate
|
||||
import java.util.*
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Predicate
|
||||
import java.util.function.Supplier
|
||||
import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Suppress("UNUSED")
|
||||
open class MatteryContainer(var listener: ContainerListener, private val size: Int) : IMatteryContainer, INBTSerializable<Tag?>, StackedContentsCompatible {
|
||||
constructor(watcher: Runnable, size: Int) : this({ _, _, _ -> watcher.run() }, size)
|
||||
constructor(size: Int) : this(EmptyListener, size)
|
||||
|
||||
fun interface ContainerListener {
|
||||
fun setChanged(slot: Int, new: ItemStack, old: ItemStack)
|
||||
}
|
||||
|
||||
object EmptyListener : ContainerListener {
|
||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {}
|
||||
}
|
||||
|
||||
init {
|
||||
require(size >= 0) { "Invalid container size $size" }
|
||||
}
|
||||
|
||||
private val slots = Array(size) { ItemStack.EMPTY }
|
||||
private val nonEmptyFlags = BitSet()
|
||||
private var nonEmptyIndices = IntArrayList()
|
||||
private var indicesReferenced = false
|
||||
private data class Update(val slot: Int, val new: ItemStack, val old: ItemStack)
|
||||
private val queuedUpdates = ArrayList<Update>()
|
||||
private var queueUpdates = false
|
||||
|
||||
private fun cowIndices() {
|
||||
if (indicesReferenced) {
|
||||
nonEmptyIndices = IntArrayList(nonEmptyIndices)
|
||||
indicesReferenced = false
|
||||
}
|
||||
}
|
||||
|
||||
private val trackedSlots: Array<ItemStack> = Array(size) { ItemStack.EMPTY }
|
||||
private val filters: Array<Item?> = arrayOfNulls(size)
|
||||
|
||||
var changeset = 0
|
||||
private set
|
||||
|
||||
override fun clearSlotFilters() {
|
||||
Arrays.fill(filters, null)
|
||||
}
|
||||
|
||||
val synchableFilters by lazy {
|
||||
immutableList<ISynchable> {
|
||||
for (i in 0 until size) {
|
||||
accept(SynchableObservedDelegate(Delegate.Of({ filters[i] }, { filters[i] = it }), StreamCodecs.ITEM_TYPE_NULLABLE))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
||||
filters[slot] = filter
|
||||
return true
|
||||
}
|
||||
|
||||
final override fun getSlotFilter(slot: Int) = filters[slot]
|
||||
final override fun hasSlotFilter(slot: Int) = filters[slot] !== null
|
||||
final override fun isSlotForbiddenForAutomation(slot: Int) = filters[slot] === Items.AIR
|
||||
|
||||
final override fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean {
|
||||
return testSlotFilter(slot, itemStack.item)
|
||||
}
|
||||
|
||||
final override fun testSlotFilter(slot: Int, item: Item): Boolean {
|
||||
if (filters[slot] == null) {
|
||||
return true
|
||||
} else {
|
||||
return filters[slot] === item
|
||||
}
|
||||
}
|
||||
|
||||
final override fun getContainerSize() = size
|
||||
protected open fun startedIgnoringUpdates() {}
|
||||
protected open fun stoppedIgnoringUpdates() {}
|
||||
|
||||
private data class SerializedItem(val item: ItemStack, val slot: Int) {
|
||||
companion object {
|
||||
val CODEC: Codec<SerializedItem> = RecordCodecBuilder.create {
|
||||
it.group(
|
||||
ItemStack.OPTIONAL_CODEC.fieldOf("item").forGetter { it.item },
|
||||
Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot },
|
||||
).apply(it, ::SerializedItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class SerializedFilter(val item: Item, val slot: Int) {
|
||||
companion object {
|
||||
val CODEC: Codec<SerializedFilter> = RecordCodecBuilder.create {
|
||||
it.group(
|
||||
BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter { it.item },
|
||||
Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot },
|
||||
).apply(it, ::SerializedFilter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class SerializedState(
|
||||
val items: List<SerializedItem>,
|
||||
val filters: List<SerializedFilter>
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<SerializedState> = RecordCodecBuilder.create {
|
||||
it.group(
|
||||
Codec.list(SerializedItem.CODEC).fieldOf("items").forGetter { it.items },
|
||||
Codec.list(SerializedFilter.CODEC).fieldOf("filters").forGetter { it.filters },
|
||||
).apply(it, ::SerializedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserializeNBT(registries: HolderLookup.Provider, tag: Tag?) {
|
||||
Arrays.fill(slots, ItemStack.EMPTY)
|
||||
Arrays.fill(filters, null)
|
||||
nonEmptyFlags.clear()
|
||||
nonEmptyIndices = IntArrayList()
|
||||
|
||||
if (tag != null) {
|
||||
SerializedState.CODEC.parse(registries.createSerializationContext(NbtOps.INSTANCE), tag)
|
||||
.resultOrPartial { LOGGER.error("Error deserializing container: $it") }
|
||||
.ifPresent {
|
||||
val freeSlots = IntAVLTreeSet()
|
||||
|
||||
for (i in 0 until size)
|
||||
freeSlots.add(i)
|
||||
|
||||
for ((item, slotID) in it.items) {
|
||||
if (item.isEmpty)
|
||||
continue
|
||||
|
||||
if (freeSlots.remove(slotID)) {
|
||||
slots[slotID] = item
|
||||
// trackedSlots[slotID] = item.copy()
|
||||
} else if (freeSlots.isEmpty()) {
|
||||
break
|
||||
} else {
|
||||
val slotID = freeSlots.firstInt()
|
||||
freeSlots.remove(slotID)
|
||||
slots[slotID] = item
|
||||
// trackedSlots[slotID] = item.copy()
|
||||
}
|
||||
}
|
||||
|
||||
for ((item, index) in it.filters) {
|
||||
if (index in 0 until size)
|
||||
filters[index] = item
|
||||
}
|
||||
|
||||
setChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalSetChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
||||
if (queueUpdates) {
|
||||
queuedUpdates.add(Update(slot, new, old))
|
||||
} else {
|
||||
setChanged(slot, new, old)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runUpdates() {
|
||||
for ((slot, new, old) in queuedUpdates) {
|
||||
setChanged(slot, new, old)
|
||||
}
|
||||
|
||||
queuedUpdates.clear()
|
||||
}
|
||||
|
||||
protected open fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
||||
listener.setChanged(slot, new, old)
|
||||
}
|
||||
|
||||
override fun serializeNBT(registries: HolderLookup.Provider): CompoundTag {
|
||||
val state = SerializedState(
|
||||
slotIterator(true).map { SerializedItem(it.item, it.slot) }.toList(size),
|
||||
filters.withIndex().iterator().filter { it.value != null }.map { SerializedFilter(it.value!!, it.index) }.toList()
|
||||
)
|
||||
|
||||
return SerializedState.CODEC.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), state)
|
||||
.resultOrPartial { throw RuntimeException("Failed to encode container contents: $it") }.get() as CompoundTag
|
||||
}
|
||||
|
||||
final override fun isEmpty(): Boolean {
|
||||
return nonEmptyIndices.isEmpty
|
||||
}
|
||||
|
||||
operator fun contains(other: ItemStack): Boolean {
|
||||
for (i in 0 until size) {
|
||||
if (ItemStack.isSameItemSameComponents(this[i], other)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
final override fun getItem(slot: Int): ItemStack {
|
||||
val item = slots[slot]
|
||||
|
||||
if (item.isEmpty) {
|
||||
if (nonEmptyFlags[slot]) {
|
||||
setChanged(slot)
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY
|
||||
} else {
|
||||
if (!nonEmptyFlags[slot]) {
|
||||
setChanged(slot)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
override fun fillStackedContents(contents: StackedContents) {
|
||||
for (item in iterator()) {
|
||||
contents.accountStack(item)
|
||||
}
|
||||
}
|
||||
|
||||
final override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||
if (amount <= 0 || slot < 0 || slot >= size || slots[slot].isEmpty)
|
||||
return ItemStack.EMPTY
|
||||
|
||||
val old = slots[slot].copy()
|
||||
val split = slots[slot].split(amount)
|
||||
trackedSlots[slot] = slots[slot].copy()
|
||||
changeset++
|
||||
updateEmptyFlag(slot)
|
||||
internalSetChanged(slot, if (slots[slot].isEmpty) ItemStack.EMPTY else slots[slot], old)
|
||||
|
||||
return split
|
||||
}
|
||||
|
||||
final override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||
val old = slots[slot]
|
||||
slots[slot] = ItemStack.EMPTY
|
||||
trackedSlots[slot] = ItemStack.EMPTY
|
||||
|
||||
if (old.isNotEmpty) {
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
}
|
||||
|
||||
return old
|
||||
}
|
||||
|
||||
final override fun setItem(slot: Int, itemStack: ItemStack) {
|
||||
if (slots[slot].isEmpty && itemStack.isEmpty || itemStack === slots[slot])
|
||||
return
|
||||
|
||||
val old = slots[slot]
|
||||
slots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack
|
||||
trackedSlots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack.copy()
|
||||
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
internalSetChanged(slot, itemStack, old)
|
||||
}
|
||||
|
||||
final override fun setChanged() {
|
||||
queueUpdates = true
|
||||
|
||||
try {
|
||||
for (slot in 0 until size) {
|
||||
setChanged(slot)
|
||||
}
|
||||
|
||||
runUpdates()
|
||||
} finally {
|
||||
queuedUpdates.clear()
|
||||
queueUpdates = false
|
||||
}
|
||||
}
|
||||
|
||||
final override fun setChanged(slot: Int) {
|
||||
if (!ItemStack.isSameItemSameComponents(slots[slot], trackedSlots[slot])) {
|
||||
trackedSlots[slot] = slots[slot].copy()
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
internalSetChanged(slot, slots[slot], trackedSlots[slot])
|
||||
// mojang соси))0)0))0)))))0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateEmptyFlag(slot: Int) {
|
||||
if (slots[slot].isEmpty) {
|
||||
if (nonEmptyFlags[slot]) {
|
||||
nonEmptyFlags[slot] = false
|
||||
cowIndices()
|
||||
nonEmptyIndices.rem(slot)
|
||||
}
|
||||
} else {
|
||||
if (!nonEmptyFlags[slot]) {
|
||||
nonEmptyFlags[slot] = true
|
||||
cowIndices()
|
||||
nonEmptyIndices.addSorted(slot, IntComparators.NATURAL_COMPARATOR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
final override fun clearContent() {
|
||||
nonEmptyFlags.clear()
|
||||
nonEmptyIndices = IntArrayList()
|
||||
|
||||
Arrays.fill(trackedSlots, ItemStack.EMPTY)
|
||||
|
||||
for (slot in 0 until size) {
|
||||
if (!slots[slot].isEmpty) {
|
||||
val old = slots[slot]
|
||||
slots[slot] = ItemStack.EMPTY
|
||||
internalSetChanged(slot, ItemStack.EMPTY, old)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class Iterator : kotlin.collections.Iterator<ItemStack> {
|
||||
init {
|
||||
indicesReferenced = true
|
||||
}
|
||||
|
||||
private val parent = nonEmptyIndices.intIterator()
|
||||
private var lastIndex = -1
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return parent.hasNext()
|
||||
}
|
||||
|
||||
override fun next(): ItemStack {
|
||||
lastIndex = parent.nextInt()
|
||||
return getItem(lastIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class Spliterator(private val parent: IntSpliterator) : java.util.Spliterator<ItemStack> {
|
||||
override fun tryAdvance(action: Consumer<in ItemStack>): Boolean {
|
||||
return parent.tryAdvance {
|
||||
action.accept(getItem(it))
|
||||
}
|
||||
}
|
||||
|
||||
override fun trySplit(): java.util.Spliterator<ItemStack>? {
|
||||
return parent.trySplit()?.let(::Spliterator)
|
||||
}
|
||||
|
||||
override fun estimateSize(): Long {
|
||||
return parent.estimateSize()
|
||||
}
|
||||
|
||||
override fun characteristics(): Int {
|
||||
return parent.characteristics()
|
||||
}
|
||||
}
|
||||
|
||||
final override fun iterator(): kotlin.collections.Iterator<ItemStack> {
|
||||
if (isEmpty) {
|
||||
return emptyIterator()
|
||||
}
|
||||
|
||||
return Iterator()
|
||||
}
|
||||
|
||||
final override fun iterator(nonEmpty: Boolean): kotlin.collections.Iterator<ItemStack> {
|
||||
if (!nonEmpty) {
|
||||
return (0 until size).iterator().map { slots[it] }
|
||||
} else if (isEmpty) {
|
||||
return emptyIterator()
|
||||
} else {
|
||||
return Iterator()
|
||||
}
|
||||
}
|
||||
|
||||
inner class Slot(val slot: Int) : IFilteredContainerSlot {
|
||||
override var item: ItemStack
|
||||
get() = this@MatteryContainer[slot]
|
||||
set(value) { this@MatteryContainer[slot] = value }
|
||||
override val maxStackSize: Int
|
||||
get() = this@MatteryContainer.maxStackSize
|
||||
|
||||
override fun remove(): ItemStack {
|
||||
return removeItemNoUpdate(slot)
|
||||
}
|
||||
|
||||
override fun remove(count: Int): ItemStack {
|
||||
return removeItem(slot, count)
|
||||
}
|
||||
|
||||
override var filter: Item?
|
||||
get() = getSlotFilter(slot)
|
||||
set(value) { setSlotFilter(slot, value) }
|
||||
|
||||
override val isForbiddenForAutomation: Boolean
|
||||
get() = isSlotForbiddenForAutomation(slot)
|
||||
|
||||
override fun maxStackSize(item: ItemStack): Int {
|
||||
return getMaxStackSize(slot, item)
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
setChanged(slot)
|
||||
}
|
||||
}
|
||||
|
||||
final override fun slotIterator(): kotlin.collections.Iterator<Slot> {
|
||||
indicesReferenced = true
|
||||
return nonEmptyIndices.iterator().map { Slot(it) }
|
||||
}
|
||||
|
||||
final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator<Slot> {
|
||||
if (!nonEmpty) {
|
||||
return (0 until size).iterator().map { Slot(it) }
|
||||
} else if (isEmpty) {
|
||||
return emptyIterator()
|
||||
} else {
|
||||
indicesReferenced = true
|
||||
return nonEmptyIndices.iterator().map { Slot(it) }
|
||||
}
|
||||
}
|
||||
|
||||
final override fun containerSlot(slot: Int): Slot {
|
||||
return Slot(slot)
|
||||
}
|
||||
|
||||
final override fun countItem(item: Item): Int {
|
||||
return iterator().filter { it.item == item }.count().toInt()
|
||||
}
|
||||
|
||||
final override fun hasAnyOf(items: Set<Item>): Boolean {
|
||||
return iterator().any { it.item in items }
|
||||
}
|
||||
|
||||
final override fun hasAnyMatching(predicate: Predicate<ItemStack>): Boolean {
|
||||
return iterator().any(predicate)
|
||||
}
|
||||
|
||||
final override fun spliterator(): java.util.Spliterator<ItemStack> {
|
||||
if (isEmpty) {
|
||||
return ObjectSpliterators.emptySpliterator()
|
||||
}
|
||||
|
||||
indicesReferenced = true
|
||||
return Spliterator(nonEmptyIndices.intSpliterator())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import net.minecraft.world.inventory.CraftingContainer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
open class MatteryCraftingContainer(listener: ContainerListener, private val width: Int, private val height: Int) : MatteryContainer(listener, width * height), CraftingContainer {
|
||||
constructor(listener: () -> Unit, width: Int, height: Int) : this({ _, _, _ -> listener.invoke() }, width, height)
|
||||
constructor(width: Int, height: Int) : this(EmptyListener, width, height)
|
||||
|
||||
final override fun getWidth(): Int {
|
||||
return width
|
||||
}
|
||||
|
||||
final override fun getHeight(): Int {
|
||||
return height
|
||||
}
|
||||
|
||||
final override fun getItems(): MutableList<ItemStack> {
|
||||
return toList()
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
class ShadowContainer(private val parent: Container) : IContainer by IContainer.wrap(parent) {
|
||||
private val shadowed = Int2ObjectArrayMap<ItemStack>(0)
|
||||
|
||||
override fun clearContent() {
|
||||
shadowed.clear()
|
||||
parent.clearContent()
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return parent.isEmpty && shadowed.isEmpty()
|
||||
}
|
||||
|
||||
override fun getItem(slot: Int): ItemStack {
|
||||
return shadowed[slot] ?: parent.getItem(slot)
|
||||
}
|
||||
|
||||
override fun removeItem(slot: Int, count: Int): ItemStack {
|
||||
val shadow = shadowed[slot] ?: return parent.removeItem(slot, count)
|
||||
val copy = shadow.copyWithCount(shadow.count.coerceAtLeast(count))
|
||||
shadow.split(count)
|
||||
if (shadow.isEmpty) shadowed[slot] = ItemStack.EMPTY
|
||||
return copy
|
||||
}
|
||||
|
||||
override fun removeItemNoUpdate(slot: Int): ItemStack {
|
||||
shadowed[slot] ?: return parent.removeItemNoUpdate(slot)
|
||||
val old = shadowed[slot]
|
||||
shadowed[slot] = ItemStack.EMPTY
|
||||
return old!!
|
||||
}
|
||||
|
||||
override fun setItem(slot: Int, item: ItemStack) {
|
||||
shadowed[slot] = item
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun shadow(container: Container, slot: Int, itemStack: ItemStack): Container {
|
||||
return ShadowContainer(container).also { it[slot] = itemStack }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import net.minecraft.world.entity.player.StackedContents
|
||||
import net.minecraft.world.inventory.CraftingContainer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.container.util.iterator
|
||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||
|
||||
class ShadowCraftingContainer(private val parent: CraftingContainer) : IContainer by ShadowContainer(parent), CraftingContainer {
|
||||
override fun fillStackedContents(contents: StackedContents) {
|
||||
for (item in iterator()) {
|
||||
contents.accountStack(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWidth(): Int {
|
||||
return parent.width
|
||||
}
|
||||
|
||||
override fun getHeight(): Int {
|
||||
return parent.height
|
||||
}
|
||||
|
||||
override fun getItems(): MutableList<ItemStack> {
|
||||
return iterator().toList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun shadow(container: CraftingContainer, slot: Int, itemStack: ItemStack): CraftingContainer {
|
||||
return ShadowCraftingContainer(container).also { it[slot] = itemStack }
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ class UpgradeContainer(
|
||||
val allowedUpgrades: Set<UpgradeType> = UpgradeType.ALL,
|
||||
val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false },
|
||||
private val listener: Runnable = Runnable {}
|
||||
) : EnhancedContainer(slotCount), IMatteryUpgrade {
|
||||
) : EnhancedContainer.Simple(slotCount), IMatteryUpgrade {
|
||||
override fun notifySlotChanged(slot: Int, old: ItemStack) {
|
||||
super.notifySlotChanged(slot, old)
|
||||
listener.run()
|
||||
|
@ -40,7 +40,7 @@ class SlottedContainer(
|
||||
slots: Collection<MarkedSlotProvider<*>>,
|
||||
private val stillValid: Predicate<Player>,
|
||||
private val globalChangeListeners: Array<Runnable>
|
||||
) : IAutomatedContainer, INBTSerializable<Tag> {
|
||||
) : IAutomatedContainer<ContainerSlot>, INBTSerializable<Tag> {
|
||||
interface ISlotGroup<T : ContainerSlot> : List<T> {
|
||||
/**
|
||||
* @see IAutomatedContainer.addItem
|
||||
@ -140,7 +140,7 @@ class SlottedContainer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun containerSlot(slot: Int): IAutomatedContainerSlot {
|
||||
override fun containerSlot(slot: Int): ContainerSlot {
|
||||
return slots[slot]
|
||||
}
|
||||
|
||||
|
@ -6,14 +6,13 @@ import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.container.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.IEnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
|
||||
fun Container.containerSlot(slot: Int): IContainerSlot {
|
||||
if (this is IEnhancedContainer) {
|
||||
if (this is IEnhancedContainer<*>) {
|
||||
return containerSlot(slot)
|
||||
} else {
|
||||
return IContainerSlot.Simple(slot, this)
|
||||
@ -24,7 +23,7 @@ fun Container.containerSlot(slot: Int): IContainerSlot {
|
||||
* Returns [IContainerSlot] only if this container is [IEnhancedContainer]
|
||||
*/
|
||||
fun Container.containerSlotOrNull(slot: Int): IContainerSlot? {
|
||||
if (this is IEnhancedContainer) {
|
||||
if (this is IEnhancedContainer<*>) {
|
||||
return containerSlot(slot)
|
||||
} else {
|
||||
return null
|
||||
@ -40,7 +39,7 @@ fun Slot.containerSlotOrNull(): IContainerSlot? {
|
||||
}
|
||||
|
||||
operator fun Container.iterator(): Iterator<ItemStack> {
|
||||
if (this is IEnhancedContainer) {
|
||||
if (this is IEnhancedContainer<*>) {
|
||||
return iterator()
|
||||
} else {
|
||||
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
|
||||
@ -48,7 +47,7 @@ operator fun Container.iterator(): Iterator<ItemStack> {
|
||||
}
|
||||
|
||||
fun Container.slotIterator(): Iterator<IContainerSlot> {
|
||||
if (this is IEnhancedContainer) {
|
||||
if (this is IEnhancedContainer<*>) {
|
||||
return slotIterator()
|
||||
} else {
|
||||
return (0 until containerSize).iterator().map { IContainerSlot.Simple(it, this) }
|
||||
@ -56,7 +55,7 @@ fun Container.slotIterator(): Iterator<IContainerSlot> {
|
||||
}
|
||||
|
||||
fun Container.nonEmptySlotIterator(): Iterator<IContainerSlot> {
|
||||
if (this is IEnhancedContainer) {
|
||||
if (this is IEnhancedContainer<*>) {
|
||||
return nonEmptySlotIterator()
|
||||
} else {
|
||||
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { IContainerSlot.Simple(it, this) }
|
||||
|
@ -23,7 +23,6 @@ import ru.dbotthepony.mc.otm.client.ShiftPressedCond
|
||||
import ru.dbotthepony.mc.otm.client.isShiftDown
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
|
@ -66,7 +66,7 @@ class MatterDustItem : Item(Properties().stacksTo(64)), IMatterItem {
|
||||
return MatterValue(value, 1.0)
|
||||
}
|
||||
|
||||
fun moveIntoContainer(matterValue: Decimal, container: IEnhancedContainer, mainSlot: Int, stackingSlot: Int): Decimal {
|
||||
fun moveIntoContainer(matterValue: Decimal, container: IEnhancedContainer<*>, mainSlot: Int, stackingSlot: Int): Decimal {
|
||||
@Suppress("name_shadowing")
|
||||
var matterValue = matterValue
|
||||
|
||||
|
@ -77,7 +77,8 @@ import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive
|
||||
import ru.dbotthepony.mc.otm.client.isShiftDown
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer
|
||||
import ru.dbotthepony.mc.otm.container.util.stream
|
||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
@ -500,7 +501,7 @@ object MatterManager {
|
||||
height = it.value.ingredients.size.coerceAtLeast(height)
|
||||
}
|
||||
|
||||
val container = MatteryCraftingContainer(width, height)
|
||||
val container = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.Simple(width * height), width, height)
|
||||
val realIngredients = ArrayList<ArrayList<RecipeEntry>>()
|
||||
|
||||
for (c in it.value.ingredients.indices) {
|
||||
|
@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IEnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||
import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull
|
||||
@ -65,8 +64,8 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
if (container is IEnhancedContainer) {
|
||||
(container as IEnhancedContainer).setChanged(containerSlot)
|
||||
if (container is IEnhancedContainer<*>) {
|
||||
(container as IEnhancedContainer<*>).setChanged(containerSlot)
|
||||
} else {
|
||||
super.setChanged()
|
||||
}
|
||||
@ -83,7 +82,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int
|
||||
override fun getMaxStackSize(): Int {
|
||||
val container = container
|
||||
|
||||
if (container is IEnhancedContainer) {
|
||||
if (container is IEnhancedContainer<*>) {
|
||||
return container.getMaxStackSize(slotIndex, ItemStack.EMPTY)
|
||||
} else {
|
||||
return super.getMaxStackSize()
|
||||
@ -93,7 +92,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int
|
||||
override fun getMaxStackSize(itemStack: ItemStack): Int {
|
||||
val container = container
|
||||
|
||||
if (container is IEnhancedContainer) {
|
||||
if (container is IEnhancedContainer<*>) {
|
||||
return container.getMaxStackSize(slotIndex, itemStack)
|
||||
} else {
|
||||
return super.getMaxStackSize(itemStack)
|
||||
@ -278,7 +277,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr
|
||||
allowedTypes[value] = BooleanSupplier { b.get() }
|
||||
}
|
||||
|
||||
val syncContainer = container ?: EnhancedContainer(count)
|
||||
val syncContainer = container ?: EnhancedContainer.Simple(count)
|
||||
val isOpen = InstantBooleanInput(this)
|
||||
|
||||
return UpgradeSlots(
|
||||
|
@ -10,7 +10,6 @@ import net.minecraft.world.item.crafting.RecipeType
|
||||
import net.minecraft.world.item.crafting.SingleRecipeInput
|
||||
import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
|
@ -16,7 +16,6 @@ import ru.dbotthepony.kommons.util.getValue
|
||||
import ru.dbotthepony.kommons.util.setValue
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
|
||||
import ru.dbotthepony.mc.otm.player.matteryPlayer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.set
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.addAll
|
||||
|
@ -21,7 +21,7 @@ class MatterRecyclerMenu @JvmOverloads constructor(
|
||||
inventory: Inventory,
|
||||
tile: MatterRecyclerBlockEntity? = null
|
||||
) : MatteryPoweredMenu(MMenus.MATTER_RECYCLER, containerID, inventory, tile) {
|
||||
val input = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer(1), 0) {
|
||||
val input = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer.Simple(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class MatterReplicatorMenu @JvmOverloads constructor(
|
||||
val upgrades = makeUpgradeSlots(3, tile?.upgrades)
|
||||
|
||||
init {
|
||||
val container = CombinedContainer(tile?.outputContainer ?: EnhancedContainer(3), tile?.dustContainer ?: EnhancedContainer(2))
|
||||
val container = CombinedContainer(tile?.outputContainer ?: EnhancedContainer.Simple(3), tile?.dustContainer ?: EnhancedContainer.Simple(2))
|
||||
|
||||
storageSlots = immutableList(5) {
|
||||
addStorageSlot(OutputMenuSlot(container, it, onTake = {
|
||||
|
@ -31,7 +31,7 @@ class MatterScannerMenu(
|
||||
val upgrades = makeUpgradeSlots(2, tile?.upgrades)
|
||||
|
||||
init {
|
||||
val container = tile?.container ?: EnhancedContainer(1)
|
||||
val container = tile?.container ?: EnhancedContainer.Simple(1)
|
||||
|
||||
input = object : MatteryMenuSlot(container, 0, 64, 38) {
|
||||
override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack)
|
||||
|
@ -32,7 +32,7 @@ class PatternStorageMenu @JvmOverloads constructor(
|
||||
})
|
||||
}
|
||||
|
||||
val patterns = tile?.container ?: EnhancedContainer(2 * 4)
|
||||
val patterns = tile?.container ?: EnhancedContainer.Simple(2 * 4)
|
||||
|
||||
storageSlots = immutableList(patterns.containerSize) {
|
||||
addStorageSlot(PatternMenuSlot(patterns, it))
|
||||
|
@ -19,7 +19,7 @@ class DriveRackMenu @JvmOverloads constructor(
|
||||
inventory: Inventory,
|
||||
tile: DriveRackBlockEntity? = null
|
||||
) : MatteryPoweredMenu(MMenus.DRIVE_RACK, containerId, inventory, tile) {
|
||||
val storageSlots = makeSlots(tile?.container ?: EnhancedContainer(4), ::DriveMenuSlot)
|
||||
val storageSlots = makeSlots(tile?.container ?: EnhancedContainer.Simple(4), ::DriveMenuSlot)
|
||||
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
|
||||
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
|
||||
val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority })
|
||||
|
@ -37,7 +37,7 @@ class DriveViewerMenu(
|
||||
) : MatteryPoweredMenu(MMenus.DRIVE_VIEWER, containerID, inventory, tile), INetworkedItemViewProvider {
|
||||
override val networkedItemView = NetworkedItemView(inventory.player, this, tile == null)
|
||||
|
||||
val driveSlot = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer(1), 0) {
|
||||
val driveSlot = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer.Simple(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
|
||||
}
|
||||
}
|
||||
|
||||
val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: EnhancedContainer(1), 0) {
|
||||
val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: EnhancedContainer.Simple(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return false
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class CobblerMenu(
|
||||
inventory: Inventory,
|
||||
tile: CobblerBlockEntity? = null
|
||||
) : MatteryMenu(MMenus.COBBLESTONE_GENERATOR, p_38852_, inventory, tile) {
|
||||
val storageSlots = makeSlots(tile?.container ?: EnhancedContainer(CobblerBlockEntity.CONTAINER_SIZE), ::OutputMenuSlot)
|
||||
val storageSlots = makeSlots(tile?.container ?: EnhancedContainer.Simple(CobblerBlockEntity.CONTAINER_SIZE), ::OutputMenuSlot)
|
||||
val redstone = EnumInputWithFeedback<RedstoneSetting>(this)
|
||||
val itemConfig = ItemConfigPlayerInput(this)
|
||||
|
||||
|
@ -34,13 +34,13 @@ class EssenceStorageMenu(
|
||||
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
|
||||
val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig)
|
||||
|
||||
val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: EnhancedContainer(1), 0) {
|
||||
val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: EnhancedContainer.Simple(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return itemStack.item is EssenceCapsuleItem && super.mayPlace(itemStack)
|
||||
}
|
||||
}
|
||||
|
||||
val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: EnhancedContainer(1), 0) {
|
||||
val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: EnhancedContainer.Simple(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack)
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class PlatePressMenu(
|
||||
isTwin: Boolean
|
||||
) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) {
|
||||
val inputSlots = makeSlots(tile?.inputContainer ?: SlottedContainer.filtered(if (isTwin) 2 else 1), ::MatteryMenuSlot)
|
||||
val outputSlots = makeSlots(tile?.outputContainer ?: EnhancedContainer(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } }
|
||||
val outputSlots = makeSlots(tile?.outputContainer ?: EnhancedContainer.Simple(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } }
|
||||
val gauges = immutableList(if (isTwin) 2 else 1) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) }
|
||||
|
||||
override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true)
|
||||
|
@ -40,7 +40,7 @@ class PoweredFurnaceMenu(
|
||||
// we can't make these slots to reject non-smeltable items
|
||||
// since mods may add obscure recipes/ingredients which never test true on client
|
||||
val inputSlots = makeSlots(tile?.inputs ?: SlottedContainer.filtered(2), ::UserFilteredMenuSlot)
|
||||
val outputSlots = makeSlots(tile?.outputs ?: EnhancedContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } }
|
||||
val outputSlots = makeSlots(tile?.outputs ?: EnhancedContainer.Simple(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } }
|
||||
val progressGauge = immutableList(2) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) }
|
||||
|
||||
override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true)
|
||||
|
@ -0,0 +1,22 @@
|
||||
package ru.dbotthepony.mc.otm.player
|
||||
|
||||
import net.minecraft.world.item.Item
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.IEnhancedContainer
|
||||
|
||||
class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer<IPlayerInventorySlot>(size) {
|
||||
private inner class Slot(slot: Int) : IContainerSlot.Simple(slot, this@ExopackContainer), IPlayerInventorySlot {
|
||||
override var shouldCharge: Boolean
|
||||
get() = (PlayerInventoryWrapper.SLOTS + slot) in player.slotsChargeFlag
|
||||
set(value) { if (value) player.slotsChargeFlag.add(PlayerInventoryWrapper.SLOTS + slot) else player.slotsChargeFlag.remove(PlayerInventoryWrapper.SLOTS + slot) }
|
||||
|
||||
override var filter: Item?
|
||||
get() = player.slotFilters[PlayerInventoryWrapper.SLOTS + slot]
|
||||
set(value) { if (value == null) player.slotFilters.remove(PlayerInventoryWrapper.SLOTS + slot) else player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] = value }
|
||||
}
|
||||
|
||||
override fun containerSlot(slot: Int): IPlayerInventorySlot {
|
||||
return Slot(slot)
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.player
|
||||
|
||||
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
||||
|
||||
interface IPlayerInventorySlot : IFilteredContainerSlot {
|
||||
var shouldCharge: Boolean
|
||||
}
|
@ -69,21 +69,20 @@ class MatteryFoodData(private var player: Player) : FoodData() {
|
||||
private var energyToDrain = Decimal.ZERO
|
||||
|
||||
private fun tickExhaustion() {
|
||||
if (exhaustionLevel >= EXHAUSTION_PER_HUNGER_POINT) {
|
||||
if (player.matteryPlayer.isAndroid && exhaustionLevel > 0f) {
|
||||
energyToDrain += PlayerConfig.ANDROID_ENERGY_PER_HUNGER_POINT * (exhaustionLevel / EXHAUSTION_PER_HUNGER_POINT)
|
||||
exhaustionLevel = 0f
|
||||
} else if (exhaustionLevel >= EXHAUSTION_PER_HUNGER_POINT) {
|
||||
var points = (exhaustionLevel / EXHAUSTION_PER_HUNGER_POINT).toInt()
|
||||
exhaustionLevel %= EXHAUSTION_PER_HUNGER_POINT
|
||||
|
||||
if (player.matteryPlayer.isAndroid) {
|
||||
energyToDrain += PlayerConfig.ANDROID_ENERGY_PER_HUNGER_POINT * points
|
||||
} else {
|
||||
if (saturationLevel > 0f) {
|
||||
val satisfied = min(saturationLevel.roundToInt(), points)
|
||||
points -= satisfied
|
||||
saturationLevel -= satisfied
|
||||
}
|
||||
|
||||
foodLevel = max(0, foodLevel - points)
|
||||
if (saturationLevel > 0f) {
|
||||
val satisfied = min(saturationLevel.roundToInt(), points)
|
||||
points -= satisfied
|
||||
saturationLevel -= satisfied
|
||||
}
|
||||
|
||||
foodLevel = max(0, foodLevel - points)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,9 +110,13 @@ class MatteryFoodData(private var player: Player) : FoodData() {
|
||||
if (player.matteryPlayer.isAndroid) {
|
||||
if (energyToDrain > Decimal.ZERO)
|
||||
energyToDrain -= player.matteryPlayer.androidEnergy.extractEnergy(energyToDrain, false)
|
||||
else if (energyToDrain < Decimal.ZERO)
|
||||
else if (energyToDrain < Decimal.ZERO) {
|
||||
energyToDrain += player.matteryPlayer.androidEnergy.receiveEnergy(-energyToDrain, false)
|
||||
|
||||
if (player.matteryPlayer.androidEnergy.missingPower <= Decimal.ZERO)
|
||||
energyToDrain = Decimal.ZERO
|
||||
}
|
||||
|
||||
if (player.level().difficulty == Difficulty.PEACEFUL && PlayerConfig.REGENERATE_ENERGY_IN_PEACEFUL)
|
||||
player.matteryPlayer.androidEnergy.receiveEnergy(PlayerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false)
|
||||
|
||||
|
@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.player
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||
import it.unimi.dsi.fastutil.ints.IntSet
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||
@ -12,6 +15,7 @@ import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
|
||||
@ -75,13 +79,13 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.config.PlayerConfig
|
||||
import ru.dbotthepony.mc.otm.config.ExopackConfig
|
||||
import ru.dbotthepony.mc.otm.container.CombinedContainer
|
||||
import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IContainer
|
||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.IEnhancedContainer
|
||||
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.container.util.slotIterator
|
||||
import ru.dbotthepony.mc.otm.container.vanishCursedItems
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
@ -95,6 +99,7 @@ import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.Savetables
|
||||
import ru.dbotthepony.mc.otm.core.util.TickList
|
||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings
|
||||
import ru.dbotthepony.mc.otm.network.*
|
||||
@ -158,18 +163,6 @@ class MatteryPlayer(val ply: Player) {
|
||||
val level: Level get() = capability.ply.level()
|
||||
}
|
||||
|
||||
private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) {
|
||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
||||
if (ply is ServerPlayer) {
|
||||
val item = new.copy()
|
||||
|
||||
tickList.once {
|
||||
MatteryInventoryChangeTrigger.trigger(ply, combinedInventory, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For fields that need to be synchronized only to owning player
|
||||
*
|
||||
@ -249,22 +242,20 @@ class MatteryPlayer(val ply: Player) {
|
||||
* If you want to properly extend Exopack suit capacity, add your value into this map
|
||||
*/
|
||||
val exopackSlotModifier = UUIDIntModifiersMap(observer = observer@{
|
||||
if (it < 0) {
|
||||
exopackContainer = PlayerMatteryContainer(0)
|
||||
} else {
|
||||
exopackContainer = PlayerMatteryContainer(it)
|
||||
}
|
||||
exopackContainer = ExopackContainer(it.coerceAtLeast(0), this)
|
||||
}, backingMap = this.exopackSlotModifierMap.delegate)
|
||||
|
||||
val regularSlotFilters = immutableList(Inventory.INVENTORY_SIZE) {
|
||||
syncher.add(null, StreamCodecs.ITEM_TYPE.nullable())
|
||||
}
|
||||
|
||||
val slotsChargeFlag = syncher.set(
|
||||
backing = ListenableSet(IntAVLTreeSet()),
|
||||
codec = StreamCodecs.VAR_INT,
|
||||
).delegate
|
||||
|
||||
val slotFilters = syncher.map(
|
||||
backing = ListenableMap(Int2ObjectOpenHashMap()),
|
||||
keyCodec = StreamCodecs.VAR_INT,
|
||||
valueCodec = StreamCodecs.ITEM_TYPE
|
||||
).delegate
|
||||
|
||||
private fun slotChargeToDefault() {
|
||||
// броня
|
||||
slotsChargeFlag.add(36)
|
||||
@ -277,15 +268,12 @@ class MatteryPlayer(val ply: Player) {
|
||||
slotChargeToDefault()
|
||||
}
|
||||
|
||||
private var exopackContainerSynchedFilters: List<Closeable> = listOf()
|
||||
|
||||
/**
|
||||
* Exopack container, which actually store items inside Exopack
|
||||
*/
|
||||
var exopackContainer: MatteryContainer = PlayerMatteryContainer(0)
|
||||
var exopackContainer: ExopackContainer = ExopackContainer(0, this)
|
||||
private set(value) {
|
||||
_exoPackMenu = null
|
||||
exopackContainerSynchedFilters.forEach { it.close() }
|
||||
|
||||
@Suppress("SENSELESS_COMPARISON") // false positive - fields of player can easily be nulls, despite annotations saying otherwise
|
||||
if (ply.containerMenu != null && (ply !is ServerPlayer || ply.connection != null)) {
|
||||
@ -300,7 +288,6 @@ class MatteryPlayer(val ply: Player) {
|
||||
}
|
||||
|
||||
value.deserializeNBT(ply.level().registryAccess(), field.serializeNBT(ply.level().registryAccess()))
|
||||
exopackContainerSynchedFilters = value.synchableFilters.map { syncher.add0(it) }
|
||||
field = value
|
||||
|
||||
_combinedInventory = null
|
||||
@ -312,34 +299,9 @@ class MatteryPlayer(val ply: Player) {
|
||||
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()
|
||||
}
|
||||
val wrappedInventory = PlayerInventoryWrapper(this)
|
||||
|
||||
override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
|
||||
regularSlotFilters.getOrNull(slot)?.accept(filter)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun setChanged(slot: Int) {
|
||||
ply.inventory.setChanged()
|
||||
}
|
||||
|
||||
override fun clearSlotFilters() {
|
||||
regularSlotFilters.forEach { it.accept(null) }
|
||||
}
|
||||
|
||||
override fun containerSlot(slot: Int): IFilteredContainerSlot {
|
||||
return object : IContainerSlot.Simple(slot, this), IFilteredContainerSlot {
|
||||
override var filter: Item?
|
||||
get() = regularSlotFilters.getOrNull(slot)?.get()
|
||||
set(value) { regularSlotFilters.getOrNull(slot)?.accept(value) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val wrappedItemInventory: IMatteryContainer = object : IMatteryContainer by wrappedInventory {
|
||||
val wrappedItemInventory: IEnhancedContainer<IPlayerInventorySlot> = object : IEnhancedContainer<IPlayerInventorySlot> by wrappedInventory {
|
||||
override fun getContainerSize(): Int {
|
||||
return 36
|
||||
}
|
||||
@ -543,8 +505,8 @@ class MatteryPlayer(val ply: Player) {
|
||||
}
|
||||
}
|
||||
|
||||
val input = MatteryContainer(Runnable { notify(IdleReason.ITEM) }, 1)
|
||||
val output = MatteryContainer(Runnable { notify(IdleReason.ITEM) }, 1)
|
||||
val input = EnhancedContainer.WithListener(1) { notify(IdleReason.ITEM) }
|
||||
val output = EnhancedContainer.WithListener(1) { notify(IdleReason.ITEM) }
|
||||
|
||||
init {
|
||||
savetables.stateful(::input, "exopack_smelter_input_$index")
|
||||
@ -573,7 +535,7 @@ class MatteryPlayer(val ply: Player) {
|
||||
*/
|
||||
val exopackEnergy = ProfiledEnergyStorage(BatteryBackedEnergyStorage(ply, syncher, Decimal.ZERO, ExopackConfig.ENERGY_CAPACITY, false, onChange = { for (v in smelters) v.notify(MachineJobEventLoop.IdleReason.POWER) }))
|
||||
|
||||
val exopackChargeSlots = MatteryContainer(4)
|
||||
val exopackChargeSlots = EnhancedContainer.Simple(4)
|
||||
var acceptExopackChargeFromWirelessCharger = true
|
||||
|
||||
init {
|
||||
@ -955,11 +917,8 @@ class MatteryPlayer(val ply: Player) {
|
||||
}
|
||||
}
|
||||
|
||||
tag["regularSlotFilters"] = ListTag().also {
|
||||
for (filter in regularSlotFilters) {
|
||||
it.add(StringTag.valueOf(filter.value?.registryName?.toString() ?: ""))
|
||||
}
|
||||
}
|
||||
tag["slotFilters"] = filtersCodec.encodeStart(registry.createSerializationContext(NbtOps.INSTANCE), slotFilters.entries.map { it.key to it.value })
|
||||
.getOrThrow { IllegalStateException("Unable to serialize slot filters: $it") }
|
||||
|
||||
tag.putIntArray("slotsChargeFlag", slotsChargeFlag.toIntArray())
|
||||
return tag
|
||||
@ -977,18 +936,16 @@ class MatteryPlayer(val ply: Player) {
|
||||
ExopackSlotsExpandedTrigger.trigger(ply, 0, exopackContainer.containerSize)
|
||||
}
|
||||
|
||||
for (filter in regularSlotFilters) {
|
||||
filter.value = null
|
||||
}
|
||||
|
||||
slotFilters.clear()
|
||||
slotsChargeFlag.clear()
|
||||
|
||||
val regularSlotFilters = tag.getStringList("regularSlotFilters")
|
||||
|
||||
for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) {
|
||||
val path = regularSlotFilters[i].asString
|
||||
if (path == "") continue
|
||||
this.regularSlotFilters[i].value = BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(path) ?: continue)
|
||||
if ("slotFilters" in tag) {
|
||||
filtersCodec.decode(registry.createSerializationContext(NbtOps.INSTANCE), tag["slotFilters"])
|
||||
.ifError { LOGGER.error("Unable to deserialize slot filters: ${it.message()}") }
|
||||
.resultOrPartial()
|
||||
.ifPresent {
|
||||
it.first.forEach { (a, b) -> slotFilters[a] = b }
|
||||
}
|
||||
}
|
||||
|
||||
if ("slotsChargeFlag" in tag) {
|
||||
@ -1341,6 +1298,15 @@ class MatteryPlayer(val ply: Player) {
|
||||
|
||||
@Suppress("unused")
|
||||
companion object {
|
||||
private val filtersCodec: Codec<List<Pair<Int, Item>>> = Codec.list(
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
Codec.INT.minRange(0).fieldOf("slot").forGetter { it.first },
|
||||
BuiltInRegistries.ITEM.byNameCodec().fieldOf("filter").forGetter { it.second }
|
||||
).apply(it, ::Pair)
|
||||
}
|
||||
)
|
||||
|
||||
private val offhandSlotRange = IntSet.of(40)
|
||||
|
||||
init {
|
||||
|
@ -0,0 +1,73 @@
|
||||
package ru.dbotthepony.mc.otm.player
|
||||
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.container.ISlottedContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.container.set
|
||||
|
||||
class PlayerInventoryWrapper(val player: MatteryPlayer) : ISlottedContainer<IPlayerInventorySlot> {
|
||||
val inventory: Inventory
|
||||
get() = player.ply.inventory
|
||||
|
||||
private inner class Slot(val slot: Int) : IPlayerInventorySlot {
|
||||
override fun setChanged() {
|
||||
inventory.setChanged()
|
||||
}
|
||||
|
||||
override var filter: Item?
|
||||
get() = player.slotFilters[slot]
|
||||
set(value) { if (value == null) player.slotFilters.remove(slot) else player.slotFilters[slot] = value }
|
||||
override var shouldCharge: Boolean
|
||||
get() = slot in player.slotsChargeFlag
|
||||
set(value) { if (value) player.slotsChargeFlag.add(slot) else player.slotsChargeFlag.remove(slot) }
|
||||
override var item: ItemStack
|
||||
get() = inventory[slot]
|
||||
set(value) { inventory[slot] = value }
|
||||
override val maxStackSize: Int
|
||||
get() = inventory.maxStackSize
|
||||
|
||||
override fun maxStackSize(item: ItemStack): Int {
|
||||
return inventory.getMaxStackSize(item)
|
||||
}
|
||||
|
||||
override fun remove(): ItemStack {
|
||||
return inventory.removeItemNoUpdate(slot)
|
||||
}
|
||||
|
||||
override fun remove(count: Int): ItemStack {
|
||||
return inventory.removeItem(slot, count)
|
||||
}
|
||||
}
|
||||
|
||||
private val slots = Array(SLOTS) { Slot(it) }
|
||||
|
||||
override val hasFilterableSlots: Boolean
|
||||
get() = true
|
||||
|
||||
override fun containerSlot(slot: Int): IPlayerInventorySlot {
|
||||
return slots[slot]
|
||||
}
|
||||
|
||||
override fun clearContent() {
|
||||
slots.forEach { it.remove() }
|
||||
}
|
||||
|
||||
override fun setChanged() {
|
||||
inventory.setChanged()
|
||||
}
|
||||
|
||||
override fun getContainerSize(): Int {
|
||||
return slots.size
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player): Boolean {
|
||||
return inventory.stillValid(player)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SLOTS = 41
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user