Compare commits
12 Commits
385e36918f
...
c9bcfd29d5
Author | SHA1 | Date |
---|---|---|
Shadowfacts | c9bcfd29d5 | |
Shadowfacts | 2198b5e10d | |
Shadowfacts | 1c405f8623 | |
Shadowfacts | 89e91796a5 | |
Shadowfacts | 219033476c | |
Shadowfacts | 32d87fbd9d | |
Shadowfacts | 72b8435834 | |
Shadowfacts | 5542f088f9 | |
Shadowfacts | 7cc96d78ad | |
Shadowfacts | da8b600f31 | |
Shadowfacts | 74aae99b36 | |
Shadowfacts | f321b2a06a |
|
@ -35,7 +35,7 @@ data class Rect(val left: Double, val top: Double, val width: Double, val height
|
|||
}
|
||||
|
||||
operator fun contains(point: Point): Boolean {
|
||||
return point.x in left..right && point.y in top..bottom
|
||||
return point.x >= left && point.x < right && point.y >= top && point.y < bottom
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ import net.shadowfacts.cacao.geometry.Point
|
|||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.RenderHelper
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* A simple View that displays text. Allows for controlling the color and shadow of the text. Label cannot be used
|
||||
|
@ -26,10 +27,10 @@ import net.shadowfacts.cacao.util.RenderHelper
|
|||
*/
|
||||
class Label(
|
||||
text: Text,
|
||||
val shadow: Boolean = false,
|
||||
var shadow: Boolean = false,
|
||||
val maxLines: Int = 0,
|
||||
val wrappingMode: WrappingMode = WrappingMode.WRAP,
|
||||
val textAlignment: TextAlignment = TextAlignment.LEFT
|
||||
var textAlignment: TextAlignment = TextAlignment.LEFT
|
||||
): View() {
|
||||
|
||||
companion object {
|
||||
|
@ -59,7 +60,8 @@ class Label(
|
|||
var text: Text = text
|
||||
set(value) {
|
||||
field = value
|
||||
updateIntrinsicContentSize()
|
||||
// todo: uhhhh
|
||||
updateIntrinsicContentSize(true)
|
||||
// todo: setNeedsLayout instead of force unwrapping window
|
||||
window!!.layout()
|
||||
}
|
||||
|
@ -75,16 +77,24 @@ class Label(
|
|||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
updateIntrinsicContentSize()
|
||||
updateIntrinsicContentSize(false)
|
||||
}
|
||||
|
||||
private fun updateIntrinsicContentSize() {
|
||||
if (RenderHelper.disabled) return
|
||||
private fun updateIntrinsicContentSize(canWrap: Boolean): Boolean {
|
||||
if (RenderHelper.disabled) return false
|
||||
|
||||
val oldSize = intrinsicContentSize
|
||||
if (wrappingMode == WrappingMode.WRAP && canWrap && hasSolver) {
|
||||
val lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
||||
val height = (if (maxLines == 0) lines.size else min(lines.size, maxLines)) * textRenderer.fontHeight
|
||||
intrinsicContentSize = Size(bounds.width, height.toDouble())
|
||||
} else {
|
||||
val width = textRenderer.getWidth(text)
|
||||
val height = textRenderer.fontHeight
|
||||
intrinsicContentSize = Size(width.toDouble(), height.toDouble())
|
||||
}
|
||||
return oldSize != intrinsicContentSize
|
||||
}
|
||||
|
||||
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||
if (!this::lines.isInitialized) {
|
||||
|
@ -110,14 +120,22 @@ class Label(
|
|||
super.didLayout()
|
||||
|
||||
computeLines()
|
||||
if (updateIntrinsicContentSize(true)) {
|
||||
// if the intrinsic content size changes, relayout
|
||||
window!!.layout()
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeLines() {
|
||||
if (wrappingMode == WrappingMode.WRAP) {
|
||||
var lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
||||
if (maxLines > 0 && maxLines < lines.size) {
|
||||
lines = lines.dropLast(lines.size - maxLines)
|
||||
}
|
||||
this.lines = lines
|
||||
} else {
|
||||
this.lines = listOf(text.asOrderedText())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -48,6 +48,9 @@ open class View(): Responder {
|
|||
*/
|
||||
var solver: Solver by solverDelegate
|
||||
|
||||
val hasSolver: Boolean
|
||||
get() = solverDelegate.isInitialized
|
||||
|
||||
/**
|
||||
* Layout anchor for the left edge of this view in the window's coordinate system.
|
||||
*/
|
||||
|
@ -92,17 +95,22 @@ open class View(): Responder {
|
|||
|
||||
/**
|
||||
* The rectangle for this view in the coordinate system of its superview view (or the window, if there is no superview).
|
||||
* If using constraint based layout, this property is not initialized until [didLayout] called.
|
||||
* If using constraint based layout, this property has zero dimensions until [didLayout] called.
|
||||
* Otherwise, this must be set manually.
|
||||
* Setting this property updates the [bounds].
|
||||
*/
|
||||
var frame: Rect by ObservableLateInitProperty { this.bounds = Rect(Point.ORIGIN, it.size) }
|
||||
var frame = Rect(0.0, 0.0, 0.0, 0.0)
|
||||
set(value) {
|
||||
field = value
|
||||
bounds = Rect(Point.ORIGIN, value.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* The rectangle for this view in its own coordinate system.
|
||||
* If using constraint based layout, this property is not initialized until [didLayout] called.
|
||||
* If using constraint based layout, this property has zero dimensions until [didLayout] called.
|
||||
* Otherwise, this will be initialized when [frame] is set.
|
||||
*/
|
||||
lateinit var bounds: Rect
|
||||
var bounds = Rect(0.0, 0.0, 0.0, 0.0)
|
||||
|
||||
/**
|
||||
* The position on the Z-axis of this view.
|
||||
|
@ -114,7 +122,7 @@ open class View(): Responder {
|
|||
* The intrinsic size of this view's content. May be null if the view doesn't have any content or there is no
|
||||
* intrinsic size.
|
||||
*
|
||||
* Setting this creates/updates [no.birkett.kiwi.Strength.WEAK] constraints on this view's width/height using
|
||||
* Setting this creates/updates [no.birkett.kiwi.Strength.MEDIUM] constraints on this view's width/height using
|
||||
* the size.
|
||||
*/
|
||||
var intrinsicContentSize: Size? = null
|
||||
|
@ -182,7 +190,7 @@ open class View(): Responder {
|
|||
subviewsSortedByZIndex = subviews.sortedBy(View::zIndex)
|
||||
|
||||
view.superview = this
|
||||
if (solverDelegate.isInitialized) {
|
||||
if (hasSolver) {
|
||||
view.solver = solver
|
||||
}
|
||||
view.window = window
|
||||
|
@ -293,7 +301,7 @@ open class View(): Responder {
|
|||
}
|
||||
|
||||
private fun updateIntrinsicContentSizeConstraints(old: Size?, new: Size?) {
|
||||
if (!usesConstraintBasedLayout || !solverDelegate.isInitialized) return
|
||||
if (!usesConstraintBasedLayout || !hasSolver) return
|
||||
|
||||
if (old != null) {
|
||||
solver.removeConstraint(intrinsicContentSizeWidthConstraint!!)
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
package net.shadowfacts.cacao.view.button
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
import net.shadowfacts.cacao.view.TextureView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
|
||||
/**
|
||||
* A button for toggling between on/off states.
|
||||
*
|
||||
* @author shadowfacts
|
||||
* @param initialState Whether the button starts as on or off.
|
||||
* @param handler The handler function to invoke when this button is pressed.
|
||||
*/
|
||||
class ToggleButton(initialState: Boolean): AbstractButton<ToggleButton>(TextureView(if (initialState) ON else OFF).apply {
|
||||
intrinsicContentSize = Size(19.0, 19.0)
|
||||
}, padding = 0.0) {
|
||||
class ToggleButton(
|
||||
initialState: Boolean,
|
||||
handler: ((ToggleButton) -> Unit)? = null,
|
||||
): AbstractButton<ToggleButton>(TextureView(if (initialState) ON else OFF), padding = 0.0) {
|
||||
|
||||
companion object {
|
||||
val ON = Texture(Identifier("asmr", "textures/gui/toggle.png"), 0, 0)
|
||||
val OFF = Texture(Identifier("asmr", "textures/gui/toggle.png"), 0, 19)
|
||||
val OFF = Texture(Identifier("textures/gui/checkbox.png"), 0, 0, 64, 64)
|
||||
val OFF_HOVERED = Texture(Identifier("textures/gui/checkbox.png"), 20, 0, 64, 64)
|
||||
val ON = Texture(Identifier("textures/gui/checkbox.png"), 0, 20, 64, 64)
|
||||
val ON_HOVERED = Texture(Identifier("textures/gui/checkbox.png"), 20, 20, 64, 64)
|
||||
}
|
||||
|
||||
private val textureView: TextureView
|
||||
|
@ -30,9 +36,14 @@ class ToggleButton(initialState: Boolean): AbstractButton<ToggleButton>(TextureV
|
|||
* Updating this property updates the button's texture.
|
||||
*/
|
||||
var state: Boolean = initialState
|
||||
set(value) {
|
||||
field = value
|
||||
textureView.texture = if (value) ON else OFF
|
||||
|
||||
init {
|
||||
this.handler = handler
|
||||
intrinsicContentSize = Size(20.0, 20.0)
|
||||
|
||||
background = null
|
||||
disabledBackground = null
|
||||
hoveredBackground = null
|
||||
}
|
||||
|
||||
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
|
||||
|
@ -43,4 +54,17 @@ class ToggleButton(initialState: Boolean): AbstractButton<ToggleButton>(TextureV
|
|||
return super.mouseClicked(point, mouseButton)
|
||||
}
|
||||
|
||||
override fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
||||
val hovered = mouse in bounds
|
||||
textureView.texture = if (state) {
|
||||
if (hovered) ON_HOVERED else ON
|
||||
} else {
|
||||
if (hovered) OFF_HOVERED else OFF
|
||||
}
|
||||
|
||||
super.draw(matrixStack, mouse, delta)
|
||||
}
|
||||
|
||||
override fun getCurrentBackground(mouse: Point) = null
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import net.shadowfacts.cacao.geometry.Axis
|
|||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.geometry.Rect
|
||||
import net.shadowfacts.cacao.geometry.Size
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.util.texture.NinePatchTexture
|
||||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
|
@ -97,6 +98,7 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
|
||||
private lateinit var outerStack: StackView
|
||||
private lateinit var tabStack: StackView
|
||||
private lateinit var currentTabController: ViewController
|
||||
// todo: this shouldn't be public, use layout guides
|
||||
lateinit var tabVCContainer: View
|
||||
private set
|
||||
|
@ -121,7 +123,11 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
tabVCContainer.zIndex = 1.0
|
||||
view.addSubview(tabVCContainer)
|
||||
|
||||
embedChild(currentTab.controller, tabVCContainer)
|
||||
currentTabController = currentTab.controller
|
||||
currentTabController.willMoveTo(this)
|
||||
embedChild(currentTabController, tabVCContainer)
|
||||
currentTabController.didMoveTo(this)
|
||||
// will/did appear events for the initial VC are provided by this class' implementations of those
|
||||
|
||||
view.solver.dsl {
|
||||
outerStack.leftAnchor equalTo view.leftAnchor
|
||||
|
@ -136,6 +142,26 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
currentTabController.viewWillAppear()
|
||||
}
|
||||
|
||||
override fun viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
currentTabController.viewDidAppear()
|
||||
}
|
||||
|
||||
override fun viewWillDisappear() {
|
||||
super.viewWillDisappear()
|
||||
currentTabController.viewWillDisappear()
|
||||
}
|
||||
|
||||
override fun viewDidDisappear() {
|
||||
super.viewDidDisappear()
|
||||
currentTabController.viewDidDisappear()
|
||||
}
|
||||
|
||||
private fun updateTabButtons() {
|
||||
while (tabStack.arrangedSubviews.isNotEmpty()) tabStack.removeArrangedSubview(tabStack.arrangedSubviews.first())
|
||||
|
||||
|
@ -186,8 +212,20 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
tabButtons.forEach {
|
||||
it.setSelected(it.tab === tab)
|
||||
}
|
||||
oldTab.controller.removeFromParent()
|
||||
embedChild(currentTab.controller, tabVCContainer)
|
||||
currentTabController.viewWillDisappear()
|
||||
currentTabController.view.removeFromSuperview()
|
||||
currentTabController.viewDidDisappear()
|
||||
currentTabController.willMoveTo(null)
|
||||
currentTabController.removeFromParent()
|
||||
currentTabController.didMoveTo(null)
|
||||
|
||||
currentTabController = currentTab.controller
|
||||
|
||||
currentTabController.willMoveTo(this)
|
||||
embedChild(currentTabController, tabVCContainer)
|
||||
currentTabController.didMoveTo(this)
|
||||
currentTabController.viewWillAppear()
|
||||
currentTabController.viewDidAppear()
|
||||
|
||||
onTabChange?.invoke(currentTab)
|
||||
|
||||
|
@ -202,7 +240,7 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
padding = 2.0
|
||||
) {
|
||||
companion object {
|
||||
val BACKGROUND = Identifier("textures/gui/container/creative_inventory/tabs.png")
|
||||
val BACKGROUND = Identifier("phycon:textures/gui/tabs.png")
|
||||
}
|
||||
|
||||
private var selected = false
|
||||
|
@ -256,7 +294,7 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
val u = when {
|
||||
superview == null -> 0
|
||||
frame.left == 0.0 -> 0
|
||||
frame.right == superview!!.bounds.right -> 140
|
||||
frame.right == superview!!.bounds.right -> 56
|
||||
else -> 28
|
||||
}
|
||||
backgroundView.texture = Texture(BACKGROUND, u, v)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package net.shadowfacts.phycon
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer
|
||||
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
|
||||
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
|
||||
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreen
|
||||
import net.shadowfacts.phycon.client.PhyModelProvider
|
||||
import net.shadowfacts.phycon.networking.ClientReceiver
|
||||
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
||||
|
||||
|
@ -16,6 +18,8 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
|||
object PhysicalConnectivityClient: ClientModInitializer {
|
||||
|
||||
override fun onInitializeClient() {
|
||||
ModelLoadingRegistry.INSTANCE.registerResourceProvider(::PhyModelProvider)
|
||||
|
||||
ScreenRegistry.register(PhyScreens.TERMINAL, ::TerminalScreen)
|
||||
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
||||
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
||||
|
|
|
@ -119,10 +119,11 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
|||
|
||||
open fun findDestination(): Interface? {
|
||||
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
|
||||
if (sides.size != 1) {
|
||||
throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
||||
return when (sides.size) {
|
||||
0 -> null
|
||||
1 -> NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
|
||||
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
||||
}
|
||||
return NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
|
|
|
@ -7,6 +7,7 @@ import net.minecraft.item.ItemPlacementContext
|
|||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.EnumProperty
|
||||
import net.minecraft.state.property.Properties
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
@ -26,7 +27,36 @@ import java.util.*
|
|||
abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): DeviceBlock<T>(settings) {
|
||||
companion object {
|
||||
val FACING = Properties.FACING
|
||||
val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java)
|
||||
val CABLE_CONNECTION = EnumProperty.of("cable_connection", FaceCableConnection::class.java)
|
||||
}
|
||||
|
||||
enum class FaceCableConnection : StringIdentifiable {
|
||||
NONE, DOWN, UP, NORTH, SOUTH, WEST, EAST;
|
||||
|
||||
companion object {
|
||||
fun from(dir: Direction?) = when (dir) {
|
||||
null -> NONE
|
||||
Direction.DOWN -> DOWN
|
||||
Direction.UP -> UP
|
||||
Direction.NORTH -> NORTH
|
||||
Direction.SOUTH -> SOUTH
|
||||
Direction.WEST -> WEST
|
||||
Direction.EAST -> EAST
|
||||
}
|
||||
}
|
||||
|
||||
val direction: Direction?
|
||||
get() = when (this) {
|
||||
NONE -> null
|
||||
DOWN -> Direction.DOWN
|
||||
UP -> Direction.UP
|
||||
NORTH -> Direction.NORTH
|
||||
SOUTH -> Direction.SOUTH
|
||||
WEST -> Direction.WEST
|
||||
EAST -> Direction.EAST
|
||||
}
|
||||
|
||||
override fun asString() = name.toLowerCase()
|
||||
}
|
||||
|
||||
protected abstract val faceThickness: Double
|
||||
|
@ -41,20 +71,21 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
|
|||
Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 16.0 - faceThickness, 10.0, 10.0)
|
||||
)
|
||||
}
|
||||
private val shapeCache = mutableMapOf<Pair<Direction, Direction>, VoxelShape>()
|
||||
private val shapeCache = mutableMapOf<Pair<Direction, FaceCableConnection>, VoxelShape>()
|
||||
|
||||
fun getShape(facing: Direction, cableConnection: Direction): VoxelShape {
|
||||
private fun getShape(facing: Direction, cableConnection: FaceCableConnection): VoxelShape {
|
||||
return shapeCache.getOrPut(facing to cableConnection) {
|
||||
VoxelShapes.union(
|
||||
faceShapes[facing],
|
||||
centerShapes[facing],
|
||||
CableBlock.SIDE_SHAPES[cableConnection]
|
||||
)
|
||||
if (cableConnection == FaceCableConnection.NONE) {
|
||||
VoxelShapes.union(faceShapes[facing], centerShapes[facing])
|
||||
} else {
|
||||
VoxelShapes.union(faceShapes[facing], centerShapes[facing], CableBlock.SIDE_SHAPES[cableConnection.direction])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
|
||||
return EnumSet.of(state[CABLE_CONNECTION])
|
||||
val direction = state[CABLE_CONNECTION].direction
|
||||
return if (direction != null) EnumSet.of(direction) else setOf()
|
||||
}
|
||||
|
||||
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||
|
@ -73,13 +104,13 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
|
|||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
||||
val cableConnection = getCableConnectedSide(context.world, context.blockPos, facing) ?: facing.opposite
|
||||
val cableConnection = FaceCableConnection.from(getCableConnectedSide(context.world, context.blockPos, facing))
|
||||
return defaultState
|
||||
.with(FACING, facing)
|
||||
.with(CABLE_CONNECTION, cableConnection)
|
||||
}
|
||||
|
||||
protected fun getCableConnectedSide(world: World, pos: BlockPos, facing: Direction): Direction? {
|
||||
private fun getCableConnectedSide(world: WorldAccess, pos: BlockPos, facing: Direction): Direction? {
|
||||
for (side in Direction.values()) {
|
||||
if (side == facing) {
|
||||
continue
|
||||
|
@ -95,10 +126,21 @@ abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): Device
|
|||
}
|
||||
|
||||
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
|
||||
if (neighborState.block is NetworkComponentBlock && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponentBlock) {
|
||||
return state.with(CABLE_CONNECTION, side)
|
||||
val current = state[CABLE_CONNECTION]
|
||||
var newConnection = current
|
||||
|
||||
if (current == FaceCableConnection.NONE) {
|
||||
if (neighborState.block is NetworkComponentBlock) {
|
||||
newConnection = FaceCableConnection.from(side)
|
||||
}
|
||||
return state
|
||||
} else {
|
||||
val currentConnectedPos = pos.offset(current.direction)
|
||||
if (neighborPos == currentConnectedPos && neighborState.block !is NetworkComponentBlock) {
|
||||
// the old cable connection is no longer correct, try to find another
|
||||
newConnection = FaceCableConnection.from(getCableConnectedSide(world, pos, state[FACING]))
|
||||
}
|
||||
}
|
||||
return state.with(CABLE_CONNECTION, newConnection)
|
||||
}
|
||||
|
||||
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||
|
|
|
@ -14,6 +14,7 @@ import net.shadowfacts.phycon.init.PhyBlockEntities
|
|||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.component.ActivationController
|
||||
import net.shadowfacts.phycon.component.NetworkStackDispatcher
|
||||
import net.shadowfacts.phycon.component.finishTimedOutPendingInsertions
|
||||
import net.shadowfacts.phycon.component.handleItemStack
|
||||
import net.shadowfacts.phycon.packet.CapacityPacket
|
||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||
|
@ -84,6 +85,8 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
|||
|
||||
if (!world!!.isClient) {
|
||||
controller.tick()
|
||||
|
||||
finishTimedOutPendingInsertions()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
|||
|
||||
override var providerPriority = 0
|
||||
override var receiverPriority = 0
|
||||
var syncPriorities = true
|
||||
|
||||
// todo: should this be a weak ref?
|
||||
private var inventory: GroupedItemInv? = null
|
||||
|
@ -121,11 +122,13 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
|||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putInt("ProviderPriority", providerPriority)
|
||||
tag.putInt("ReceiverPriority", receiverPriority)
|
||||
tag.putBoolean("SyncPriorities", syncPriorities)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
providerPriority = tag.getInt("ProviderPriority")
|
||||
receiverPriority = tag.getInt("ReceiverPriority")
|
||||
syncPriorities = tag.getBoolean("SyncPriorities")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,19 +3,24 @@ package net.shadowfacts.phycon.block.netswitch
|
|||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.entity.ItemEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.util.Tickable
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.frame.BasePacketFrame
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.util.NetworkUtil
|
||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.util.NetworkUtil
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.Deque
|
||||
import java.util.LinkedList
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -25,13 +30,14 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
|||
Tickable {
|
||||
|
||||
companion object {
|
||||
var SWITCHING_CAPACITY = 256 // 256 items/tick
|
||||
var SWITCHING_CAPACITY = 256 // 256 packets/tick
|
||||
}
|
||||
|
||||
val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) }
|
||||
|
||||
private val macTable = mutableMapOf<MACAddress, Direction>()
|
||||
private var itemsHandledThisTick = 0
|
||||
private var packetsHandledThisTick = 0
|
||||
private var delayedPackets: Deque<Pair<PacketFrame, SwitchInterface>> = LinkedList()
|
||||
|
||||
fun interfaceForSide(side: Direction): SwitchInterface {
|
||||
return interfaces.find { it.side == side }!!
|
||||
|
@ -40,18 +46,20 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
|||
private fun handle(frame: EthernetFrame, fromItf: SwitchInterface) {
|
||||
macTable[frame.source] = fromItf.side
|
||||
|
||||
if (frame is PacketFrame && frame.packet is ItemStackPacket) {
|
||||
val packet = frame.packet as ItemStackPacket
|
||||
if (itemsHandledThisTick + packet.stack.count > SWITCHING_CAPACITY) {
|
||||
// todo: calculate entity spawn point by finding non-obstructed location
|
||||
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
|
||||
world!!.spawnEntity(entity)
|
||||
if (frame is PacketFrame) {
|
||||
if (packetsHandledThisTick > SWITCHING_CAPACITY) {
|
||||
PhysicalConnectivity.NETWORK_LOGGER.debug("{} reached capacity, delaying forwarding {}", this, frame)
|
||||
delayedPackets.addLast(frame to fromItf)
|
||||
return
|
||||
} else {
|
||||
itemsHandledThisTick += packet.stack.count
|
||||
packetsHandledThisTick++
|
||||
}
|
||||
}
|
||||
|
||||
resend(frame, fromItf)
|
||||
}
|
||||
|
||||
private fun resend(frame: EthernetFrame, fromItf: SwitchInterface) {
|
||||
if (frame.destination.type != MACAddress.Type.BROADCAST && macTable.containsKey(frame.destination)) {
|
||||
val dir = macTable[frame.destination]!!
|
||||
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) forwarding {} to side {}", this, fromItf.side, fromItf.macAddress, frame, dir)
|
||||
|
@ -75,11 +83,30 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
|||
}
|
||||
|
||||
override fun tick() {
|
||||
itemsHandledThisTick = 0
|
||||
packetsHandledThisTick = 0
|
||||
|
||||
while (delayedPackets.isNotEmpty() && packetsHandledThisTick <= SWITCHING_CAPACITY) {
|
||||
val (frame, fromItf) = delayedPackets.pop()
|
||||
resend(frame, fromItf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||
val list = ListTag()
|
||||
for ((frame, fromItf) in delayedPackets) {
|
||||
val packet = frame.packet
|
||||
if (packet !is ItemStackPacket) continue
|
||||
val compound = CompoundTag()
|
||||
compound.putInt("FromItfSide", fromItf.side.ordinal)
|
||||
compound.putInt("SourceIP", packet.source.address)
|
||||
compound.putInt("DestinationIP", packet.destination.address)
|
||||
compound.putLong("SourceMAC", frame.source.address)
|
||||
compound.putLong("DestinationMAC", frame.destination.address)
|
||||
compound.put("Stack", packet.stack.toTag(CompoundTag()))
|
||||
list.add(compound)
|
||||
}
|
||||
tag.put("DelayedStackPackets", list)
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
|
@ -88,6 +115,21 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
|||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
||||
interfaces[i].macAddress = MACAddress(l)
|
||||
}
|
||||
tag.getList("DelayedStackPackets", 10).forEach { it ->
|
||||
val compound = it as CompoundTag
|
||||
val fromItfSide = Direction.values()[compound.getInt("FromItfSide")]
|
||||
val fromItf = interfaces.find { it.side == fromItfSide }!!
|
||||
val sourceIP = IPAddress(compound.getInt("SourceIP"))
|
||||
val destinationIP = IPAddress(compound.getInt("DestinationIP"))
|
||||
val sourceMAC = MACAddress(compound.getLong("SourceMAC"))
|
||||
val destinationMAC = MACAddress(compound.getLong("DestinationMAC"))
|
||||
val stack = ItemStack.fromTag(compound.getCompound("Stack"))
|
||||
if (!stack.isEmpty) {
|
||||
val packet = ItemStackPacket(stack, sourceIP, destinationIP)
|
||||
val frame = BasePacketFrame(packet, sourceMAC, destinationMAC)
|
||||
delayedPackets.addLast(frame to fromItf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
|
|
|
@ -2,13 +2,20 @@ package net.shadowfacts.phycon.block.terminal
|
|||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.Properties
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.ItemScatterer
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
|
@ -18,7 +25,7 @@ import net.minecraft.world.WorldAccess
|
|||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import java.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -33,10 +40,22 @@ class TerminalBlock: DeviceBlock<TerminalBlockEntity>(
|
|||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||
val FACING = Properties.FACING
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
|
||||
return EnumSet.allOf(Direction::class.java)
|
||||
val set = EnumSet.allOf(Direction::class.java)
|
||||
set.remove(state[FACING])
|
||||
return set
|
||||
}
|
||||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
super.appendProperties(builder)
|
||||
builder.add(FACING)
|
||||
}
|
||||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
return defaultState.with(FACING, context.playerLookDirection.opposite)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = TerminalBlockEntity()
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package net.shadowfacts.phycon.client
|
||||
|
||||
import net.fabricmc.fabric.api.client.model.ModelProviderContext
|
||||
import net.fabricmc.fabric.api.client.model.ModelResourceProvider
|
||||
import net.minecraft.client.render.model.UnbakedModel
|
||||
import net.minecraft.resource.ResourceManager
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.client.model.RedstoneControllerModel
|
||||
import net.shadowfacts.phycon.client.model.SimpleFaceDeviceModel
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider {
|
||||
companion object {
|
||||
val INTERFACE = Identifier(PhysicalConnectivity.MODID, "block/network_interface")
|
||||
val INTERFACE_SIDE = Identifier(PhysicalConnectivity.MODID, "block/interface_side")
|
||||
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")
|
||||
}
|
||||
|
||||
override fun loadModelResource(resourceId: Identifier, context: ModelProviderContext): UnbakedModel? {
|
||||
return when (resourceId) {
|
||||
INTERFACE -> SimpleFaceDeviceModel(INTERFACE_SIDE)
|
||||
REDSTONE_CONTROLLER -> RedstoneControllerModel
|
||||
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
package net.shadowfacts.phycon.client.model
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.client.render.model.*
|
||||
import net.minecraft.client.texture.Sprite
|
||||
import net.minecraft.client.util.SpriteIdentifier
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock.FaceCableConnection
|
||||
import java.util.Random
|
||||
import java.util.function.Function
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class FaceDeviceModel: UnbakedModel, BakedModel {
|
||||
|
||||
private val interfaceCableStraightID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_straight")
|
||||
private val interfaceCableCornerID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner")
|
||||
private val interfaceCableCorner2ID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner_2")
|
||||
private val interfaceCableCapID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_cap")
|
||||
private var interfaceCableStraight = Array<BakedModel?>(6) { null }
|
||||
private var interfaceCableCap = Array<BakedModel?>(6) { null }
|
||||
private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>()
|
||||
private var interfaceCableCorner2 = mutableMapOf<ModelRotation, BakedModel>()
|
||||
|
||||
protected val defaultRotations = listOf(
|
||||
ModelRotation.X0_Y0,
|
||||
ModelRotation.X180_Y0,
|
||||
ModelRotation.X270_Y0,
|
||||
ModelRotation.X90_Y0,
|
||||
ModelRotation.X90_Y90,
|
||||
ModelRotation.X90_Y270,
|
||||
)
|
||||
|
||||
abstract fun getSideModelIDs(): Collection<Identifier>
|
||||
abstract fun bakeSideModels(loader: ModelLoader)
|
||||
abstract fun getSideModel(state: BlockState): BakedModel?
|
||||
|
||||
override fun getModelDependencies(): Collection<Identifier> {
|
||||
return getSideModelIDs() + listOf(
|
||||
interfaceCableStraightID,
|
||||
interfaceCableCornerID,
|
||||
interfaceCableCorner2ID,
|
||||
interfaceCableCapID
|
||||
)
|
||||
}
|
||||
|
||||
override fun getTextureDependencies(
|
||||
unbakedModelGetter: Function<Identifier, UnbakedModel>,
|
||||
unresolvedTextureReferences: MutableSet<com.mojang.datafixers.util.Pair<String, String>>
|
||||
): Collection<SpriteIdentifier> {
|
||||
return modelDependencies.map(unbakedModelGetter::apply).flatMap { it.getTextureDependencies(unbakedModelGetter, unresolvedTextureReferences) }
|
||||
}
|
||||
|
||||
override fun bake(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>, rotationContainer: ModelBakeSettings, modelId: Identifier): BakedModel {
|
||||
bakeSideModels(loader)
|
||||
|
||||
defaultRotations.forEachIndexed { i, rot ->
|
||||
interfaceCableStraight[i] = loader.bake(interfaceCableStraightID, rot)
|
||||
interfaceCableCap[i] = loader.bake(interfaceCableCapID, rot)
|
||||
}
|
||||
|
||||
mapOf(
|
||||
interfaceCableCorner to interfaceCableCornerID to ModelRotation.values().toList(),
|
||||
interfaceCableCorner2 to interfaceCableCorner2ID to listOf(
|
||||
ModelRotation.X0_Y0,
|
||||
ModelRotation.X0_Y90,
|
||||
ModelRotation.X0_Y180,
|
||||
ModelRotation.X0_Y270,
|
||||
ModelRotation.X180_Y0,
|
||||
ModelRotation.X180_Y90,
|
||||
ModelRotation.X180_Y180,
|
||||
ModelRotation.X180_Y270,
|
||||
),
|
||||
).forEach { (k, rotations) ->
|
||||
val (map, id) = k
|
||||
map.clear()
|
||||
rotations.forEach { rot ->
|
||||
val model = loader.bake(id, rot)
|
||||
if (model == null) map.remove(rot)
|
||||
else map[rot] = model
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getQuads(state: BlockState?, face: Direction?, random: Random): List<BakedQuad> {
|
||||
if (state == null) return listOf()
|
||||
val facing = state[FaceDeviceBlock.FACING]
|
||||
val connection = state[FaceDeviceBlock.CABLE_CONNECTION]
|
||||
|
||||
val sideQuads = getSideModel(state)?.getQuads(state, face, random) ?: listOf()
|
||||
val cableQuads = if (connection.direction == facing.opposite) {
|
||||
interfaceCableStraight[facing.ordinal]?.getQuads(state, face, random) ?: listOf()
|
||||
} else if (connection == FaceCableConnection.NONE) {
|
||||
interfaceCableCap[facing.ordinal]?.getQuads(state, face, random) ?: listOf()
|
||||
} else {
|
||||
val model = when (facing) {
|
||||
Direction.DOWN -> when (connection) {
|
||||
FaceCableConnection.NORTH -> interfaceCableCorner[ModelRotation.X0_Y0]
|
||||
FaceCableConnection.EAST -> interfaceCableCorner[ModelRotation.X0_Y90]
|
||||
FaceCableConnection.SOUTH -> interfaceCableCorner[ModelRotation.X0_Y180]
|
||||
FaceCableConnection.WEST -> interfaceCableCorner[ModelRotation.X0_Y270]
|
||||
else -> null
|
||||
}
|
||||
Direction.UP -> when (connection) {
|
||||
FaceCableConnection.NORTH -> interfaceCableCorner[ModelRotation.X180_Y180]
|
||||
FaceCableConnection.EAST -> interfaceCableCorner[ModelRotation.X180_Y270]
|
||||
FaceCableConnection.SOUTH -> interfaceCableCorner[ModelRotation.X180_Y0]
|
||||
FaceCableConnection.WEST -> interfaceCableCorner[ModelRotation.X180_Y90]
|
||||
else -> null
|
||||
}
|
||||
Direction.NORTH -> when (connection) {
|
||||
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y0]
|
||||
FaceCableConnection.EAST -> interfaceCableCorner2[ModelRotation.X180_Y180]
|
||||
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y180]
|
||||
FaceCableConnection.WEST -> interfaceCableCorner2[ModelRotation.X0_Y0]
|
||||
else -> null
|
||||
}
|
||||
Direction.SOUTH -> when (connection) {
|
||||
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y180]
|
||||
FaceCableConnection.WEST -> interfaceCableCorner2[ModelRotation.X180_Y0]
|
||||
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y0]
|
||||
FaceCableConnection.EAST -> interfaceCableCorner2[ModelRotation.X0_Y180]
|
||||
else -> null
|
||||
}
|
||||
Direction.WEST -> when (connection) {
|
||||
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y270]
|
||||
FaceCableConnection.NORTH -> interfaceCableCorner2[ModelRotation.X180_Y90]
|
||||
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y90]
|
||||
FaceCableConnection.SOUTH -> interfaceCableCorner2[ModelRotation.X0_Y270]
|
||||
else -> null
|
||||
}
|
||||
Direction.EAST -> when (connection) {
|
||||
FaceCableConnection.UP -> interfaceCableCorner[ModelRotation.X270_Y90]
|
||||
FaceCableConnection.SOUTH -> interfaceCableCorner2[ModelRotation.X180_Y270]
|
||||
FaceCableConnection.DOWN -> interfaceCableCorner[ModelRotation.X90_Y270]
|
||||
FaceCableConnection.NORTH -> interfaceCableCorner2[ModelRotation.X0_Y90]
|
||||
else -> null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
model?.getQuads(state, face, random) ?: listOf()
|
||||
}
|
||||
|
||||
return sideQuads + cableQuads
|
||||
}
|
||||
|
||||
override fun useAmbientOcclusion() = true
|
||||
|
||||
override fun hasDepth() = false
|
||||
|
||||
override fun isSideLit() = false
|
||||
|
||||
override fun isBuiltin() = false
|
||||
|
||||
abstract override fun getSprite(): Sprite
|
||||
|
||||
override fun getTransformation() = null
|
||||
|
||||
override fun getOverrides() = null
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package net.shadowfacts.phycon.client.model
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.client.render.model.BakedModel
|
||||
import net.minecraft.client.render.model.ModelLoader
|
||||
import net.minecraft.client.texture.Sprite
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object RedstoneControllerModel: FaceDeviceModel() {
|
||||
|
||||
private val ON = Identifier(PhysicalConnectivity.MODID, "block/redstone_controller_side_on")
|
||||
private val OFF = Identifier(PhysicalConnectivity.MODID, "block/redstone_controller_side_off")
|
||||
private val onModels = Array<BakedModel?>(6) { null }
|
||||
private val offModels = Array<BakedModel?>(6) { null }
|
||||
|
||||
override fun getSideModelIDs(): Collection<Identifier> {
|
||||
return listOf(ON, OFF)
|
||||
}
|
||||
|
||||
override fun bakeSideModels(loader: ModelLoader) {
|
||||
defaultRotations.forEachIndexed { i, rot ->
|
||||
onModels[i] = loader.bake(ON, rot)
|
||||
offModels[i] = loader.bake(OFF, rot)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSideModel(state: BlockState): BakedModel? {
|
||||
return if (state[RedstoneControllerBlock.POWERED]) {
|
||||
onModels[state[FaceDeviceBlock.FACING].ordinal]
|
||||
} else {
|
||||
offModels[state[FaceDeviceBlock.FACING].ordinal]
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSprite(): Sprite {
|
||||
return offModels.first()!!.sprite
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package net.shadowfacts.phycon.client.model
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.client.render.model.BakedModel
|
||||
import net.minecraft.client.render.model.ModelLoader
|
||||
import net.minecraft.client.texture.Sprite
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class SimpleFaceDeviceModel(
|
||||
private val sideModelID: Identifier,
|
||||
): FaceDeviceModel() {
|
||||
private val sideModels = Array<BakedModel?>(6) { null }
|
||||
|
||||
override fun getSideModelIDs(): Collection<Identifier> {
|
||||
return listOf(sideModelID)
|
||||
}
|
||||
|
||||
override fun bakeSideModels(loader: ModelLoader) {
|
||||
defaultRotations.forEachIndexed { i, rot ->
|
||||
sideModels[i] = loader.bake(sideModelID, rot)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSideModel(state: BlockState): BakedModel? {
|
||||
return sideModels[state[FaceDeviceBlock.FACING].ordinal]
|
||||
}
|
||||
|
||||
override fun getSprite(): Sprite {
|
||||
return sideModels.first()!!.sprite
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import net.minecraft.item.BlockItem
|
|||
import net.minecraft.item.Item
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.item.ConsoleItem
|
||||
import net.shadowfacts.phycon.item.ScrewdriverItem
|
||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||
|
@ -34,6 +35,7 @@ object PhyItems {
|
|||
|
||||
val SCREWDRIVER = ScrewdriverItem()
|
||||
val CONSOLE = ConsoleItem()
|
||||
val TWISTED_PAIR = Item(Item.Settings())
|
||||
|
||||
fun init() {
|
||||
register(InterfaceBlock.ID, INTERFACE)
|
||||
|
@ -48,6 +50,7 @@ object PhyItems {
|
|||
|
||||
register(ScrewdriverItem.ID, SCREWDRIVER)
|
||||
register(ConsoleItem.ID, CONSOLE)
|
||||
register(Identifier(PhysicalConnectivity.MODID, "twisted_pair"), TWISTED_PAIR)
|
||||
}
|
||||
|
||||
private fun register(id: Identifier, item: Item) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import net.minecraft.util.ActionResult
|
|||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -35,6 +36,11 @@ class ScrewdriverItem: Item(Settings()) {
|
|||
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)
|
||||
|
||||
|
|
|
@ -3,11 +3,16 @@ package net.shadowfacts.phycon.screen.console
|
|||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.text.TranslatableText
|
||||
import net.shadowfacts.cacao.geometry.Axis
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.StackView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.cacao.view.button.ToggleButton
|
||||
import net.shadowfacts.cacao.view.textfield.NumberField
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
|
@ -18,6 +23,9 @@ class ProviderViewController<T>(
|
|||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackProvider {
|
||||
|
||||
private lateinit var field: NumberField
|
||||
private var syncButton: ToggleButton? = null
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
@ -26,9 +34,14 @@ class ProviderViewController<T>(
|
|||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.providerPriority) {
|
||||
field = NumberField(device.providerPriority) {
|
||||
if (it.number != null) {
|
||||
device.providerPriority = it.number!!
|
||||
|
||||
if (device is InterfaceBlockEntity && device.syncPriorities) {
|
||||
device.receiverPriority = it.number!!
|
||||
}
|
||||
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +52,30 @@ class ProviderViewController<T>(
|
|||
}
|
||||
view.addSubview(desc)
|
||||
|
||||
if (device is InterfaceBlockEntity) {
|
||||
val syncLabel = Label(TranslatableText("gui.phycon.console.provider.sync")).apply {
|
||||
textColor = Color.TEXT
|
||||
textAlignment = Label.TextAlignment.RIGHT
|
||||
}
|
||||
view.addSubview(syncLabel)
|
||||
|
||||
val syncButton = ToggleButton(device.syncPriorities) {
|
||||
device.syncPriorities = it.state
|
||||
device.receiverPriority = device.providerPriority
|
||||
}
|
||||
this.syncButton = syncButton
|
||||
view.addSubview(syncButton)
|
||||
|
||||
view.solver.dsl {
|
||||
syncButton.topAnchor equalTo (desc.bottomAnchor + 4)
|
||||
syncButton.leftAnchor equalTo field.leftAnchor
|
||||
|
||||
syncLabel.centerYAnchor equalTo syncButton.centerYAnchor
|
||||
syncLabel.leftAnchor equalTo view.leftAnchor
|
||||
syncLabel.rightAnchor equalTo (syncButton.leftAnchor - 4)
|
||||
}
|
||||
}
|
||||
|
||||
view.solver.dsl {
|
||||
field.widthAnchor equalTo 100
|
||||
field.heightAnchor equalTo 20
|
||||
|
@ -54,4 +91,13 @@ class ProviderViewController<T>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
|
||||
field.number = device.providerPriority
|
||||
if (device is InterfaceBlockEntity) {
|
||||
syncButton!!.state = device.syncPriorities
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ import net.minecraft.client.MinecraftClient
|
|||
import net.minecraft.text.TranslatableText
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.button.ToggleButton
|
||||
import net.shadowfacts.cacao.view.textfield.NumberField
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
|
@ -18,6 +20,9 @@ class ReceiverViewController<T>(
|
|||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackReceiver {
|
||||
|
||||
private lateinit var field: NumberField
|
||||
private var syncButton: ToggleButton? = null
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
@ -26,9 +31,14 @@ class ReceiverViewController<T>(
|
|||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.receiverPriority) {
|
||||
field = NumberField(device.receiverPriority) {
|
||||
if (it.number != null) {
|
||||
device.receiverPriority = it.number!!
|
||||
|
||||
if (device is InterfaceBlockEntity && device.syncPriorities) {
|
||||
device.providerPriority = it.number!!
|
||||
}
|
||||
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +49,30 @@ class ReceiverViewController<T>(
|
|||
}
|
||||
view.addSubview(desc)
|
||||
|
||||
if (device is InterfaceBlockEntity) {
|
||||
val syncLabel = Label(TranslatableText("gui.phycon.console.receiver.sync")).apply {
|
||||
textColor = Color.TEXT
|
||||
textAlignment = Label.TextAlignment.RIGHT
|
||||
}
|
||||
view.addSubview(syncLabel)
|
||||
|
||||
val syncButton = ToggleButton(device.syncPriorities) {
|
||||
device.syncPriorities = it.state
|
||||
device.providerPriority = device.receiverPriority
|
||||
}
|
||||
this.syncButton = syncButton
|
||||
view.addSubview(syncButton)
|
||||
|
||||
view.solver.dsl {
|
||||
syncButton.topAnchor equalTo (desc.bottomAnchor + 4)
|
||||
syncButton.leftAnchor equalTo field.leftAnchor
|
||||
|
||||
syncLabel.centerYAnchor equalTo syncButton.centerYAnchor
|
||||
syncLabel.leftAnchor equalTo view.leftAnchor
|
||||
syncLabel.rightAnchor equalTo (syncButton.leftAnchor - 4)
|
||||
}
|
||||
}
|
||||
|
||||
view.solver.dsl {
|
||||
field.widthAnchor equalTo 100
|
||||
field.heightAnchor equalTo 20
|
||||
|
@ -54,4 +88,13 @@ class ReceiverViewController<T>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
|
||||
field.number = device.receiverPriority
|
||||
if (device is InterfaceBlockEntity) {
|
||||
syncButton!!.state = device.syncPriorities
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,159 +1,8 @@
|
|||
{
|
||||
"multipart": [
|
||||
{
|
||||
"apply": { "model": "phycon:block/cable_center" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "down" },
|
||||
"apply": { "model": "phycon:block/interface_side" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "up" },
|
||||
"apply": { "model": "phycon:block/interface_side", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "north" },
|
||||
"apply": { "model": "phycon:block/interface_side", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "south" },
|
||||
"apply": { "model": "phycon:block/interface_side", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "west" },
|
||||
"apply": { "model": "phycon:block/interface_side", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "east" },
|
||||
"apply": { "model": "phycon:block/interface_side", "x": 90, "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": { "cable_connection": "up", "facing": "down" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight" }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "down", "facing": "up" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "north", "facing": "south" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "south", "facing": "north" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "west", "facing": "east" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "east", "facing": "west" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 90 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 90 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 180 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 180 }
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"when": {"cable_connection": "down", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 270 }
|
||||
"_comment": "see SimpleFaceDeviceModel",
|
||||
"apply": { "model": "phycon:block/network_interface" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,183 +1,8 @@
|
|||
{
|
||||
"multipart": [
|
||||
{
|
||||
"apply": { "model": "phycon:block/cable_center" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "down", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "up", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "north", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "south", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "west", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "east", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "down", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "up", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "north", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "south", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "west", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "east", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90, "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": { "cable_connection": "up", "facing": "down" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight" }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "down", "facing": "up" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "north", "facing": "south" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "south", "facing": "north" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "west", "facing": "east" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "east", "facing": "west" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 90 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 90 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 180 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 180 }
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"when": {"cable_connection": "down", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 270 }
|
||||
"_comment": "see RedstoneControllerModel",
|
||||
"apply": { "model": "phycon:block/redstone_controller" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,159 +1,7 @@
|
|||
{
|
||||
"multipart": [
|
||||
{
|
||||
"apply": { "model": "phycon:block/cable_center" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "down" },
|
||||
"apply": { "model": "phycon:block/redstone_emitter_side" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "up" },
|
||||
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "north" },
|
||||
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "south" },
|
||||
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "west" },
|
||||
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "east" },
|
||||
"apply": { "model": "phycon:block/redstone_emitter_side", "x": 90, "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": { "cable_connection": "up", "facing": "down" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight" }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "down", "facing": "up" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "north", "facing": "south" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "south", "facing": "north" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "west", "facing": "east" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "cable_connection": "east", "facing": "west" },
|
||||
"apply": { "model": "phycon:block/interface_cable_straight", "x": 90, "y": 90 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "down"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "up"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 180, "y": 90 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "north"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 180 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 180 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "west", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3" }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "east", "facing": "south"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 180 }
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"when": {"cable_connection": "down", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "west"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_3", "x": 180, "y": 270 }
|
||||
},
|
||||
|
||||
{
|
||||
"when": {"cable_connection": "down", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "up", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner", "x": 270, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "north", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": {"cable_connection": "south", "facing": "east"},
|
||||
"apply": { "model": "phycon:block/interface_cable_corner_2", "x": 180, "y": 270 }
|
||||
"apply": { "model": "phycon:block/redstone_emitter" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
"item.phycon.screwdriver": "Screwdriver",
|
||||
"item.phycon.console": "Console",
|
||||
"item.phycon.twisted_pair": "Twisted Pair",
|
||||
|
||||
"gui.phycon.terminal_buffer": "Buffer",
|
||||
"gui.phycon.console.details": "Device Details",
|
||||
|
@ -24,9 +25,11 @@
|
|||
"gui.phycon.console.provider": "Item Provider",
|
||||
"gui.phycon.console.provider.priority": "Provider Priority",
|
||||
"gui.phycon.console.provider.priority_desc": "When a device requests items from the network, it send requests to providers (e.g., interfaces) with higher priorities first. Priorities can be negative.",
|
||||
"gui.phycon.console.provider.sync": "Sync with Receiver Priority",
|
||||
"gui.phycon.console.receiver": "Item Receiver",
|
||||
"gui.phycon.console.receiver.priority": "Receiver Priority",
|
||||
"gui.phycon.console.receiver.priority_desc": "When a device puts items into the network, it starts with receiver (e.g., interfaces) with higher priorities. Priorities can be negative.",
|
||||
"gui.phycon.console.receiver.sync": "Sync with Provider Priority",
|
||||
"gui.phycon.redstone_mode.high": "High",
|
||||
"gui.phycon.redstone_mode.low": "Low",
|
||||
"gui.phycon.redstone_mode.toggle": "Toggle",
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"textures": {
|
||||
"cap": "phycon:block/cable_cap_end",
|
||||
"straight": "phycon:block/cable_straight"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [6, 6, 6],
|
||||
"to": [10, 9, 10],
|
||||
"faces": {
|
||||
"north": {"texture": "#straight"},
|
||||
"south": {"texture": "#straight"},
|
||||
"west": {"texture": "#straight"},
|
||||
"east": {"texture": "#straight"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 9, 6],
|
||||
"to": [10, 10, 10],
|
||||
"faces": {
|
||||
"up": {"texture": "#cap"},
|
||||
"north": {"texture": "#cap"},
|
||||
"south": {"texture": "#cap"},
|
||||
"west": {"texture": "#cap"},
|
||||
"east": {"texture": "#cap"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"textures": {
|
||||
"straight": "phycon:block/cable_straight_rotated",
|
||||
"cap": "phycon:block/cable_cap_end",
|
||||
"corner_down": "phycon:block/interface_cable_corner_l_up",
|
||||
"corner_up": "phycon:block/interface_cable_corner_r"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 6, 6],
|
||||
"to": [10, 10, 10],
|
||||
"faces": {
|
||||
"down": {"texture": "#corner_down"},
|
||||
"up": {"texture": "#corner_up"},
|
||||
"north": {"texture": "#straight"},
|
||||
"south": {"texture": "#straight"},
|
||||
"west": {"texture": "#cap", "cullface": "west"},
|
||||
"east": {"texture": "#straight"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -4,7 +4,8 @@
|
|||
"cable": "phycon:block/cable_straight",
|
||||
"front": "phycon:block/redstone_controller_front_off",
|
||||
"back": "phycon:block/redstone_controller_back",
|
||||
"side": "phycon:block/redstone_controller_back"
|
||||
"side": "phycon:block/redstone_controller_back",
|
||||
"particle": "#front"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
"cable": "phycon:block/cable_straight",
|
||||
"front": "phycon:block/redstone_controller_front_on",
|
||||
"back": "phycon:block/redstone_controller_back",
|
||||
"side": "phycon:block/redstone_controller_back"
|
||||
"side": "phycon:block/redstone_controller_back",
|
||||
"particle": "#front"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "phycon:item/twisted_pair"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 709 B |
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"phycon:cable"
|
||||
]
|
||||
},
|
||||
"criteria": {
|
||||
"has_twisted_pair": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"item": "phycon:twisted_pair"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"trigger": "minecraft:recipe_unlocked",
|
||||
"conditions": {
|
||||
"recipe": "phycon:cable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"has_twisted_pair",
|
||||
"has_the_recipe"
|
||||
]
|
||||
]
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"phycon:twisted_pair"
|
||||
]
|
||||
},
|
||||
"criteria": {
|
||||
"has_copper_nuggets": {
|
||||
"trigger": "minecraft:inventory_changed",
|
||||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"tag": "c:copper_nuggets"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"trigger": "minecraft:recipe_unlocked",
|
||||
"conditions": {
|
||||
"recipe": "phycon:twisted_pair"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"has_copper_nuggets",
|
||||
"has_the_recipe"
|
||||
]
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"CCC",
|
||||
"TRT",
|
||||
"CCC"
|
||||
],
|
||||
"key": {
|
||||
"C": {"tag": "minecraft:carpets"},
|
||||
"T": {"item": "phycon:twisted_pair"},
|
||||
"R": {"item": "minecraft:redstone"}
|
||||
},
|
||||
"result": {
|
||||
"item": "phycon:cable",
|
||||
"count": 3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"pattern": [
|
||||
"NNN",
|
||||
" ",
|
||||
"NNN"
|
||||
],
|
||||
"key": {
|
||||
"N": {"tag": "c:copper_nuggets"}
|
||||
},
|
||||
"result": {
|
||||
"item": "phycon:twisted_pair"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue