package net.shadowfacts.phycon.block.redstone_emitter import alexiil.mc.lib.attributes.item.GroupedItemInvView import net.minecraft.block.BlockState import net.minecraft.item.ItemStack import net.minecraft.nbt.NbtCompound import net.minecraft.text.TranslatableText import net.minecraft.util.math.BlockPos import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.block.DeviceBlockEntity import net.shadowfacts.phycon.block.FaceDeviceBlock import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.packet.DeviceRemovedPacket import net.shadowfacts.phycon.packet.ReadInventoryPacket import net.shadowfacts.phycon.packet.RequestInventoryPacket import net.shadowfacts.phycon.util.ClientConfigurableDevice import net.shadowfacts.phycon.util.GhostInv import kotlin.math.round /** * @author shadowfacts */ class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER, pos, state), ClientConfigurableDevice, GhostInv { private val inventoryCache = mutableMapOf() var cachedEmittedPower: Int = 0 private set var stackToMonitor: ItemStack = ItemStack.EMPTY override var ghostSlotStack: ItemStack get() = stackToMonitor set(value) { stackToMonitor = value } var maxAmount = 64 var mode = Mode.ANALOG set(value) { field = value recalculateRedstone() } override fun handle(packet: Packet) { when (packet) { is ReadInventoryPacket -> handleReadInventory(packet) is DeviceRemovedPacket -> handleDeviceRemoved(packet) } } private fun handleReadInventory(packet: ReadInventoryPacket) { inventoryCache[packet.source] = packet.inventory recalculateRedstone() } private fun handleDeviceRemoved(packet: DeviceRemovedPacket) { inventoryCache.remove(packet.source) recalculateRedstone() } override fun tick() { super.tick() if (!world!!.isClient && counter % 20 == 0L) { if (counter % 80 == 0L) { updateInventories() } else if (counter % 20 == 0L) { recalculateRedstone() } } } private fun updateInventories() { sendPacket(RequestInventoryPacket(ipAddress)) } private fun recalculateRedstone() { if (world == null || world!!.isClient) return if (stackToMonitor.isEmpty) { cachedEmittedPower = 0 updateWorld() return } val networkAmount = inventoryCache.values.fold(0) { acc, inv -> acc + inv.getAmount(stackToMonitor) } cachedEmittedPower = when (mode) { Mode.ANALOG -> if (networkAmount == 0) { 0 } else { 1 + round(networkAmount / maxAmount.toDouble() * 14).toInt() } Mode.DIGITAL -> if (networkAmount >= maxAmount) 15 else 0 } updateWorld() } private fun updateWorld() { world!!.updateNeighborsAlways(pos, cachedState.block) world!!.updateNeighborsAlways(pos.offset(cachedState[FaceDeviceBlock.FACING]), cachedState.block) } override fun toCommonTag(tag: NbtCompound) { super.toCommonTag(tag) tag.putInt("CachedEmittedPower", cachedEmittedPower) tag.put("StackToMonitor", stackToMonitor.writeNbt(NbtCompound())) writeDeviceConfiguration(tag) } override fun fromCommonTag(tag: NbtCompound) { super.fromCommonTag(tag) cachedEmittedPower = tag.getInt("CachedEmittedPower") stackToMonitor = ItemStack.fromNbt(tag.getCompound("StackToMonitor")) loadDeviceConfiguration(tag) } override fun writeDeviceConfiguration(tag: NbtCompound) { tag.putInt("MaxAmount", maxAmount) tag.putString("Mode", mode.name) } override fun loadDeviceConfiguration(tag: NbtCompound) { maxAmount = tag.getInt("MaxAmount") mode = Mode.valueOf(tag.getString("Mode")) } enum class Mode { ANALOG, DIGITAL; val friendlyName = TranslatableText("gui.phycon.redstone_emitter_mode.${name.lowercase()}") } }