Add Inserter
This commit is contained in:
parent
9b4fc548e5
commit
e13154943e
|
@ -16,7 +16,7 @@ import java.util.*
|
|||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||
open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||
handler: Handler,
|
||||
playerInv: PlayerInventory,
|
||||
title: Text,
|
||||
|
|
|
@ -28,6 +28,7 @@ object PhysicalConnectivity: ModInitializer {
|
|||
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
||||
registerGlobalReceiver(C2SConfigureActivationMode)
|
||||
registerGlobalReceiver(C2SConfigureRedstoneController)
|
||||
registerGlobalReceiver(C2SConfigureInserterAmount)
|
||||
}
|
||||
|
||||
private fun registerGlobalReceiver(receiver: ServerReceiver) {
|
||||
|
|
|
@ -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.screenhandler.v1.ScreenRegistry
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreen
|
||||
|
@ -17,9 +18,8 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
|||
object PhysicalConnectivityClient: ClientModInitializer {
|
||||
|
||||
override fun onInitializeClient() {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent())
|
||||
|
||||
ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
|
||||
ScreenRegistry.register(PhyScreens.INSERTER_SCREEN_HANDLER, ::InserterScreen)
|
||||
|
||||
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(Settings.of(Material.MET
|
|||
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
|
||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
||||
return defaultState.with(FACING, facing)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -183,7 +183,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
inventoryCache.clear()
|
||||
sendPacket(RequestInventoryPacket(ipAddress))
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ import net.minecraft.util.Identifier
|
|||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||
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.MinerBlockEntity
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||
|
@ -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 INSERTER = create(::InserterBlockEntity, PhyBlocks.INSERTER)
|
||||
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
||||
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
|
||||
|
||||
|
@ -39,6 +42,7 @@ object PhyBlockEntities {
|
|||
register(TerminalBlock.ID, TERMINAL)
|
||||
register(SwitchBlock.ID, SWITCH)
|
||||
register(ExtractorBlock.ID, EXTRACTOR)
|
||||
register(InserterBlock.ID, INSERTER)
|
||||
register(MinerBlock.ID, MINER)
|
||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import net.minecraft.util.Identifier
|
|||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||
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.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||
|
@ -21,6 +22,7 @@ object PhyBlocks {
|
|||
val SWITCH = SwitchBlock()
|
||||
val CABLE = CableBlock()
|
||||
val EXTRACTOR = ExtractorBlock()
|
||||
val INSERTER = InserterBlock()
|
||||
val MINER = MinerBlock()
|
||||
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
|
||||
|
||||
|
@ -30,6 +32,7 @@ object PhyBlocks {
|
|||
register(SwitchBlock.ID, SWITCH)
|
||||
register(CableBlock.ID, CABLE)
|
||||
register(ExtractorBlock.ID, EXTRACTOR)
|
||||
register(InserterBlock.ID, INSERTER)
|
||||
register(MinerBlock.ID, MINER)
|
||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import net.shadowfacts.phycon.item.ConsoleItem
|
|||
import net.shadowfacts.phycon.item.ScrewdriverItem
|
||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||
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.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||
|
@ -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 INSERTER = BlockItem(PhyBlocks.INSERTER, Item.Settings())
|
||||
val MINER = BlockItem(PhyBlocks.MINER, Item.Settings())
|
||||
val REDSTONE_CONTROLLER = BlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
|
||||
|
||||
|
@ -36,6 +38,7 @@ object PhyItems {
|
|||
register(SwitchBlock.ID, SWITCH)
|
||||
register(CableBlock.ID, CABLE)
|
||||
register(ExtractorBlock.ID, EXTRACTOR)
|
||||
register(InserterBlock.ID, INSERTER)
|
||||
register(MinerBlock.ID, MINER)
|
||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||
|
||||
|
|
|
@ -4,15 +4,19 @@ import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
|||
import net.minecraft.screen.ScreenHandlerType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||
|
||||
object PhyScreens {
|
||||
|
||||
lateinit var TERMINAL_SCREEN_HANDLER: ScreenHandlerType<TerminalScreenHandler>
|
||||
private set
|
||||
lateinit var INSERTER_SCREEN_HANDLER: ScreenHandlerType<InserterScreenHandler>
|
||||
private set
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
"block.phycon.terminal": "Terminal",
|
||||
"block.phycon.cable": "Cable",
|
||||
"block.phycon.extractor": "Inventory Extractor",
|
||||
"block.phycon.inserter": "Inventory Inserter",
|
||||
"block.phycon.miner": "Block Miner",
|
||||
"block.phycon.redstone_controller": "Redstone Controller",
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"cable_side": "phycon:block/cable_straight",
|
||||
"cable_end": "phycon:block/cable_cap_end"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 2, 16],
|
||||
"faces": {
|
||||
"down": {"texture": "phycon:block/extractor_front"},
|
||||
"down": {"texture": "phycon:block/extractor_front", "cullface": "down"},
|
||||
"up": {"texture": "phycon:block/extractor_back"},
|
||||
"north": {"texture": "phycon:block/extractor_side"},
|
||||
"south": {"texture": "phycon:block/extractor_side"},
|
||||
|
@ -39,11 +43,11 @@
|
|||
"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"}
|
||||
"up": {"texture": "#cable_end", "cullface": "up"},
|
||||
"north": {"texture": "#cable_side"},
|
||||
"south": {"texture": "#cable_side"},
|
||||
"west": {"texture": "#cable_side"},
|
||||
"east": {"texture": "#cable_side"}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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 |
Loading…
Reference in New Issue