Compare commits

...

12 Commits

64 changed files with 291 additions and 1299 deletions

View File

@ -29,7 +29,6 @@ import net.minecraft.world.phys.Vec3
import net.neoforged.neoforge.capabilities.Capabilities import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer

View File

@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler
import ru.dbotthepony.mc.otm.capability.moveFluid import ru.dbotthepony.mc.otm.capability.moveFluid
import ru.dbotthepony.mc.otm.config.ItemsConfig import ru.dbotthepony.mc.otm.config.ItemsConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.get
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters

View File

@ -19,7 +19,6 @@ import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler import net.neoforged.neoforge.fluids.capability.IFluidHandler
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList

View File

@ -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.MatterStorageImpl
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot

View File

@ -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.IMatterStorage
import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList

View File

@ -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.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot

View File

@ -26,7 +26,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal

View File

@ -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.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer

View File

@ -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.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu

View File

@ -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.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.EnhancedContainer 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.get
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter 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)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
val energyConfig = ConfigurableEnergy(energy) 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) { override fun notifySlotChanged(slot: Int, old: ItemStack) {
super.notifySlotChanged(slot, old) super.notifySlotChanged(slot, old)
markDirtyFast() markDirtyFast()

View File

@ -31,7 +31,6 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.CombinedContainer
import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer
import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer 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.container.util.slotIterator
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.collect.map 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 howMuchPlayerCrafted(ply: Player): Int = craftingAmount.getInt(ply)
fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply] fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply]
val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.withListener(3 * 3) { val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.WithListener(3 * 3) {
markDirtyFast() markDirtyFast()
if (!inProcessOfCraft) { if (!inProcessOfCraft) {

View File

@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
import ru.dbotthepony.mc.otm.capability.transcieveEnergy import ru.dbotthepony.mc.otm.capability.transcieveEnergy
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer

View File

@ -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.GeneratorEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer

View File

@ -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.JobContainer
import ru.dbotthepony.mc.otm.block.entity.JobStatus import ru.dbotthepony.mc.otm.block.entity.JobStatus
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer

View File

@ -17,7 +17,6 @@ import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.math.RelativeSide

View File

@ -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.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.math.RelativeSide

View File

@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.extractEnergy
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.capability.receiveEnergy 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot

View File

@ -25,7 +25,6 @@ import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer 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 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) val mendingContainer = SlottedContainer.simple(1, ::MendingSlot, ::markDirtyFast).also(::addDroppableContainer)
private var mending: Holder<Enchantment>? = null private var mending: Holder<Enchantment>? = null

View File

@ -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.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag

View File

@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage
import ru.dbotthepony.mc.otm.capability.moveMatter import ru.dbotthepony.mc.otm.capability.moveMatter
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal

View File

@ -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.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.HandlerFilter
import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.container.balance
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.capability.item
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.neoforged.neoforge.items.IItemHandler import net.neoforged.neoforge.items.IItemHandler
import ru.dbotthepony.mc.otm.container.ContainerHandler
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import java.util.stream.Stream 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(handlers: Collection<IItemHandler>) : this(ImmutableList.copyOf(handlers))
constructor(vararg handlers: 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 val lastSizes = IntArray(this.handlers.size)
private var totalSize = 0 private var totalSize = 0
private val mappings = ArrayList<Mapping>() private val mappings = ArrayList<Mapping>()

View File

@ -11,7 +11,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots
class MatteryChestMenu( class MatteryChestMenu(
type: MenuType<*>, containerId: Int, type: MenuType<*>, containerId: Int,
inventory: Inventory, override val rows: Int, override val columns: 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) { ) : AbstractVanillaChestMenu(type, containerId, inventory, container) {
override val containerSlots = makeSlots(container, ::MatteryMenuSlot) override val containerSlots = makeSlots(container, ::MatteryMenuSlot)

View File

@ -10,7 +10,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots
class MatteryShulkerBoxMenu( class MatteryShulkerBoxMenu(
containerId: Int, containerId: Int,
inventory: Inventory, inventory: Inventory,
container: Container = EnhancedContainer(27) container: Container = EnhancedContainer.Simple(27)
) : AbstractVanillaChestMenu(VanillaMenuTypes.SHULKER_BOX, containerId, inventory, container) { ) : AbstractVanillaChestMenu(VanillaMenuTypes.SHULKER_BOX, containerId, inventory, container) {
override val containerSlots = makeSlots(container, ::Slot) override val containerSlots = makeSlots(container, ::Slot)
override val rows: Int override val rows: Int

View File

@ -16,11 +16,11 @@ object PlayerConfig : AbstractConfig("player") {
val REGENERATE_ENERGY_EFFICIENCY_FOOD: Double by builder val REGENERATE_ENERGY_EFFICIENCY_FOOD: Double by builder
.comment("How much % of food points to convert to energy") .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 val REGENERATE_ENERGY_EFFICIENCY_SATURATION: Double by builder
.comment("How much % of food saturation points to convert to energy") .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 val REGENERATE_ENERGY_IN_PEACEFUL: Boolean by builder
.comment("Regenerate energy while in peaceful") .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") .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) .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 { init {
builder.pop() 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 { object EnderTeleporter {
init { init {
builder.comment("Ender Teleporter ability").push("EnderTeleporter") builder.comment("Ender Teleporter ability").push("EnderTeleporter")

View File

@ -23,9 +23,9 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.stream import ru.dbotthepony.mc.otm.core.stream
import java.util.stream.Stream import java.util.stream.Stream
class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int>>>) : ISlottedContainer, IMatteryContainer { 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(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) }) constructor(containers: Collection<IEnhancedContainer<*>>) : this(containers.stream().map { it to (0 until it.containerSize) })
private val slots: ImmutableList<IContainerSlot> private val slots: ImmutableList<IContainerSlot>
private val slotsMap: ImmutableMap<Container, List<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> { override fun slotIterator(): Iterator<IContainerSlot> {
return slots.iterator().map { return slots.iterator()
if (it is IFilteredContainerSlot) it else IFilteredContainerSlot.Dummy(it)
}
} }
override fun containerSlot(slot: Int): IFilteredContainerSlot { override fun containerSlot(slot: Int): IContainerSlot {
val getSlot = slots[slot] return 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 setChanged(slot: Int) { override fun setChanged(slot: Int) {
@ -145,7 +129,7 @@ class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int
} }
class Builder { class Builder {
private val values = ArrayList<Pair<IEnhancedContainer, Iterable<Int>>>() private val values = ArrayList<Pair<IEnhancedContainer<*>, Iterable<Int>>>()
fun add(container: Container): Builder { fun add(container: Container): Builder {
return add(IEnhancedContainer.wrap(container)) return add(IEnhancedContainer.wrap(container))
@ -167,27 +151,27 @@ class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int
return add(IEnhancedContainer.wrap(container), slots) return add(IEnhancedContainer.wrap(container), slots)
} }
fun add(container: IEnhancedContainer): Builder { fun add(container: IEnhancedContainer<*>): Builder {
values.add(container to container.slotRange) values.add(container to container.slotRange)
return this return this
} }
fun add(container: IEnhancedContainer, slots: Iterator<Int>): Builder { fun add(container: IEnhancedContainer<*>, slots: Iterator<Int>): Builder {
values.add(container to IntArrayList(slots)) values.add(container to IntArrayList(slots))
return this return this
} }
fun add(container: IEnhancedContainer, slot: Int): Builder { fun add(container: IEnhancedContainer<*>, slot: Int): Builder {
values.add(container to intArrayOf(slot).asIterable()) values.add(container to intArrayOf(slot).asIterable())
return this 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)) values.add(container to (from .. to))
return this return this
} }
fun add(container: IEnhancedContainer, slots: Iterable<Int>): Builder { fun add(container: IEnhancedContainer<*>, slots: Iterable<Int>): Builder {
values.add(container to slots) values.add(container to slots)
return this return this
} }

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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 * This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features
* and improved performance (inside [IEnhancedContainer] defined methods). * 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 items = Array(size) { ItemStack.EMPTY }
private val observedItems = 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) {} protected open fun notifySlotChanged(slot: Int, old: ItemStack) {}
@ -184,16 +178,22 @@ open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSe
} }
} }
companion object { open class Simple(size: Int) : EnhancedContainer<IContainerSlot>(size) {
private val LOGGER = LogManager.getLogger() private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } }
fun withListener(slots: Int, listener: Runnable): EnhancedContainer { override fun containerSlot(slot: Int): IContainerSlot {
return object : EnhancedContainer(slots) { return slots[slot]
override fun notifySlotChanged(slot: Int, old: ItemStack) {
super.notifySlotChanged(slot, old)
listener.run()
}
}
} }
} }
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()
}
} }

View File

@ -10,9 +10,7 @@ import net.neoforged.neoforge.items.IItemHandlerModifiable
* Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which * Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which
* subsequently allow this container to implement [IItemHandler] * subsequently allow this container to implement [IItemHandler]
*/ */
interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { interface IAutomatedContainer<S : IAutomatedContainerSlot> : ISlottedContainer<S>, IItemHandlerModifiable {
override fun containerSlot(slot: Int): IAutomatedContainerSlot
override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean {
return containerSlot(slot).canAutomationPlaceItem(itemStack) return containerSlot(slot).canAutomationPlaceItem(itemStack)
} }

View File

@ -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)
}
}
}
}
}

View File

@ -19,12 +19,41 @@ import java.util.stream.Stream
import java.util.stream.StreamSupport 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, * 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. * 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 // provide non-ambiguous get and set operators
operator fun get(slot: Int): ItemStack { operator fun get(slot: Int): ItemStack {
return getItem(slot) return getItem(slot)
@ -34,9 +63,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
setItem(slot, value) setItem(slot, value)
} }
fun containerSlot(slot: Int): IContainerSlot { fun containerSlot(slot: Int): S
return IContainerSlot.Simple(slot, this)
}
override fun fillStackedContents(contents: StackedContents) { override fun fillStackedContents(contents: StackedContents) {
forEach { contents.accountStack(it) } forEach { contents.accountStack(it) }
@ -45,11 +72,11 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
/** /**
* Returns iterator over **all** slots this container has * Returns iterator over **all** slots this container has
*/ */
fun slotIterator(): Iterator<IContainerSlot> { fun slotIterator(): Iterator<S> {
return (0 until containerSize).iterator().map { containerSlot(it) } return (0 until containerSize).iterator().map { containerSlot(it) }
} }
fun nonEmptySlotIterator(): Iterator<IContainerSlot> { fun nonEmptySlotIterator(): Iterator<S> {
return slotIterator().filter { it.isNotEmpty } return slotIterator().filter { it.isNotEmpty }
} }
@ -307,7 +334,11 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
return StreamSupport.stream(spliterator(), false) 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() { override fun clearContent() {
return parent.clearContent() return parent.clearContent()
} }
@ -378,8 +409,8 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack>, Sta
} }
companion object { companion object {
fun wrap(other: Container): IEnhancedContainer { fun wrap(other: Container): IEnhancedContainer<*> {
if (other is IEnhancedContainer) if (other is IEnhancedContainer<*>)
return other return other
return Wrapper(other) return Wrapper(other)

View File

@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.StackedContents
import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { interface IEnhancedCraftingContainer<S : IContainerSlot> : IEnhancedContainer<S>, CraftingContainer {
override fun getItems(): MutableList<ItemStack> { override fun getItems(): MutableList<ItemStack> {
return toList() return toList()
} }
@ -13,7 +13,7 @@ interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer {
forEach { contents.accountSimpleStack(it) } 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 { init {
require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" } require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" }
} }

View File

@ -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
}
}

View File

@ -8,7 +8,7 @@ import ru.dbotthepony.kommons.collect.any
/** /**
* Skeletal implementation for containers which revolve around [IContainerSlot] * Skeletal implementation for containers which revolve around [IContainerSlot]
*/ */
interface ISlottedContainer : IEnhancedContainer { interface ISlottedContainer<S : IContainerSlot> : IEnhancedContainer<S> {
override fun setChanged(slot: Int) { override fun setChanged(slot: Int) {
containerSlot(slot).setChanged() containerSlot(slot).setChanged()
} }

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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 }
}
}
}

View File

@ -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 }
}
}
}

View File

@ -17,7 +17,7 @@ class UpgradeContainer(
val allowedUpgrades: Set<UpgradeType> = UpgradeType.ALL, val allowedUpgrades: Set<UpgradeType> = UpgradeType.ALL,
val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false }, val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false },
private val listener: Runnable = Runnable {} private val listener: Runnable = Runnable {}
) : EnhancedContainer(slotCount), IMatteryUpgrade { ) : EnhancedContainer.Simple(slotCount), IMatteryUpgrade {
override fun notifySlotChanged(slot: Int, old: ItemStack) { override fun notifySlotChanged(slot: Int, old: ItemStack) {
super.notifySlotChanged(slot, old) super.notifySlotChanged(slot, old)
listener.run() listener.run()

View File

@ -40,7 +40,7 @@ class SlottedContainer(
slots: Collection<MarkedSlotProvider<*>>, slots: Collection<MarkedSlotProvider<*>>,
private val stillValid: Predicate<Player>, private val stillValid: Predicate<Player>,
private val globalChangeListeners: Array<Runnable> private val globalChangeListeners: Array<Runnable>
) : IAutomatedContainer, INBTSerializable<Tag> { ) : IAutomatedContainer<ContainerSlot>, INBTSerializable<Tag> {
interface ISlotGroup<T : ContainerSlot> : List<T> { interface ISlotGroup<T : ContainerSlot> : List<T> {
/** /**
* @see IAutomatedContainer.addItem * @see IAutomatedContainer.addItem
@ -140,7 +140,7 @@ class SlottedContainer(
} }
} }
override fun containerSlot(slot: Int): IAutomatedContainerSlot { override fun containerSlot(slot: Int): ContainerSlot {
return slots[slot] return slots[slot]
} }

View File

@ -6,14 +6,13 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IContainerSlot
import ru.dbotthepony.mc.otm.container.IEnhancedContainer 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.container.get
import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty
fun Container.containerSlot(slot: Int): IContainerSlot { fun Container.containerSlot(slot: Int): IContainerSlot {
if (this is IEnhancedContainer) { if (this is IEnhancedContainer<*>) {
return containerSlot(slot) return containerSlot(slot)
} else { } else {
return IContainerSlot.Simple(slot, this) return IContainerSlot.Simple(slot, this)
@ -24,7 +23,7 @@ fun Container.containerSlot(slot: Int): IContainerSlot {
* Returns [IContainerSlot] only if this container is [IEnhancedContainer] * Returns [IContainerSlot] only if this container is [IEnhancedContainer]
*/ */
fun Container.containerSlotOrNull(slot: Int): IContainerSlot? { fun Container.containerSlotOrNull(slot: Int): IContainerSlot? {
if (this is IEnhancedContainer) { if (this is IEnhancedContainer<*>) {
return containerSlot(slot) return containerSlot(slot)
} else { } else {
return null return null
@ -40,7 +39,7 @@ fun Slot.containerSlotOrNull(): IContainerSlot? {
} }
operator fun Container.iterator(): Iterator<ItemStack> { operator fun Container.iterator(): Iterator<ItemStack> {
if (this is IEnhancedContainer) { if (this is IEnhancedContainer<*>) {
return iterator() return iterator()
} else { } else {
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } 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> { fun Container.slotIterator(): Iterator<IContainerSlot> {
if (this is IEnhancedContainer) { if (this is IEnhancedContainer<*>) {
return slotIterator() return slotIterator()
} else { } else {
return (0 until containerSize).iterator().map { IContainerSlot.Simple(it, this) } return (0 until containerSize).iterator().map { IContainerSlot.Simple(it, this) }
@ -56,7 +55,7 @@ fun Container.slotIterator(): Iterator<IContainerSlot> {
} }
fun Container.nonEmptySlotIterator(): Iterator<IContainerSlot> { fun Container.nonEmptySlotIterator(): Iterator<IContainerSlot> {
if (this is IEnhancedContainer) { if (this is IEnhancedContainer<*>) {
return nonEmptySlotIterator() return nonEmptySlotIterator()
} else { } else {
return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { IContainerSlot.Simple(it, this) } return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { IContainerSlot.Simple(it, this) }

View File

@ -23,7 +23,6 @@ import ru.dbotthepony.mc.otm.client.ShiftPressedCond
import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.isShiftDown
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.config.ClientConfig 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.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map

View File

@ -66,7 +66,7 @@ class MatterDustItem : Item(Properties().stacksTo(64)), IMatterItem {
return MatterValue(value, 1.0) 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") @Suppress("name_shadowing")
var matterValue = matterValue var matterValue = matterValue

View File

@ -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.isShiftDown
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.config.ClientConfig 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.container.util.stream
import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
@ -500,7 +501,7 @@ object MatterManager {
height = it.value.ingredients.size.coerceAtLeast(height) 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>>() val realIngredients = ArrayList<ArrayList<RecipeEntry>>()
for (c in it.value.ingredients.indices) { for (c in it.value.ingredients.indices) {

View File

@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer
import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IEnhancedContainer
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot 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.ItemFilter
import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull 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() { override fun setChanged() {
if (container is IEnhancedContainer) { if (container is IEnhancedContainer<*>) {
(container as IEnhancedContainer).setChanged(containerSlot) (container as IEnhancedContainer<*>).setChanged(containerSlot)
} else { } else {
super.setChanged() super.setChanged()
} }
@ -83,7 +82,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int
override fun getMaxStackSize(): Int { override fun getMaxStackSize(): Int {
val container = container val container = container
if (container is IEnhancedContainer) { if (container is IEnhancedContainer<*>) {
return container.getMaxStackSize(slotIndex, ItemStack.EMPTY) return container.getMaxStackSize(slotIndex, ItemStack.EMPTY)
} else { } else {
return super.getMaxStackSize() 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 { override fun getMaxStackSize(itemStack: ItemStack): Int {
val container = container val container = container
if (container is IEnhancedContainer) { if (container is IEnhancedContainer<*>) {
return container.getMaxStackSize(slotIndex, itemStack) return container.getMaxStackSize(slotIndex, itemStack)
} else { } else {
return super.getMaxStackSize(itemStack) return super.getMaxStackSize(itemStack)
@ -278,7 +277,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr
allowedTypes[value] = BooleanSupplier { b.get() } allowedTypes[value] = BooleanSupplier { b.get() }
} }
val syncContainer = container ?: EnhancedContainer(count) val syncContainer = container ?: EnhancedContainer.Simple(count)
val isOpen = InstantBooleanInput(this) val isOpen = InstantBooleanInput(this)
return UpgradeSlots( return UpgradeSlots(

View File

@ -10,7 +10,6 @@ import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.item.crafting.SingleRecipeInput import net.minecraft.world.item.crafting.SingleRecipeInput
import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity 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.ContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList

View File

@ -16,7 +16,6 @@ import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
import ru.dbotthepony.mc.otm.player.matteryPlayer 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.set
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.addAll

View File

@ -21,7 +21,7 @@ class MatterRecyclerMenu @JvmOverloads constructor(
inventory: Inventory, inventory: Inventory,
tile: MatterRecyclerBlockEntity? = null tile: MatterRecyclerBlockEntity? = null
) : MatteryPoweredMenu(MMenus.MATTER_RECYCLER, containerID, inventory, tile) { ) : 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 { override fun mayPlace(itemStack: ItemStack): Boolean {
return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null
} }

View File

@ -35,7 +35,7 @@ class MatterReplicatorMenu @JvmOverloads constructor(
val upgrades = makeUpgradeSlots(3, tile?.upgrades) val upgrades = makeUpgradeSlots(3, tile?.upgrades)
init { 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) { storageSlots = immutableList(5) {
addStorageSlot(OutputMenuSlot(container, it, onTake = { addStorageSlot(OutputMenuSlot(container, it, onTake = {

View File

@ -31,7 +31,7 @@ class MatterScannerMenu(
val upgrades = makeUpgradeSlots(2, tile?.upgrades) val upgrades = makeUpgradeSlots(2, tile?.upgrades)
init { init {
val container = tile?.container ?: EnhancedContainer(1) val container = tile?.container ?: EnhancedContainer.Simple(1)
input = object : MatteryMenuSlot(container, 0, 64, 38) { input = object : MatteryMenuSlot(container, 0, 64, 38) {
override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack)

View File

@ -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) { storageSlots = immutableList(patterns.containerSize) {
addStorageSlot(PatternMenuSlot(patterns, it)) addStorageSlot(PatternMenuSlot(patterns, it))

View File

@ -19,7 +19,7 @@ class DriveRackMenu @JvmOverloads constructor(
inventory: Inventory, inventory: Inventory,
tile: DriveRackBlockEntity? = null tile: DriveRackBlockEntity? = null
) : MatteryPoweredMenu(MMenus.DRIVE_RACK, containerId, inventory, tile) { ) : 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 energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority }) val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority })

View File

@ -37,7 +37,7 @@ class DriveViewerMenu(
) : MatteryPoweredMenu(MMenus.DRIVE_VIEWER, containerID, inventory, tile), INetworkedItemViewProvider { ) : MatteryPoweredMenu(MMenus.DRIVE_VIEWER, containerID, inventory, tile), INetworkedItemViewProvider {
override val networkedItemView = NetworkedItemView(inventory.player, this, tile == null) 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 { override fun mayPlace(itemStack: ItemStack): Boolean {
return itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null return itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null
} }

View File

@ -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 { override fun mayPlace(itemStack: ItemStack): Boolean {
return false return false
} }

View File

@ -17,7 +17,7 @@ class CobblerMenu(
inventory: Inventory, inventory: Inventory,
tile: CobblerBlockEntity? = null tile: CobblerBlockEntity? = null
) : MatteryMenu(MMenus.COBBLESTONE_GENERATOR, p_38852_, inventory, tile) { ) : 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 redstone = EnumInputWithFeedback<RedstoneSetting>(this)
val itemConfig = ItemConfigPlayerInput(this) val itemConfig = ItemConfigPlayerInput(this)

View File

@ -34,13 +34,13 @@ class EssenceStorageMenu(
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) 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 { override fun mayPlace(itemStack: ItemStack): Boolean {
return itemStack.item is EssenceCapsuleItem && super.mayPlace(itemStack) 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 { override fun mayPlace(itemStack: ItemStack): Boolean {
return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack) return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack)
} }

View File

@ -31,7 +31,7 @@ class PlatePressMenu(
isTwin: Boolean isTwin: Boolean
) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) {
val inputSlots = makeSlots(tile?.inputContainer ?: SlottedContainer.filtered(if (isTwin) 2 else 1), ::MatteryMenuSlot) 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)) } val gauges = immutableList(if (isTwin) 2 else 1) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) }
override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true)

View File

@ -40,7 +40,7 @@ class PoweredFurnaceMenu(
// we can't make these slots to reject non-smeltable items // we can't make these slots to reject non-smeltable items
// since mods may add obscure recipes/ingredients which never test true on client // since mods may add obscure recipes/ingredients which never test true on client
val inputSlots = makeSlots(tile?.inputs ?: SlottedContainer.filtered(2), ::UserFilteredMenuSlot) 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)) } val progressGauge = immutableList(2) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) }
override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true)

View File

@ -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)
}
}

View File

@ -0,0 +1,7 @@
package ru.dbotthepony.mc.otm.player
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
interface IPlayerInventorySlot : IFilteredContainerSlot {
var shouldCharge: Boolean
}

View File

@ -69,21 +69,20 @@ class MatteryFoodData(private var player: Player) : FoodData() {
private var energyToDrain = Decimal.ZERO private var energyToDrain = Decimal.ZERO
private fun tickExhaustion() { 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() var points = (exhaustionLevel / EXHAUSTION_PER_HUNGER_POINT).toInt()
exhaustionLevel %= EXHAUSTION_PER_HUNGER_POINT exhaustionLevel %= EXHAUSTION_PER_HUNGER_POINT
if (player.matteryPlayer.isAndroid) { if (saturationLevel > 0f) {
energyToDrain += PlayerConfig.ANDROID_ENERGY_PER_HUNGER_POINT * points val satisfied = min(saturationLevel.roundToInt(), points)
} else { points -= satisfied
if (saturationLevel > 0f) { saturationLevel -= satisfied
val satisfied = min(saturationLevel.roundToInt(), points)
points -= satisfied
saturationLevel -= satisfied
}
foodLevel = max(0, foodLevel - points)
} }
foodLevel = max(0, foodLevel - points)
} }
} }
@ -111,9 +110,13 @@ class MatteryFoodData(private var player: Player) : FoodData() {
if (player.matteryPlayer.isAndroid) { if (player.matteryPlayer.isAndroid) {
if (energyToDrain > Decimal.ZERO) if (energyToDrain > Decimal.ZERO)
energyToDrain -= player.matteryPlayer.androidEnergy.extractEnergy(energyToDrain, false) energyToDrain -= player.matteryPlayer.androidEnergy.extractEnergy(energyToDrain, false)
else if (energyToDrain < Decimal.ZERO) else if (energyToDrain < Decimal.ZERO) {
energyToDrain += player.matteryPlayer.androidEnergy.receiveEnergy(-energyToDrain, false) 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) if (player.level().difficulty == Difficulty.PEACEFUL && PlayerConfig.REGENERATE_ENERGY_IN_PEACEFUL)
player.matteryPlayer.androidEnergy.receiveEnergy(PlayerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false) player.matteryPlayer.androidEnergy.receiveEnergy(PlayerConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false)

View File

@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.player
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack 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.IntAVLTreeSet
import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.ints.IntSet
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap 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.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag import net.minecraft.nbt.ListTag
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.StringTag import net.minecraft.nbt.StringTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.protocol.common.custom.CustomPacketPayload 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.PlayerConfig
import ru.dbotthepony.mc.otm.config.ExopackConfig import ru.dbotthepony.mc.otm.config.ExopackConfig
import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.CombinedContainer
import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer
import ru.dbotthepony.mc.otm.container.IContainer
import ru.dbotthepony.mc.otm.container.IContainerSlot 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.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.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.util.slotIterator
import ru.dbotthepony.mc.otm.container.vanishCursedItems import ru.dbotthepony.mc.otm.container.vanishCursedItems
import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.*
@ -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.nbt.set
import ru.dbotthepony.mc.otm.core.util.Savetables import ru.dbotthepony.mc.otm.core.util.Savetables
import ru.dbotthepony.mc.otm.core.util.TickList 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.ExopackInventoryMenu
import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings
import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.network.*
@ -158,18 +163,6 @@ class MatteryPlayer(val ply: Player) {
val level: Level get() = capability.ply.level() 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 * 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 * If you want to properly extend Exopack suit capacity, add your value into this map
*/ */
val exopackSlotModifier = UUIDIntModifiersMap(observer = observer@{ val exopackSlotModifier = UUIDIntModifiersMap(observer = observer@{
if (it < 0) { exopackContainer = ExopackContainer(it.coerceAtLeast(0), this)
exopackContainer = PlayerMatteryContainer(0)
} else {
exopackContainer = PlayerMatteryContainer(it)
}
}, backingMap = this.exopackSlotModifierMap.delegate) }, backingMap = this.exopackSlotModifierMap.delegate)
val regularSlotFilters = immutableList(Inventory.INVENTORY_SIZE) {
syncher.add(null, StreamCodecs.ITEM_TYPE.nullable())
}
val slotsChargeFlag = syncher.set( val slotsChargeFlag = syncher.set(
backing = ListenableSet(IntAVLTreeSet()), backing = ListenableSet(IntAVLTreeSet()),
codec = StreamCodecs.VAR_INT, codec = StreamCodecs.VAR_INT,
).delegate ).delegate
val slotFilters = syncher.map(
backing = ListenableMap(Int2ObjectOpenHashMap()),
keyCodec = StreamCodecs.VAR_INT,
valueCodec = StreamCodecs.ITEM_TYPE
).delegate
private fun slotChargeToDefault() { private fun slotChargeToDefault() {
// броня // броня
slotsChargeFlag.add(36) slotsChargeFlag.add(36)
@ -277,15 +268,12 @@ class MatteryPlayer(val ply: Player) {
slotChargeToDefault() slotChargeToDefault()
} }
private var exopackContainerSynchedFilters: List<Closeable> = listOf()
/** /**
* Exopack container, which actually store items inside Exopack * Exopack container, which actually store items inside Exopack
*/ */
var exopackContainer: MatteryContainer = PlayerMatteryContainer(0) var exopackContainer: ExopackContainer = ExopackContainer(0, this)
private set(value) { private set(value) {
_exoPackMenu = null _exoPackMenu = null
exopackContainerSynchedFilters.forEach { it.close() }
@Suppress("SENSELESS_COMPARISON") // false positive - fields of player can easily be nulls, despite annotations saying otherwise @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)) { 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())) value.deserializeNBT(ply.level().registryAccess(), field.serializeNBT(ply.level().registryAccess()))
exopackContainerSynchedFilters = value.synchableFilters.map { syncher.add0(it) }
field = value field = value
_combinedInventory = null _combinedInventory = null
@ -312,34 +299,9 @@ class MatteryPlayer(val ply: Player) {
private var _combinedInventory2: CombinedContainer? = null private var _combinedInventory2: CombinedContainer? = null
private var _combinedInventory3: CombinedContainer? = null private var _combinedInventory3: CombinedContainer? = null
val wrappedInventory: IMatteryContainer = object : IMatteryContainer, IContainer by DynamicallyProxiedContainer(ply::getInventory) { val wrappedInventory = PlayerInventoryWrapper(this)
override fun getSlotFilter(slot: Int): Item? {
return regularSlotFilters.getOrNull(slot)?.get()
}
override fun setSlotFilter(slot: Int, filter: Item?): Boolean { val wrappedItemInventory: IEnhancedContainer<IPlayerInventorySlot> = object : IEnhancedContainer<IPlayerInventorySlot> by wrappedInventory {
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 {
override fun getContainerSize(): Int { override fun getContainerSize(): Int {
return 36 return 36
} }
@ -543,8 +505,8 @@ class MatteryPlayer(val ply: Player) {
} }
} }
val input = MatteryContainer(Runnable { notify(IdleReason.ITEM) }, 1) val input = EnhancedContainer.WithListener(1) { notify(IdleReason.ITEM) }
val output = MatteryContainer(Runnable { notify(IdleReason.ITEM) }, 1) val output = EnhancedContainer.WithListener(1) { notify(IdleReason.ITEM) }
init { init {
savetables.stateful(::input, "exopack_smelter_input_$index") 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 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 var acceptExopackChargeFromWirelessCharger = true
init { init {
@ -955,11 +917,8 @@ class MatteryPlayer(val ply: Player) {
} }
} }
tag["regularSlotFilters"] = ListTag().also { tag["slotFilters"] = filtersCodec.encodeStart(registry.createSerializationContext(NbtOps.INSTANCE), slotFilters.entries.map { it.key to it.value })
for (filter in regularSlotFilters) { .getOrThrow { IllegalStateException("Unable to serialize slot filters: $it") }
it.add(StringTag.valueOf(filter.value?.registryName?.toString() ?: ""))
}
}
tag.putIntArray("slotsChargeFlag", slotsChargeFlag.toIntArray()) tag.putIntArray("slotsChargeFlag", slotsChargeFlag.toIntArray())
return tag return tag
@ -977,18 +936,16 @@ class MatteryPlayer(val ply: Player) {
ExopackSlotsExpandedTrigger.trigger(ply, 0, exopackContainer.containerSize) ExopackSlotsExpandedTrigger.trigger(ply, 0, exopackContainer.containerSize)
} }
for (filter in regularSlotFilters) { slotFilters.clear()
filter.value = null
}
slotsChargeFlag.clear() slotsChargeFlag.clear()
val regularSlotFilters = tag.getStringList("regularSlotFilters") if ("slotFilters" in tag) {
filtersCodec.decode(registry.createSerializationContext(NbtOps.INSTANCE), tag["slotFilters"])
for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) { .ifError { LOGGER.error("Unable to deserialize slot filters: ${it.message()}") }
val path = regularSlotFilters[i].asString .resultOrPartial()
if (path == "") continue .ifPresent {
this.regularSlotFilters[i].value = BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(path) ?: continue) it.first.forEach { (a, b) -> slotFilters[a] = b }
}
} }
if ("slotsChargeFlag" in tag) { if ("slotsChargeFlag" in tag) {
@ -1341,6 +1298,15 @@ class MatteryPlayer(val ply: Player) {
@Suppress("unused") @Suppress("unused")
companion object { 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) private val offhandSlotRange = IntSet.of(40)
init { init {

View File

@ -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
}
}