Compare commits
21 Commits
2c19b8456b
...
385e36918f
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 385e36918f | |
Shadowfacts | 8dbccc541e | |
Shadowfacts | 868b0d42f9 | |
Shadowfacts | 170e50755a | |
Shadowfacts | 2d3ac4538d | |
Shadowfacts | 5b314120a7 | |
Shadowfacts | ca090d0924 | |
Shadowfacts | 2958fa295a | |
Shadowfacts | 3cd4a7aa0d | |
Shadowfacts | 4fe6391e69 | |
Shadowfacts | e2fa31b680 | |
Shadowfacts | 9aa1077977 | |
Shadowfacts | c976c3f607 | |
Shadowfacts | e4e8dde2fb | |
Shadowfacts | ccefb8ae2f | |
Shadowfacts | 4c2148b30f | |
Shadowfacts | f5268aef51 | |
Shadowfacts | 2084a749fb | |
Shadowfacts | e13154943e | |
Shadowfacts | 9b4fc548e5 | |
Shadowfacts | a8f0387577 |
|
@ -3,7 +3,7 @@ package net.shadowfacts.phycon.mixin.client;
|
|||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreen;
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreen;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
|
|
|
@ -7,6 +7,7 @@ import net.minecraft.screen.ScreenHandler
|
|||
import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.text.Text
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.util.KeyModifiers
|
||||
import net.shadowfacts.cacao.util.MouseButton
|
||||
import net.shadowfacts.cacao.util.RenderHelper
|
||||
import net.shadowfacts.cacao.window.ScreenHandlerWindow
|
||||
|
@ -16,7 +17,7 @@ import java.util.*
|
|||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||
open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||
handler: Handler,
|
||||
playerInv: PlayerInventory,
|
||||
title: Text,
|
||||
|
@ -57,15 +58,16 @@ class CacaoHandledScreen<Handler: ScreenHandler>(
|
|||
}
|
||||
|
||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||
renderBackground(matrixStack)
|
||||
}
|
||||
|
||||
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
renderBackground(matrixStack)
|
||||
|
||||
val mouse = Point(mouseX, mouseY)
|
||||
windows.forEachIndexed { index, it ->
|
||||
it.draw(matrixStack, mouse, delta)
|
||||
if (it is ScreenHandlerWindow) {
|
||||
if (index == windows.size - 1) {
|
||||
super.render(matrixStack, mouseX, mouseY, delta)
|
||||
|
@ -74,7 +76,10 @@ class CacaoHandledScreen<Handler: ScreenHandler>(
|
|||
super.render(matrixStack, -1, -1, delta)
|
||||
}
|
||||
}
|
||||
it.draw(matrixStack, mouse, delta)
|
||||
}
|
||||
|
||||
drawMouseoverTooltip(matrixStack, mouseX, mouseY)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
|
@ -90,4 +95,20 @@ class CacaoHandledScreen<Handler: ScreenHandler>(
|
|||
}
|
||||
}
|
||||
|
||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||
val modifiersSet by lazy { KeyModifiers(modifiers) }
|
||||
if (findResponder { it.keyPressed(keyCode, modifiersSet) }) {
|
||||
return true
|
||||
}
|
||||
return super.keyPressed(keyCode, scanCode, modifiers)
|
||||
}
|
||||
|
||||
override fun charTyped(char: Char, modifiers: Int): Boolean {
|
||||
val modifiersSet by lazy { KeyModifiers(modifiers) }
|
||||
if (findResponder { it.charTyped(char, modifiersSet) }) {
|
||||
return true
|
||||
}
|
||||
return super.charTyped(char, modifiers)
|
||||
}
|
||||
|
||||
}
|
|
@ -139,15 +139,15 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
|
|||
return super.charTyped(char, modifiers)
|
||||
}
|
||||
|
||||
private fun findResponder(fn: (Responder) -> Boolean): Boolean {
|
||||
var responder = windows.lastOrNull()?.firstResponder
|
||||
while (responder != null) {
|
||||
if (fn(responder)) {
|
||||
return true
|
||||
}
|
||||
responder = responder.nextResponder
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun AbstractCacaoScreen.findResponder(fn: (Responder) -> Boolean): Boolean {
|
||||
var responder = windows.lastOrNull()?.firstResponder
|
||||
while (responder != null) {
|
||||
if (fn(responder)) {
|
||||
return true
|
||||
}
|
||||
responder = responder.nextResponder
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ data class Color(val red: Int, val green: Int, val blue: Int, val alpha: Int = 2
|
|||
val RED = Color(0xff0000)
|
||||
val GREEN = Color(0x00ff00)
|
||||
val BLUE = Color(0x0000ff)
|
||||
val MAGENTA = Color(0xfc46e4)
|
||||
|
||||
val TEXT = Color(0x404040)
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ class Label(
|
|||
for (i in 0 until lines.size) {
|
||||
val x = when (textAlignment) {
|
||||
TextAlignment.LEFT -> 0.0
|
||||
TextAlignment.CENTER -> (bounds.width + textRenderer.getWidth(lines[i])) / 2
|
||||
TextAlignment.CENTER -> (bounds.width - textRenderer.getWidth(lines[i])) / 2
|
||||
TextAlignment.RIGHT -> bounds.width - textRenderer.getWidth(lines[i])
|
||||
}
|
||||
val y = i * textRenderer.fontHeight
|
||||
|
|
|
@ -6,6 +6,7 @@ import net.shadowfacts.cacao.geometry.Axis
|
|||
import net.shadowfacts.cacao.geometry.AxisPosition
|
||||
import net.shadowfacts.cacao.geometry.AxisPosition.*
|
||||
import no.birkett.kiwi.Constraint
|
||||
import java.lang.RuntimeException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
@ -18,6 +19,7 @@ import java.util.*
|
|||
* @param axis The primary axis that this stack lays out its children along.
|
||||
* @param distribution The mode by which this stack lays out its children along the axis perpendicular to the
|
||||
* primary [axis].
|
||||
* @param spacing The distance between arranged subviews along the primary axis.
|
||||
*/
|
||||
open class StackView(
|
||||
val axis: Axis,
|
||||
|
@ -25,7 +27,7 @@ open class StackView(
|
|||
val spacing: Double = 0.0
|
||||
): View() {
|
||||
|
||||
// the internal mutable, list of arranged subviews
|
||||
// the internal, mutable list of arranged subviews
|
||||
private val _arrangedSubviews = LinkedList<View>()
|
||||
/**
|
||||
* The list of arranged subviews belonging to this stack view.
|
||||
|
@ -57,6 +59,64 @@ open class StackView(
|
|||
return view
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given arranged subview from this stack view's arranged subviews.
|
||||
*/
|
||||
fun removeArrangedSubview(view: View) {
|
||||
val index = arrangedSubviews.indexOf(view)
|
||||
if (index < 0) {
|
||||
throw RuntimeException("Cannot remove view that is not arranged subview")
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
solver.removeConstraint(leadingConnection)
|
||||
val next = arrangedSubviews.getOrNull(1)
|
||||
if (next != null) {
|
||||
solver.dsl {
|
||||
leadingConnection = anchor(LEADING) equalTo anchor(LEADING, next)
|
||||
}
|
||||
} else {
|
||||
leadingConnection = null
|
||||
}
|
||||
}
|
||||
if (index == arrangedSubviews.size - 1) {
|
||||
solver.removeConstraint(trailingConnection)
|
||||
val prev = arrangedSubviews.getOrNull(arrangedSubviews.size - 2)
|
||||
if (prev != null) {
|
||||
solver.dsl {
|
||||
trailingConnection = anchor(TRAILING) equalTo anchor(TRAILING, prev)
|
||||
}
|
||||
} else {
|
||||
trailingConnection = null
|
||||
}
|
||||
}
|
||||
|
||||
// if the removed view is in the middle
|
||||
if (arrangedSubviews.size >= 3 && index > 0 && index < arrangedSubviews.size - 1) {
|
||||
val prev = arrangedSubviews[index - 1]
|
||||
val next = arrangedSubviews[index + 1]
|
||||
solver.dsl {
|
||||
solver.removeConstraint(arrangedSubviewConnections[index - 1])
|
||||
solver.removeConstraint(arrangedSubviewConnections[index])
|
||||
|
||||
// todo: double check me
|
||||
arrangedSubviewConnections[index - 1] = anchor(TRAILING, prev) equalTo anchor(LEADING, next)
|
||||
arrangedSubviewConnections.removeAt(index)
|
||||
}
|
||||
}
|
||||
|
||||
_arrangedSubviews.remove(view)
|
||||
removeSubview(view)
|
||||
}
|
||||
|
||||
override fun removeSubview(view: View) {
|
||||
if (arrangedSubviews.contains(view)) {
|
||||
removeArrangedSubview(view)
|
||||
} else {
|
||||
super.removeSubview(view)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addConstraintsForArrangedView(view: View, index: Int) {
|
||||
if (index == 0) {
|
||||
if (leadingConnection != null) {
|
||||
|
|
|
@ -197,10 +197,13 @@ open class View(): Responder {
|
|||
* its children (recursively) to a view outside of the subview's hierarchy. Constraints internal to the subview's
|
||||
* hierarchy (e.g., one between the subview and its child) will be left in place.
|
||||
*
|
||||
* This method may be overridden by layout-providing views (such as [StackView]) to update its layout when a managed
|
||||
* subview is removed.
|
||||
*
|
||||
* @param view The view to removed as a child of this view.
|
||||
* @throws RuntimeException If the given [view] is not a subview of this view.
|
||||
*/
|
||||
fun removeSubview(view: View) {
|
||||
open fun removeSubview(view: View) {
|
||||
if (view.superview !== this) {
|
||||
throw RuntimeException("Cannot remove subview whose superview is not this view")
|
||||
}
|
||||
|
|
|
@ -62,12 +62,22 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
|||
minecraftWidget.setMaxLength(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the Minecraft builtin black background and border are drawn. Defaults to true.
|
||||
*/
|
||||
var drawBackground = true
|
||||
set(value) {
|
||||
field = value
|
||||
minecraftWidget.setHasBorder(value)
|
||||
}
|
||||
|
||||
private lateinit var originInWindow: Point
|
||||
private var minecraftWidget = ProxyWidget()
|
||||
|
||||
init {
|
||||
minecraftWidget.text = initialText
|
||||
minecraftWidget.setTextPredicate { this.validate(it) }
|
||||
minecraftWidget.setHasBorder(drawBackground)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package net.shadowfacts.cacao.view.textfield
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class NumberField(
|
||||
initialValue: Int,
|
||||
handler: ((NumberField) -> Unit)? = null,
|
||||
): AbstractTextField<NumberField>(initialValue.toString()) {
|
||||
|
||||
var number: Int?
|
||||
get() {
|
||||
return if (isTextTemporarilyAllowed(text)) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
Integer.parseInt(text)
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
set(value) {
|
||||
text = value?.toString() ?: ""
|
||||
}
|
||||
|
||||
var validator: ((Int) -> Boolean)? = null
|
||||
|
||||
init {
|
||||
this.handler = handler
|
||||
}
|
||||
|
||||
override fun validate(proposedText: String): Boolean {
|
||||
return isTextTemporarilyAllowed(proposedText) || try {
|
||||
val value = Integer.parseInt(proposedText)
|
||||
validator?.invoke(value) ?: true
|
||||
} catch (e: NumberFormatException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun isTextTemporarilyAllowed(s: String): Boolean {
|
||||
return s.isEmpty() || s == "-"
|
||||
}
|
||||
|
||||
}
|
|
@ -61,6 +61,13 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
* may be reused or created from scratch each time.
|
||||
*/
|
||||
val controller: ViewController
|
||||
|
||||
/**
|
||||
* Used by the tab view controller to determine whether the button for this tab should be displayed.
|
||||
* If the conditions that control this change, call [TabViewController.visibleTabsChanged].
|
||||
*/
|
||||
val isVisible: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,12 +75,17 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
* @param tabView The view to display on the tab's button.
|
||||
* @param tooltip The tooltip to display when the tab's button is hovered (or `null`, if none).
|
||||
* @param controller The content view controller for this tab.
|
||||
* @param visible A function that determines if the tab should currently be visible.
|
||||
*/
|
||||
class SimpleTab(
|
||||
override val tabView: View,
|
||||
override val tooltip: Text? = null,
|
||||
override val controller: ViewController,
|
||||
): Tab
|
||||
private val visible: (() -> Boolean)? = null
|
||||
): Tab {
|
||||
override val isVisible: Boolean
|
||||
get() = visible?.invoke() ?: true
|
||||
}
|
||||
|
||||
/**
|
||||
* The currently selected tab.
|
||||
|
@ -100,20 +112,7 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
tabStack = StackView(Axis.HORIZONTAL, StackView.Distribution.FILL)
|
||||
tabStack.zIndex = 1.0
|
||||
outerStack.addArrangedSubview(tabStack)
|
||||
|
||||
tabButtons = tabs.mapIndexed { index, tab ->
|
||||
val btn = TabButton(tab)
|
||||
btn.handler = { selectTab(it.tab) }
|
||||
if (tab == currentTab) {
|
||||
btn.setSelected(true)
|
||||
}
|
||||
btn
|
||||
}
|
||||
// todo: batch calls to addArrangedSubview
|
||||
tabButtons.forEach(tabStack::addArrangedSubview)
|
||||
|
||||
// spacer
|
||||
tabStack.addArrangedSubview(View())
|
||||
updateTabButtons()
|
||||
|
||||
val background = NinePatchView(NinePatchTexture.PANEL_BG)
|
||||
outerStack.addArrangedSubview(background)
|
||||
|
@ -137,6 +136,37 @@ class TabViewController<T: TabViewController.Tab>(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateTabButtons() {
|
||||
while (tabStack.arrangedSubviews.isNotEmpty()) tabStack.removeArrangedSubview(tabStack.arrangedSubviews.first())
|
||||
|
||||
tabButtons = tabs.mapNotNull { tab ->
|
||||
if (!tab.isVisible) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
val btn = TabButton(tab)
|
||||
btn.handler = { selectTab(it.tab) }
|
||||
if (tab == currentTab) {
|
||||
btn.setSelected(true)
|
||||
}
|
||||
btn
|
||||
}
|
||||
// todo: batch calls to addArrangedSubview
|
||||
tabButtons.forEach(tabStack::addArrangedSubview)
|
||||
|
||||
// spacer
|
||||
tabStack.addArrangedSubview(View())
|
||||
|
||||
window!!.layout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when the conditions that make the configured tabs visible change.
|
||||
*/
|
||||
fun visibleTabsChanged() {
|
||||
updateTabButtons()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the provided tab as the currently active tab for this controller. Updates the state of tab bar buttons and
|
||||
* swaps the content view controller.
|
||||
|
|
|
@ -26,8 +26,7 @@ object PhysicalConnectivity: ModInitializer {
|
|||
|
||||
registerGlobalReceiver(C2STerminalRequestItem)
|
||||
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
||||
registerGlobalReceiver(C2SConfigureActivationMode)
|
||||
registerGlobalReceiver(C2SConfigureRedstoneController)
|
||||
registerGlobalReceiver(C2SConfigureDevice)
|
||||
}
|
||||
|
||||
private fun registerGlobalReceiver(receiver: ServerReceiver) {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package net.shadowfacts.phycon
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
|
||||
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
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.network.block.terminal.TerminalScreen
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreen
|
||||
import net.shadowfacts.phycon.networking.ClientReceiver
|
||||
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
||||
|
||||
|
@ -17,9 +16,9 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
|||
object PhysicalConnectivityClient: ClientModInitializer {
|
||||
|
||||
override fun onInitializeClient() {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent())
|
||||
|
||||
ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
|
||||
ScreenRegistry.register(PhyScreens.TERMINAL, ::TerminalScreen)
|
||||
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
||||
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
||||
|
||||
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network
|
||||
package net.shadowfacts.phycon.block
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
|
@ -8,7 +8,6 @@ import net.minecraft.world.World
|
|||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network
|
||||
package net.shadowfacts.phycon.block
|
||||
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.minecraft.block.BlockState
|
||||
|
@ -16,10 +16,11 @@ import net.shadowfacts.phycon.api.frame.PacketFrame
|
|||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.network.frame.ARPQueryFrame
|
||||
import net.shadowfacts.phycon.network.frame.ARPResponseFrame
|
||||
import net.shadowfacts.phycon.network.frame.BasePacketFrame
|
||||
import net.shadowfacts.phycon.network.packet.*
|
||||
import net.shadowfacts.phycon.util.NetworkUtil
|
||||
import net.shadowfacts.phycon.frame.ARPQueryFrame
|
||||
import net.shadowfacts.phycon.frame.ARPResponseFrame
|
||||
import net.shadowfacts.phycon.frame.BasePacketFrame
|
||||
import net.shadowfacts.phycon.packet.*
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
@ -146,27 +147,33 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
|||
}
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
protected open fun toCommonTag(tag: CompoundTag) {
|
||||
tag.putInt("IPAddress", ipAddress.address)
|
||||
tag.putLong("MACAddress", macAddress.address)
|
||||
}
|
||||
|
||||
protected open fun fromCommonTag(tag: CompoundTag) {
|
||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
toCommonTag(tag)
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||
fromCommonTag(tag)
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putInt("IPAddress", ipAddress.address)
|
||||
tag.putLong("MACAddress", macAddress.address)
|
||||
toCommonTag(tag)
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||
fromCommonTag(tag)
|
||||
}
|
||||
|
||||
fun onBreak() {
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network
|
||||
package net.shadowfacts.phycon.block
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
|
@ -16,7 +16,7 @@ import net.minecraft.world.World
|
|||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||
import java.util.*
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.cable
|
||||
package net.shadowfacts.phycon.block.cable
|
||||
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.block.piston.PistonBehavior
|
||||
|
@ -31,6 +31,7 @@ import java.util.*
|
|||
*/
|
||||
class CableBlock: Block(
|
||||
Settings.of(CABLE_MATERIAL)
|
||||
.strength(1f)
|
||||
.nonOpaque()
|
||||
), NetworkCableBlock {
|
||||
companion object {
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.extractor
|
||||
package net.shadowfacts.phycon.block.extractor
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
|
@ -7,6 +7,7 @@ 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
|
||||
|
@ -19,13 +20,17 @@ 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.network.DeviceBlock
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(Settings.of(Material.METAL)) {
|
||||
class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "extractor")
|
||||
|
@ -88,7 +93,7 @@ class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(Settings.of(Material.MET
|
|||
override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity()
|
||||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
||||
return defaultState.with(FACING, facing)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.extractor
|
||||
package net.shadowfacts.phycon.block.extractor
|
||||
|
||||
import alexiil.mc.lib.attributes.SearchOptions
|
||||
import alexiil.mc.lib.attributes.Simulation
|
||||
|
@ -11,14 +11,15 @@ 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.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.ActivationController
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackDispatcher
|
||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
import net.shadowfacts.phycon.network.packet.CapacityPacket
|
||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.network.packet.RemoteActivationPacket
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.component.ActivationController
|
||||
import net.shadowfacts.phycon.component.NetworkStackDispatcher
|
||||
import net.shadowfacts.phycon.component.handleItemStack
|
||||
import net.shadowfacts.phycon.packet.CapacityPacket
|
||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.packet.RemoteActivationPacket
|
||||
import net.shadowfacts.phycon.util.ActivationMode
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
|
@ -26,7 +27,8 @@ import kotlin.properties.Delegates
|
|||
*/
|
||||
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
||||
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
||||
ActivationController.ActivatableDevice {
|
||||
ActivationController.ActivatableDevice,
|
||||
ClientConfigurableDevice {
|
||||
|
||||
companion object {
|
||||
val SLEEP_TIME = 40L
|
||||
|
@ -37,7 +39,7 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
|||
|
||||
private var inventory: FixedItemInv? = null
|
||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||
override val dispatchStackTimeout = 40L
|
||||
override val dispatchStackTimeout = 1L
|
||||
override val controller = ActivationController(SLEEP_TIME, this)
|
||||
|
||||
fun updateInventory() {
|
||||
|
@ -99,23 +101,21 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
|||
return false
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
loadDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putString("ActivationMode", controller.activationMode.name)
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putString("ActivationMode", controller.activationMode.name)
|
||||
return super.toClientTag(tag)
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
super.fromClientTag(tag)
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package net.shadowfacts.phycon.block.inserter
|
||||
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.block.ShapeContext
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.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
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
import net.minecraft.util.shape.VoxelShapes
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InserterBlock: DeviceBlock<InserterBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.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 {
|
||||
val components = arrayOf(
|
||||
doubleArrayOf(4.0, 0.0, 4.0, 12.0, 2.0, 12.0),
|
||||
doubleArrayOf(2.0, 2.0, 2.0, 14.0, 4.0, 14.0),
|
||||
doubleArrayOf(0.0, 4.0, 0.0, 16.0, 6.0, 16.0),
|
||||
doubleArrayOf(6.0, 6.0, 6.0, 10.0, 16.0, 10.0)
|
||||
)
|
||||
val directions = arrayOf(
|
||||
Triple(Direction.DOWN, null, false),
|
||||
Triple(Direction.UP, null, true),
|
||||
Triple(Direction.NORTH, 2, false),
|
||||
Triple(Direction.SOUTH, 2, true),
|
||||
Triple(Direction.WEST, 1, false),
|
||||
Triple(Direction.EAST, 1, true),
|
||||
)
|
||||
for ((dir, rotate, flip) in directions) {
|
||||
val shapes = components.map { it ->
|
||||
val arr = it.copyOf()
|
||||
if (rotate != null) {
|
||||
for (i in 0 until 3) {
|
||||
arr[i] = it[(i + rotate) % 3]
|
||||
arr[3 + i] = it[3 + ((i + rotate) % 3)]
|
||||
}
|
||||
}
|
||||
if (flip) {
|
||||
for (i in arr.indices) {
|
||||
arr[i] = 16.0 - arr[i]
|
||||
}
|
||||
}
|
||||
createCuboidShape(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5])
|
||||
}
|
||||
INSERTER_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
|
||||
return EnumSet.of(state[FACING].opposite)
|
||||
}
|
||||
|
||||
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||
return if (side == state[FACING].opposite) {
|
||||
getBlockEntity(world, pos)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
super.appendProperties(builder)
|
||||
builder.add(FACING)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = InserterBlockEntity()
|
||||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
||||
return defaultState.with(FACING, facing)
|
||||
}
|
||||
|
||||
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||
return INSERTER_SHAPES[state[FACING]]!!
|
||||
}
|
||||
|
||||
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
||||
if (!world.isClient) {
|
||||
getBlockEntity(world, pos)!!.updateInventory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||
if (!world.isClient) {
|
||||
getBlockEntity(world, pos)!!.updateInventory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
||||
if (!world.isClient) {
|
||||
val be = getBlockEntity(world, pos)!!
|
||||
|
||||
be.sync()
|
||||
|
||||
val factory = object: ExtendedScreenHandlerFactory {
|
||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||
return InserterScreenHandler(syncId, playerInv, be)
|
||||
}
|
||||
|
||||
override fun getDisplayName() = this@InserterBlock.name
|
||||
|
||||
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
||||
buf.writeBlockPos(be.pos)
|
||||
}
|
||||
}
|
||||
player.openHandledScreen(factory)
|
||||
}
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package net.shadowfacts.phycon.block.inserter
|
||||
|
||||
import alexiil.mc.lib.attributes.SearchOptions
|
||||
import alexiil.mc.lib.attributes.Simulation
|
||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||
import alexiil.mc.lib.attributes.item.ItemInsertable
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.component.ActivationController
|
||||
import net.shadowfacts.phycon.component.ItemStackPacketHandler
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.component.handleItemStack
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.packet.*
|
||||
import net.shadowfacts.phycon.util.ActivationMode
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InserterBlockEntity: DeviceBlockEntity(PhyBlockEntities.INSERTER),
|
||||
ItemStackPacketHandler,
|
||||
ActivationController.ActivatableDevice,
|
||||
ClientConfigurableDevice {
|
||||
|
||||
companion object {
|
||||
val SLEEP_TIME = 40L
|
||||
val REQUEST_TIMEOUT = 40
|
||||
}
|
||||
|
||||
private val facing: Direction
|
||||
get() = cachedState[InserterBlock.FACING]
|
||||
|
||||
private var inventory: ItemInsertable? = null
|
||||
private var currentRequest: PendingExtractRequest? = null
|
||||
var stackToExtract: ItemStack = ItemStack.EMPTY
|
||||
var amountToExtract = 1
|
||||
override val controller = ActivationController(SLEEP_TIME, this)
|
||||
|
||||
fun updateInventory() {
|
||||
val offsetPos = pos.offset(facing)
|
||||
val option = SearchOptions.inDirection(facing)
|
||||
inventory = ItemAttributes.INSERTABLE.getFirstOrNull(world, offsetPos, option)
|
||||
}
|
||||
|
||||
private fun getInventory(): ItemInsertable? {
|
||||
if (inventory == null) updateInventory()
|
||||
return inventory
|
||||
}
|
||||
|
||||
override fun handle(packet: Packet) {
|
||||
when (packet) {
|
||||
is RemoteActivationPacket -> controller.handleRemoteActivation(packet)
|
||||
is StackLocationPacket -> handleStackLocation(packet)
|
||||
is ItemStackPacket -> handleItemStack(packet)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||
val inventory = getInventory()
|
||||
return if (inventory != null) {
|
||||
inventory.attemptInsertion(packet.stack, Simulation.ACTION)
|
||||
} else {
|
||||
// no inventory, entire stack remains
|
||||
packet.stack
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleStackLocation(packet: StackLocationPacket) {
|
||||
val request = currentRequest
|
||||
if (request != null && ItemStackUtil.areEqualIgnoreAmounts(request.stack, packet.stack)) {
|
||||
request.results.add(packet.amount to packet.stackProvider)
|
||||
if (request.isFinishable(counter)) {
|
||||
finishRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (!world!!.isClient) {
|
||||
controller.tick()
|
||||
|
||||
val request = currentRequest
|
||||
if (request != null) {
|
||||
if (request.isFinishable(counter)) {
|
||||
finishRequest()
|
||||
} else if (counter - request.timestamp >= REQUEST_TIMEOUT && request.totalAmount == 0) {
|
||||
currentRequest = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun activate(): Boolean {
|
||||
if (currentRequest != null || stackToExtract.isEmpty) {
|
||||
return false
|
||||
}
|
||||
|
||||
// todo: configure me
|
||||
currentRequest = PendingExtractRequest(stackToExtract, counter)
|
||||
sendPacket(LocateStackPacket(stackToExtract, ipAddress))
|
||||
return true
|
||||
}
|
||||
|
||||
private fun finishRequest() {
|
||||
val request = currentRequest ?: return
|
||||
|
||||
// todo: dedup with TerminalBlockEntity.stackLocateRequestCompleted
|
||||
val actualAmount = min(min(request.stack.maxCount, request.totalAmount), amountToExtract)
|
||||
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
|
||||
var amountRequested = 0
|
||||
while (amountRequested < actualAmount && sortedResults.isNotEmpty()) {
|
||||
val (sourceAmount, source) = sortedResults.removeAt(0)
|
||||
val amountToRequest = min(sourceAmount, actualAmount - amountRequested)
|
||||
amountRequested += amountToRequest
|
||||
sendPacket(ExtractStackPacket(request.stack, amountToRequest, ipAddress, source.ipAddress))
|
||||
}
|
||||
|
||||
currentRequest = null
|
||||
}
|
||||
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
tag.put("StackToExtract", stackToExtract.toTag(CompoundTag()))
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
loadDeviceConfiguration(tag)
|
||||
stackToExtract = ItemStack.fromTag(tag.getCompound("StackToExtract"))
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putString("ActivationMode", controller.activationMode.name)
|
||||
tag.putInt("AmountToExtract", amountToExtract)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||
amountToExtract = tag.getInt("AmountToExtract")
|
||||
}
|
||||
|
||||
class PendingExtractRequest(
|
||||
val stack: ItemStack,
|
||||
val timestamp: Long,
|
||||
var results: MutableSet<Pair<Int, NetworkStackProvider>> = mutableSetOf()
|
||||
) {
|
||||
val totalAmount: Int
|
||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
|
||||
fun isFinishable(currentTimestamp: Long): Boolean {
|
||||
return totalAmount >= stack.maxCount || (currentTimestamp - timestamp >= REQUEST_TIMEOUT && totalAmount > 0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package net.shadowfacts.phycon.block.inserter
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.text.LiteralText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
import java.lang.NumberFormatException
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InserterScreen(
|
||||
handler: InserterScreenHandler,
|
||||
playerInv: PlayerInventory,
|
||||
title: Text,
|
||||
): HandledScreen<InserterScreenHandler>(
|
||||
handler,
|
||||
playerInv,
|
||||
title
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/inserter.png")
|
||||
}
|
||||
|
||||
private lateinit var amountField: TextFieldWidget
|
||||
|
||||
init {
|
||||
backgroundWidth = 176
|
||||
backgroundHeight = 133
|
||||
playerInventoryTitleY = backgroundHeight - 94
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
|
||||
amountField = TextFieldWidget(textRenderer, x + 57, y + 24, 80, 9, LiteralText("Amount"))
|
||||
amountField.text = handler.inserter.amountToExtract.toString()
|
||||
amountField.setHasBorder(false)
|
||||
amountField.isVisible = true
|
||||
amountField.setSelected(true)
|
||||
amountField.setEditableColor(0xffffff)
|
||||
amountField.setTextPredicate {
|
||||
if (it.isEmpty()) {
|
||||
true
|
||||
} else {
|
||||
try {
|
||||
val value = Integer.parseInt(it)
|
||||
value in 1..64
|
||||
} catch (e: NumberFormatException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
addChild(amountField)
|
||||
}
|
||||
|
||||
fun amountUpdated() {
|
||||
if (amountField.text.isNotEmpty()) {
|
||||
handler.inserter.amountToExtract = Integer.parseInt(amountField.text)
|
||||
client!!.player!!.networkHandler.sendPacket(C2SConfigureDevice(handler.inserter))
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
amountField.tick()
|
||||
}
|
||||
|
||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||
renderBackground(matrixStack)
|
||||
|
||||
RenderSystem.color4f(1f, 1f, 1f, 1f)
|
||||
client!!.textureManager.bindTexture(BACKGROUND)
|
||||
val x = (width - backgroundWidth) / 2
|
||||
val y = (height - backgroundHeight) / 2
|
||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||
}
|
||||
|
||||
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
super.render(matrixStack, mouseX, mouseY, delta)
|
||||
|
||||
amountField.render(matrixStack, mouseX, mouseY, delta)
|
||||
|
||||
drawMouseoverTooltip(matrixStack, mouseX, mouseY)
|
||||
}
|
||||
|
||||
override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, slotActionType: SlotActionType?) {
|
||||
super.onMouseClick(slot, invSlot, clickData, slotActionType)
|
||||
|
||||
amountField.setSelected(true)
|
||||
}
|
||||
|
||||
override fun charTyped(c: Char, i: Int): Boolean {
|
||||
val oldText = amountField.text
|
||||
if (amountField.charTyped(c, i)) {
|
||||
if (oldText != amountField.text) {
|
||||
amountUpdated()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return super.charTyped(c, i)
|
||||
}
|
||||
|
||||
override fun keyPressed(i: Int, j: Int, k: Int): Boolean {
|
||||
val oldText = amountField.text
|
||||
if (amountField.keyPressed(i, j, k)) {
|
||||
if (oldText != amountField.text) {
|
||||
amountUpdated()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return super.keyPressed(i, j, k)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package net.shadowfacts.phycon.block.inserter
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import net.shadowfacts.phycon.util.GhostSlot
|
||||
import net.shadowfacts.phycon.util.copyWithCount
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InserterScreenHandler(
|
||||
syncId: Int,
|
||||
playerInv: PlayerInventory,
|
||||
val inserter: InserterBlockEntity,
|
||||
): ScreenHandler(PhyScreens.INSERTER, syncId) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "inserter")
|
||||
}
|
||||
|
||||
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
|
||||
this(
|
||||
syncId,
|
||||
playerInv,
|
||||
PhyBlocks.INSERTER.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!
|
||||
)
|
||||
|
||||
init {
|
||||
// fake slot
|
||||
addSlot(GhostSlot(inserter::stackToExtract, 31, 20))
|
||||
|
||||
// player inv
|
||||
for (y in 0 until 3) {
|
||||
for (x in 0 until 9) {
|
||||
addSlot(Slot(playerInv, x + y * 9 + 9, 8 + x * 18, 51 + y * 18))
|
||||
}
|
||||
}
|
||||
|
||||
// hotbar
|
||||
for (x in 0 until 9) {
|
||||
addSlot(Slot(playerInv, x, 8 + x * 18, 109))
|
||||
}
|
||||
}
|
||||
|
||||
private fun stackToExtractChanged() {
|
||||
inserter.amountToExtract = min(inserter.stackToExtract.maxCount, inserter.amountToExtract)
|
||||
}
|
||||
|
||||
override fun canUse(player: PlayerEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
|
||||
// fake slot
|
||||
if (slotId == 0) {
|
||||
if (player.inventory.cursorStack.isEmpty) {
|
||||
inserter.stackToExtract = ItemStack.EMPTY
|
||||
} else {
|
||||
inserter.stackToExtract = player.inventory.cursorStack.copyWithCount(1)
|
||||
}
|
||||
stackToExtractChanged()
|
||||
}
|
||||
return super.onSlotClick(slotId, clickData, actionType, player)
|
||||
}
|
||||
|
||||
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||
val slot = slots[slotId]
|
||||
inserter.stackToExtract = slot.stack.copyWithCount(1)
|
||||
stackToExtractChanged()
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.miner
|
||||
package net.shadowfacts.phycon.block.miner
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
|
@ -6,6 +6,7 @@ import net.minecraft.block.Material
|
|||
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
|
||||
|
@ -16,14 +17,18 @@ 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.network.DeviceBlock
|
||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class MinerBlock: DeviceBlock<MinerBlockEntity>(Settings.of(Material.METAL)) {
|
||||
class MinerBlock: DeviceBlock<MinerBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "miner")
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.miner
|
||||
package net.shadowfacts.phycon.block.miner
|
||||
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
|
@ -6,20 +6,25 @@ import alexiil.mc.lib.attributes.item.filter.ItemFilter
|
|||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.Items
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.text.TranslatableText
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackDispatcher
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
import net.shadowfacts.phycon.network.component.spawnItemStack
|
||||
import net.shadowfacts.phycon.network.packet.*
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.component.ActivationController
|
||||
import net.shadowfacts.phycon.component.NetworkStackDispatcher
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.component.handleItemStack
|
||||
import net.shadowfacts.phycon.packet.*
|
||||
import net.shadowfacts.phycon.util.ActivationMode
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import net.shadowfacts.phycon.util.copyWithCount
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
|
@ -27,7 +32,9 @@ import kotlin.math.min
|
|||
*/
|
||||
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||
NetworkStackProvider,
|
||||
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion> {
|
||||
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion>,
|
||||
ActivationController.ActivatableDevice,
|
||||
ClientConfigurableDevice {
|
||||
|
||||
private val facing: Direction
|
||||
get() = cachedState[MinerBlock.FACING]
|
||||
|
@ -36,6 +43,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
|
||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||
override val dispatchStackTimeout = TerminalBlockEntity.INSERTION_TIMEOUT
|
||||
override val controller = ActivationController(40L, this)
|
||||
override var providerPriority = 0
|
||||
|
||||
var minerMode = MinerMode.ON_DEMAND
|
||||
|
||||
override fun handle(packet: Packet) {
|
||||
when (packet) {
|
||||
|
@ -48,10 +59,16 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
}
|
||||
|
||||
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||
if (minerMode != MinerMode.ON_DEMAND) {
|
||||
return
|
||||
}
|
||||
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
|
||||
}
|
||||
|
||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||
if (minerMode != MinerMode.ON_DEMAND) {
|
||||
return
|
||||
}
|
||||
val amount = invProxy.getAmount(packet.stack)
|
||||
if (amount > 0) {
|
||||
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||
|
@ -59,6 +76,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
}
|
||||
|
||||
private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||
if (minerMode != MinerMode.ON_DEMAND) {
|
||||
return
|
||||
}
|
||||
|
||||
// always recalculate immediately before breaking
|
||||
val drops = invProxy.getDrops(recalculate = true)
|
||||
if (invProxy.getAmount(packet.stack) > 0) {
|
||||
|
@ -73,14 +94,13 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
|
||||
continue
|
||||
}
|
||||
val copy = droppedStack.copy()
|
||||
|
||||
val toDecr = min(droppedStack.count, remaining)
|
||||
val copy = droppedStack.copyWithCount(toDecr)
|
||||
droppedStack.decrement(toDecr)
|
||||
remaining -= toDecr
|
||||
|
||||
// todo: should this try to combine stacks and send as few packets as possible?
|
||||
copy.count = toDecr
|
||||
sendPacket(ItemStackPacket(copy, ipAddress, packet.source))
|
||||
}
|
||||
|
||||
|
@ -99,7 +119,76 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
|
||||
override fun createPendingInsertion(stack: ItemStack) = PendingInsertion(stack, counter)
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (!world!!.isClient && minerMode == MinerMode.AUTOMATIC) {
|
||||
|
||||
controller.tick()
|
||||
}
|
||||
}
|
||||
|
||||
override fun activate(): Boolean {
|
||||
if (minerMode == MinerMode.ON_DEMAND) {
|
||||
return false
|
||||
}
|
||||
|
||||
val drops = invProxy.getDrops(recalculate = true)
|
||||
if (!world!!.getBlockState(pos.offset(facing)).isAir) {
|
||||
world!!.breakBlock(pos.offset(facing), false)
|
||||
|
||||
for (stack in drops) {
|
||||
if (stack.isEmpty) continue
|
||||
dispatchItemStack(stack)
|
||||
}
|
||||
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun canConfigureActivationController(): Boolean {
|
||||
return minerMode == MinerMode.AUTOMATIC
|
||||
}
|
||||
|
||||
override fun canConfigureProviderPriority(): Boolean {
|
||||
return minerMode == MinerMode.ON_DEMAND
|
||||
}
|
||||
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
loadDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putString("MinerMode", minerMode.name)
|
||||
tag.putString("ActivationMode", controller.activationMode.name)
|
||||
tag.putInt("ProviderPriority", providerPriority)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
minerMode = MinerMode.valueOf(tag.getString("MinerMode"))
|
||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||
providerPriority = tag.getInt("ProviderPriority")
|
||||
}
|
||||
|
||||
enum class MinerMode {
|
||||
ON_DEMAND, AUTOMATIC;
|
||||
|
||||
val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.toLowerCase()}")
|
||||
}
|
||||
|
||||
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
|
||||
companion object {
|
||||
val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
|
||||
}
|
||||
|
||||
private var cachedState: BlockState? = null
|
||||
private var cachedDrops: List<ItemStack>? = null
|
||||
|
||||
|
@ -117,12 +206,15 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
if (cachedDrops == null || realState != cachedState || recalculate) {
|
||||
cachedState = realState
|
||||
val be = if (realState.block.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
||||
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be)
|
||||
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL)
|
||||
}
|
||||
return cachedDrops!!
|
||||
}
|
||||
|
||||
override fun getStoredStacks(): Set<ItemStack> {
|
||||
if (miner.minerMode != MinerMode.ON_DEMAND) {
|
||||
return setOf()
|
||||
}
|
||||
return getDrops().toSet()
|
||||
}
|
||||
|
||||
|
@ -132,7 +224,7 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
|||
|
||||
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
|
||||
var totalCount = 0
|
||||
for (s in getDrops()) {
|
||||
for (s in storedStacks) {
|
||||
if (filter.matches(s)) {
|
||||
totalCount += s.count
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package net.shadowfacts.phycon.network.block.netinterface
|
||||
package net.shadowfacts.phycon.block.netinterface
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
|
@ -12,12 +13,16 @@ import net.minecraft.world.BlockView
|
|||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.network.FaceDeviceBlock
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InterfaceBlock: FaceDeviceBlock<InterfaceBlockEntity>(Settings.of(Material.METAL)),
|
||||
class InterfaceBlock: FaceDeviceBlock<InterfaceBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
),
|
||||
NetworkComponentBlock,
|
||||
AttributeProvider {
|
||||
|
|
@ -1,20 +1,23 @@
|
|||
package net.shadowfacts.phycon.network.block.netinterface
|
||||
package net.shadowfacts.phycon.block.netinterface
|
||||
|
||||
import alexiil.mc.lib.attributes.SearchOptions
|
||||
import alexiil.mc.lib.attributes.Simulation
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||
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.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.FaceDeviceBlock
|
||||
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
import net.shadowfacts.phycon.network.packet.*
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
import net.shadowfacts.phycon.component.ItemStackPacketHandler
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.component.handleItemStack
|
||||
import net.shadowfacts.phycon.packet.*
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
|
@ -23,11 +26,15 @@ import kotlin.math.min
|
|||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||
ItemStackPacketHandler,
|
||||
NetworkStackProvider,
|
||||
NetworkStackReceiver {
|
||||
NetworkStackReceiver,
|
||||
ClientConfigurableDevice {
|
||||
|
||||
private val facing: Direction
|
||||
get() = cachedState[FaceDeviceBlock.FACING]
|
||||
|
||||
override var providerPriority = 0
|
||||
override var receiverPriority = 0
|
||||
|
||||
// todo: should this be a weak ref?
|
||||
private var inventory: GroupedItemInv? = null
|
||||
|
||||
|
@ -101,4 +108,24 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
|||
}
|
||||
}
|
||||
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
loadDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putInt("ProviderPriority", providerPriority)
|
||||
tag.putInt("ReceiverPriority", receiverPriority)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
providerPriority = tag.getInt("ProviderPriority")
|
||||
receiverPriority = tag.getInt("ReceiverPriority")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package net.shadowfacts.phycon.network.block.netswitch
|
||||
package net.shadowfacts.phycon.block.netswitch
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
|
@ -19,7 +20,11 @@ import java.util.*
|
|||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)),
|
||||
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
),
|
||||
NetworkComponentBlock,
|
||||
AttributeProvider {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.netswitch
|
||||
package net.shadowfacts.phycon.block.netswitch
|
||||
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.minecraft.block.BlockState
|
||||
|
@ -13,8 +13,8 @@ import net.shadowfacts.phycon.api.frame.EthernetFrame
|
|||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.NetworkUtil
|
||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.util.NetworkUtil
|
||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
|
@ -1,10 +1,10 @@
|
|||
package net.shadowfacts.phycon.network.block.redstone
|
||||
package net.shadowfacts.phycon.block.redstone_controller
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
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.Identifier
|
||||
|
@ -12,22 +12,23 @@ import net.minecraft.util.math.BlockPos
|
|||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.FaceDeviceBlock
|
||||
import java.util.*
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(Settings.of(Material.METAL)) {
|
||||
class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "redstone_controller")
|
||||
val LIT = Properties.LIT
|
||||
val POWERED = Properties.POWERED
|
||||
}
|
||||
|
||||
// todo: don't just copy this from the Interface block
|
||||
override val faceThickness = 3.0
|
||||
override val faceShapes = mapOf(
|
||||
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 3.0, 16.0),
|
||||
|
@ -40,20 +41,20 @@ class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(Se
|
|||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
super.appendProperties(builder)
|
||||
builder.add(LIT)
|
||||
builder.add(POWERED)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = RedstoneControllerBlockEntity()
|
||||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
val state = super.getPlacementState(context)
|
||||
return state.with(LIT, isPowered(context.world, context.blockPos, state[FACING]))
|
||||
return state.with(POWERED, isPowered(context.world, context.blockPos, state[FACING]))
|
||||
}
|
||||
|
||||
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||
// this can't be done in getStateForNeighborUpdate because getEmittedRedstonePower is defined in World not WorldAccess
|
||||
if (!world.isClient) {
|
||||
val wasLit = state[LIT]
|
||||
val wasLit = state[POWERED]
|
||||
val isLit = isPowered(world, pos, state[FACING])
|
||||
if (wasLit != isLit) {
|
||||
toggleLit(state, world, pos)
|
||||
|
@ -67,7 +68,7 @@ class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(Se
|
|||
}
|
||||
|
||||
private fun toggleLit(state: BlockState, world: World, pos: BlockPos) {
|
||||
world.setBlockState(pos, state.cycle(LIT), 2)
|
||||
world.setBlockState(pos, state.cycle(POWERED), 2)
|
||||
getBlockEntity(world, pos)!!.redstoneStateChanged()
|
||||
}
|
||||
|
|
@ -1,18 +1,19 @@
|
|||
package net.shadowfacts.phycon.network.block.redstone
|
||||
package net.shadowfacts.phycon.block.redstone_controller
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.packet.RemoteActivationPacket
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.packet.RemoteActivationPacket
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import net.shadowfacts.phycon.util.RedstoneMode
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER) {
|
||||
class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER),
|
||||
ClientConfigurableDevice {
|
||||
|
||||
var managedDevices = Array<IPAddress?>(5) { null }
|
||||
var redstoneMode = RedstoneMode.HIGH
|
||||
|
@ -24,7 +25,7 @@ class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE
|
|||
|
||||
fun redstoneStateChanged() {
|
||||
val oldPowered = redstonePowered
|
||||
redstonePowered = cachedState[RedstoneControllerBlock.LIT]
|
||||
redstonePowered = cachedState[RedstoneControllerBlock.POWERED]
|
||||
|
||||
val mode: RemoteActivationPacket.Mode? = when (redstoneMode) {
|
||||
RedstoneMode.TOGGLE -> if (oldPowered != redstonePowered) RemoteActivationPacket.Mode.SINGLE else null
|
||||
|
@ -46,27 +47,22 @@ class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE
|
|||
}
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
writeDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
loadDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putIntArray("ManagedDevices", managedDevices.mapNotNull { it?.address })
|
||||
tag.putString("RedstoneMode", redstoneMode.name)
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
val addresses = tag.getIntArray("ManagedDevices")
|
||||
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
|
||||
redstoneMode = RedstoneMode.valueOf(tag.getString("RedstoneMode"))
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putIntArray("ManagedDevices", managedDevices.mapNotNull { it?.address })
|
||||
tag.putString("RedstoneMode", redstoneMode.name)
|
||||
return super.toClientTag(tag)
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
super.fromClientTag(tag)
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
val addresses = tag.getIntArray("ManagedDevices")
|
||||
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
|
||||
redstoneMode = RedstoneMode.valueOf(tag.getString("RedstoneMode"))
|
|
@ -0,0 +1,88 @@
|
|||
package net.shadowfacts.phycon.block.redstone_emitter
|
||||
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RedstoneEmitterBlock: FaceDeviceBlock<RedstoneEmitterBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "redstone_emitter")
|
||||
}
|
||||
|
||||
// todo: don't just copy the redstone controller
|
||||
override val faceThickness = 3.0
|
||||
override val faceShapes = mapOf(
|
||||
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 3.0, 16.0),
|
||||
Direction.UP to createCuboidShape(0.0, 13.0, 0.0, 16.0, 16.0, 16.0),
|
||||
Direction.NORTH to createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 3.0),
|
||||
Direction.SOUTH to createCuboidShape(0.0, 0.0, 13.0, 16.0, 16.0, 16.0),
|
||||
Direction.WEST to createCuboidShape(0.0, 0.0, 0.0, 3.0, 16.0, 16.0),
|
||||
Direction.EAST to createCuboidShape(13.0, 0.0, 0.0, 16.0, 16.0, 16.0)
|
||||
)
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = RedstoneEmitterBlockEntity()
|
||||
|
||||
override fun emitsRedstonePower(state: BlockState): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getStrongRedstonePower(state: BlockState, world: BlockView, pos: BlockPos, receivingSide: Direction): Int {
|
||||
return if (receivingSide.opposite == state[FACING]) {
|
||||
getBlockEntity(world, pos)!!.cachedEmittedPower
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWeakRedstonePower(state: BlockState, world: BlockView, pos: BlockPos, receivingSide: Direction): Int {
|
||||
return getStrongRedstonePower(state, world, pos, receivingSide)
|
||||
}
|
||||
|
||||
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, result: BlockHitResult): ActionResult {
|
||||
if (!world.isClient) {
|
||||
val be = getBlockEntity(world, pos)!!
|
||||
|
||||
be.sync()
|
||||
|
||||
val factory = object: ExtendedScreenHandlerFactory {
|
||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||
return RedstoneEmitterScreenHandler(syncId, playerInv, be)
|
||||
}
|
||||
|
||||
override fun getDisplayName() = this@RedstoneEmitterBlock.name
|
||||
|
||||
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
||||
buf.writeBlockPos(be.pos)
|
||||
}
|
||||
}
|
||||
player.openHandledScreen(factory)
|
||||
}
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package net.shadowfacts.phycon.block.redstone_emitter
|
||||
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.packet.DeviceRemovedPacket
|
||||
import net.shadowfacts.phycon.packet.ReadInventoryPacket
|
||||
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
import kotlin.math.round
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RedstoneEmitterBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER),
|
||||
ClientConfigurableDevice {
|
||||
|
||||
private val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||
var cachedEmittedPower: Int = 0
|
||||
private set
|
||||
|
||||
var stackToMonitor: ItemStack = ItemStack.EMPTY
|
||||
var maxAmount = 64
|
||||
|
||||
override fun handle(packet: Packet) {
|
||||
when (packet) {
|
||||
is ReadInventoryPacket -> handleReadInventory(packet)
|
||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleReadInventory(packet: ReadInventoryPacket) {
|
||||
inventoryCache[packet.source] = packet.inventory
|
||||
recalculateRedstone()
|
||||
}
|
||||
|
||||
private fun handleDeviceRemoved(packet: DeviceRemovedPacket) {
|
||||
inventoryCache.remove(packet.source)
|
||||
recalculateRedstone()
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (!world!!.isClient && counter % 20 == 0L) {
|
||||
if (counter % 80 == 0L) {
|
||||
updateInventories()
|
||||
} else if (counter % 20 == 0L) {
|
||||
recalculateRedstone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateInventories() {
|
||||
sendPacket(RequestInventoryPacket(ipAddress))
|
||||
}
|
||||
|
||||
private fun recalculateRedstone() {
|
||||
if (stackToMonitor.isEmpty) {
|
||||
cachedEmittedPower = 0
|
||||
updateWorld()
|
||||
return
|
||||
}
|
||||
val networkAmount = inventoryCache.values.fold(0) { acc, inv ->
|
||||
acc + inv.getAmount(stackToMonitor)
|
||||
}
|
||||
cachedEmittedPower =
|
||||
if (networkAmount == 0) {
|
||||
0
|
||||
} else {
|
||||
1 + round(networkAmount / maxAmount.toDouble() * 14).toInt()
|
||||
}
|
||||
updateWorld()
|
||||
}
|
||||
|
||||
private fun updateWorld() {
|
||||
world!!.updateNeighborsAlways(pos, cachedState.block)
|
||||
world!!.updateNeighborsAlways(pos.offset(cachedState[FaceDeviceBlock.FACING]), cachedState.block)
|
||||
}
|
||||
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
tag.putInt("CachedEmittedPower", cachedEmittedPower)
|
||||
tag.put("StackToMonitor", stackToMonitor.toTag(CompoundTag()))
|
||||
writeDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
cachedEmittedPower = tag.getInt("CachedEmittedPower")
|
||||
stackToMonitor = ItemStack.fromTag(tag.getCompound("StackToMonitor"))
|
||||
loadDeviceConfiguration(tag)
|
||||
}
|
||||
|
||||
override fun writeDeviceConfiguration(tag: CompoundTag) {
|
||||
tag.putInt("MaxAmount", maxAmount)
|
||||
}
|
||||
|
||||
override fun loadDeviceConfiguration(tag: CompoundTag) {
|
||||
maxAmount = tag.getInt("MaxAmount")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package net.shadowfacts.phycon.block.redstone_emitter
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.text.TranslatableText
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.cacao.CacaoHandledScreen
|
||||
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.textfield.NumberField
|
||||
import net.shadowfacts.cacao.window.ScreenHandlerWindow
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
import no.birkett.kiwi.Variable
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RedstoneEmitterScreen(
|
||||
handler: RedstoneEmitterScreenHandler,
|
||||
playerInv: PlayerInventory,
|
||||
title: Text
|
||||
): CacaoHandledScreen<RedstoneEmitterScreenHandler>(
|
||||
handler,
|
||||
playerInv,
|
||||
title
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/redstone_emitter.png")
|
||||
}
|
||||
|
||||
init {
|
||||
backgroundWidth = 176
|
||||
backgroundHeight = 166
|
||||
|
||||
addWindow(ScreenHandlerWindow(handler, ViewController(handler.emitter)))
|
||||
}
|
||||
|
||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||
super.drawBackground(matrixStack, delta, mouseX, mouseY)
|
||||
|
||||
RenderSystem.color4f(1f, 1f, 1f, 1f)
|
||||
client!!.textureManager.bindTexture(BACKGROUND)
|
||||
val x = (width - backgroundWidth) / 2
|
||||
val y = (height - backgroundHeight) / 2
|
||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||
}
|
||||
|
||||
class ViewController(
|
||||
private val emitter: RedstoneEmitterBlockEntity,
|
||||
): net.shadowfacts.cacao.viewcontroller.ViewController() {
|
||||
|
||||
lateinit var halfLabel: Label
|
||||
lateinit var fullLabel: Label
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
val title = Label(PhyBlocks.REDSTONE_EMITTER.name)
|
||||
title.textColor = Color.TEXT
|
||||
view.addSubview(title)
|
||||
|
||||
val inv = Label(MinecraftClient.getInstance().player!!.inventory.displayName)
|
||||
inv.textColor = Color.TEXT
|
||||
view.addSubview(inv)
|
||||
|
||||
val field = NumberField(emitter.maxAmount) {
|
||||
if (it.number != null) {
|
||||
emitter.maxAmount = it.number!!
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(emitter))
|
||||
}
|
||||
updateLabelTexts()
|
||||
}
|
||||
field.validator = { it >= 0 }
|
||||
field.drawBackground = false
|
||||
view.addSubview(field)
|
||||
|
||||
val hStack = StackView(Axis.HORIZONTAL, StackView.Distribution.FILL, spacing = 2.0)
|
||||
view.addSubview(hStack)
|
||||
|
||||
val zeroStack = hStack.addArrangedSubview(StackView(Axis.VERTICAL))
|
||||
zeroStack.addArrangedSubview(Label(TranslatableText("gui.phycon.emitter.count", 0), textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
zeroStack.addArrangedSubview(View())
|
||||
zeroStack.addArrangedSubview(Label("0", textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||
textColor = Color.RED
|
||||
}
|
||||
|
||||
val halfStack = hStack.addArrangedSubview(StackView(Axis.VERTICAL))
|
||||
halfLabel = halfStack.addArrangedSubview(Label("half", textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
halfStack.addArrangedSubview(View())
|
||||
halfStack.addArrangedSubview(Label("8", textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||
textColor = Color.RED
|
||||
}
|
||||
|
||||
val fullStack = hStack.addArrangedSubview(StackView(Axis.VERTICAL))
|
||||
fullLabel = fullStack.addArrangedSubview(Label("full", textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
fullStack.addArrangedSubview(View())
|
||||
fullStack.addArrangedSubview(Label("15", textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||
textColor = Color.RED
|
||||
}
|
||||
|
||||
updateLabelTexts()
|
||||
|
||||
view.solver.dsl {
|
||||
val minX = Variable("minX")
|
||||
val minY = Variable("minY")
|
||||
minX equalTo ((view.widthAnchor - 176) / 2)
|
||||
minY equalTo ((view.heightAnchor - 166) / 2)
|
||||
|
||||
title.leftAnchor equalTo (minX + 8)
|
||||
title.topAnchor equalTo (minY + 6)
|
||||
|
||||
inv.leftAnchor equalTo (minX + 8)
|
||||
inv.topAnchor equalTo (minY + 72)
|
||||
|
||||
// offset by 1 on each edge to account for MC border
|
||||
field.widthAnchor equalTo 82
|
||||
field.heightAnchor equalTo 11
|
||||
field.leftAnchor equalTo (minX + 56)
|
||||
field.topAnchor equalTo (minY + 23)
|
||||
|
||||
hStack.centerXAnchor equalTo view.centerXAnchor
|
||||
hStack.widthAnchor equalTo (176 - 4)
|
||||
hStack.topAnchor equalTo (field.bottomAnchor + 8)
|
||||
hStack.bottomAnchor equalTo inv.topAnchor
|
||||
|
||||
zeroStack.widthAnchor equalTo halfStack.widthAnchor
|
||||
halfStack.widthAnchor equalTo fullStack.widthAnchor
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLabelTexts() {
|
||||
halfLabel.text = TranslatableText("gui.phycon.emitter.count", ceil(emitter.maxAmount / 2.0).toInt())
|
||||
fullLabel.text = TranslatableText("gui.phycon.emitter.count", emitter.maxAmount)
|
||||
window!!.layout()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package net.shadowfacts.phycon.block.redstone_emitter
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import net.shadowfacts.phycon.util.GhostSlot
|
||||
import net.shadowfacts.phycon.util.copyWithCount
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RedstoneEmitterScreenHandler(
|
||||
syncId: Int,
|
||||
playerInv: PlayerInventory,
|
||||
val emitter: RedstoneEmitterBlockEntity,
|
||||
): ScreenHandler(PhyScreens.REDSTONE_EMITTER, syncId) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "redstone_emitter")
|
||||
}
|
||||
|
||||
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
|
||||
this(
|
||||
syncId,
|
||||
playerInv,
|
||||
PhyBlocks.REDSTONE_EMITTER.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!
|
||||
)
|
||||
|
||||
init {
|
||||
// fake slot
|
||||
addSlot(GhostSlot(emitter::stackToMonitor, 31, 20))
|
||||
|
||||
// player inv
|
||||
for (y in 0 until 3) {
|
||||
for (x in 0 until 9) {
|
||||
addSlot(Slot(playerInv, x + y * 9 + 9, 8 + x * 18, 84 + y * 18))
|
||||
}
|
||||
}
|
||||
|
||||
// hotbar
|
||||
for (x in 0 until 9) {
|
||||
addSlot(Slot(playerInv, x, 8 + x * 18, 142))
|
||||
}
|
||||
}
|
||||
|
||||
override fun canUse(player: PlayerEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSlotClick(slotId: Int, clickData: Int, slotActionType: SlotActionType, player: PlayerEntity): ItemStack {
|
||||
// fake slot
|
||||
if (slotId == 0) {
|
||||
if (player.inventory.cursorStack.isEmpty) {
|
||||
emitter.stackToMonitor = ItemStack.EMPTY
|
||||
} else {
|
||||
emitter.stackToMonitor = player.inventory.cursorStack.copyWithCount(1)
|
||||
}
|
||||
}
|
||||
return super.onSlotClick(slotId, clickData, slotActionType, player)
|
||||
}
|
||||
|
||||
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||
val slot = slots[slotId]
|
||||
emitter.stackToMonitor = slot.stack.copyWithCount(1)
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
package net.shadowfacts.phycon.block.terminal
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
|
@ -16,13 +17,17 @@ import net.minecraft.world.World
|
|||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.network.DeviceBlock
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TerminalBlock: DeviceBlock<TerminalBlockEntity>(Settings.of(Material.METAL)),
|
||||
class TerminalBlock: DeviceBlock<TerminalBlockEntity>(
|
||||
Settings.of(Material.METAL)
|
||||
.strength(1.5f)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
),
|
||||
NetworkComponentBlock,
|
||||
AttributeProvider {
|
||||
|
||||
|
@ -41,6 +46,15 @@ class TerminalBlock: DeviceBlock<TerminalBlockEntity>(Settings.of(Material.METAL
|
|||
return ActionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun onStateReplaced(state: BlockState, world: World, pos: BlockPos, newState: BlockState, moved: Boolean) {
|
||||
if (!state.isOf(newState.block)) {
|
||||
val be = getBlockEntity(world, pos)!!
|
||||
ItemScatterer.spawn(world, pos, be.internalBuffer)
|
||||
|
||||
super.onStateReplaced(state, world, pos, newState, moved)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||
to.offer(getBlockEntity(world, pos))
|
||||
}
|
|
@ -1,18 +1,16 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
package net.shadowfacts.phycon.block.terminal
|
||||
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.inventory.Inventory
|
||||
import net.minecraft.inventory.InventoryChangedListener
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
@ -23,10 +21,10 @@ import net.shadowfacts.phycon.api.Interface
|
|||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.NetworkUtil
|
||||
import net.shadowfacts.phycon.network.component.*
|
||||
import net.shadowfacts.phycon.network.packet.*
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.util.NetworkUtil
|
||||
import net.shadowfacts.phycon.component.*
|
||||
import net.shadowfacts.phycon.packet.*
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
@ -43,8 +41,10 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
NetworkStackDispatcher<TerminalBlockEntity.PendingInsertion> {
|
||||
|
||||
companion object {
|
||||
val LOCATE_REQUEST_TIMEOUT: Long = 40 // ticks
|
||||
val INSERTION_TIMEOUT: Long = 40
|
||||
// the locate/insertion timeouts are only 1 tick because that's long enough to hear from every device on the network
|
||||
// in a degraded state (when there's latency in the network), not handling interface priorities correctly is acceptable
|
||||
val LOCATE_REQUEST_TIMEOUT: Long = 1 // ticks
|
||||
val INSERTION_TIMEOUT: Long = 1
|
||||
}
|
||||
|
||||
private val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||
|
@ -164,14 +164,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (counter % 20 == 0L) {
|
||||
if (!world!!.isClient) {
|
||||
finishPendingRequests()
|
||||
beginInsertions()
|
||||
finishTimedOutPendingInsertions()
|
||||
}
|
||||
if (!world!!.isClient) {
|
||||
finishPendingRequests()
|
||||
finishTimedOutPendingInsertions()
|
||||
}
|
||||
|
||||
if (observers > 0 && !world!!.isClient) {
|
||||
if (counter % 20 == 0L && !world!!.isClient) {
|
||||
beginInsertions()
|
||||
|
||||
if (observers > 0) {
|
||||
updateAndSync()
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +185,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
inventoryCache.clear()
|
||||
sendPacket(RequestInventoryPacket(ipAddress))
|
||||
val factory = object: ExtendedScreenHandlerFactory {
|
||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
||||
}
|
||||
|
||||
|
@ -210,8 +211,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||
pendingRequests.remove(request)
|
||||
|
||||
// todo: also sort results by interface priority
|
||||
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
|
||||
val sortedResults = request.results.toMutableList()
|
||||
sortedResults.sortWith { a, b ->
|
||||
// sort results first by provider priority, and then by the count that it can provide
|
||||
if (a.second.providerPriority == b.second.providerPriority) {
|
||||
b.first - a.first
|
||||
} else {
|
||||
b.second.providerPriority - a.second.providerPriority
|
||||
}
|
||||
}
|
||||
var amountRequested = 0
|
||||
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
||||
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
||||
|
@ -240,25 +248,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
|||
}
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
override fun toCommonTag(tag: CompoundTag) {
|
||||
super.toCommonTag(tag)
|
||||
tag.put("InternalBuffer", internalBuffer.toTag())
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
override fun fromCommonTag(tag: CompoundTag) {
|
||||
super.fromCommonTag(tag)
|
||||
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.put("InternalBuffer", internalBuffer.toTag())
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||
}
|
||||
|
||||
interface NetItemObserver {
|
||||
fun netItemsChanged()
|
||||
}
|
||||
|
@ -279,6 +277,8 @@ data class StackLocateRequest(
|
|||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
|
||||
fun isFinishable(currentTimestamp: Long): Boolean {
|
||||
return totalResultAmount >= amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||
// we can't check totalResultAmount >= amount because we need to hear back from all network stack providers to
|
||||
// correctly sort by priority
|
||||
return currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
package net.shadowfacts.phycon.block.terminal
|
||||
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import net.minecraft.inventory.SimpleInventory
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
package net.shadowfacts.phycon.block.terminal
|
||||
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.entity.player.PlayerEntity
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
package net.shadowfacts.phycon.block.terminal
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.MinecraftClient
|
|
@ -1,6 +1,5 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
package net.shadowfacts.phycon.block.terminal
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
|
@ -14,17 +13,16 @@ import net.minecraft.util.registry.Registry
|
|||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import net.shadowfacts.phycon.networking.C2STerminalRequestItem
|
||||
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.min
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId),
|
||||
class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL, syncId),
|
||||
TerminalBlockEntity.NetItemObserver {
|
||||
|
||||
companion object {
|
||||
|
@ -40,9 +38,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
|
|||
field = value
|
||||
if (terminal.world!!.isClient) {
|
||||
itemsForDisplay = value.map {
|
||||
val stack = it.stack.copy()
|
||||
stack.count = it.amount
|
||||
stack
|
||||
it.stack.copyWithCount(it.amount)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package net.shadowfacts.phycon.network.component
|
||||
package net.shadowfacts.phycon.component
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.shadowfacts.phycon.network.packet.RemoteActivationPacket
|
||||
import net.shadowfacts.phycon.packet.RemoteActivationPacket
|
||||
import net.shadowfacts.phycon.util.ActivationMode
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -50,11 +51,15 @@ class ActivationController<T>(
|
|||
}
|
||||
}
|
||||
|
||||
interface ActivatableDevice {
|
||||
interface ActivatableDevice: ClientConfigurableDevice {
|
||||
val controller: ActivationController<*>
|
||||
|
||||
val counter: Long
|
||||
|
||||
fun activate(): Boolean
|
||||
|
||||
fun canConfigureActivationController(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package net.shadowfacts.phycon.network.component
|
||||
package net.shadowfacts.phycon.component
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.entity.ItemEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.PacketSink
|
||||
import net.shadowfacts.phycon.api.PacketSource
|
||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
|
@ -1,12 +1,14 @@
|
|||
package net.shadowfacts.phycon.network.component
|
||||
package net.shadowfacts.phycon.component
|
||||
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.packet.CapacityPacket
|
||||
import net.shadowfacts.phycon.network.packet.CheckCapacityPacket
|
||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.packet.CapacityPacket
|
||||
import net.shadowfacts.phycon.packet.CheckCapacityPacket
|
||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||
import net.shadowfacts.phycon.util.copyWithCount
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -27,10 +29,10 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
|||
}
|
||||
|
||||
fun handleCapacity(packet: CapacityPacket) {
|
||||
val insertion = pendingInsertions.firstOrNull {
|
||||
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
|
||||
}
|
||||
if (insertion != null) {
|
||||
pendingInsertions.firstOrNull { insertion ->
|
||||
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, insertion.stack) &&
|
||||
insertion.results.none { it.second.ipAddress == packet.source }
|
||||
}?.also { insertion ->
|
||||
insertion.results.add(packet.capacity to packet.stackReceiver)
|
||||
if (insertion.isFinishable(this)) {
|
||||
val remaining = finishInsertion(insertion)
|
||||
|
@ -42,14 +44,22 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
|||
fun finishInsertion(insertion: Insertion): ItemStack {
|
||||
pendingInsertions.remove(insertion)
|
||||
|
||||
// todo: also sort results by interface priority
|
||||
val sortedResults = insertion.results.sortedBy { it.first }.toMutableList()
|
||||
val sortedResults = insertion.results.toMutableList()//.sortedBy { it.first }.toMutableList()
|
||||
sortedResults.sortWith { a, b ->
|
||||
// sort results first by receiver priority, and then by capacity
|
||||
if (a.second.receiverPriority == b.second.receiverPriority) {
|
||||
b.first - a.first
|
||||
} else {
|
||||
b.second.receiverPriority - a.second.receiverPriority
|
||||
}
|
||||
}
|
||||
// copy the insertion stack so subclasses that override this method can still see the originally dispatched stack after the super call
|
||||
val remaining = insertion.stack.copy()
|
||||
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
||||
val (capacity, receivingInterface) = sortedResults.removeFirst()
|
||||
if (capacity <= 0) continue
|
||||
sendPacket(ItemStackPacket(remaining.copy(), ipAddress, receivingInterface.ipAddress))
|
||||
val copy = remaining.copyWithCount(min(capacity, remaining.count))
|
||||
sendPacket(ItemStackPacket(copy, ipAddress, receivingInterface.ipAddress))
|
||||
// todo: the destination should confirm how much was actually inserted, in case of race condition
|
||||
remaining.count -= capacity
|
||||
}
|
||||
|
@ -67,7 +77,8 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
|||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
|
||||
fun isFinishable(owner: NetworkStackDispatcher<Self>): Boolean {
|
||||
return totalCapacity >= stack.count || owner.counter - timestamp >= owner.dispatchStackTimeout
|
||||
// can't check totalCapacity >= stack.count because we need to wait for all responses to correctly sort by priority
|
||||
return owner.counter - timestamp >= owner.dispatchStackTimeout
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package net.shadowfacts.phycon.component
|
||||
|
||||
import net.shadowfacts.phycon.api.NetworkDevice
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface NetworkStackProvider: NetworkDevice, ClientConfigurableDevice {
|
||||
|
||||
var providerPriority: Int
|
||||
|
||||
fun canConfigureProviderPriority(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.shadowfacts.phycon.component
|
||||
|
||||
import net.shadowfacts.phycon.api.NetworkDevice
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface NetworkStackReceiver: NetworkDevice, ClientConfigurableDevice {
|
||||
|
||||
var receiverPriority: Int
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.frame
|
||||
package net.shadowfacts.phycon.frame
|
||||
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
|
@ -1,8 +1,6 @@
|
|||
package net.shadowfacts.phycon.network.frame
|
||||
package net.shadowfacts.phycon.frame
|
||||
|
||||
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
|
||||
/**
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.frame
|
||||
package net.shadowfacts.phycon.frame
|
||||
|
||||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
|
@ -5,22 +5,22 @@ import net.minecraft.block.entity.BlockEntity
|
|||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
||||
import net.shadowfacts.phycon.network.block.miner.MinerBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlock
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlockEntity
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity
|
||||
import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||
import net.shadowfacts.phycon.block.inserter.InserterBlockEntity
|
||||
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlockEntity
|
||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -31,11 +31,10 @@ object PhyBlockEntities {
|
|||
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
||||
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
||||
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
|
||||
val INSERTER = create(::InserterBlockEntity, PhyBlocks.INSERTER)
|
||||
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
||||
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
|
||||
|
||||
val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE)
|
||||
val DEST = create(::DestBlockEntity, PhyBlocks.DEST)
|
||||
val REDSTONE_EMITTER = create(::RedstoneEmitterBlockEntity, PhyBlocks.REDSTONE_EMITTER)
|
||||
|
||||
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
||||
return BlockEntityType.Builder.create(builder, block).build(null)
|
||||
|
@ -46,11 +45,10 @@ object PhyBlockEntities {
|
|||
register(TerminalBlock.ID, TERMINAL)
|
||||
register(SwitchBlock.ID, SWITCH)
|
||||
register(ExtractorBlock.ID, EXTRACTOR)
|
||||
register(InserterBlock.ID, INSERTER)
|
||||
register(MinerBlock.ID, MINER)
|
||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||
|
||||
register(SourceBlock.ID, SOURCE)
|
||||
register(DestBlock.ID, DEST)
|
||||
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||
}
|
||||
|
||||
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
||||
|
|
|
@ -3,15 +3,15 @@ package net.shadowfacts.phycon.init
|
|||
import net.minecraft.block.Block
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlock
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -23,11 +23,10 @@ object PhyBlocks {
|
|||
val SWITCH = SwitchBlock()
|
||||
val CABLE = CableBlock()
|
||||
val EXTRACTOR = ExtractorBlock()
|
||||
val INSERTER = InserterBlock()
|
||||
val MINER = MinerBlock()
|
||||
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
|
||||
|
||||
val SOURCE = SourceBlock()
|
||||
val DEST = DestBlock()
|
||||
val REDSTONE_EMITTER = RedstoneEmitterBlock()
|
||||
|
||||
fun init() {
|
||||
register(InterfaceBlock.ID, INTERFACE)
|
||||
|
@ -35,11 +34,10 @@ object PhyBlocks {
|
|||
register(SwitchBlock.ID, SWITCH)
|
||||
register(CableBlock.ID, CABLE)
|
||||
register(ExtractorBlock.ID, EXTRACTOR)
|
||||
register(InserterBlock.ID, INSERTER)
|
||||
register(MinerBlock.ID, MINER)
|
||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||
|
||||
register(SourceBlock.ID, SOURCE)
|
||||
register(DestBlock.ID, DEST)
|
||||
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||
}
|
||||
|
||||
private fun register(id: Identifier, block: Block) {
|
||||
|
|
|
@ -6,31 +6,31 @@ import net.minecraft.util.Identifier
|
|||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.item.ConsoleItem
|
||||
import net.shadowfacts.phycon.item.ScrewdriverItem
|
||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlock
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||
import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||
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
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object PhyItems {
|
||||
|
||||
val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
||||
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
||||
val INTERFACE = DeviceBlockItem(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 = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
|
||||
val MINER = BlockItem(PhyBlocks.MINER, Item.Settings())
|
||||
val REDSTONE_CONTROLLER = BlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
|
||||
|
||||
val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings())
|
||||
val DEST = BlockItem(PhyBlocks.DEST , 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 SCREWDRIVER = ScrewdriverItem()
|
||||
val CONSOLE = ConsoleItem()
|
||||
|
@ -41,11 +41,10 @@ object PhyItems {
|
|||
register(SwitchBlock.ID, SWITCH)
|
||||
register(CableBlock.ID, CABLE)
|
||||
register(ExtractorBlock.ID, EXTRACTOR)
|
||||
register(InserterBlock.ID, INSERTER)
|
||||
register(MinerBlock.ID, MINER)
|
||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||
|
||||
register(SourceBlock.ID, SOURCE)
|
||||
register(DestBlock.ID, DEST)
|
||||
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||
|
||||
register(ScrewdriverItem.ID, SCREWDRIVER)
|
||||
register(ConsoleItem.ID, CONSOLE)
|
||||
|
|
|
@ -2,17 +2,23 @@ package net.shadowfacts.phycon.init
|
|||
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
||||
import net.minecraft.screen.ScreenHandlerType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
||||
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreenHandler
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||
|
||||
object PhyScreens {
|
||||
|
||||
lateinit var TERMINAL_SCREEN_HANDLER: ScreenHandlerType<TerminalScreenHandler>
|
||||
lateinit var TERMINAL: ScreenHandlerType<TerminalScreenHandler>
|
||||
private set
|
||||
lateinit var INSERTER: ScreenHandlerType<InserterScreenHandler>
|
||||
private set
|
||||
lateinit var REDSTONE_EMITTER: ScreenHandlerType<RedstoneEmitterScreenHandler>
|
||||
private set
|
||||
|
||||
fun init() {
|
||||
TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler)
|
||||
TERMINAL = ScreenHandlerRegistry.registerExtended(TerminalScreenHandler.ID, ::TerminalScreenHandler)
|
||||
INSERTER = ScreenHandlerRegistry.registerExtended(InserterScreenHandler.ID, ::InserterScreenHandler)
|
||||
REDSTONE_EMITTER = ScreenHandlerRegistry.registerExtended(RedstoneEmitterScreenHandler.ID, ::RedstoneEmitterScreenHandler)
|
||||
}
|
||||
|
||||
}
|
|
@ -6,8 +6,8 @@ import net.minecraft.item.ItemUsageContext
|
|||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.DeviceBlock
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.screen.console.DeviceConsoleScreen
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package net.shadowfacts.phycon.item
|
||||
|
||||
import net.minecraft.client.item.TooltipContext
|
||||
import net.minecraft.item.BlockItem
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
import net.shadowfacts.phycon.util.text
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
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")
|
||||
if (beTag != null) {
|
||||
val ip = IPAddress(beTag.getInt("IPAddress"))
|
||||
list.add(text {
|
||||
withStyle(lightPurple) {
|
||||
+translate("tooltip.phycon.device.configured")
|
||||
}
|
||||
+" ("
|
||||
+translate("tooltip.phycon.device.ip")
|
||||
withStyle(darkPurple) {
|
||||
+ip.toString()
|
||||
}
|
||||
+")"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,16 @@
|
|||
package net.shadowfacts.phycon.item
|
||||
|
||||
import net.minecraft.block.Blocks
|
||||
import net.minecraft.entity.ItemEntity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ItemUsageContext
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.block.DeviceBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -11,4 +19,33 @@ class ScrewdriverItem: Item(Settings()) {
|
|||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "screwdriver")
|
||||
}
|
||||
|
||||
override fun useOnBlock(context: ItemUsageContext): ActionResult {
|
||||
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")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
context.world.playSound(context.player, context.blockPos, SoundEvents.BLOCK_METAL_PLACE, SoundCategory.BLOCKS, 0.8f, 0.65f)
|
||||
|
||||
return ActionResult.SUCCESS
|
||||
} else {
|
||||
return ActionResult.PASS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.block.test
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.DeviceBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class DestBlock: DeviceBlock<DestBlockEntity>(Settings.of(Material.METAL)) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "dest")
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView): DestBlockEntity {
|
||||
return DestBlockEntity()
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): MutableCollection<Direction> {
|
||||
return EnumSet.allOf(Direction::class.java)
|
||||
}
|
||||
|
||||
override fun onUse(
|
||||
blockState: BlockState?,
|
||||
world: World,
|
||||
pos: BlockPos,
|
||||
playerEntity: PlayerEntity?,
|
||||
hand: Hand?,
|
||||
blockHitResult: BlockHitResult?
|
||||
): ActionResult {
|
||||
println("dest IP: ${getBlockEntity(world, pos)!!.ipAddress}")
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.block.test
|
||||
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.NetworkUtil
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class DestBlockEntity: DeviceBlockEntity(PhyBlockEntities.DEST) {
|
||||
|
||||
override fun handle(packet: Packet) {
|
||||
println("$this ($ipAddress) received packet: $packet")
|
||||
}
|
||||
|
||||
override fun findDestination(): Interface? {
|
||||
for (dir in Direction.values()) {
|
||||
val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir)
|
||||
if (itf != null) {
|
||||
return itf
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.block.test
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.DeviceBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class SourceBlock: DeviceBlock<SourceBlockEntity>(Settings.of(Material.METAL)) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "source")
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView): SourceBlockEntity {
|
||||
return SourceBlockEntity()
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): MutableCollection<Direction> {
|
||||
return EnumSet.allOf(Direction::class.java)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.block.test
|
||||
|
||||
import net.minecraft.util.Tickable
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.NetworkUtil
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class SourceBlockEntity: DeviceBlockEntity(PhyBlockEntities.SOURCE), Tickable {
|
||||
|
||||
override fun handle(packet: Packet) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
if (!world!!.isClient && counter % 40 == 0L) {
|
||||
sendPacket(TestPacket(ipAddress, IPAddress(170, 171, 101, 168)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun findDestination(): Interface? {
|
||||
for (dir in Direction.values()) {
|
||||
val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir)
|
||||
if (itf != null) {
|
||||
return itf
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.block.test
|
||||
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.packet.BasePacket
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TestPacket(source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.component
|
||||
|
||||
import net.shadowfacts.phycon.api.NetworkDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface NetworkStackProvider: NetworkDevice {
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package net.shadowfacts.phycon.network.component
|
||||
|
||||
import net.shadowfacts.phycon.api.NetworkDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface NetworkStackReceiver: NetworkDevice {
|
||||
}
|
|
@ -2,31 +2,31 @@ package net.shadowfacts.phycon.networking
|
|||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketSender
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.Packet
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.minecraft.util.registry.RegistryKey
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.ActivationController
|
||||
import net.shadowfacts.phycon.util.ActivationMode
|
||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object C2SConfigureActivationMode: ServerReceiver {
|
||||
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "configure_activation_mode")
|
||||
object C2SConfigureDevice: ServerReceiver {
|
||||
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "configure_device")
|
||||
|
||||
operator fun <T> invoke(be: T): Packet<*> where T: DeviceBlockEntity, T: ActivationController.ActivatableDevice {
|
||||
operator fun <T> invoke(be: T): Packet<*> where T: BlockEntity, T: ClientConfigurableDevice {
|
||||
val buf = PacketByteBufs.create()
|
||||
|
||||
buf.writeIdentifier(be.world!!.registryKey.value)
|
||||
buf.writeBlockPos(be.pos)
|
||||
buf.writeString(be.controller.activationMode.name)
|
||||
val tag = CompoundTag()
|
||||
be.writeDeviceConfiguration(tag)
|
||||
buf.writeCompoundTag(tag)
|
||||
|
||||
return createPacket(buf)
|
||||
}
|
||||
|
@ -34,16 +34,16 @@ object C2SConfigureActivationMode: ServerReceiver {
|
|||
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||
val dimID = buf.readIdentifier()
|
||||
val pos = buf.readBlockPos()
|
||||
val mode = ActivationMode.valueOf(buf.readString())
|
||||
val tag = buf.readCompoundTag() ?: return
|
||||
|
||||
server.execute {
|
||||
// todo: check the player is close enough
|
||||
val key = RegistryKey.of(Registry.DIMENSION, dimID)
|
||||
val world = server.getWorld(key) ?: return@execute
|
||||
val device = world.getBlockEntity(pos) ?: return@execute
|
||||
if (device !is ActivationController.ActivatableDevice) return@execute
|
||||
device.controller.activationMode = mode
|
||||
device.markDirty()
|
||||
// todo: check if the player is close enough
|
||||
val world = player.world
|
||||
if (world.registryKey.value != dimID) return@execute
|
||||
val be = world.getBlockEntity(pos) ?: return@execute
|
||||
val device = be as? ClientConfigurableDevice ?: return@execute
|
||||
device.loadDeviceConfiguration(tag)
|
||||
be.markDirty()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package net.shadowfacts.phycon.networking
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketSender
|
||||
import net.minecraft.network.Packet
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.minecraft.util.registry.RegistryKey
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.util.RedstoneMode
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object C2SConfigureRedstoneController: ServerReceiver {
|
||||
// todo: it would be nice if there wasn't so much duplication with C2SConfigureActivationMode
|
||||
|
||||
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "configure_redstone_controller")
|
||||
|
||||
operator fun invoke(be: RedstoneControllerBlockEntity): Packet<*> {
|
||||
val buf = PacketByteBufs.create()
|
||||
|
||||
buf.writeIdentifier(be.world!!.registryKey.value)
|
||||
buf.writeBlockPos(be.pos)
|
||||
buf.writeString(be.redstoneMode.name)
|
||||
be.managedDevices.forEach {
|
||||
buf.writeInt(it?.address ?: 0)
|
||||
}
|
||||
|
||||
return createPacket(buf)
|
||||
}
|
||||
|
||||
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||
val dimID = buf.readIdentifier()
|
||||
val pos = buf.readBlockPos()
|
||||
val mode = RedstoneMode.valueOf(buf.readString())
|
||||
val managedDevices = Array<IPAddress?>(5) { null }
|
||||
(0..4).map {
|
||||
val v = buf.readInt()
|
||||
managedDevices[it] = if (v == 0) null else IPAddress(v)
|
||||
}
|
||||
|
||||
server.execute {
|
||||
// todo: check if the player is close enough
|
||||
val key = RegistryKey.of(Registry.DIMENSION, dimID)
|
||||
val world = server.getWorld(key) ?: return@execute
|
||||
val device = world.getBlockEntity(pos) as? RedstoneControllerBlockEntity ?: return@execute
|
||||
device.redstoneMode = mode
|
||||
device.managedDevices = managedDevices
|
||||
device.markDirty()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,8 @@ import net.minecraft.util.Identifier
|
|||
import net.minecraft.util.registry.Registry
|
||||
import net.minecraft.util.registry.RegistryKey
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.util.copyWithCount
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -30,9 +31,7 @@ object C2STerminalRequestItem: ServerReceiver {
|
|||
// Force the count of the stack to be 1 before serializing for the network because
|
||||
// PacketByteBuf serializes the stack count as a byte. Otherwise counts > 127 will result in
|
||||
// an overflow and be negative on the receiving side.
|
||||
val stackCopy = stack.copy()
|
||||
stackCopy.count = 1
|
||||
buf.writeItemStack(stackCopy)
|
||||
buf.writeItemStack(stack.copyWithCount(1))
|
||||
|
||||
buf.writeVarInt(amount)
|
||||
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
||||
|
|
|
@ -10,8 +10,8 @@ import net.minecraft.server.network.ServerPlayNetworkHandler
|
|||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||
import net.shadowfacts.phycon.util.SortMode
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,8 +7,8 @@ import net.minecraft.client.MinecraftClient
|
|||
import net.minecraft.client.network.ClientPlayNetworkHandler
|
||||
import net.minecraft.network.Packet
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||
import net.shadowfacts.phycon.util.SortMode
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
@ -1,8 +1,8 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
@ -1,7 +1,7 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
package net.shadowfacts.phycon.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
|
@ -2,16 +2,14 @@ package net.shadowfacts.phycon.screen.console
|
|||
|
||||
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.button.EnumButton
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.ActivationController
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureActivationMode
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.component.ActivationController
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
import net.shadowfacts.phycon.util.ActivationMode
|
||||
|
||||
/**
|
||||
|
@ -32,7 +30,7 @@ class ActivatableDeviceViewController<T>(
|
|||
val mode = EnumButton(device.controller.activationMode, ActivationMode::friendlyName)
|
||||
mode.handler = {
|
||||
device.controller.activationMode = it.value
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureActivationMode(device))
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
view.addSubview(mode)
|
||||
|
||||
|
|
|
@ -12,9 +12,12 @@ import net.shadowfacts.cacao.viewcontroller.TabViewController
|
|||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.cacao.window.Window
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.ActivationController
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.component.ActivationController
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
import org.lwjgl.glfw.GLFW
|
||||
|
||||
/**
|
||||
|
@ -40,7 +43,8 @@ class DeviceConsoleScreen(
|
|||
intrinsicContentSize = Size(16.0, 16.0)
|
||||
},
|
||||
TranslatableText("gui.phycon.console.remote"),
|
||||
ActivatableDeviceViewController(device)
|
||||
ActivatableDeviceViewController(device),
|
||||
device::canConfigureActivationController
|
||||
))
|
||||
}
|
||||
if (device is RedstoneControllerBlockEntity) {
|
||||
|
@ -52,7 +56,30 @@ class DeviceConsoleScreen(
|
|||
RedstoneControllerViewController(device)
|
||||
))
|
||||
}
|
||||
|
||||
if (device is MinerBlockEntity) {
|
||||
tabs.add(TabViewController.SimpleTab(
|
||||
TextureView(Texture(Identifier("textures/item/diamond_pickaxe.png"), 0, 0, 16, 16)).apply {
|
||||
intrinsicContentSize = Size(16.0, 16.0)
|
||||
},
|
||||
TranslatableText("block.phycon.miner"),
|
||||
MinerViewController(device)
|
||||
))
|
||||
}
|
||||
if (device is NetworkStackProvider) {
|
||||
tabs.add(TabViewController.SimpleTab(
|
||||
Label("P").apply { textColor = Color.TEXT },
|
||||
TranslatableText("gui.phycon.console.provider"),
|
||||
ProviderViewController(device),
|
||||
device::canConfigureProviderPriority
|
||||
))
|
||||
}
|
||||
if (device is NetworkStackReceiver) {
|
||||
tabs.add(TabViewController.SimpleTab(
|
||||
Label("R").apply { textColor = Color.TEXT },
|
||||
TranslatableText("gui.phycon.console.receiver"),
|
||||
ReceiverViewController(device),
|
||||
))
|
||||
}
|
||||
|
||||
tabController = TabViewController(tabs)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import net.shadowfacts.cacao.view.Label
|
|||
import net.shadowfacts.cacao.view.StackView
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package net.shadowfacts.phycon.screen.console
|
||||
|
||||
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.EnumButton
|
||||
import net.shadowfacts.cacao.viewcontroller.TabViewController
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class MinerViewController(
|
||||
val device: MinerBlockEntity,
|
||||
): ViewController() {
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
val label = Label(TranslatableText("gui.phycon.console.miner.mode")).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val mode = EnumButton(device.minerMode, MinerBlockEntity.MinerMode::friendlyName)
|
||||
mode.handler = {
|
||||
device.minerMode = it.value
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
|
||||
(parent as TabViewController<TabViewController.SimpleTab>).visibleTabsChanged()
|
||||
}
|
||||
view.addSubview(mode)
|
||||
|
||||
view.solver.dsl {
|
||||
mode.widthAnchor equalTo 100
|
||||
mode.heightAnchor equalTo 20
|
||||
mode.topAnchor equalTo view.topAnchor
|
||||
mode.rightAnchor equalTo view.rightAnchor
|
||||
|
||||
label.centerYAnchor equalTo mode.centerYAnchor
|
||||
label.rightAnchor equalTo (mode.leftAnchor - 4)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
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.util.Color
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.textfield.NumberField
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProviderViewController<T>(
|
||||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackProvider {
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
val label = Label(TranslatableText("gui.phycon.console.provider.priority")).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.providerPriority) {
|
||||
if (it.number != null) {
|
||||
device.providerPriority = it.number!!
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
view.addSubview(field)
|
||||
|
||||
val desc = Label(TranslatableText("gui.phycon.console.provider.priority_desc")).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
view.addSubview(desc)
|
||||
|
||||
view.solver.dsl {
|
||||
field.widthAnchor equalTo 100
|
||||
field.heightAnchor equalTo 20
|
||||
field.rightAnchor equalTo view.rightAnchor
|
||||
field.topAnchor equalTo view.topAnchor
|
||||
|
||||
label.centerYAnchor equalTo field.centerYAnchor
|
||||
label.rightAnchor equalTo (field.leftAnchor - 4)
|
||||
|
||||
desc.topAnchor equalTo (field.bottomAnchor + 4)
|
||||
desc.leftAnchor equalTo view.leftAnchor
|
||||
desc.rightAnchor equalTo view.rightAnchor
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
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.util.Color
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.textfield.NumberField
|
||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ReceiverViewController<T>(
|
||||
private val device: T
|
||||
): ViewController() where T: BlockEntity, T: NetworkStackReceiver {
|
||||
|
||||
override fun viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
val label = Label(TranslatableText("gui.phycon.console.receiver.priority")).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
view.addSubview(label)
|
||||
|
||||
val field = NumberField(device.receiverPriority) {
|
||||
if (it.number != null) {
|
||||
device.receiverPriority = it.number!!
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
view.addSubview(field)
|
||||
|
||||
val desc = Label(TranslatableText("gui.phycon.console.receiver.priority_desc")).apply {
|
||||
textColor = Color.TEXT
|
||||
}
|
||||
view.addSubview(desc)
|
||||
|
||||
view.solver.dsl {
|
||||
field.widthAnchor equalTo 100
|
||||
field.heightAnchor equalTo 20
|
||||
field.rightAnchor equalTo view.rightAnchor
|
||||
field.topAnchor equalTo view.topAnchor
|
||||
|
||||
label.centerYAnchor equalTo field.centerYAnchor
|
||||
label.rightAnchor equalTo (field.leftAnchor - 4)
|
||||
|
||||
desc.topAnchor equalTo (field.bottomAnchor + 4)
|
||||
desc.leftAnchor equalTo view.leftAnchor
|
||||
desc.rightAnchor equalTo view.rightAnchor
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,8 +11,8 @@ import net.shadowfacts.cacao.view.textfield.TextField
|
|||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureRedstoneController
|
||||
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||
import net.shadowfacts.phycon.util.RedstoneMode
|
||||
|
||||
/**
|
||||
|
@ -39,14 +39,14 @@ class RedstoneControllerViewController(val device: RedstoneControllerBlockEntity
|
|||
val mode = EnumButton(device.redstoneMode, RedstoneMode::friendlyName)
|
||||
mode.handler = {
|
||||
device.redstoneMode = it.value
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureRedstoneController(device))
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
controls.addArrangedSubview(mode)
|
||||
|
||||
val textFields = (0 until 5).map { i ->
|
||||
TextField(device.managedDevices[i]?.toString() ?: "") {
|
||||
device.managedDevices[i] = IPAddress.parse(it.text)
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureRedstoneController(device))
|
||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||
}
|
||||
}
|
||||
textFields.forEach(controls::addArrangedSubview)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package net.shadowfacts.phycon.util
|
||||
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface ClientConfigurableDevice {
|
||||
|
||||
fun writeDeviceConfiguration(tag: CompoundTag)
|
||||
|
||||
fun loadDeviceConfiguration(tag: CompoundTag)
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package net.shadowfacts.phycon.util
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.inventory.Inventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import kotlin.reflect.KMutableProperty
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class GhostSlot(prop: KMutableProperty<ItemStack>, x: Int, y: Int): Slot(GhostInv(prop), 0, x, y) {
|
||||
|
||||
override fun canInsert(stack: ItemStack) = false
|
||||
|
||||
override fun setStack(itemStack: ItemStack?) {
|
||||
}
|
||||
|
||||
override fun canTakeItems(player: PlayerEntity) = false
|
||||
|
||||
class GhostInv(private val prop: KMutableProperty<ItemStack>): Inventory {
|
||||
override fun clear() {
|
||||
prop.setter.call(ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
override fun size() = 1
|
||||
|
||||
override fun isEmpty() = prop.getter.call().isEmpty
|
||||
|
||||
override fun getStack(i: Int): ItemStack {
|
||||
return if (i == 0) prop.getter.call()
|
||||
else ItemStack.EMPTY
|
||||
}
|
||||
|
||||
override fun removeStack(i: Int, j: Int) = ItemStack.EMPTY
|
||||
|
||||
override fun removeStack(i: Int) = ItemStack.EMPTY
|
||||
|
||||
override fun setStack(i: Int, itemStack: ItemStack) {}
|
||||
|
||||
override fun markDirty() {}
|
||||
|
||||
override fun canPlayerUse(playerEntity: PlayerEntity?) = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package net.shadowfacts.phycon.util
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
fun ItemStack.copyWithCount(count: Int): ItemStack {
|
||||
return copy().also { it.count = count }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package net.shadowfacts.phycon.network
|
||||
package net.shadowfacts.phycon.util
|
||||
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
|
@ -0,0 +1,120 @@
|
|||
package net.shadowfacts.phycon.util
|
||||
|
||||
import net.minecraft.text.*
|
||||
import net.minecraft.util.Formatting
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
fun text(build: TextContext.() -> Unit): Text {
|
||||
val context = TextContext()
|
||||
context.build()
|
||||
return context.toText()
|
||||
}
|
||||
|
||||
class TextContext(
|
||||
private val texts: MutableList<Text> = mutableListOf(),
|
||||
private val styles: Deque<Style> = LinkedList()
|
||||
) {
|
||||
|
||||
fun toText(): MutableText {
|
||||
val text = LiteralText("")
|
||||
texts.forEach(text::append)
|
||||
return text
|
||||
}
|
||||
|
||||
operator fun String.unaryPlus() {
|
||||
+LiteralText(this)
|
||||
}
|
||||
|
||||
operator fun MutableText.unaryPlus() {
|
||||
if (styles.isNotEmpty()) {
|
||||
texts.add(this.setStyle(styles.peek()))
|
||||
} else {
|
||||
texts.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun translate(key: String, vararg parameters: Any): TranslatableText {
|
||||
return TranslatableText(key, *parameters)
|
||||
}
|
||||
|
||||
fun withStyle(style: Style, build: TextContext.() -> Unit) {
|
||||
styles.push(style)
|
||||
build()
|
||||
styles.pop()
|
||||
}
|
||||
|
||||
fun withStyle(style: Style.() -> Style, build: TextContext.() -> Unit) {
|
||||
withStyle(Style.EMPTY.style(), build)
|
||||
}
|
||||
|
||||
fun withStyle(formatting: Formatting, build: TextContext.() -> Unit) {
|
||||
withStyle(Style.EMPTY.withFormatting(formatting), build)
|
||||
}
|
||||
|
||||
val bold = Formatting.BOLD
|
||||
fun Style.bold(): Style = withBold(true)
|
||||
|
||||
val italic = Formatting.ITALIC
|
||||
fun Style.italic(): Style = withItalic(true)
|
||||
|
||||
val strikethrough = Formatting.STRIKETHROUGH
|
||||
fun Style.strikethrough(): Style = withFormatting(strikethrough)
|
||||
|
||||
val underline = Formatting.UNDERLINE
|
||||
fun Style.underline(): Style = withFormatting(underline)
|
||||
|
||||
val obfuscated = Formatting.OBFUSCATED
|
||||
fun Style.obfuscated(): Style = withFormatting(obfuscated)
|
||||
|
||||
val black = Formatting.BLACK
|
||||
fun Style.black(): Style = withFormatting(black)
|
||||
|
||||
val darkBlue = Formatting.DARK_BLUE
|
||||
fun Style.darkBlue(): Style = withFormatting(darkBlue)
|
||||
|
||||
val darkGreen = Formatting.DARK_GREEN
|
||||
fun Style.darkGreen(): Style = withFormatting(darkGreen)
|
||||
|
||||
val darkAqua = Formatting.DARK_AQUA
|
||||
fun Style.darkAqua(): Style = withFormatting(darkAqua)
|
||||
|
||||
val darkRed = Formatting.DARK_RED
|
||||
fun Style.darkRed(): Style = withFormatting(darkRed)
|
||||
|
||||
val darkPurple = Formatting.DARK_PURPLE
|
||||
fun Style.darkPurple(): Style = withFormatting(darkPurple)
|
||||
|
||||
val gold = Formatting.GOLD
|
||||
fun Style.gold(): Style = withFormatting(gold)
|
||||
|
||||
val gray = Formatting.GRAY
|
||||
fun Style.gray(): Style = withFormatting(gray)
|
||||
|
||||
val darkGray = Formatting.DARK_GRAY
|
||||
fun Style.darkGray(): Style = withFormatting(darkGray)
|
||||
|
||||
val blue = Formatting.BLUE
|
||||
fun Style.blue(): Style = withFormatting(blue)
|
||||
|
||||
val green = Formatting.GREEN
|
||||
fun Style.green(): Style = withFormatting(green)
|
||||
|
||||
val aqua = Formatting.RED
|
||||
fun Style.aqua(): Style = withFormatting(aqua)
|
||||
|
||||
val red = Formatting.RED
|
||||
fun Style.red(): Style = withFormatting(red)
|
||||
|
||||
val lightPurple = Formatting.LIGHT_PURPLE
|
||||
fun Style.lightPurple(): Style = withFormatting(lightPurple)
|
||||
|
||||
val yellow = Formatting.YELLOW
|
||||
fun Style.yellow(): Style = withFormatting(yellow)
|
||||
|
||||
val white = Formatting.WHITE
|
||||
fun Style.white(): Style = withFormatting(white)
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"variants": {
|
||||
"facing=down": {
|
||||
"model": "phycon:block/inserter"
|
||||
},
|
||||
"facing=up": {
|
||||
"model": "phycon:block/inserter",
|
||||
"x": 180
|
||||
},
|
||||
"facing=north": {
|
||||
"model": "phycon:block/inserter",
|
||||
"x": 270
|
||||
},
|
||||
"facing=south": {
|
||||
"model": "phycon:block/inserter",
|
||||
"x": 90
|
||||
},
|
||||
"facing=west": {
|
||||
"model": "phycon:block/inserter",
|
||||
"x": 90,
|
||||
"y": 90
|
||||
},
|
||||
"facing=east": {
|
||||
"model": "phycon:block/inserter",
|
||||
"x": 90,
|
||||
"y": 270
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,51 +4,51 @@
|
|||
"apply": { "model": "phycon:block/cable_center" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "down", "lit": "false" },
|
||||
"when": { "facing": "down", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "up", "lit": "false" },
|
||||
"when": { "facing": "up", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "north", "lit": "false" },
|
||||
"when": { "facing": "north", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "south", "lit": "false" },
|
||||
"when": { "facing": "south", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "west", "lit": "false" },
|
||||
"when": { "facing": "west", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "east", "lit": "false" },
|
||||
"when": { "facing": "east", "powered": "false" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_off", "x": 90, "y": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "down", "lit": "true" },
|
||||
"when": { "facing": "down", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on" }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "up", "lit": "true" },
|
||||
"when": { "facing": "up", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 180 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "north", "lit": "true" },
|
||||
"when": { "facing": "north", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 270 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "south", "lit": "true" },
|
||||
"when": { "facing": "south", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "west", "lit": "true" },
|
||||
"when": { "facing": "west", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90, "y": 90 }
|
||||
},
|
||||
{
|
||||
"when": { "facing": "east", "lit": "true" },
|
||||
"when": { "facing": "east", "powered": "true" },
|
||||
"apply": { "model": "phycon:block/redstone_controller_side_on", "x": 90, "y": 270 }
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
{
|
||||
"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 }
|
||||
}
|
||||
]
|
||||
}
|
|
@ -4,8 +4,10 @@
|
|||
"block.phycon.terminal": "Terminal",
|
||||
"block.phycon.cable": "Cable",
|
||||
"block.phycon.extractor": "Inventory Extractor",
|
||||
"block.phycon.inserter": "Inventory Inserter",
|
||||
"block.phycon.miner": "Block Miner",
|
||||
"block.phycon.redstone_controller": "Redstone Controller",
|
||||
"block.phycon.redstone_emitter": "Redstone Emitter",
|
||||
|
||||
"item.phycon.screwdriver": "Screwdriver",
|
||||
"item.phycon.console": "Console",
|
||||
|
@ -18,11 +20,24 @@
|
|||
"gui.phycon.console.redstone.devices": "Managed Devices",
|
||||
"gui.phycon.console.remote": "Remote Management",
|
||||
"gui.phycon.console.remote.mode": "Activation Mode",
|
||||
"gui.phycon.console.miner.mode": "Miner Mode",
|
||||
"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.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.redstone_mode.high": "High",
|
||||
"gui.phycon.redstone_mode.low": "Low",
|
||||
"gui.phycon.redstone_mode.toggle": "Toggle",
|
||||
"gui.phycon.redstone_mode.rising_edge": "Rising Edge",
|
||||
"gui.phycon.redstone_mode.falling_edge": "Falling Edge",
|
||||
"gui.phycon.activation_mode.automatic": "Automatic",
|
||||
"gui.phycon.activation_mode.managed": "Managed"
|
||||
"gui.phycon.activation_mode.managed": "Managed",
|
||||
"gui.phycon.emitter.count": "%d Item(s)",
|
||||
"gui.phycon.miner_mode.automatic": "Automatic",
|
||||
"gui.phycon.miner_mode.on_demand": "On Demand",
|
||||
|
||||
"tooltip.phycon.device.configured": "Configured",
|
||||
"tooltip.phycon.device.ip": "IP: "
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"cable_side": "phycon:block/cable_straight",
|
||||
"cable_end": "phycon:block/cable_cap_end"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 2, 16],
|
||||
"faces": {
|
||||
"down": {"texture": "phycon:block/extractor_front"},
|
||||
"down": {"texture": "phycon:block/extractor_front", "cullface": "down"},
|
||||
"up": {"texture": "phycon:block/extractor_back"},
|
||||
"north": {"texture": "phycon:block/extractor_side"},
|
||||
"south": {"texture": "phycon:block/extractor_side"},
|
||||
|
@ -39,11 +43,11 @@
|
|||
"from": [6, 6, 6],
|
||||
"to": [10, 16, 10],
|
||||
"faces": {
|
||||
"up": {"texture": "phycon:block/cable_side"},
|
||||
"north": {"texture": "phycon:block/cable_side"},
|
||||
"south": {"texture": "phycon:block/cable_side"},
|
||||
"west": {"texture": "phycon:block/cable_side"},
|
||||
"east": {"texture": "phycon:block/cable_side"}
|
||||
"up": {"texture": "#cable_end", "cullface": "up"},
|
||||
"north": {"texture": "#cable_side"},
|
||||
"south": {"texture": "#cable_side"},
|
||||
"west": {"texture": "#cable_side"},
|
||||
"east": {"texture": "#cable_side"}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"cable_side": "phycon:block/cable_straight",
|
||||
"cable_end": "phycon:block/cable_cap_end"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [4, 0, 4],
|
||||
"to": [12, 2, 12],
|
||||
"faces": {
|
||||
"down": {"texture": "phycon:block/extractor_front", "cullface": "down"},
|
||||
"north": {"texture": "phycon:block/extractor_side"},
|
||||
"south": {"texture": "phycon:block/extractor_side"},
|
||||
"west": {"texture": "phycon:block/extractor_side"},
|
||||
"east": {"texture": "phycon:block/extractor_side"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [2, 2, 2],
|
||||
"to": [14, 4, 14],
|
||||
"faces": {
|
||||
"down": {"texture": "phycon:block/extractor_front"},
|
||||
"north": {"texture": "phycon:block/extractor_side"},
|
||||
"south": {"texture": "phycon:block/extractor_side"},
|
||||
"west": {"texture": "phycon:block/extractor_side"},
|
||||
"east": {"texture": "phycon:block/extractor_side"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 4, 0],
|
||||
"to": [16, 6, 16],
|
||||
"faces": {
|
||||
"down": {"texture": "phycon:block/extractor_front"},
|
||||
"up": {"texture": "phycon:block/extractor_back"},
|
||||
"north": {"texture": "phycon:block/extractor_side"},
|
||||
"south": {"texture": "phycon:block/extractor_side"},
|
||||
"west": {"texture": "phycon:block/extractor_side"},
|
||||
"east": {"texture": "phycon:block/extractor_side"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 6, 6],
|
||||
"to": [10, 16, 10],
|
||||
"faces": {
|
||||
"up": {"texture": "#cable_end", "cullface": "up"},
|
||||
"north": {"texture": "#cable_side"},
|
||||
"south": {"texture": "#cable_side"},
|
||||
"west": {"texture": "#cable_side"},
|
||||
"east": {"texture": "#cable_side"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"cable": "phycon:block/cable_straight",
|
||||
"front": "phycon:block/redstone_emitter_front",
|
||||
"back": "phycon:block/redstone_emitter_back",
|
||||
"side": "phycon:block/redstone_emitter_back"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 3, 16],
|
||||
"faces": {
|
||||
"down": { "texture": "#front" },
|
||||
"up": { "texture": "#back" },
|
||||
"north": { "texture": "#side" },
|
||||
"south": { "texture": "#side" },
|
||||
"west": { "texture": "#side" },
|
||||
"east": { "texture": "#side" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, 3, 6],
|
||||
"to": [10, 6, 10],
|
||||
"faces": {
|
||||
"north": { "texture": "#cable" },
|
||||
"south": { "texture": "#cable" },
|
||||
"west": { "texture": "#cable" },
|
||||
"east": { "texture": "#cable" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "phycon:item/screwdriver"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue