Add Inserter

This commit is contained in:
Shadowfacts 2021-02-28 17:56:25 -05:00
parent 9b4fc548e5
commit e13154943e
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
19 changed files with 718 additions and 14 deletions

View File

@ -16,7 +16,7 @@ import java.util.*
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class CacaoHandledScreen<Handler: ScreenHandler>( open class CacaoHandledScreen<Handler: ScreenHandler>(
handler: Handler, handler: Handler,
playerInv: PlayerInventory, playerInv: PlayerInventory,
title: Text, title: Text,
@ -90,4 +90,4 @@ class CacaoHandledScreen<Handler: ScreenHandler>(
} }
} }
} }

View File

@ -28,6 +28,7 @@ object PhysicalConnectivity: ModInitializer {
registerGlobalReceiver(C2STerminalUpdateDisplayedItems) registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
registerGlobalReceiver(C2SConfigureActivationMode) registerGlobalReceiver(C2SConfigureActivationMode)
registerGlobalReceiver(C2SConfigureRedstoneController) registerGlobalReceiver(C2SConfigureRedstoneController)
registerGlobalReceiver(C2SConfigureInserterAmount)
} }
private fun registerGlobalReceiver(receiver: ServerReceiver) { private fun registerGlobalReceiver(receiver: ServerReceiver) {

View File

@ -5,6 +5,7 @@ import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.RenderLayer
import net.shadowfacts.phycon.block.inserter.InserterScreen
import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyScreens import net.shadowfacts.phycon.init.PhyScreens
import net.shadowfacts.phycon.block.terminal.TerminalScreen import net.shadowfacts.phycon.block.terminal.TerminalScreen
@ -17,9 +18,8 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
object PhysicalConnectivityClient: ClientModInitializer { object PhysicalConnectivityClient: ClientModInitializer {
override fun onInitializeClient() { override fun onInitializeClient() {
BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent())
ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen) ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
ScreenRegistry.register(PhyScreens.INSERTER_SCREEN_HANDLER, ::InserterScreen)
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems) registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
} }

View File

@ -88,7 +88,7 @@ class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(Settings.of(Material.MET
override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity() override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity()
override fun getPlacementState(context: ItemPlacementContext): BlockState { override fun getPlacementState(context: ItemPlacementContext): BlockState {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
return defaultState.with(FACING, facing) return defaultState.with(FACING, facing)
} }

View File

@ -0,0 +1,143 @@
package net.shadowfacts.phycon.block.inserter
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
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.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.state.StateManager
import net.minecraft.state.property.Properties
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.util.hit.BlockHitResult
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.minecraft.world.WorldAccess
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.block.DeviceBlock
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
import java.util.*
/**
* @author shadowfacts
*/
class InserterBlock: DeviceBlock<InserterBlockEntity>(Settings.of(Material.METAL)) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "inserter")
val FACING = Properties.FACING
private val INSERTER_SHAPES = mutableMapOf<Direction, VoxelShape>()
init {
val components = arrayOf(
doubleArrayOf(4.0, 0.0, 4.0, 12.0, 2.0, 12.0),
doubleArrayOf(2.0, 2.0, 2.0, 14.0, 4.0, 14.0),
doubleArrayOf(0.0, 4.0, 0.0, 16.0, 6.0, 16.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])
}
INSERTER_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
}
}
}
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
return EnumSet.of(state[FACING].opposite)
}
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, 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) = InserterBlockEntity()
override fun getPlacementState(context: ItemPlacementContext): BlockState {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
return defaultState.with(FACING, facing)
}
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
return INSERTER_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, neighborBlock: Block, neighborPos: BlockPos, bl: Boolean) {
if (!world.isClient) {
getBlockEntity(world, pos)!!.updateInventory()
}
}
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
if (!world.isClient) {
val be = getBlockEntity(world, pos)!!
be.sync()
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
return InserterScreenHandler(syncId, playerInv, be)
}
override fun getDisplayName() = this@InserterBlock.name
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
buf.writeBlockPos(be.pos)
}
}
player.openHandledScreen(factory)
}
return ActionResult.SUCCESS
}
}

View File

@ -0,0 +1,168 @@
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.block.BlockState
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
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
import kotlin.math.min
/**
* @author shadowfacts
*/
class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
ItemStackPacketHandler,
ActivationController.ActivatableDevice {
companion object {
val SLEEP_TIME = 40L
val REQUEST_TIMEOUT = 40
}
private val facing: Direction
get() = cachedState[InserterBlock.FACING]
private var inventory: ItemInsertable? = null
private var currentRequest: PendingExtractRequest? = null
var stackToExtract = ItemStack.EMPTY
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
}
override fun toTag(tag: CompoundTag): CompoundTag {
tag.putString("ActivationMode", controller.activationMode.name)
tag.put("StackToExtract", stackToExtract.toTag(CompoundTag()))
tag.putInt("AmountToExtract", amountToExtract)
return super.toTag(tag)
}
override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag)
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
stackToExtract = ItemStack.fromTag(tag.getCompound("StackToExtract"))
amountToExtract = tag.getInt("AmountToExtract")
}
override fun toClientTag(tag: CompoundTag): CompoundTag {
tag.putString("ActivationMode", controller.activationMode.name)
tag.put("StackToExtract", stackToExtract.toTag(CompoundTag()))
tag.putInt("AmountToExtract", amountToExtract)
return super.toClientTag(tag)
}
override fun fromClientTag(tag: CompoundTag) {
super.fromClientTag(tag)
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
stackToExtract = ItemStack.fromTag(tag.getCompound("StackToExtract"))
amountToExtract = tag.getInt("AmountToExtract")
}
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)
}
}
}

View File

@ -0,0 +1,123 @@
package net.shadowfacts.phycon.block.inserter
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.LiteralText
import net.minecraft.text.Text
import net.minecraft.text.TranslatableText
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.networking.C2SConfigureInserterAmount
import java.lang.NumberFormatException
/**
* @author shadowfacts
*/
class InserterScreen(
handler: InserterScreenHandler,
playerInv: PlayerInventory,
title: Text,
): HandledScreen<InserterScreenHandler>(
handler,
playerInv,
title
) {
companion object {
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/inserter.png")
}
private lateinit var amountField: TextFieldWidget
init {
backgroundWidth = 176
backgroundHeight = 133
playerInventoryTitleY = backgroundHeight - 94
}
override fun init() {
super.init()
amountField = TextFieldWidget(textRenderer, x + 57, y + 24, 80, 9, LiteralText("Amount"))
amountField.text = handler.inserter.amountToExtract.toString()
amountField.setHasBorder(false)
amountField.isVisible = true
amountField.setSelected(true)
amountField.setEditableColor(0xffffff)
amountField.setTextPredicate {
if (it.isEmpty()) {
true
} else {
try {
val value = Integer.parseInt(it)
value in 1..64
} catch (e: NumberFormatException) {
false
}
}
}
addChild(amountField)
}
fun amountUpdated() {
if (amountField.text.isNotEmpty()) {
handler.inserter.amountToExtract = Integer.parseInt(amountField.text)
client!!.player!!.networkHandler.sendPacket(C2SConfigureInserterAmount(handler.inserter))
}
}
override fun tick() {
super.tick()
amountField.tick()
}
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND)
val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
}
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
super.render(matrixStack, mouseX, mouseY, delta)
amountField.render(matrixStack, mouseX, mouseY, delta)
drawMouseoverTooltip(matrixStack, mouseX, mouseY)
}
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, slotActionType: SlotActionType?) {
super.onMouseClick(slot, invSlot, clickData, slotActionType)
amountField.setSelected(true)
}
override fun charTyped(c: Char, i: Int): Boolean {
val oldText = amountField.text
if (amountField.charTyped(c, i)) {
if (oldText != amountField.text) {
amountUpdated()
}
return true
}
return super.charTyped(c, i)
}
override fun keyPressed(i: Int, j: Int, k: Int): Boolean {
val oldText = amountField.text
if (amountField.keyPressed(i, j, k)) {
if (oldText != amountField.text) {
amountUpdated()
}
return true
}
return super.keyPressed(i, j, k)
}
}

View File

@ -0,0 +1,122 @@
package net.shadowfacts.phycon.block.inserter
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.Inventory
import net.minecraft.item.ItemStack
import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyScreens
import kotlin.math.min
/**
* @author shadowfacts
*/
class InserterScreenHandler(
syncId: Int,
playerInv: PlayerInventory,
val inserter: InserterBlockEntity,
): ScreenHandler(PhyScreens.INSERTER_SCREEN_HANDLER, syncId) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "inserter")
}
private val fakeInv = FakeInventory(inserter)
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
this(
syncId,
playerInv,
PhyBlocks.INSERTER.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!
)
init {
// fake slot
addSlot(FakeSlot(fakeInv, 31, 20))
// player inv
for (y in 0 until 3) {
for (x in 0 until 9) {
addSlot(Slot(playerInv, x + y * 9 + 9, 8 + x * 18, 51 + y * 18))
}
}
// hotbar
for (x in 0 until 9) {
addSlot(Slot(playerInv, x, 8 + x * 18, 109))
}
}
private fun stackToExtractChanged() {
inserter.amountToExtract = min(inserter.stackToExtract.maxCount, inserter.amountToExtract)
}
override fun canUse(player: PlayerEntity): Boolean {
return true
}
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
// fake slot
if (slotId == 0) {
if (player.inventory.cursorStack.isEmpty) {
inserter.stackToExtract = ItemStack.EMPTY
} else {
val copy = player.inventory.cursorStack.copy()
copy.count = 1
inserter.stackToExtract = copy
}
stackToExtractChanged()
}
return super.onSlotClick(slotId, clickData, actionType, player)
}
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
val slot = slots[slotId]
val copy = slot.stack.copy()
copy.count = 1
inserter.stackToExtract = copy
stackToExtractChanged()
return ItemStack.EMPTY
}
class FakeSlot(inv: FakeInventory, x: Int, y: Int): Slot(inv, 0, x, y) {
override fun canInsert(stack: ItemStack) = false
override fun setStack(stack: ItemStack) {
}
override fun canTakeItems(player: PlayerEntity) = false
}
class FakeInventory(val inserter: InserterBlockEntity): Inventory {
override fun clear() {
inserter.stackToExtract = ItemStack.EMPTY
}
override fun size() = 1
override fun isEmpty() = inserter.stackToExtract.isEmpty
override fun getStack(i: Int): ItemStack {
return if (i == 0) inserter.stackToExtract else ItemStack.EMPTY
}
override fun removeStack(i: Int, j: Int) = ItemStack.EMPTY
override fun removeStack(i: Int) = ItemStack.EMPTY
override fun setStack(i: Int, itemStack: ItemStack?) {}
override fun markDirty() {}
override fun canPlayerUse(playerEntity: PlayerEntity?) = true
}
}

View File

@ -183,7 +183,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
inventoryCache.clear() inventoryCache.clear()
sendPacket(RequestInventoryPacket(ipAddress)) sendPacket(RequestInventoryPacket(ipAddress))
val factory = object: ExtendedScreenHandlerFactory { val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? { override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity) return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
} }

View File

@ -7,6 +7,8 @@ import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.block.extractor.ExtractorBlock import net.shadowfacts.phycon.block.extractor.ExtractorBlock
import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity
import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.inserter.InserterBlockEntity
import net.shadowfacts.phycon.block.miner.MinerBlock import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.miner.MinerBlockEntity import net.shadowfacts.phycon.block.miner.MinerBlockEntity
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
@ -27,6 +29,7 @@ object PhyBlockEntities {
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH) val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR) val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
val INSERTER = create(::InserterBlockEntity, PhyBlocks.INSERTER)
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER) val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER) val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
@ -39,6 +42,7 @@ object PhyBlockEntities {
register(TerminalBlock.ID, TERMINAL) register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH) register(SwitchBlock.ID, SWITCH)
register(ExtractorBlock.ID, EXTRACTOR) register(ExtractorBlock.ID, EXTRACTOR)
register(InserterBlock.ID, INSERTER)
register(MinerBlock.ID, MINER) register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER) register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
} }

View File

@ -5,6 +5,7 @@ import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.block.cable.CableBlock import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.block.extractor.ExtractorBlock import net.shadowfacts.phycon.block.extractor.ExtractorBlock
import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.miner.MinerBlock import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.block.netswitch.SwitchBlock import net.shadowfacts.phycon.block.netswitch.SwitchBlock
@ -21,6 +22,7 @@ object PhyBlocks {
val SWITCH = SwitchBlock() val SWITCH = SwitchBlock()
val CABLE = CableBlock() val CABLE = CableBlock()
val EXTRACTOR = ExtractorBlock() val EXTRACTOR = ExtractorBlock()
val INSERTER = InserterBlock()
val MINER = MinerBlock() val MINER = MinerBlock()
val REDSTONE_CONTROLLER = RedstoneControllerBlock() val REDSTONE_CONTROLLER = RedstoneControllerBlock()
@ -30,6 +32,7 @@ object PhyBlocks {
register(SwitchBlock.ID, SWITCH) register(SwitchBlock.ID, SWITCH)
register(CableBlock.ID, CABLE) register(CableBlock.ID, CABLE)
register(ExtractorBlock.ID, EXTRACTOR) register(ExtractorBlock.ID, EXTRACTOR)
register(InserterBlock.ID, INSERTER)
register(MinerBlock.ID, MINER) register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER) register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
} }

View File

@ -8,6 +8,7 @@ import net.shadowfacts.phycon.item.ConsoleItem
import net.shadowfacts.phycon.item.ScrewdriverItem import net.shadowfacts.phycon.item.ScrewdriverItem
import net.shadowfacts.phycon.block.cable.CableBlock import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.block.extractor.ExtractorBlock import net.shadowfacts.phycon.block.extractor.ExtractorBlock
import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.miner.MinerBlock import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.block.netswitch.SwitchBlock import net.shadowfacts.phycon.block.netswitch.SwitchBlock
@ -24,6 +25,7 @@ object PhyItems {
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings()) val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings()) val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
val EXTRACTOR = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings()) val EXTRACTOR = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
val INSERTER = BlockItem(PhyBlocks.INSERTER, Item.Settings())
val MINER = BlockItem(PhyBlocks.MINER, Item.Settings()) val MINER = BlockItem(PhyBlocks.MINER, Item.Settings())
val REDSTONE_CONTROLLER = BlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings()) val REDSTONE_CONTROLLER = BlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
@ -36,6 +38,7 @@ object PhyItems {
register(SwitchBlock.ID, SWITCH) register(SwitchBlock.ID, SWITCH)
register(CableBlock.ID, CABLE) register(CableBlock.ID, CABLE)
register(ExtractorBlock.ID, EXTRACTOR) register(ExtractorBlock.ID, EXTRACTOR)
register(InserterBlock.ID, INSERTER)
register(MinerBlock.ID, MINER) register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER) register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)

View File

@ -4,15 +4,19 @@ import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
import net.minecraft.screen.ScreenHandlerType import net.minecraft.screen.ScreenHandlerType
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
object PhyScreens { object PhyScreens {
lateinit var TERMINAL_SCREEN_HANDLER: ScreenHandlerType<TerminalScreenHandler> lateinit var TERMINAL_SCREEN_HANDLER: ScreenHandlerType<TerminalScreenHandler>
private set private set
lateinit var INSERTER_SCREEN_HANDLER: ScreenHandlerType<InserterScreenHandler>
private set
fun init() { fun init() {
TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler) TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(TerminalScreenHandler.ID, ::TerminalScreenHandler)
INSERTER_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(InserterScreenHandler.ID, ::InserterScreenHandler)
} }
} }

View File

@ -0,0 +1,45 @@
package net.shadowfacts.phycon.networking
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.PacketSender
import net.minecraft.network.Packet
import net.minecraft.network.PacketByteBuf
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayNetworkHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry
import net.minecraft.util.registry.RegistryKey
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.inserter.InserterBlockEntity
/**
* @author shadowfacts
*/
object C2SConfigureInserterAmount: ServerReceiver {
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "configure_inserter_amount")
operator fun invoke(be: InserterBlockEntity): Packet<*> {
val buf = PacketByteBufs.create()
buf.writeIdentifier(be.world!!.registryKey.value)
buf.writeBlockPos(be.pos)
buf.writeVarInt(be.amountToExtract)
return createPacket(buf)
}
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
val dimID = buf.readIdentifier()
val pos = buf.readBlockPos()
val amount = buf.readVarInt()
server.execute {
val key = RegistryKey.of(Registry.DIMENSION, dimID)
val world = server.getWorld(key) ?: return@execute
val be = world.getBlockEntity(pos) as? InserterBlockEntity ?: return@execute
be.amountToExtract = amount
be.markDirty()
}
}
}

View File

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

View File

@ -4,6 +4,7 @@
"block.phycon.terminal": "Terminal", "block.phycon.terminal": "Terminal",
"block.phycon.cable": "Cable", "block.phycon.cable": "Cable",
"block.phycon.extractor": "Inventory Extractor", "block.phycon.extractor": "Inventory Extractor",
"block.phycon.inserter": "Inventory Inserter",
"block.phycon.miner": "Block Miner", "block.phycon.miner": "Block Miner",
"block.phycon.redstone_controller": "Redstone Controller", "block.phycon.redstone_controller": "Redstone Controller",

View File

@ -1,11 +1,15 @@
{ {
"parent": "block/block", "parent": "block/block",
"textures": {
"cable_side": "phycon:block/cable_straight",
"cable_end": "phycon:block/cable_cap_end"
},
"elements": [ "elements": [
{ {
"from": [0, 0, 0], "from": [0, 0, 0],
"to": [16, 2, 16], "to": [16, 2, 16],
"faces": { "faces": {
"down": {"texture": "phycon:block/extractor_front"}, "down": {"texture": "phycon:block/extractor_front", "cullface": "down"},
"up": {"texture": "phycon:block/extractor_back"}, "up": {"texture": "phycon:block/extractor_back"},
"north": {"texture": "phycon:block/extractor_side"}, "north": {"texture": "phycon:block/extractor_side"},
"south": {"texture": "phycon:block/extractor_side"}, "south": {"texture": "phycon:block/extractor_side"},
@ -39,12 +43,12 @@
"from": [6, 6, 6], "from": [6, 6, 6],
"to": [10, 16, 10], "to": [10, 16, 10],
"faces": { "faces": {
"up": {"texture": "phycon:block/cable_side"}, "up": {"texture": "#cable_end", "cullface": "up"},
"north": {"texture": "phycon:block/cable_side"}, "north": {"texture": "#cable_side"},
"south": {"texture": "phycon:block/cable_side"}, "south": {"texture": "#cable_side"},
"west": {"texture": "phycon:block/cable_side"}, "west": {"texture": "#cable_side"},
"east": {"texture": "phycon:block/cable_side"} "east": {"texture": "#cable_side"}
} }
} }
] ]
} }

View File

@ -0,0 +1,54 @@
{
"parent": "block/block",
"textures": {
"cable_side": "phycon:block/cable_straight",
"cable_end": "phycon:block/cable_cap_end"
},
"elements": [
{
"from": [4, 0, 4],
"to": [12, 2, 12],
"faces": {
"down": {"texture": "phycon:block/extractor_front", "cullface": "down"},
"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": {
"down": {"texture": "phycon:block/extractor_front"},
"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": [0, 4, 0],
"to": [16, 6, 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": [6, 6, 6],
"to": [10, 16, 10],
"faces": {
"up": {"texture": "#cable_end", "cullface": "up"},
"north": {"texture": "#cable_side"},
"south": {"texture": "#cable_side"},
"west": {"texture": "#cable_side"},
"east": {"texture": "#cable_side"}
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB