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
|
2021-03-27 14:22:18 +00:00
|
|
|
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>()
|
2021-03-27 14:22:18 +00:00
|
|
|
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
|
|
|
}
|