2021-02-28 22:56:25 +00:00
|
|
|
package net.shadowfacts.phycon.block.inserter
|
|
|
|
|
|
|
|
import alexiil.mc.lib.attributes.SearchOptions
|
|
|
|
import alexiil.mc.lib.attributes.Simulation
|
|
|
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
|
|
|
import alexiil.mc.lib.attributes.item.ItemInsertable
|
|
|
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
|
|
|
import net.minecraft.item.ItemStack
|
|
|
|
import net.minecraft.nbt.CompoundTag
|
|
|
|
import net.minecraft.util.math.Direction
|
|
|
|
import net.shadowfacts.phycon.api.packet.Packet
|
|
|
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
2021-03-07 16:16:02 +00:00
|
|
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
2021-02-28 22:56:25 +00:00
|
|
|
import net.shadowfacts.phycon.component.ActivationController
|
|
|
|
import net.shadowfacts.phycon.component.ItemStackPacketHandler
|
|
|
|
import net.shadowfacts.phycon.component.NetworkStackProvider
|
|
|
|
import net.shadowfacts.phycon.component.handleItemStack
|
|
|
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
|
|
|
import net.shadowfacts.phycon.packet.*
|
|
|
|
import net.shadowfacts.phycon.util.ActivationMode
|
2021-03-03 03:32:30 +00:00
|
|
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
2021-02-28 22:56:25 +00:00
|
|
|
import kotlin.math.min
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @author shadowfacts
|
|
|
|
*/
|
|
|
|
class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
|
|
|
|
ItemStackPacketHandler,
|
2021-03-03 03:32:30 +00:00
|
|
|
ActivationController.ActivatableDevice,
|
|
|
|
ClientConfigurableDevice {
|
2021-02-28 22:56:25 +00:00
|
|
|
|
|
|
|
companion object {
|
|
|
|
val SLEEP_TIME = 40L
|
|
|
|
val REQUEST_TIMEOUT = 40
|
|
|
|
}
|
|
|
|
|
|
|
|
private val facing: Direction
|
2021-03-07 16:16:02 +00:00
|
|
|
get() = cachedState[FaceDeviceBlock.FACING]
|
2021-02-28 22:56:25 +00:00
|
|
|
|
|
|
|
private var inventory: ItemInsertable? = null
|
|
|
|
private var currentRequest: PendingExtractRequest? = null
|
2021-03-01 03:01:45 +00:00
|
|
|
var stackToExtract: ItemStack = ItemStack.EMPTY
|
2021-02-28 22:56:25 +00:00
|
|
|
var amountToExtract = 1
|
|
|
|
override val controller = ActivationController(SLEEP_TIME, this)
|
|
|
|
|
|
|
|
fun updateInventory() {
|
|
|
|
val offsetPos = pos.offset(facing)
|
|
|
|
val option = SearchOptions.inDirection(facing)
|
|
|
|
inventory = ItemAttributes.INSERTABLE.getFirstOrNull(world, offsetPos, option)
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun getInventory(): ItemInsertable? {
|
|
|
|
if (inventory == null) updateInventory()
|
|
|
|
return inventory
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun handle(packet: Packet) {
|
|
|
|
when (packet) {
|
|
|
|
is RemoteActivationPacket -> controller.handleRemoteActivation(packet)
|
|
|
|
is StackLocationPacket -> handleStackLocation(packet)
|
|
|
|
is ItemStackPacket -> handleItemStack(packet)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
|
|
|
val inventory = getInventory()
|
|
|
|
return if (inventory != null) {
|
|
|
|
inventory.attemptInsertion(packet.stack, Simulation.ACTION)
|
|
|
|
} else {
|
|
|
|
// no inventory, entire stack remains
|
|
|
|
packet.stack
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun handleStackLocation(packet: StackLocationPacket) {
|
|
|
|
val request = currentRequest
|
|
|
|
if (request != null && ItemStackUtil.areEqualIgnoreAmounts(request.stack, packet.stack)) {
|
|
|
|
request.results.add(packet.amount to packet.stackProvider)
|
|
|
|
if (request.isFinishable(counter)) {
|
|
|
|
finishRequest()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun tick() {
|
|
|
|
super.tick()
|
|
|
|
|
|
|
|
if (!world!!.isClient) {
|
|
|
|
controller.tick()
|
|
|
|
|
|
|
|
val request = currentRequest
|
|
|
|
if (request != null) {
|
|
|
|
if (request.isFinishable(counter)) {
|
|
|
|
finishRequest()
|
|
|
|
} else if (counter - request.timestamp >= REQUEST_TIMEOUT && request.totalAmount == 0) {
|
|
|
|
currentRequest = null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun activate(): Boolean {
|
|
|
|
if (currentRequest != null || stackToExtract.isEmpty) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// todo: configure me
|
|
|
|
currentRequest = PendingExtractRequest(stackToExtract, counter)
|
|
|
|
sendPacket(LocateStackPacket(stackToExtract, ipAddress))
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun finishRequest() {
|
|
|
|
val request = currentRequest ?: return
|
|
|
|
|
|
|
|
// todo: dedup with TerminalBlockEntity.stackLocateRequestCompleted
|
|
|
|
val actualAmount = min(min(request.stack.maxCount, request.totalAmount), amountToExtract)
|
|
|
|
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
|
|
|
|
var amountRequested = 0
|
|
|
|
while (amountRequested < actualAmount && sortedResults.isNotEmpty()) {
|
|
|
|
val (sourceAmount, source) = sortedResults.removeAt(0)
|
|
|
|
val amountToRequest = min(sourceAmount, actualAmount - amountRequested)
|
|
|
|
amountRequested += amountToRequest
|
|
|
|
sendPacket(ExtractStackPacket(request.stack, amountToRequest, ipAddress, source.ipAddress))
|
|
|
|
}
|
|
|
|
|
|
|
|
currentRequest = null
|
|
|
|
}
|
|
|
|
|
2021-03-01 03:47:54 +00:00
|
|
|
override fun toCommonTag(tag: CompoundTag) {
|
|
|
|
super.toCommonTag(tag)
|
2021-03-03 03:32:30 +00:00
|
|
|
writeDeviceConfiguration(tag)
|
2021-02-28 22:56:25 +00:00
|
|
|
tag.put("StackToExtract", stackToExtract.toTag(CompoundTag()))
|
|
|
|
}
|
|
|
|
|
2021-03-01 03:47:54 +00:00
|
|
|
override fun fromCommonTag(tag: CompoundTag) {
|
|
|
|
super.fromCommonTag(tag)
|
2021-03-03 03:32:30 +00:00
|
|
|
loadDeviceConfiguration(tag)
|
2021-02-28 22:56:25 +00:00
|
|
|
stackToExtract = ItemStack.fromTag(tag.getCompound("StackToExtract"))
|
2021-03-03 03:32:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
|
|
|
tag.putString("ActivationMode", controller.activationMode.name)
|
|
|
|
tag.putInt("AmountToExtract", amountToExtract)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
|
|
|
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
2021-02-28 22:56:25 +00:00
|
|
|
amountToExtract = tag.getInt("AmountToExtract")
|
|
|
|
}
|
2021-03-03 03:32:30 +00:00
|
|
|
|
2021-02-28 22:56:25 +00:00
|
|
|
class PendingExtractRequest(
|
|
|
|
val stack: ItemStack,
|
|
|
|
val timestamp: Long,
|
|
|
|
var results: MutableSet<Pair<Int, NetworkStackProvider>> = mutableSetOf()
|
|
|
|
) {
|
|
|
|
val totalAmount: Int
|
|
|
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
|
|
|
|
|
|
|
fun isFinishable(currentTimestamp: Long): Boolean {
|
|
|
|
return totalAmount >= stack.maxCount || (currentTimestamp - timestamp >= REQUEST_TIMEOUT && totalAmount > 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|