From 0f7689d73cd4773f3cda545919c2286b4393d611 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 14 Feb 2021 23:42:19 -0500 Subject: [PATCH] Add Miner block --- .../phycon/init/PhyBlockEntities.kt | 4 + .../net/shadowfacts/phycon/init/PhyBlocks.kt | 3 + .../net/shadowfacts/phycon/init/PhyItems.kt | 3 + .../phycon/network/block/miner/MinerBlock.kt | 68 ++++++++++ .../network/block/miner/MinerBlockEntity.kt | 127 ++++++++++++++++++ .../block/terminal/TerminalBlockEntity.kt | 4 +- .../network/packet/ReadInventoryPacket.kt | 8 +- .../resources/assets/phycon/lang/en_us.json | 1 + 8 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlock.kt create mode 100644 src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlockEntity.kt diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt index db553e6..8f9bd00 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt @@ -7,6 +7,8 @@ import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock import net.shadowfacts.phycon.network.block.extractor.ExtractorBlockEntity +import net.shadowfacts.phycon.network.block.miner.MinerBlock +import net.shadowfacts.phycon.network.block.miner.MinerBlockEntity import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock @@ -27,6 +29,7 @@ object PhyBlockEntities { val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH) val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR) + val MINER = create(::MinerBlockEntity, PhyBlocks.MINER) val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE) val DEST = create(::DestBlockEntity, PhyBlocks.DEST) @@ -40,6 +43,7 @@ object PhyBlockEntities { register(TerminalBlock.ID, TERMINAL) register(SwitchBlock.ID, SWITCH) register(ExtractorBlock.ID, EXTRACTOR) + register(MinerBlock.ID, MINER) register(SourceBlock.ID, SOURCE) register(DestBlock.ID, DEST) diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt index 8b70b77..9a90e4f 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt @@ -5,6 +5,7 @@ import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.network.block.cable.CableBlock import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock +import net.shadowfacts.phycon.network.block.miner.MinerBlock import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock @@ -21,6 +22,7 @@ object PhyBlocks { val SWITCH = SwitchBlock() val CABLE = CableBlock() val EXTRACTOR = ExtractorBlock() + val MINER = MinerBlock() val SOURCE = SourceBlock() val DEST = DestBlock() @@ -31,6 +33,7 @@ object PhyBlocks { register(SwitchBlock.ID, SWITCH) register(CableBlock.ID, CABLE) register(ExtractorBlock.ID, EXTRACTOR) + register(MinerBlock.ID, MINER) register(SourceBlock.ID, SOURCE) register(DestBlock.ID, DEST) diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt index bcb9c12..a25f779 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt @@ -8,6 +8,7 @@ import net.shadowfacts.phycon.item.ConsoleItem import net.shadowfacts.phycon.item.ScrewdriverItem import net.shadowfacts.phycon.network.block.cable.CableBlock import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock +import net.shadowfacts.phycon.network.block.miner.MinerBlock import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock @@ -24,6 +25,7 @@ object PhyItems { val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings()) val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings()) val EXTRACTOR = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings()) + val MINER = BlockItem(PhyBlocks.MINER, Item.Settings()) val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings()) val DEST = BlockItem(PhyBlocks.DEST , Item.Settings()) @@ -37,6 +39,7 @@ object PhyItems { register(SwitchBlock.ID, SWITCH) register(CableBlock.ID, CABLE) register(ExtractorBlock.ID, EXTRACTOR) + register(MinerBlock.ID, MINER) register(SourceBlock.ID, SOURCE) register(DestBlock.ID, DEST) diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlock.kt new file mode 100644 index 0000000..f4c6a37 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlock.kt @@ -0,0 +1,68 @@ +package net.shadowfacts.phycon.network.block.miner + +import net.minecraft.block.Block +import net.minecraft.block.BlockState +import net.minecraft.block.Material +import net.minecraft.entity.LivingEntity +import net.minecraft.item.ItemPlacementContext +import net.minecraft.item.ItemStack +import net.minecraft.state.StateManager +import net.minecraft.state.property.Properties +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.world.BlockView +import net.minecraft.world.World +import net.shadowfacts.phycon.PhysicalConnectivity +import net.shadowfacts.phycon.api.Interface +import net.shadowfacts.phycon.network.DeviceBlock +import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock +import java.util.* + +/** + * @author shadowfacts + */ +class MinerBlock: DeviceBlock(Settings.of(Material.METAL)) { + + companion object { + val ID = Identifier(PhysicalConnectivity.MODID, "miner") + val FACING = Properties.FACING + } + + override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection { + return EnumSet.of(state[FACING].opposite) + } + + override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { + return if (side == state[FACING]) { + null + } else { + getBlockEntity(world, pos) + } + } + + override fun appendProperties(builder: StateManager.Builder) { + super.appendProperties(builder) + builder.add(FACING) + } + + override fun createBlockEntity(world: BlockView) = MinerBlockEntity() + + override fun getPlacementState(context: ItemPlacementContext): BlockState? { + val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite + return defaultState.with(ExtractorBlock.FACING, facing) + } + + override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, itemStack: ItemStack) { + if (!world.isClient) { +// getBlockEntity(world, pos)!!.updateBlockToMine() + } + } + + override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighbor: Block, neighborPos: BlockPos, bl: Boolean) { + if (!world.isClient) { +// getBlockEntity(world, pos)!!.updateBlockToMine() + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlockEntity.kt new file mode 100644 index 0000000..f210534 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlockEntity.kt @@ -0,0 +1,127 @@ +package net.shadowfacts.phycon.network.block.miner + +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 +import net.minecraft.server.world.ServerWorld +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.api.util.IPAddress +import net.shadowfacts.phycon.init.PhyBlockEntities +import net.shadowfacts.phycon.network.DeviceBlockEntity +import net.shadowfacts.phycon.network.component.NetworkStackProvider +import net.shadowfacts.phycon.network.packet.* +import kotlin.math.min + +/** + * @author shadowfacts + */ +class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER), + NetworkStackProvider { + + private val facing: Direction + get() = cachedState[MinerBlock.FACING] + + private val invProxy = MinerInvProxy(this) + + override fun handle(packet: Packet) { + when (packet) { + is RequestInventoryPacket -> handleRequestInventory(packet) + is LocateStackPacket -> handleLocateStack(packet) + is ExtractStackPacket -> handleExtractStack(packet) + } + } + + private fun handleRequestInventory(packet: RequestInventoryPacket) { + sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source)) + } + + private fun handleLocateStack(packet: LocateStackPacket) { + val amount = invProxy.getAmount(packet.stack) + if (amount > 0) { + sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source)) + } + } + + private fun handleExtractStack(packet: ExtractStackPacket) { + // always recalculate immediately before breaking + val drops = invProxy.getDrops(true) + 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 copy = droppedStack.copy() + + val toDecr = min(droppedStack.count, remaining) + droppedStack.decrement(toDecr) + remaining -= toDecr + + // todo: should this try to combine stacks and send as few packets as possible? + copy.count = toDecr + sendPacket(ItemStackPacket(copy, ipAddress, packet.source)) + } + + // dump any remaining drops into the network + for (droppedStack in drops) { + if (droppedStack.isEmpty) continue + sendPacket(ItemStackPacket(droppedStack, ipAddress, IPAddress.BROADCAST)) + } + } + } + + class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView { + private var cachedState: BlockState? = null + private var cachedDrops: List? = 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 { + val targetPos = pos.offset(facing) + val realState = world.getBlockState(targetPos) + // todo: does BlockState.equals actually work? + if (cachedDrops == null || realState != cachedState || recalculate) { + cachedState = realState + val be = if (realState.block.hasBlockEntity()) world.getBlockEntity(targetPos) else null + cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be) + } + return cachedDrops!! + } + + override fun getStoredStacks(): Set { + return getDrops().toSet() + } + + override fun getTotalCapacity(): Int { + return Int.MAX_VALUE + } + + override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic { + var totalCount = 0 + for (s in getDrops()) { + if (filter.matches(s)) { + totalCount += s.count + } + } + return GroupedItemInvView.ItemInvStatistic(filter, totalCount, 0, Int.MAX_VALUE) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt index 0a0d616..578760a 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt @@ -1,6 +1,6 @@ package net.shadowfacts.phycon.network.block.terminal -import alexiil.mc.lib.attributes.item.GroupedItemInv +import alexiil.mc.lib.attributes.item.GroupedItemInvView import alexiil.mc.lib.attributes.item.ItemStackCollections import alexiil.mc.lib.attributes.item.ItemStackUtil import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap @@ -44,7 +44,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento val INSERTION_TIMEOUT = 40 } - private val inventoryCache = mutableMapOf() + private val inventoryCache = mutableMapOf() val internalBuffer = TerminalBufferInventory(18) private val locateRequestQueue = LinkedList() diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt index ee59f44..bd12bb7 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt @@ -1,13 +1,13 @@ package net.shadowfacts.phycon.network.packet -import alexiil.mc.lib.attributes.item.GroupedItemInv +import alexiil.mc.lib.attributes.item.GroupedItemInvView import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ class ReadInventoryPacket( - val inventory: GroupedItemInv, - source: IPAddress, - destination: IPAddress + val inventory: GroupedItemInvView, + source: IPAddress, + destination: IPAddress ): BasePacket(source, destination) diff --git a/src/main/resources/assets/phycon/lang/en_us.json b/src/main/resources/assets/phycon/lang/en_us.json index 4fd4750..0ae03a5 100644 --- a/src/main/resources/assets/phycon/lang/en_us.json +++ b/src/main/resources/assets/phycon/lang/en_us.json @@ -4,6 +4,7 @@ "block.phycon.terminal": "Terminal", "block.phycon.cable": "Cable", "block.phycon.extractor": "Inventory Extractor", + "block.phycon.miner": "Block Miner", "item.phycon.screwdriver": "Screwdriver", "item.phycon.console": "Console"