Compare commits

...

6 Commits

27 changed files with 341 additions and 203 deletions

View File

@ -20,6 +20,9 @@ repositories {
maven {
url = "https://mod-buildcraft.com/maven"
}
maven {
url = "http://server.bbkr.space:8081/artifactory/libs-release/"
}
jcenter()
}
@ -39,6 +42,8 @@ dependencies {
include "alexiil.mc.lib:libblockattributes-core:${project.libblockattributes_version}"
include "alexiil.mc.lib:libblockattributes-items:${project.libblockattributes_version}"
modImplementation "io.github.cottonmc:cotton-resources:${project.cotton_resources_version}"
shadow project(":kiwi-java")
testImplementation "org.junit.jupiter:junit-jupiter:${project.junit_version}"

View File

@ -13,5 +13,6 @@ fabric_version=0.30.0+1.16
fabric_kotlin_version=1.4.30+build.2
libblockattributes_version=0.8.5
cotton_resources_version=1.7.4
junit_version = 5.4.0

View File

@ -60,7 +60,7 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
}
protected abstract val faceThickness: Double
protected abstract val faceShapes: Map<Direction, VoxelShape>
abstract val faceShapes: Map<Direction, VoxelShape>
private val centerShapes: Map<Direction, VoxelShape> by lazy {
mapOf(
Direction.DOWN to createCuboidShape(6.0, faceThickness, 6.0, 10.0, 10.0, 10.0),

View File

@ -1,5 +1,6 @@
package net.shadowfacts.phycon.block.cable
import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings
import net.minecraft.block.*
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.player.PlayerEntity
@ -23,20 +24,23 @@ import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkCableBlock
import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.init.PhyItems
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
import net.shadowfacts.phycon.util.CableConnection
import net.shadowfacts.phycon.util.containsInclusive
import java.util.*
/**
* @author shadowfacts
*/
class CableBlock: Block(
Settings.of(CABLE_MATERIAL)
.strength(1f)
FabricBlockSettings.of(CABLE_MATERIAL)
.strength(0.3f)
.nonOpaque()
.breakByHand(true)
), NetworkCableBlock {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL)
val CABLE_MATERIAL = Material.Builder(MaterialColor.BLUE).build()
val CENTER_SHAPE = createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 10.0)
val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
Direction.DOWN to createCuboidShape(6.0, 0.0, 6.0, 10.0, 6.0, 10.0),
@ -85,12 +89,16 @@ class CableBlock: Block(
}
}
override fun getPlacementState(context: ItemPlacementContext): BlockState {
fun getInitialState(world: World, pos: BlockPos): BlockState {
return CONNECTIONS.entries.fold(defaultState, { acc, (dir, prop) ->
acc.with(prop, getConnectionStateInDirection(context.world, context.blockPos, dir))
acc.with(prop, getConnectionStateInDirection(world, pos, dir))
})
}
override fun getPlacementState(context: ItemPlacementContext): BlockState {
return getInitialState(context.world, context.blockPos)
}
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, blockPos_1: BlockPos, blockPos_2: BlockPos): BlockState {
val prop = CONNECTIONS[side]
val current = state[prop]
@ -139,8 +147,7 @@ class CableBlock: Block(
if (player.getStackInHand(hand).item == PhyItems.SCREWDRIVER) {
val hitPos = Vec3d(hitResult.pos.x - pos.x, hitResult.pos.y - pos.y, hitResult.pos.z - pos.z)
val hitConnection = SIDE_SHAPES.entries.firstOrNull { (_, shape) ->
val box = shape.boundingBox
hitPos.x >= box.minX && hitPos.x <= box.maxX && hitPos.y >= box.minY && hitPos.y <= box.maxY && hitPos.z >= box.minZ && hitPos.z <= box.maxZ
shape.boundingBox.containsInclusive(hitPos)
}
if (hitConnection != null) {
val side = hitConnection.key
@ -167,6 +174,10 @@ class CableBlock: Block(
return ActionResult.PASS
}
override fun canReplace(state: BlockState, context: ItemPlacementContext): Boolean {
return context.stack.item is FaceDeviceBlockItem
}
override fun isTranslucent(blockState_1: BlockState?, blockView_1: BlockView?, blockPos_1: BlockPos?): Boolean {
return true
}

View File

@ -3,13 +3,9 @@ package net.shadowfacts.phycon.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.sound.BlockSoundGroup
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
@ -17,16 +13,13 @@ 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 java.util.*
import net.shadowfacts.phycon.block.FaceDeviceBlock
/**
* @author shadowfacts
*/
class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(
class ExtractorBlock: FaceDeviceBlock<ExtractorBlockEntity>(
Settings.of(Material.METAL)
.strength(1.5f)
.sounds(BlockSoundGroup.METAL)
@ -34,7 +27,6 @@ class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "extractor")
val FACING = Properties.FACING
private val EXTRACTOR_SHAPES = mutableMapOf<Direction, VoxelShape>()
init {
@ -42,7 +34,6 @@ class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(
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),
@ -73,34 +64,11 @@ class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(
}
}
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 val faceThickness = 6.0
override val faceShapes: Map<Direction, VoxelShape> = EXTRACTOR_SHAPES
override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity()
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 EXTRACTOR_SHAPES[state[FACING]]!!
}
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
if (!world.isClient) {
getBlockEntity(world, pos)!!.updateInventory()

View File

@ -5,13 +5,13 @@ import alexiil.mc.lib.attributes.Simulation
import alexiil.mc.lib.attributes.item.FixedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes
import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter
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.init.PhyBlockEntities
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.component.ActivationController
import net.shadowfacts.phycon.component.NetworkStackDispatcher
import net.shadowfacts.phycon.component.finishTimedOutPendingInsertions
@ -36,7 +36,7 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
}
private val facing: Direction
get() = cachedState[ExtractorBlock.FACING]
get() = cachedState[FaceDeviceBlock.FACING]
private var inventory: FixedItemInv? = null
override val pendingInsertions = mutableListOf<PendingInsertion>()

View File

@ -4,19 +4,14 @@ 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.sound.BlockSoundGroup
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
@ -27,24 +22,20 @@ 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 net.shadowfacts.phycon.block.FaceDeviceBlock
import java.util.*
/**
* @author shadowfacts
*/
class InserterBlock: DeviceBlock<InserterBlockEntity>(
class InserterBlock: FaceDeviceBlock<InserterBlockEntity>(
Settings.of(Material.METAL)
.strength(1.5f)
.sounds(BlockSoundGroup.METAL)
) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "inserter")
val FACING = Properties.FACING
private val INSERTER_SHAPES = mutableMapOf<Direction, VoxelShape>()
init {
@ -52,7 +43,6 @@ class InserterBlock: DeviceBlock<InserterBlockEntity>(
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),
@ -83,34 +73,11 @@ class InserterBlock: DeviceBlock<InserterBlockEntity>(
}
}
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 val faceThickness = 6.0
override val faceShapes: Map<Direction, VoxelShape> = INSERTER_SHAPES
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()

View File

@ -10,6 +10,7 @@ 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.block.FaceDeviceBlock
import net.shadowfacts.phycon.component.ActivationController
import net.shadowfacts.phycon.component.ItemStackPacketHandler
import net.shadowfacts.phycon.component.NetworkStackProvider
@ -34,7 +35,7 @@ class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
}
private val facing: Direction
get() = cachedState[InserterBlock.FACING]
get() = cachedState[FaceDeviceBlock.FACING]
private var inventory: ItemInsertable? = null
private var currentRequest: PendingExtractRequest? = null

View File

@ -18,7 +18,6 @@ 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.*
/**
@ -56,7 +55,7 @@ class MinerBlock: DeviceBlock<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)
return defaultState.with(FACING, facing)
}
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, itemStack: ItemStack) {

View File

@ -17,6 +17,7 @@ import net.minecraft.text.LiteralText
import net.minecraft.text.Text
import net.minecraft.text.TranslatableText
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.networking.C2STerminalRequestItem
import net.shadowfacts.phycon.networking.C2STerminalUpdateDisplayedItems
@ -28,6 +29,7 @@ import java.lang.NumberFormatException
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.min
import kotlin.math.roundToInt
/**
* @author shadowfacts
@ -59,6 +61,15 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
}
private var dialogChildren = mutableListOf<AbstractButtonWidget>()
private var scrollPosition = 0f
private var isDraggingScrollThumb = false
private val trackMinY = 18
private val trackHeight = 106
private val thumbHeight = 15
private val thumbWidth = 12
private val scrollThumbTop: Int
get() = trackMinY + (scrollPosition * (trackHeight - thumbHeight)).roundToInt()
private val dialogWidth = 158
private val dialogHeight = 62
@ -150,7 +161,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
private fun requestUpdatedItems() {
val player = MinecraftClient.getInstance().player!!
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchBox.text, sortButton.mode))
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchBox.text, sortButton.mode, scrollPosition))
}
override fun tick() {
@ -176,6 +187,9 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
// scroll thumb
drawTexture(matrixStack, x + 232, y + scrollThumbTop, 52, 230, thumbWidth, thumbHeight)
}
@ExperimentalUnsignedTypes
@ -227,6 +241,16 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
}
private fun isPointInsScrollThumb(mouseX: Double, mouseY: Double): Boolean {
val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2
val thumbMinX = x + 232
val thumbMaxX = thumbMinX + thumbWidth
val thumbMinY = y + scrollThumbTop
val thumbMaxY = thumbMinY + thumbHeight
return mouseX >= thumbMinX && mouseX < thumbMaxX && mouseY >= thumbMinY && mouseY < thumbMaxY
}
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
super.onMouseClick(slot, invSlot, clickData, type)
@ -261,15 +285,25 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
}
return false
} else {
if (isPointInsScrollThumb(mouseX, mouseY)) {
isDraggingScrollThumb = true
return true
}
return super.mouseClicked(mouseX, mouseY, button)
}
}
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (showingAmountDialog) {
return false
} else if (isDraggingScrollThumb) {
scrollPosition = (mouseY.toFloat() - (y + trackMinY) - 7.5f) / (trackHeight - 15)
scrollPosition = MathHelper.clamp(scrollPosition, 0f, 1f)
requestUpdatedItems()
return true
} else {
return super.mouseDragged(d, e, i, f, g)
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
}
@ -284,15 +318,23 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
if (showingAmountDialog) {
return false
} else {
isDraggingScrollThumb = false
return super.mouseReleased(d, e, i)
}
}
override fun mouseScrolled(d: Double, e: Double, f: Double): Boolean {
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
if (showingAmountDialog) {
return false
} else {
return super.mouseScrolled(d, e, f)
var newOffsetInRows = handler.currentScrollOffsetInRows() - amount.toInt()
newOffsetInRows = MathHelper.clamp(newOffsetInRows, 0, handler.maxScrollOffsetInRows())
val newScrollPosition = newOffsetInRows / handler.maxScrollOffsetInRows().toFloat()
scrollPosition = newScrollPosition
requestUpdatedItems()
return super.mouseScrolled(mouseX, mouseY, amount)
}
}
@ -303,6 +345,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
val oldText = searchBox.text
if (searchBox.charTyped(c, i)) {
if (searchBox.text != oldText) {
scrollPosition = 0f
requestUpdatedItems()
}
return true
@ -331,6 +374,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
val oldText = searchBox.text
if (searchBox.keyPressed(key, j, k)) {
if (searchBox.text != oldText) {
scrollPosition = 0f
requestUpdatedItems()
}
return true

View File

@ -17,7 +17,10 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.copyWithCount
import java.lang.ref.WeakReference
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
/**
* @author shadowfacts
@ -29,10 +32,15 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
}
private val rowsDisplayed = 6
private val fakeInv = FakeInventory(this)
private var searchQuery: String = ""
var sortMode = SortMode.COUNT_HIGH_FIRST
private set
var totalEntries = 0
private set
private var scrollPosition = 0f
private var itemEntries = listOf<Entry>()
set(value) {
field = value
@ -96,6 +104,8 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
it.key.name.string.contains(searchQuery, true)
}
totalEntries = filtered.size
val sorted =
when (sortMode) {
SortMode.COUNT_HIGH_FIRST -> filtered.sortedByDescending { it.intValue }
@ -103,22 +113,46 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
SortMode.ALPHABETICAL -> filtered.sortedBy { it.key.name.string }
}
itemEntries = sorted.map { Entry(it.key, it.intValue) }
(player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, sortMode))
val offsetInItems = currentScrollOffsetInItems()
val end = min(offsetInItems + rowsDisplayed * 9, sorted.size)
itemEntries = sorted.subList(offsetInItems, end).map { Entry(it.key, it.intValue) }
// itemEntries = sorted.map { Entry(it.key, it.intValue) }
(player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, sortMode, scrollPosition, totalEntries))
}
fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, sortMode: SortMode) {
fun totalRows(): Int {
return ceil(totalEntries / 9f).toInt()
}
fun maxScrollOffsetInRows(): Int {
return totalRows() - rowsDisplayed
}
fun currentScrollOffsetInRows(): Int {
return max(0, (scrollPosition * maxScrollOffsetInRows()).roundToInt())
}
fun currentScrollOffsetInItems(): Int {
return currentScrollOffsetInRows() * 9
}
fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, sortMode: SortMode, scrollPosition: Float) {
this.searchQuery = query
this.sortMode = sortMode
this.scrollPosition = scrollPosition
netItemsChanged()
}
fun receivedUpdatedItemsFromServer(entries: List<Entry>, query: String, sortMode: SortMode) {
fun receivedUpdatedItemsFromServer(entries: List<Entry>, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int) {
assert(playerInv.player.world.isClient)
this.searchQuery = query
this.sortMode = sortMode
this.scrollPosition = scrollPosition
this.totalEntries = totalEntries
itemEntries = entries
}

View File

@ -19,6 +19,10 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
val REDSTONE_CONTROLLER = Identifier(PhysicalConnectivity.MODID, "block/redstone_controller")
val REDSTONE_EMITTER = Identifier(PhysicalConnectivity.MODID, "block/redstone_emitter")
val REDSTONE_EMITTER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/redstone_emitter_side")
val EXTRACTOR = Identifier(PhysicalConnectivity.MODID, "block/extractor")
val EXTRACTOR_SIDE = Identifier(PhysicalConnectivity.MODID, "block/extractor_side")
val INSERTER = Identifier(PhysicalConnectivity.MODID, "block/inserter")
val INSERTER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/inserter_side")
}
override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? {
@ -26,6 +30,8 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
INTERFACE -> SimpleFaceDeviceModel(INTERFACE_SIDE)
REDSTONE_CONTROLLER -> RedstoneControllerModel
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
EXTRACTOR -> SimpleFaceDeviceModel(EXTRACTOR_SIDE)
INSERTER -> SimpleFaceDeviceModel(INSERTER_SIDE)
else -> null
}
}

View File

@ -17,21 +17,22 @@ import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
import net.shadowfacts.phycon.block.terminal.TerminalBlock
import net.shadowfacts.phycon.item.DeviceBlockItem
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
/**
* @author shadowfacts
*/
object PhyItems {
val INTERFACE = DeviceBlockItem(PhyBlocks.INTERFACE, Item.Settings())
val INTERFACE = FaceDeviceBlockItem(PhyBlocks.INTERFACE, Item.Settings())
val TERMINAL = DeviceBlockItem(PhyBlocks.TERMINAL, Item.Settings())
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
val EXTRACTOR = DeviceBlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
val INSERTER = DeviceBlockItem(PhyBlocks.INSERTER, Item.Settings())
val MINER = DeviceBlockItem(PhyBlocks.MINER, Item.Settings())
val REDSTONE_CONTROLLER = DeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
val REDSTONE_EMITTER = DeviceBlockItem(PhyBlocks.REDSTONE_EMITTER, Item.Settings())
val REDSTONE_CONTROLLER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
val REDSTONE_EMITTER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_EMITTER, Item.Settings())
val SCREWDRIVER = ScrewdriverItem()
val CONSOLE = ConsoleItem()

View File

@ -12,7 +12,7 @@ import net.shadowfacts.phycon.util.text
/**
* @author shadowfacts
*/
class DeviceBlockItem(block: DeviceBlock<*>, settings: Settings = Settings()): BlockItem(block, settings) {
open class DeviceBlockItem(block: DeviceBlock<*>, settings: Settings = Settings()): BlockItem(block, settings) {
override fun appendTooltip(stack: ItemStack, world: World?, list: MutableList<Text>, context: TooltipContext) {
val beTag = stack.getSubTag("BlockEntityTag")

View File

@ -0,0 +1,40 @@
package net.shadowfacts.phycon.item
import net.minecraft.block.BlockState
import net.minecraft.item.ItemPlacementContext
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.util.CableConnection
/**
* @author shadowfacts
*/
class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settings()): DeviceBlockItem(block, settings) {
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
val hitState = context.world.getBlockState(context.blockPos)
if (hitState.block == PhyBlocks.CABLE) {
val hitBlockEdge = context.hitPos.getComponentAlongAxis(context.side.axis) % 1 == 0.0
val placementSide = if (hitBlockEdge) context.side.opposite else context.side
if (hitState[CableBlock.CONNECTIONS[placementSide]] != CableConnection.ON) {
var connection = FaceDeviceBlock.FaceCableConnection.NONE
for (dir in Direction.values()) {
if (hitState[CableBlock.CONNECTIONS[dir]] == CableConnection.ON) {
connection = FaceDeviceBlock.FaceCableConnection.from(dir)
break
}
}
return block.defaultState
.with(FaceDeviceBlock.FACING, placementSide)
.with(FaceDeviceBlock.CABLE_CONNECTION, connection)
}
}
return null
}
}

View File

@ -1,5 +1,6 @@
package net.shadowfacts.phycon.item
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.entity.ItemEntity
import net.minecraft.item.Item
@ -9,9 +10,12 @@ import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.util.ActionResult
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.DeviceBlock
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.util.containsInclusive
/**
* @author shadowfacts
@ -22,36 +26,85 @@ class ScrewdriverItem: Item(Settings()) {
}
override fun useOnBlock(context: ItemUsageContext): ActionResult {
if (context.player?.isSneaking != true) return ActionResult.PASS
val state = context.world.getBlockState(context.blockPos)
val block = state.block
if (block is DeviceBlock<*>) {
if (!context.world.isClient) {
val be = block.getBlockEntity(context.world, context.blockPos)!!
val stack = ItemStack(block)
val beTag = stack.getOrCreateSubTag("BlockEntityTag")
be.toTag(beTag)
// remove x, y, z entries for stacking purposes
beTag.remove("x")
beTag.remove("y")
beTag.remove("z")
if (block === PhyBlocks.TERMINAL) {
// remove the terminal's internal buffer since it drops its items
beTag.remove("InternalBuffer")
}
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), stack)
context.world.spawnEntity(entity)
context.world.setBlockState(context.blockPos, Blocks.AIR.defaultState, 3, 512)
val newState =
when (block) {
is DeviceBlock<*> -> screwdriverDeviceBlock(context, state, block)
PhyBlocks.CABLE -> screwdriverCableBlock(context)
PhyBlocks.SWITCH -> screwdriverSwitchBlock(context)
else -> null
}
if (newState != null) {
context.world.setBlockState(context.blockPos, newState)
context.world.playSound(context.player, context.blockPos, SoundEvents.BLOCK_METAL_PLACE, SoundCategory.BLOCKS, 0.8f, 0.65f)
return ActionResult.SUCCESS
} else {
return ActionResult.PASS
}
}
private fun screwdriverDeviceBlock(context: ItemUsageContext, state: BlockState, block: DeviceBlock<*>): BlockState? {
if (!context.world.isClient) {
val be = block.getBlockEntity(context.world, context.blockPos)!!
val stack = ItemStack(block)
val beTag = stack.getOrCreateSubTag("BlockEntityTag")
be.toTag(beTag)
// remove x, y, z entries for stacking purposes
beTag.remove("x")
beTag.remove("y")
beTag.remove("z")
if (block === PhyBlocks.TERMINAL) {
// remove the terminal's internal buffer since it drops its items
beTag.remove("InternalBuffer")
}
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), stack)
context.world.spawnEntity(entity)
}
return if (block is FaceDeviceBlock<*>) {
screwdriverFaceDeviceBlock(context, state, block)
} else {
Blocks.AIR.defaultState
}
}
private fun screwdriverFaceDeviceBlock(context: ItemUsageContext, state: BlockState, block: FaceDeviceBlock<*>): BlockState? {
val hitInsideBlock = Vec3d(context.hitPos.x - context.blockPos.x, context.hitPos.y - context.blockPos.y, context.hitPos.z - context.blockPos.z)
val faceShape = block.faceShapes[state[FaceDeviceBlock.FACING]]!!
// if we hit the face part of block, leave the cable behind
if (faceShape.boundingBox.containsInclusive(hitInsideBlock)) {
return PhyBlocks.CABLE.getInitialState(context.world, context.blockPos)
} else {
if (!context.world.isClient) {
val cable = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(PhyBlocks.CABLE))
context.world.spawnEntity(cable)
}
return Blocks.AIR.defaultState
}
}
private fun screwdriverCableBlock(context: ItemUsageContext): BlockState? {
if (!context.world.isClient) {
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(PhyBlocks.CABLE))
context.world.spawnEntity(entity)
}
return Blocks.AIR.defaultState
}
private fun screwdriverSwitchBlock(context: ItemUsageContext): BlockState? {
if (!context.world.isClient) {
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(PhyBlocks.SWITCH))
context.world.spawnEntity(entity)
}
return Blocks.AIR.defaultState
}
}

View File

@ -21,7 +21,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "terminal_update_displayed")
operator fun invoke(terminal: TerminalBlockEntity, query: String, sortMode: SortMode): Packet<*> {
operator fun invoke(terminal: TerminalBlockEntity, query: String, sortMode: SortMode, scrollPosition: Float): Packet<*> {
val buf = PacketByteBufs.create()
buf.writeIdentifier(terminal.world!!.registryKey.value)
@ -29,6 +29,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
buf.writeString(query)
buf.writeVarInt(sortMode.ordinal)
buf.writeFloat(scrollPosition)
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
}
@ -38,13 +39,14 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
val pos = buf.readBlockPos()
val query = buf.readString()
val sortMode = SortMode.values()[buf.readVarInt()]
val scrollPosition = buf.readFloat()
server.execute {
if (player.world.registryKey.value != dimID) return@execute
val screenHandler = player.currentScreenHandler
if (screenHandler !is TerminalScreenHandler) return@execute
if (screenHandler.terminal.pos != pos) return@execute
screenHandler.sendUpdatedItemsToClient(player, query, sortMode)
screenHandler.sendUpdatedItemsToClient(player, query, sortMode, scrollPosition)
}
}
}

View File

@ -17,7 +17,7 @@ import net.shadowfacts.phycon.util.SortMode
object S2CTerminalUpdateDisplayedItems: ClientReceiver {
override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL
operator fun invoke(terminal: TerminalBlockEntity, entries: List<TerminalScreenHandler.Entry>, query: String, sortMode: SortMode): Packet<*> {
operator fun invoke(terminal: TerminalBlockEntity, entries: List<TerminalScreenHandler.Entry>, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int): Packet<*> {
val buf = PacketByteBufs.create()
buf.writeIdentifier(terminal.world!!.registryKey.value)
@ -31,6 +31,8 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
buf.writeString(query)
buf.writeVarInt(sortMode.ordinal)
buf.writeFloat(scrollPosition)
buf.writeInt(totalEntries)
return ServerPlayNetworking.createS2CPacket(CHANNEL, buf)
}
@ -45,13 +47,15 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
}
val query = buf.readString()
val sortMode = SortMode.values()[buf.readVarInt()]
val scrollPosition = buf.readFloat()
val totalEntries = buf.readInt()
client.execute {
if (client.player!!.world.registryKey.value != dimID) return@execute
val screenHandler = client.player!!.currentScreenHandler
if (screenHandler !is TerminalScreenHandler) return@execute
if (screenHandler.terminal.pos != pos) return@execute
screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode)
screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode, scrollPosition, totalEntries)
}
}
}

View File

@ -0,0 +1,11 @@
package net.shadowfacts.phycon.util
import net.minecraft.util.math.Box
import net.minecraft.util.math.Vec3d
/**
* @author shadowfacts
*/
fun Box.containsInclusive(point: Vec3d): Boolean {
return point.x >= minX && point.x <= maxX && point.y >= minY && point.y <= maxY && point.z >= minZ && point.z <= maxZ
}

View File

@ -1,29 +1,7 @@
{
"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
"multipart": [
{
"apply": {"model": "phycon:block/extractor"}
}
}
}
]
}

View File

@ -1,29 +1,7 @@
{
"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
"multipart": [
{
"apply": {"model": "phycon:block/inserter"}
}
}
]
}

View File

@ -1,8 +1,6 @@
{
"parent": "block/block",
"textures": {
"cable_side": "phycon:block/cable_straight",
"cable_end": "phycon:block/cable_cap_end"
},
"elements": [
{
@ -38,17 +36,6 @@
"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"}
}
}
]
}

View File

@ -1,8 +1,6 @@
{
"parent": "block/block",
"textures": {
"cable_side": "phycon:block/cable_straight",
"cable_end": "phycon:block/cable_cap_end"
},
"elements": [
{
@ -38,17 +36,6 @@
"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.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,33 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "phycon:network_interface"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
},
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "phycon:cable"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View File

@ -14,6 +14,20 @@
"condition": "minecraft:survives_explosion"
}
]
},
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "phycon:cable"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View File

@ -14,6 +14,20 @@
"condition": "minecraft:survives_explosion"
}
]
},
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "phycon:cable"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}