PhysicalConnectivity/src/main/kotlin/net/shadowfacts/phycon/block/miner/MinerBlockEntity.kt

241 lines
7.1 KiB
Kotlin
Raw Normal View History

2021-02-28 18:48:39 +00:00
package net.shadowfacts.phycon.block.miner
2021-02-15 04:42:19 +00:00
import alexiil.mc.lib.attributes.item.GroupedItemInvView
import alexiil.mc.lib.attributes.item.ItemStackUtil
import alexiil.mc.lib.attributes.item.filter.ItemFilter
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.item.ItemStack
2021-03-03 22:23:57 +00:00
import net.minecraft.item.Items
2021-12-22 23:59:51 +00:00
import net.minecraft.nbt.NbtCompound
2021-02-15 04:42:19 +00:00
import net.minecraft.server.world.ServerWorld
2021-03-03 22:23:57 +00:00
import net.minecraft.text.TranslatableText
2021-02-15 04:42:19 +00:00
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities
2021-02-28 18:48:39 +00:00
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.block.terminal.AbstractTerminalBlockEntity
2021-03-09 23:25:59 +00:00
import net.shadowfacts.phycon.component.*
2021-02-28 18:48:39 +00:00
import net.shadowfacts.phycon.packet.*
2021-03-03 22:23:57 +00:00
import net.shadowfacts.phycon.util.ActivationMode
import net.shadowfacts.phycon.util.ClientConfigurableDevice
2021-03-02 02:29:14 +00:00
import net.shadowfacts.phycon.util.copyWithCount
2021-02-15 04:42:19 +00:00
import kotlin.math.min
/**
* @author shadowfacts
*/
2021-12-22 23:59:51 +00:00
class MinerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.MINER, pos, state),
2021-02-18 03:39:37 +00:00
NetworkStackProvider,
2021-03-03 22:23:57 +00:00
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion>,
ActivationController.ActivatableDevice,
ClientConfigurableDevice {
2021-02-15 04:42:19 +00:00
private val facing: Direction
get() = cachedState[MinerBlock.FACING]
private val invProxy = MinerInvProxy(this)
2021-02-18 03:39:37 +00:00
override val pendingInsertions = mutableListOf<PendingInsertion>()
override val dispatchStackTimeout = AbstractTerminalBlockEntity.INSERTION_TIMEOUT
2021-03-03 22:23:57 +00:00
override val controller = ActivationController(40L, this)
2021-03-04 03:00:21 +00:00
override var providerPriority = 0
2021-03-03 22:23:57 +00:00
var minerMode = MinerMode.ON_DEMAND
2021-02-18 03:39:37 +00:00
2021-02-15 04:42:19 +00:00
override fun handle(packet: Packet) {
when (packet) {
is RequestInventoryPacket -> handleRequestInventory(packet)
is LocateStackPacket -> handleLocateStack(packet)
is ExtractStackPacket -> handleExtractStack(packet)
2021-02-18 03:39:37 +00:00
is CapacityPacket -> handleCapacity(packet)
is ItemStackPacket -> handleItemStack(packet)
2021-03-09 23:25:59 +00:00
is RemoteActivationPacket -> controller.handleRemoteActivation(packet)
2021-02-15 04:42:19 +00:00
}
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
2021-03-03 22:23:57 +00:00
if (minerMode != MinerMode.ON_DEMAND) {
return
}
2021-02-15 04:42:19 +00:00
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
}
private fun handleLocateStack(packet: LocateStackPacket) {
2021-03-03 22:23:57 +00:00
if (minerMode != MinerMode.ON_DEMAND) {
return
}
2021-02-15 04:42:19 +00:00
val amount = invProxy.getAmount(packet.stack)
if (amount > 0) {
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
}
}
private fun handleExtractStack(packet: ExtractStackPacket) {
2021-03-03 22:23:57 +00:00
if (minerMode != MinerMode.ON_DEMAND) {
return
}
2021-02-15 04:42:19 +00:00
// always recalculate immediately before breaking
2021-02-18 03:39:37 +00:00
val drops = invProxy.getDrops(recalculate = true)
2021-02-15 04:42:19 +00:00
if (invProxy.getAmount(packet.stack) > 0) {
world!!.breakBlock(pos.offset(facing), false)
// send the requested amount back to the requester
var remaining = packet.amount
for (droppedStack in drops) {
if (remaining <= 0) {
break
}
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
continue
}
val toDecr = min(droppedStack.count, remaining)
2021-03-02 02:29:14 +00:00
val copy = droppedStack.copyWithCount(toDecr)
2021-02-15 04:42:19 +00:00
droppedStack.decrement(toDecr)
remaining -= toDecr
// todo: should this try to combine stacks and send as few packets as possible?
sendPacket(ItemStackPacket(copy, ipAddress, packet.source))
}
// dump any remaining drops into the network
for (droppedStack in drops) {
if (droppedStack.isEmpty) continue
2021-02-18 03:39:37 +00:00
dispatchItemStack(droppedStack)
2021-02-15 04:42:19 +00:00
}
}
}
2021-02-18 03:39:37 +00:00
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
// miner can't receive stacks, so remaining is the entire packet stack
return packet.stack
}
override fun createPendingInsertion(stack: ItemStack) = PendingInsertion(stack, counter)
2021-03-03 22:23:57 +00:00
override fun tick() {
super.tick()
2021-03-09 23:25:59 +00:00
if (!world!!.isClient) {
if (minerMode == MinerMode.AUTOMATIC) {
controller.tick()
}
finishTimedOutPendingInsertions()
2021-03-03 22:23:57 +00:00
}
}
override fun activate(): Boolean {
if (minerMode == MinerMode.ON_DEMAND) {
return false
}
val drops = invProxy.getDrops(recalculate = true)
if (!world!!.getBlockState(pos.offset(facing)).isAir) {
world!!.breakBlock(pos.offset(facing), false)
for (stack in drops) {
if (stack.isEmpty) continue
dispatchItemStack(stack)
}
return true
} else {
return false
}
}
override fun canConfigureActivationController(): Boolean {
return minerMode == MinerMode.AUTOMATIC
}
2021-03-04 03:00:21 +00:00
override fun canConfigureProviderPriority(): Boolean {
return minerMode == MinerMode.ON_DEMAND
}
2021-12-22 23:59:51 +00:00
override fun toCommonTag(tag: NbtCompound) {
2021-03-03 22:23:57 +00:00
super.toCommonTag(tag)
writeDeviceConfiguration(tag)
}
2021-12-22 23:59:51 +00:00
override fun fromCommonTag(tag: NbtCompound) {
2021-03-03 22:23:57 +00:00
super.fromCommonTag(tag)
loadDeviceConfiguration(tag)
}
2021-12-22 23:59:51 +00:00
override fun writeDeviceConfiguration(tag: NbtCompound) {
2021-03-03 22:23:57 +00:00
tag.putString("MinerMode", minerMode.name)
tag.putString("ActivationMode", controller.activationMode.name)
2021-03-04 03:00:21 +00:00
tag.putInt("ProviderPriority", providerPriority)
2021-03-03 22:23:57 +00:00
}
2021-12-22 23:59:51 +00:00
override fun loadDeviceConfiguration(tag: NbtCompound) {
2021-03-03 22:23:57 +00:00
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
2021-03-04 03:00:21 +00:00
providerPriority = tag.getInt("ProviderPriority")
2021-03-03 22:23:57 +00:00
}
enum class MinerMode {
ON_DEMAND, AUTOMATIC;
2021-12-22 23:59:51 +00:00
val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.lowercase()}")
2021-03-03 22:23:57 +00:00
}
2021-02-15 04:42:19 +00:00
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
2021-03-03 22:23:57 +00:00
companion object {
val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
}
2021-02-15 04:42:19 +00:00
private var cachedState: BlockState? = null
private var cachedDrops: List<ItemStack>? = null
private val world: World
get() = miner.world!!
private val pos: BlockPos
get() = miner.pos!!
private val facing: Direction
get() = miner.facing
fun getDrops(recalculate: Boolean = false): List<ItemStack> {
val targetPos = pos.offset(facing)
val realState = world.getBlockState(targetPos)
2021-02-18 03:39:37 +00:00
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
2021-02-15 04:42:19 +00:00
if (cachedDrops == null || realState != cachedState || recalculate) {
cachedState = realState
2021-12-22 23:59:51 +00:00
val be = if (realState.hasBlockEntity()) world.getBlockEntity(targetPos) else null
2021-03-03 22:23:57 +00:00
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL)
2021-02-15 04:42:19 +00:00
}
return cachedDrops!!
}
override fun getStoredStacks(): Set<ItemStack> {
2021-03-03 22:23:57 +00:00
if (miner.minerMode != MinerMode.ON_DEMAND) {
return setOf()
}
2021-02-15 04:42:19 +00:00
return getDrops().toSet()
}
override fun getTotalCapacity(): Int {
return Int.MAX_VALUE
}
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
var totalCount = 0
2021-03-03 22:23:57 +00:00
for (s in storedStacks) {
2021-02-15 04:42:19 +00:00
if (filter.matches(s)) {
totalCount += s.count
}
}
return GroupedItemInvView.ItemInvStatistic(filter, totalCount, 0, Int.MAX_VALUE)
}
}
2021-02-18 03:39:37 +00:00
class PendingInsertion(stack: ItemStack, timestamp: Long): NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
}
2021-02-28 18:48:39 +00:00
}