Add Extractor block

This commit is contained in:
Shadowfacts 2021-02-14 20:01:33 -05:00
parent 0dcb647de4
commit 649408c509
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
15 changed files with 314 additions and 16 deletions

View File

@ -5,6 +5,8 @@ import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
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.netinterface.InterfaceBlock
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
@ -24,6 +26,8 @@ object PhyBlockEntities {
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE)
val DEST = create(::DestBlockEntity, PhyBlocks.DEST)
@ -35,6 +39,8 @@ object PhyBlockEntities {
register(InterfaceBlock.ID, INTERFACE)
register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH)
register(ExtractorBlock.ID, EXTRACTOR)
register(SourceBlock.ID, SOURCE)
register(DestBlock.ID, DEST)
}

View File

@ -4,6 +4,7 @@ import net.minecraft.block.Block
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.netinterface.InterfaceBlock
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
@ -19,6 +20,8 @@ object PhyBlocks {
val TERMINAL = TerminalBlock()
val SWITCH = SwitchBlock()
val CABLE = CableBlock()
val EXTRACTOR = ExtractorBlock()
val SOURCE = SourceBlock()
val DEST = DestBlock()
@ -27,6 +30,8 @@ object PhyBlocks {
register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH)
register(CableBlock.ID, CABLE)
register(ExtractorBlock.ID, EXTRACTOR)
register(SourceBlock.ID, SOURCE)
register(DestBlock.ID, DEST)
}

View File

@ -7,6 +7,7 @@ import net.minecraft.util.registry.Registry
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.netinterface.InterfaceBlock
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
@ -22,6 +23,8 @@ object PhyItems {
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
val EXTRACTOR = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings())
val DEST = BlockItem(PhyBlocks.DEST , Item.Settings())
@ -33,6 +36,8 @@ object PhyItems {
register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH)
register(CableBlock.ID, CABLE)
register(ExtractorBlock.ID, EXTRACTOR)
register(SourceBlock.ID, SOURCE)
register(DestBlock.ID, DEST)

View File

@ -25,6 +25,10 @@ object NetworkUtil {
if (connectedSides.size == 1) {
curSide = connectedSides.first()
pos = pos.offset(curSide)
if (!world.isChunkLoaded(pos)) {
// avoid loading unloaded chunks
return null
}
state = world.getBlockState(pos)
} else {
return null

View File

@ -0,0 +1,110 @@
package net.shadowfacts.phycon.network.block.extractor
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.Material
import net.minecraft.block.ShapeContext
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.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
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 java.util.*
/**
* @author shadowfacts
*/
class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(Settings.of(Material.METAL)) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "extractor")
val FACING = Properties.FACING
private val EXTRACTOR_SHAPES = mutableMapOf<Direction, VoxelShape>()
init {
val components = arrayOf(
doubleArrayOf(0.0, 0.0, 0.0, 16.0, 2.0, 16.0),
doubleArrayOf(2.0, 2.0, 2.0, 14.0, 4.0, 14.0),
doubleArrayOf(4.0, 4.0, 4.0, 12.0, 6.0, 12.0),
doubleArrayOf(6.0, 6.0, 6.0, 10.0, 16.0, 10.0)
)
val directions = arrayOf(
Triple(Direction.DOWN, null, false),
Triple(Direction.UP, null, true),
Triple(Direction.NORTH, 2, false),
Triple(Direction.SOUTH, 2, true),
Triple(Direction.WEST, 1, false),
Triple(Direction.EAST, 1, true),
)
for ((dir, rotate, flip) in directions) {
val shapes = components.map { it ->
val arr = it.copyOf()
if (rotate != null) {
for (i in 0 until 3) {
arr[i] = it[(i + rotate) % 3]
arr[3 + i] = it[3 + ((i + rotate) % 3)]
}
}
if (flip) {
for (i in arr.indices) {
arr[i] = 16.0 - arr[i]
}
}
createCuboidShape(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5])
}
EXTRACTOR_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
}
}
}
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
return EnumSet.of(state[FACING].opposite)
}
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
return if (side == state[FACING].opposite) {
getBlockEntity(world, pos)
} else {
null
}
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
super.appendProperties(builder)
builder.add(FACING)
}
override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity()
override fun getPlacementState(context: ItemPlacementContext): BlockState {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
return defaultState.with(FACING, facing)
}
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
return EXTRACTOR_SHAPES[state[FACING]]!!
}
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
if (!world.isClient) {
getBlockEntity(world, pos)!!.updateInventory()
}
}
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighbor: Block, neighborPos: BlockPos, bl: Boolean) {
if (!world.isClient) {
getBlockEntity(world, pos)!!.updateInventory()
}
}
}

View File

@ -0,0 +1,59 @@
package net.shadowfacts.phycon.network.block.extractor
import alexiil.mc.lib.attributes.SearchOptions
import alexiil.mc.lib.attributes.item.FixedItemInv
import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes
import net.minecraft.util.math.Direction
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.packet.CapacityPacket
import net.shadowfacts.phycon.network.packet.CheckCapacityPacket
import net.shadowfacts.phycon.network.packet.ItemStackPacket
/**
* @author shadowfacts
*/
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR) {
private val facing: Direction
get() = cachedState[ExtractorBlock.FACING]
private var inventory: GroupedItemInv? = null
private var shouldExtract = false
fun updateInventory() {
val offsetPos = pos.offset(facing)
val option = SearchOptions.inDirection(facing)
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
}
private fun getInventory(): GroupedItemInv? {
if (inventory == null) updateInventory()
return inventory
}
override fun handle(packet: Packet) {
if (packet is CapacityPacket && shouldExtract) {
getInventory()?.also { inv ->
shouldExtract = false
val extracted = inv.extract(packet.stack, packet.capacity)
sendPacket(ItemStackPacket(extracted, ipAddress, packet.stackReceiver.ipAddress))
}
}
}
override fun tick() {
super.tick()
if (!world!!.isClient && counter % 40 == 0L) {
getInventory()?.also {
val stack = it.storedStacks.firstOrNull() ?: return
shouldExtract = true
sendPacket(CheckCapacityPacket(stack, ipAddress, IPAddress.BROADCAST))
}
}
}
}

View File

@ -10,16 +10,21 @@ import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
import net.shadowfacts.phycon.network.component.NetworkStackProvider
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.packet.*
/**
* @author shadowfacts
*/
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler {
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
ItemStackPacketHandler,
NetworkStackProvider,
NetworkStackReceiver {
private val facing: Direction
get() = world!!.getBlockState(pos)[InterfaceBlock.FACING]
get() = cachedState[InterfaceBlock.FACING]
// todo: should this be a weak ref?
private var inventory: GroupedItemInv? = null

View File

@ -17,7 +17,6 @@ import net.minecraft.nbt.ListTag
import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.LiteralText
import net.minecraft.text.TranslatableText
import net.minecraft.util.Tickable
import net.minecraft.util.math.Direction
@ -27,8 +26,9 @@ import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.NetworkUtil
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
import net.shadowfacts.phycon.network.component.NetworkStackProvider
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.packet.*
import java.util.*
@ -96,7 +96,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
}
if (request != null) {
request.results.add(packet.amount to packet.sourceInterface)
request.results.add(packet.amount to packet.stackProvider)
if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
stackLocateRequestCompleted(request)
}
@ -119,7 +119,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
}
if (insertion != null) {
insertion.results.add(packet.capacity to packet.receivingInterface)
insertion.results.add(packet.capacity to packet.stackReceiver)
if (insertion.isFinishable(counter)) {
finishInsertion(insertion)
}
@ -325,7 +325,7 @@ data class StackLocateRequest(
val stack: ItemStack,
val amount: Int,
val timestamp: Long,
var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf()
var results: MutableSet<Pair<Int, NetworkStackProvider>> = mutableSetOf()
) {
val totalResultAmount: Int
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
@ -339,7 +339,7 @@ data class PendingStackInsertion(
val bufferSlot: Int,
val stack: ItemStack,
val timestamp: Long,
val results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf(),
val results: MutableSet<Pair<Int, NetworkStackReceiver>> = mutableSetOf(),
) {
val totalCapacity: Int
get() = results.fold(0) { acc, (amount, _) -> acc + amount }

View File

@ -0,0 +1,9 @@
package net.shadowfacts.phycon.network.component
import net.shadowfacts.phycon.api.NetworkDevice
/**
* @author shadowfacts
*/
interface NetworkStackProvider: NetworkDevice {
}

View File

@ -0,0 +1,9 @@
package net.shadowfacts.phycon.network.component
import net.shadowfacts.phycon.api.NetworkDevice
/**
* @author shadowfacts
*/
interface NetworkStackReceiver: NetworkDevice {
}

View File

@ -2,10 +2,16 @@ package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
/**
* @author shadowfacts
*/
class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
class CapacityPacket(
val stack: ItemStack,
val capacity: Int,
val stackReceiver: NetworkStackReceiver,
source: IPAddress,
destination: IPAddress
): BasePacket(source, destination) {
}

View File

@ -2,17 +2,17 @@ package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.component.NetworkStackProvider
/**
* @author shadowfacts
*/
// todo: better name with LocateStackPacket
class StackLocationPacket(
val stack: ItemStack,
val amount: Int,
val sourceInterface: InterfaceBlockEntity,
source: IPAddress,
destination: IPAddress
val stack: ItemStack,
val amount: Int,
val stackProvider: NetworkStackProvider,
source: IPAddress,
destination: IPAddress
): BasePacket(source, destination) {
}

View File

@ -0,0 +1,29 @@
{
"variants": {
"facing=down": {
"model": "phycon:block/extractor"
},
"facing=up": {
"model": "phycon:block/extractor",
"x": 180
},
"facing=north": {
"model": "phycon:block/extractor",
"x": 270
},
"facing=south": {
"model": "phycon:block/extractor",
"x": 90
},
"facing=west": {
"model": "phycon:block/extractor",
"x": 90,
"y": 90
},
"facing=east": {
"model": "phycon:block/extractor",
"x": 90,
"y": 270
}
}
}

View File

@ -3,6 +3,7 @@
"block.phycon.network_interface": "Inventory Interface",
"block.phycon.terminal": "Terminal",
"block.phycon.cable": "Cable",
"block.phycon.extractor": "Inventory Extractor",
"item.phycon.screwdriver": "Screwdriver",
"item.phycon.console": "Console"

View File

@ -0,0 +1,50 @@
{
"parent": "block/block",
"elements": [
{
"from": [0, 0, 0],
"to": [16, 2, 16],
"faces": {
"down": {"texture": "phycon:block/extractor_front"},
"up": {"texture": "phycon:block/extractor_back"},
"north": {"texture": "phycon:block/extractor_side"},
"south": {"texture": "phycon:block/extractor_side"},
"west": {"texture": "phycon:block/extractor_side"},
"east": {"texture": "phycon:block/extractor_side"}
}
},
{
"from": [2, 2, 2],
"to": [14, 4, 14],
"faces": {
"up": {"texture": "phycon:block/extractor_back"},
"north": {"texture": "phycon:block/extractor_side"},
"south": {"texture": "phycon:block/extractor_side"},
"west": {"texture": "phycon:block/extractor_side"},
"east": {"texture": "phycon:block/extractor_side"}
}
},
{
"from": [4, 4, 4],
"to": [12, 6, 12],
"faces": {
"up": {"texture": "phycon:block/extractor_back"},
"north": {"texture": "phycon:block/extractor_side"},
"south": {"texture": "phycon:block/extractor_side"},
"west": {"texture": "phycon:block/extractor_side"},
"east": {"texture": "phycon:block/extractor_side"}
}
},
{
"from": [6, 6, 6],
"to": [10, 16, 10],
"faces": {
"up": {"texture": "phycon:block/cable_side"},
"north": {"texture": "phycon:block/cable_side"},
"south": {"texture": "phycon:block/cable_side"},
"west": {"texture": "phycon:block/cable_side"},
"east": {"texture": "phycon:block/cable_side"}
}
}
]
}