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.gui.screen.ingame.HandledScreen;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.screen.slot.Slot;
|
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.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import net.minecraft.screen.ScreenHandler
|
||||||
import net.minecraft.sound.SoundEvents
|
import net.minecraft.sound.SoundEvents
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.shadowfacts.cacao.geometry.Point
|
import net.shadowfacts.cacao.geometry.Point
|
||||||
|
import net.shadowfacts.cacao.util.KeyModifiers
|
||||||
import net.shadowfacts.cacao.util.MouseButton
|
import net.shadowfacts.cacao.util.MouseButton
|
||||||
import net.shadowfacts.cacao.util.RenderHelper
|
import net.shadowfacts.cacao.util.RenderHelper
|
||||||
import net.shadowfacts.cacao.window.ScreenHandlerWindow
|
import net.shadowfacts.cacao.window.ScreenHandlerWindow
|
||||||
|
@ -16,7 +17,7 @@ import java.util.*
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class CacaoHandledScreen<Handler: ScreenHandler>(
|
open class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
playerInv: PlayerInventory,
|
playerInv: PlayerInventory,
|
||||||
title: Text,
|
title: Text,
|
||||||
|
@ -57,15 +58,16 @@ class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
|
renderBackground(matrixStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
renderBackground(matrixStack)
|
|
||||||
|
|
||||||
val mouse = Point(mouseX, mouseY)
|
val mouse = Point(mouseX, mouseY)
|
||||||
windows.forEachIndexed { index, it ->
|
windows.forEachIndexed { index, it ->
|
||||||
it.draw(matrixStack, mouse, delta)
|
|
||||||
if (it is ScreenHandlerWindow) {
|
if (it is ScreenHandlerWindow) {
|
||||||
if (index == windows.size - 1) {
|
if (index == windows.size - 1) {
|
||||||
super.render(matrixStack, mouseX, mouseY, delta)
|
super.render(matrixStack, mouseX, mouseY, delta)
|
||||||
|
@ -74,7 +76,10 @@ class CacaoHandledScreen<Handler: ScreenHandler>(
|
||||||
super.render(matrixStack, -1, -1, delta)
|
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 {
|
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,7 +139,9 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
|
||||||
return super.charTyped(char, modifiers)
|
return super.charTyped(char, modifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findResponder(fn: (Responder) -> Boolean): Boolean {
|
}
|
||||||
|
|
||||||
|
fun AbstractCacaoScreen.findResponder(fn: (Responder) -> Boolean): Boolean {
|
||||||
var responder = windows.lastOrNull()?.firstResponder
|
var responder = windows.lastOrNull()?.firstResponder
|
||||||
while (responder != null) {
|
while (responder != null) {
|
||||||
if (fn(responder)) {
|
if (fn(responder)) {
|
||||||
|
@ -148,6 +150,4 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")): Screen(title),
|
||||||
responder = responder.nextResponder
|
responder = responder.nextResponder
|
||||||
}
|
}
|
||||||
return false
|
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 RED = Color(0xff0000)
|
||||||
val GREEN = Color(0x00ff00)
|
val GREEN = Color(0x00ff00)
|
||||||
val BLUE = Color(0x0000ff)
|
val BLUE = Color(0x0000ff)
|
||||||
|
val MAGENTA = Color(0xfc46e4)
|
||||||
|
|
||||||
val TEXT = Color(0x404040)
|
val TEXT = Color(0x404040)
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ class Label(
|
||||||
for (i in 0 until lines.size) {
|
for (i in 0 until lines.size) {
|
||||||
val x = when (textAlignment) {
|
val x = when (textAlignment) {
|
||||||
TextAlignment.LEFT -> 0.0
|
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])
|
TextAlignment.RIGHT -> bounds.width - textRenderer.getWidth(lines[i])
|
||||||
}
|
}
|
||||||
val y = i * textRenderer.fontHeight
|
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 net.shadowfacts.cacao.geometry.AxisPosition.*
|
import net.shadowfacts.cacao.geometry.AxisPosition.*
|
||||||
import no.birkett.kiwi.Constraint
|
import no.birkett.kiwi.Constraint
|
||||||
|
import java.lang.RuntimeException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +19,7 @@ import java.util.*
|
||||||
* @param axis The primary axis that this stack lays out its children along.
|
* @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
|
* @param distribution The mode by which this stack lays out its children along the axis perpendicular to the
|
||||||
* primary [axis].
|
* primary [axis].
|
||||||
|
* @param spacing The distance between arranged subviews along the primary axis.
|
||||||
*/
|
*/
|
||||||
open class StackView(
|
open class StackView(
|
||||||
val axis: Axis,
|
val axis: Axis,
|
||||||
|
@ -25,7 +27,7 @@ open class StackView(
|
||||||
val spacing: Double = 0.0
|
val spacing: Double = 0.0
|
||||||
): View() {
|
): View() {
|
||||||
|
|
||||||
// the internal mutable, list of arranged subviews
|
// the internal, mutable list of arranged subviews
|
||||||
private val _arrangedSubviews = LinkedList<View>()
|
private val _arrangedSubviews = LinkedList<View>()
|
||||||
/**
|
/**
|
||||||
* The list of arranged subviews belonging to this stack view.
|
* The list of arranged subviews belonging to this stack view.
|
||||||
|
@ -57,6 +59,64 @@ open class StackView(
|
||||||
return view
|
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) {
|
private fun addConstraintsForArrangedView(view: View, index: Int) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
if (leadingConnection != null) {
|
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
|
* 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.
|
* 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.
|
* @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.
|
* @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) {
|
if (view.superview !== this) {
|
||||||
throw RuntimeException("Cannot remove subview whose superview is not this view")
|
throw RuntimeException("Cannot remove subview whose superview is not this view")
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,12 +62,22 @@ abstract class AbstractTextField<Impl: AbstractTextField<Impl>>(
|
||||||
minecraftWidget.setMaxLength(value)
|
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 lateinit var originInWindow: Point
|
||||||
private var minecraftWidget = ProxyWidget()
|
private var minecraftWidget = ProxyWidget()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
minecraftWidget.text = initialText
|
minecraftWidget.text = initialText
|
||||||
minecraftWidget.setTextPredicate { this.validate(it) }
|
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.
|
* may be reused or created from scratch each time.
|
||||||
*/
|
*/
|
||||||
val controller: ViewController
|
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 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 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 controller The content view controller for this tab.
|
||||||
|
* @param visible A function that determines if the tab should currently be visible.
|
||||||
*/
|
*/
|
||||||
class SimpleTab(
|
class SimpleTab(
|
||||||
override val tabView: View,
|
override val tabView: View,
|
||||||
override val tooltip: Text? = null,
|
override val tooltip: Text? = null,
|
||||||
override val controller: ViewController,
|
override val controller: ViewController,
|
||||||
): Tab
|
private val visible: (() -> Boolean)? = null
|
||||||
|
): Tab {
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = visible?.invoke() ?: true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The currently selected tab.
|
* The currently selected tab.
|
||||||
|
@ -100,20 +112,7 @@ class TabViewController<T: TabViewController.Tab>(
|
||||||
tabStack = StackView(Axis.HORIZONTAL, StackView.Distribution.FILL)
|
tabStack = StackView(Axis.HORIZONTAL, StackView.Distribution.FILL)
|
||||||
tabStack.zIndex = 1.0
|
tabStack.zIndex = 1.0
|
||||||
outerStack.addArrangedSubview(tabStack)
|
outerStack.addArrangedSubview(tabStack)
|
||||||
|
updateTabButtons()
|
||||||
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())
|
|
||||||
|
|
||||||
val background = NinePatchView(NinePatchTexture.PANEL_BG)
|
val background = NinePatchView(NinePatchTexture.PANEL_BG)
|
||||||
outerStack.addArrangedSubview(background)
|
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
|
* 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.
|
* swaps the content view controller.
|
||||||
|
|
|
@ -26,8 +26,7 @@ object PhysicalConnectivity: ModInitializer {
|
||||||
|
|
||||||
registerGlobalReceiver(C2STerminalRequestItem)
|
registerGlobalReceiver(C2STerminalRequestItem)
|
||||||
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
||||||
registerGlobalReceiver(C2SConfigureActivationMode)
|
registerGlobalReceiver(C2SConfigureDevice)
|
||||||
registerGlobalReceiver(C2SConfigureRedstoneController)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerGlobalReceiver(receiver: ServerReceiver) {
|
private fun registerGlobalReceiver(receiver: ServerReceiver) {
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package net.shadowfacts.phycon
|
package net.shadowfacts.phycon
|
||||||
|
|
||||||
import net.fabricmc.api.ClientModInitializer
|
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.networking.v1.ClientPlayNetworking
|
||||||
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
|
import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
|
||||||
import net.minecraft.client.render.RenderLayer
|
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
|
||||||
import net.shadowfacts.phycon.init.PhyScreens
|
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.ClientReceiver
|
||||||
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
||||||
|
|
||||||
|
@ -17,9 +16,9 @@ import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
||||||
object PhysicalConnectivityClient: ClientModInitializer {
|
object PhysicalConnectivityClient: ClientModInitializer {
|
||||||
|
|
||||||
override fun onInitializeClient() {
|
override fun onInitializeClient() {
|
||||||
BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent())
|
ScreenRegistry.register(PhyScreens.TERMINAL, ::TerminalScreen)
|
||||||
|
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
||||||
ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
|
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
||||||
|
|
||||||
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
|
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package net.shadowfacts.phycon.network
|
package net.shadowfacts.phycon.block
|
||||||
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
@ -8,7 +8,6 @@ import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||||
import net.minecraft.block.BlockState
|
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.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
import net.shadowfacts.phycon.network.frame.ARPQueryFrame
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import net.shadowfacts.phycon.network.frame.ARPResponseFrame
|
import net.shadowfacts.phycon.frame.ARPQueryFrame
|
||||||
import net.shadowfacts.phycon.network.frame.BasePacketFrame
|
import net.shadowfacts.phycon.frame.ARPResponseFrame
|
||||||
import net.shadowfacts.phycon.network.packet.*
|
import net.shadowfacts.phycon.frame.BasePacketFrame
|
||||||
|
import net.shadowfacts.phycon.packet.*
|
||||||
import java.util.*
|
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.putInt("IPAddress", ipAddress.address)
|
||||||
tag.putLong("MACAddress", macAddress.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)
|
return super.toTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||||
super.fromTag(state, tag)
|
super.fromTag(state, tag)
|
||||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
fromCommonTag(tag)
|
||||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||||
tag.putInt("IPAddress", ipAddress.address)
|
toCommonTag(tag)
|
||||||
tag.putLong("MACAddress", macAddress.address)
|
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromClientTag(tag: CompoundTag) {
|
override fun fromClientTag(tag: CompoundTag) {
|
||||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
fromCommonTag(tag)
|
||||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onBreak() {
|
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.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
|
@ -16,7 +16,7 @@ import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||||
import java.util.*
|
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.*
|
||||||
import net.minecraft.block.piston.PistonBehavior
|
import net.minecraft.block.piston.PistonBehavior
|
||||||
|
@ -31,6 +31,7 @@ import java.util.*
|
||||||
*/
|
*/
|
||||||
class CableBlock: Block(
|
class CableBlock: Block(
|
||||||
Settings.of(CABLE_MATERIAL)
|
Settings.of(CABLE_MATERIAL)
|
||||||
|
.strength(1f)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
), NetworkCableBlock {
|
), NetworkCableBlock {
|
||||||
companion object {
|
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.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
|
@ -7,6 +7,7 @@ import net.minecraft.block.ShapeContext
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
import net.minecraft.state.StateManager
|
import net.minecraft.state.StateManager
|
||||||
import net.minecraft.state.property.Properties
|
import net.minecraft.state.property.Properties
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
@ -19,13 +20,17 @@ import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.network.DeviceBlock
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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 {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "extractor")
|
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 createBlockEntity(world: BlockView) = ExtractorBlockEntity()
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
||||||
return defaultState.with(FACING, facing)
|
return defaultState.with(FACING, facing)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.SearchOptions
|
||||||
import alexiil.mc.lib.attributes.Simulation
|
import alexiil.mc.lib.attributes.Simulation
|
||||||
|
@ -11,14 +11,15 @@ import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.component.ActivationController
|
import net.shadowfacts.phycon.component.ActivationController
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackDispatcher
|
import net.shadowfacts.phycon.component.NetworkStackDispatcher
|
||||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.network.packet.CapacityPacket
|
import net.shadowfacts.phycon.packet.CapacityPacket
|
||||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import net.shadowfacts.phycon.network.packet.RemoteActivationPacket
|
import net.shadowfacts.phycon.packet.RemoteActivationPacket
|
||||||
import net.shadowfacts.phycon.util.ActivationMode
|
import net.shadowfacts.phycon.util.ActivationMode
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +27,8 @@ import kotlin.properties.Delegates
|
||||||
*/
|
*/
|
||||||
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
||||||
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
||||||
ActivationController.ActivatableDevice {
|
ActivationController.ActivatableDevice,
|
||||||
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val SLEEP_TIME = 40L
|
val SLEEP_TIME = 40L
|
||||||
|
@ -37,7 +39,7 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
||||||
|
|
||||||
private var inventory: FixedItemInv? = null
|
private var inventory: FixedItemInv? = null
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = 40L
|
override val dispatchStackTimeout = 1L
|
||||||
override val controller = ActivationController(SLEEP_TIME, this)
|
override val controller = ActivationController(SLEEP_TIME, this)
|
||||||
|
|
||||||
fun updateInventory() {
|
fun updateInventory() {
|
||||||
|
@ -99,23 +101,21 @@ class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR),
|
||||||
return false
|
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)
|
tag.putString("ActivationMode", controller.activationMode.name)
|
||||||
return super.toTag(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun loadDeviceConfiguration(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)
|
|
||||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
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.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
|
@ -6,6 +6,7 @@ import net.minecraft.block.Material
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
import net.minecraft.state.StateManager
|
import net.minecraft.state.StateManager
|
||||||
import net.minecraft.state.property.Properties
|
import net.minecraft.state.property.Properties
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
@ -16,14 +17,18 @@ import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.Interface
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.network.DeviceBlock
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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 {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "miner")
|
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.GroupedItemInvView
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
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.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.item.Items
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.server.world.ServerWorld
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackDispatcher
|
import net.shadowfacts.phycon.component.ActivationController
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
import net.shadowfacts.phycon.component.NetworkStackDispatcher
|
||||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||||
import net.shadowfacts.phycon.network.component.spawnItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.network.packet.*
|
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
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +32,9 @@ import kotlin.math.min
|
||||||
*/
|
*/
|
||||||
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
NetworkStackProvider,
|
NetworkStackProvider,
|
||||||
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion> {
|
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion>,
|
||||||
|
ActivationController.ActivatableDevice,
|
||||||
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = cachedState[MinerBlock.FACING]
|
get() = cachedState[MinerBlock.FACING]
|
||||||
|
@ -36,6 +43,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
|
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = TerminalBlockEntity.INSERTION_TIMEOUT
|
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) {
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
|
@ -48,10 +59,16 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||||
|
if (minerMode != MinerMode.ON_DEMAND) {
|
||||||
|
return
|
||||||
|
}
|
||||||
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
|
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||||
|
if (minerMode != MinerMode.ON_DEMAND) {
|
||||||
|
return
|
||||||
|
}
|
||||||
val amount = invProxy.getAmount(packet.stack)
|
val amount = invProxy.getAmount(packet.stack)
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||||
|
@ -59,6 +76,10 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleExtractStack(packet: ExtractStackPacket) {
|
private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||||
|
if (minerMode != MinerMode.ON_DEMAND) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// always recalculate immediately before breaking
|
// always recalculate immediately before breaking
|
||||||
val drops = invProxy.getDrops(recalculate = true)
|
val drops = invProxy.getDrops(recalculate = true)
|
||||||
if (invProxy.getAmount(packet.stack) > 0) {
|
if (invProxy.getAmount(packet.stack) > 0) {
|
||||||
|
@ -73,14 +94,13 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
|
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val copy = droppedStack.copy()
|
|
||||||
|
|
||||||
val toDecr = min(droppedStack.count, remaining)
|
val toDecr = min(droppedStack.count, remaining)
|
||||||
|
val copy = droppedStack.copyWithCount(toDecr)
|
||||||
droppedStack.decrement(toDecr)
|
droppedStack.decrement(toDecr)
|
||||||
remaining -= toDecr
|
remaining -= toDecr
|
||||||
|
|
||||||
// todo: should this try to combine stacks and send as few packets as possible?
|
// todo: should this try to combine stacks and send as few packets as possible?
|
||||||
copy.count = toDecr
|
|
||||||
sendPacket(ItemStackPacket(copy, ipAddress, packet.source))
|
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 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 {
|
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
|
||||||
|
companion object {
|
||||||
|
val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
|
||||||
|
}
|
||||||
|
|
||||||
private var cachedState: BlockState? = null
|
private var cachedState: BlockState? = null
|
||||||
private var cachedDrops: List<ItemStack>? = null
|
private var cachedDrops: List<ItemStack>? = null
|
||||||
|
|
||||||
|
@ -117,12 +206,15 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
if (cachedDrops == null || realState != cachedState || recalculate) {
|
if (cachedDrops == null || realState != cachedState || recalculate) {
|
||||||
cachedState = realState
|
cachedState = realState
|
||||||
val be = if (realState.block.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
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!!
|
return cachedDrops!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStoredStacks(): Set<ItemStack> {
|
override fun getStoredStacks(): Set<ItemStack> {
|
||||||
|
if (miner.minerMode != MinerMode.ON_DEMAND) {
|
||||||
|
return setOf()
|
||||||
|
}
|
||||||
return getDrops().toSet()
|
return getDrops().toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +224,7 @@ class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
|
|
||||||
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
|
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
|
||||||
var totalCount = 0
|
var totalCount = 0
|
||||||
for (s in getDrops()) {
|
for (s in storedStacks) {
|
||||||
if (filter.matches(s)) {
|
if (filter.matches(s)) {
|
||||||
totalCount += s.count
|
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.AttributeList
|
||||||
import alexiil.mc.lib.attributes.AttributeProvider
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.*
|
import net.minecraft.block.*
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
@ -12,12 +13,16 @@ import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.network.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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,
|
NetworkComponentBlock,
|
||||||
AttributeProvider {
|
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.SearchOptions
|
||||||
import alexiil.mc.lib.attributes.Simulation
|
import alexiil.mc.lib.attributes.Simulation
|
||||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
import net.shadowfacts.phycon.component.ItemStackPacketHandler
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.network.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,11 +26,15 @@ import kotlin.math.min
|
||||||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
NetworkStackProvider,
|
NetworkStackProvider,
|
||||||
NetworkStackReceiver {
|
NetworkStackReceiver,
|
||||||
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = cachedState[FaceDeviceBlock.FACING]
|
get() = cachedState[FaceDeviceBlock.FACING]
|
||||||
|
|
||||||
|
override var providerPriority = 0
|
||||||
|
override var receiverPriority = 0
|
||||||
|
|
||||||
// todo: should this be a weak ref?
|
// todo: should this be a weak ref?
|
||||||
private var inventory: GroupedItemInv? = null
|
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.AttributeList
|
||||||
import alexiil.mc.lib.attributes.AttributeProvider
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.Material
|
import net.minecraft.block.Material
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
|
@ -19,7 +20,11 @@ import java.util.*
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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,
|
NetworkComponentBlock,
|
||||||
AttributeProvider {
|
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.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||||
import net.minecraft.block.BlockState
|
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.frame.PacketFrame
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.NetworkUtil
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import java.lang.ref.WeakReference
|
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.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.Material
|
import net.minecraft.block.Material
|
||||||
import net.minecraft.item.ItemPlacementContext
|
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.StateManager
|
||||||
import net.minecraft.state.property.Properties
|
import net.minecraft.state.property.Properties
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
@ -12,22 +12,23 @@ import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.world.BlockView
|
import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.network.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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 {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "redstone_controller")
|
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 faceThickness = 3.0
|
||||||
override val faceShapes = mapOf(
|
override val faceShapes = mapOf(
|
||||||
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 3.0, 16.0),
|
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>) {
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
super.appendProperties(builder)
|
super.appendProperties(builder)
|
||||||
builder.add(LIT)
|
builder.add(POWERED)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = RedstoneControllerBlockEntity()
|
override fun createBlockEntity(world: BlockView) = RedstoneControllerBlockEntity()
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
val state = super.getPlacementState(context)
|
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) {
|
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
|
// this can't be done in getStateForNeighborUpdate because getEmittedRedstonePower is defined in World not WorldAccess
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
val wasLit = state[LIT]
|
val wasLit = state[POWERED]
|
||||||
val isLit = isPowered(world, pos, state[FACING])
|
val isLit = isPowered(world, pos, state[FACING])
|
||||||
if (wasLit != isLit) {
|
if (wasLit != isLit) {
|
||||||
toggleLit(state, world, pos)
|
toggleLit(state, world, pos)
|
||||||
|
@ -67,7 +68,7 @@ class RedstoneControllerBlock: FaceDeviceBlock<RedstoneControllerBlockEntity>(Se
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleLit(state: BlockState, world: World, pos: BlockPos) {
|
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()
|
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.minecraft.nbt.CompoundTag
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.packet.RemoteActivationPacket
|
import net.shadowfacts.phycon.packet.RemoteActivationPacket
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.util.RedstoneMode
|
import net.shadowfacts.phycon.util.RedstoneMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER) {
|
class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER),
|
||||||
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
var managedDevices = Array<IPAddress?>(5) { null }
|
var managedDevices = Array<IPAddress?>(5) { null }
|
||||||
var redstoneMode = RedstoneMode.HIGH
|
var redstoneMode = RedstoneMode.HIGH
|
||||||
|
@ -24,7 +25,7 @@ class RedstoneControllerBlockEntity: DeviceBlockEntity(PhyBlockEntities.REDSTONE
|
||||||
|
|
||||||
fun redstoneStateChanged() {
|
fun redstoneStateChanged() {
|
||||||
val oldPowered = redstonePowered
|
val oldPowered = redstonePowered
|
||||||
redstonePowered = cachedState[RedstoneControllerBlock.LIT]
|
redstonePowered = cachedState[RedstoneControllerBlock.POWERED]
|
||||||
|
|
||||||
val mode: RemoteActivationPacket.Mode? = when (redstoneMode) {
|
val mode: RemoteActivationPacket.Mode? = when (redstoneMode) {
|
||||||
RedstoneMode.TOGGLE -> if (oldPowered != redstonePowered) RemoteActivationPacket.Mode.SINGLE else null
|
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.putIntArray("ManagedDevices", managedDevices.mapNotNull { it?.address })
|
||||||
tag.putString("RedstoneMode", redstoneMode.name)
|
tag.putString("RedstoneMode", redstoneMode.name)
|
||||||
return super.toTag(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun loadDeviceConfiguration(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)
|
|
||||||
val addresses = tag.getIntArray("ManagedDevices")
|
val addresses = tag.getIntArray("ManagedDevices")
|
||||||
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
|
managedDevices = (0..4).map { if (it >= addresses.size) null else IPAddress(addresses[it]) }.toTypedArray()
|
||||||
redstoneMode = RedstoneMode.valueOf(tag.getString("RedstoneMode"))
|
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.AttributeList
|
||||||
import alexiil.mc.lib.attributes.AttributeProvider
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.Material
|
import net.minecraft.block.Material
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.sound.BlockSoundGroup
|
||||||
import net.minecraft.util.ActionResult
|
import net.minecraft.util.ActionResult
|
||||||
import net.minecraft.util.Hand
|
import net.minecraft.util.Hand
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
@ -16,13 +17,17 @@ import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.network.DeviceBlock
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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,
|
NetworkComponentBlock,
|
||||||
AttributeProvider {
|
AttributeProvider {
|
||||||
|
|
||||||
|
@ -41,6 +46,15 @@ class TerminalBlock: DeviceBlock<TerminalBlockEntity>(Settings.of(Material.METAL
|
||||||
return ActionResult.SUCCESS
|
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<*>) {
|
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||||
to.offer(getBlockEntity(world, pos))
|
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.GroupedItemInvView
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||||
import net.minecraft.block.BlockState
|
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.inventory.Inventory
|
import net.minecraft.inventory.Inventory
|
||||||
import net.minecraft.inventory.InventoryChangedListener
|
import net.minecraft.inventory.InventoryChangedListener
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.nbt.ListTag
|
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.minecraft.screen.ScreenHandler
|
import net.minecraft.screen.ScreenHandler
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
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.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.NetworkUtil
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import net.shadowfacts.phycon.network.component.*
|
import net.shadowfacts.phycon.component.*
|
||||||
import net.shadowfacts.phycon.network.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
@ -43,8 +41,10 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
NetworkStackDispatcher<TerminalBlockEntity.PendingInsertion> {
|
NetworkStackDispatcher<TerminalBlockEntity.PendingInsertion> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val LOCATE_REQUEST_TIMEOUT: Long = 40 // ticks
|
// the locate/insertion timeouts are only 1 tick because that's long enough to hear from every device on the network
|
||||||
val INSERTION_TIMEOUT: Long = 40
|
// 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>()
|
private val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||||
|
@ -164,14 +164,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
super.tick()
|
super.tick()
|
||||||
|
|
||||||
if (counter % 20 == 0L) {
|
|
||||||
if (!world!!.isClient) {
|
if (!world!!.isClient) {
|
||||||
finishPendingRequests()
|
finishPendingRequests()
|
||||||
beginInsertions()
|
|
||||||
finishTimedOutPendingInsertions()
|
finishTimedOutPendingInsertions()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (observers > 0 && !world!!.isClient) {
|
if (counter % 20 == 0L && !world!!.isClient) {
|
||||||
|
beginInsertions()
|
||||||
|
|
||||||
|
if (observers > 0) {
|
||||||
updateAndSync()
|
updateAndSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +185,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
inventoryCache.clear()
|
inventoryCache.clear()
|
||||||
sendPacket(RequestInventoryPacket(ipAddress))
|
sendPacket(RequestInventoryPacket(ipAddress))
|
||||||
val factory = object: ExtendedScreenHandlerFactory {
|
val factory = object: ExtendedScreenHandlerFactory {
|
||||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
||||||
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,8 +211,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
|
||||||
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||||
pendingRequests.remove(request)
|
pendingRequests.remove(request)
|
||||||
|
|
||||||
// todo: also sort results by interface priority
|
val sortedResults = request.results.toMutableList()
|
||||||
val sortedResults = request.results.sortedByDescending { it.first }.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
|
var amountRequested = 0
|
||||||
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
||||||
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
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())
|
tag.put("InternalBuffer", internalBuffer.toTag())
|
||||||
return super.toTag(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun fromCommonTag(tag: CompoundTag) {
|
||||||
super.fromTag(state, tag)
|
super.fromCommonTag(tag)
|
||||||
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
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 {
|
interface NetItemObserver {
|
||||||
fun netItemsChanged()
|
fun netItemsChanged()
|
||||||
}
|
}
|
||||||
|
@ -279,6 +277,8 @@ data class StackLocateRequest(
|
||||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||||
|
|
||||||
fun isFinishable(currentTimestamp: Long): Boolean {
|
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 alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.inventory.SimpleInventory
|
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.screen.slot.Slot
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
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 com.mojang.blaze3d.systems.RenderSystem
|
||||||
import net.minecraft.client.MinecraftClient
|
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.Slot
|
||||||
import net.minecraft.screen.slot.SlotActionType
|
import net.minecraft.screen.slot.SlotActionType
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
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.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
import net.shadowfacts.phycon.init.PhyBlocks
|
||||||
import net.shadowfacts.phycon.init.PhyScreens
|
import net.shadowfacts.phycon.init.PhyScreens
|
||||||
import net.shadowfacts.phycon.networking.C2STerminalRequestItem
|
|
||||||
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
|
||||||
import net.shadowfacts.phycon.util.SortMode
|
import net.shadowfacts.phycon.util.SortMode
|
||||||
|
import net.shadowfacts.phycon.util.copyWithCount
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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 {
|
TerminalBlockEntity.NetItemObserver {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -40,9 +38,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
|
||||||
field = value
|
field = value
|
||||||
if (terminal.world!!.isClient) {
|
if (terminal.world!!.isClient) {
|
||||||
itemsForDisplay = value.map {
|
itemsForDisplay = value.map {
|
||||||
val stack = it.stack.copy()
|
it.stack.copyWithCount(it.amount)
|
||||||
stack.count = it.amount
|
|
||||||
stack
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
package net.shadowfacts.phycon.network.component
|
package net.shadowfacts.phycon.component
|
||||||
|
|
||||||
import net.minecraft.block.entity.BlockEntity
|
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.ActivationMode
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -50,11 +51,15 @@ class ActivationController<T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ActivatableDevice {
|
interface ActivatableDevice: ClientConfigurableDevice {
|
||||||
val controller: ActivationController<*>
|
val controller: ActivationController<*>
|
||||||
|
|
||||||
val counter: Long
|
val counter: Long
|
||||||
|
|
||||||
fun activate(): Boolean
|
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.block.entity.BlockEntity
|
||||||
import net.minecraft.entity.ItemEntity
|
import net.minecraft.entity.ItemEntity
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.PacketSink
|
import net.shadowfacts.phycon.api.PacketSink
|
||||||
import net.shadowfacts.phycon.api.PacketSource
|
import net.shadowfacts.phycon.api.PacketSource
|
||||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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 alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.packet.CapacityPacket
|
import net.shadowfacts.phycon.packet.CapacityPacket
|
||||||
import net.shadowfacts.phycon.network.packet.CheckCapacityPacket
|
import net.shadowfacts.phycon.packet.CheckCapacityPacket
|
||||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
|
import net.shadowfacts.phycon.util.copyWithCount
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -27,10 +29,10 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleCapacity(packet: CapacityPacket) {
|
fun handleCapacity(packet: CapacityPacket) {
|
||||||
val insertion = pendingInsertions.firstOrNull {
|
pendingInsertions.firstOrNull { insertion ->
|
||||||
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
|
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, insertion.stack) &&
|
||||||
}
|
insertion.results.none { it.second.ipAddress == packet.source }
|
||||||
if (insertion != null) {
|
}?.also { insertion ->
|
||||||
insertion.results.add(packet.capacity to packet.stackReceiver)
|
insertion.results.add(packet.capacity to packet.stackReceiver)
|
||||||
if (insertion.isFinishable(this)) {
|
if (insertion.isFinishable(this)) {
|
||||||
val remaining = finishInsertion(insertion)
|
val remaining = finishInsertion(insertion)
|
||||||
|
@ -42,14 +44,22 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
||||||
fun finishInsertion(insertion: Insertion): ItemStack {
|
fun finishInsertion(insertion: Insertion): ItemStack {
|
||||||
pendingInsertions.remove(insertion)
|
pendingInsertions.remove(insertion)
|
||||||
|
|
||||||
// todo: also sort results by interface priority
|
val sortedResults = insertion.results.toMutableList()//.sortedBy { it.first }.toMutableList()
|
||||||
val sortedResults = insertion.results.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
|
// 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()
|
val remaining = insertion.stack.copy()
|
||||||
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
||||||
val (capacity, receivingInterface) = sortedResults.removeFirst()
|
val (capacity, receivingInterface) = sortedResults.removeFirst()
|
||||||
if (capacity <= 0) continue
|
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
|
// todo: the destination should confirm how much was actually inserted, in case of race condition
|
||||||
remaining.count -= capacity
|
remaining.count -= capacity
|
||||||
}
|
}
|
||||||
|
@ -67,7 +77,8 @@ interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsert
|
||||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||||
|
|
||||||
fun isFinishable(owner: NetworkStackDispatcher<Self>): Boolean {
|
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.IPAddress
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
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.EthernetFrame
|
||||||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
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.frame.PacketFrame
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
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.block.entity.BlockEntityType
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlockEntity
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||||
import net.shadowfacts.phycon.network.block.miner.MinerBlockEntity
|
import net.shadowfacts.phycon.block.inserter.InserterBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlock
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||||
import net.shadowfacts.phycon.network.block.test.DestBlockEntity
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
import net.shadowfacts.phycon.network.block.test.SourceBlockEntity
|
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -31,11 +31,10 @@ object PhyBlockEntities {
|
||||||
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
||||||
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
||||||
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
|
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
|
||||||
|
val INSERTER = create(::InserterBlockEntity, PhyBlocks.INSERTER)
|
||||||
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
||||||
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
|
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
|
||||||
|
val REDSTONE_EMITTER = create(::RedstoneEmitterBlockEntity, PhyBlocks.REDSTONE_EMITTER)
|
||||||
val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE)
|
|
||||||
val DEST = create(::DestBlockEntity, PhyBlocks.DEST)
|
|
||||||
|
|
||||||
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
||||||
return BlockEntityType.Builder.create(builder, block).build(null)
|
return BlockEntityType.Builder.create(builder, block).build(null)
|
||||||
|
@ -46,11 +45,10 @@ object PhyBlockEntities {
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(ExtractorBlock.ID, EXTRACTOR)
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
|
register(InserterBlock.ID, INSERTER)
|
||||||
register(MinerBlock.ID, MINER)
|
register(MinerBlock.ID, MINER)
|
||||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||||
|
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||||
register(SourceBlock.ID, SOURCE)
|
|
||||||
register(DestBlock.ID, DEST)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
||||||
|
|
|
@ -3,15 +3,15 @@ package net.shadowfacts.phycon.init
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||||
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlock
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -23,11 +23,10 @@ object PhyBlocks {
|
||||||
val SWITCH = SwitchBlock()
|
val SWITCH = SwitchBlock()
|
||||||
val CABLE = CableBlock()
|
val CABLE = CableBlock()
|
||||||
val EXTRACTOR = ExtractorBlock()
|
val EXTRACTOR = ExtractorBlock()
|
||||||
|
val INSERTER = InserterBlock()
|
||||||
val MINER = MinerBlock()
|
val MINER = MinerBlock()
|
||||||
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
|
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
|
||||||
|
val REDSTONE_EMITTER = RedstoneEmitterBlock()
|
||||||
val SOURCE = SourceBlock()
|
|
||||||
val DEST = DestBlock()
|
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
|
@ -35,11 +34,10 @@ object PhyBlocks {
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(CableBlock.ID, CABLE)
|
register(CableBlock.ID, CABLE)
|
||||||
register(ExtractorBlock.ID, EXTRACTOR)
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
|
register(InserterBlock.ID, INSERTER)
|
||||||
register(MinerBlock.ID, MINER)
|
register(MinerBlock.ID, MINER)
|
||||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||||
|
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||||
register(SourceBlock.ID, SOURCE)
|
|
||||||
register(DestBlock.ID, DEST)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, block: Block) {
|
private fun register(id: Identifier, block: Block) {
|
||||||
|
|
|
@ -6,31 +6,31 @@ import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
import net.shadowfacts.phycon.item.ConsoleItem
|
import net.shadowfacts.phycon.item.ConsoleItem
|
||||||
import net.shadowfacts.phycon.item.ScrewdriverItem
|
import net.shadowfacts.phycon.item.ScrewdriverItem
|
||||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
import net.shadowfacts.phycon.block.cable.CableBlock
|
||||||
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
import net.shadowfacts.phycon.block.extractor.ExtractorBlock
|
||||||
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
import net.shadowfacts.phycon.block.inserter.InserterBlock
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlock
|
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
|
||||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
|
||||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
import net.shadowfacts.phycon.block.terminal.TerminalBlock
|
||||||
|
import net.shadowfacts.phycon.item.DeviceBlockItem
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
object PhyItems {
|
object PhyItems {
|
||||||
|
|
||||||
val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
val INTERFACE = DeviceBlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
||||||
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
val TERMINAL = DeviceBlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
||||||
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
||||||
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
|
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
|
||||||
val EXTRACTOR = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
|
val EXTRACTOR = DeviceBlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
|
||||||
val MINER = BlockItem(PhyBlocks.MINER, Item.Settings())
|
val INSERTER = DeviceBlockItem(PhyBlocks.INSERTER, Item.Settings())
|
||||||
val REDSTONE_CONTROLLER = BlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
|
val MINER = DeviceBlockItem(PhyBlocks.MINER, Item.Settings())
|
||||||
|
val REDSTONE_CONTROLLER = DeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
|
||||||
val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings())
|
val REDSTONE_EMITTER = DeviceBlockItem(PhyBlocks.REDSTONE_EMITTER, Item.Settings())
|
||||||
val DEST = BlockItem(PhyBlocks.DEST , Item.Settings())
|
|
||||||
|
|
||||||
val SCREWDRIVER = ScrewdriverItem()
|
val SCREWDRIVER = ScrewdriverItem()
|
||||||
val CONSOLE = ConsoleItem()
|
val CONSOLE = ConsoleItem()
|
||||||
|
@ -41,11 +41,10 @@ object PhyItems {
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(CableBlock.ID, CABLE)
|
register(CableBlock.ID, CABLE)
|
||||||
register(ExtractorBlock.ID, EXTRACTOR)
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
|
register(InserterBlock.ID, INSERTER)
|
||||||
register(MinerBlock.ID, MINER)
|
register(MinerBlock.ID, MINER)
|
||||||
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
|
||||||
|
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
|
||||||
register(SourceBlock.ID, SOURCE)
|
|
||||||
register(DestBlock.ID, DEST)
|
|
||||||
|
|
||||||
register(ScrewdriverItem.ID, SCREWDRIVER)
|
register(ScrewdriverItem.ID, SCREWDRIVER)
|
||||||
register(ConsoleItem.ID, CONSOLE)
|
register(ConsoleItem.ID, CONSOLE)
|
||||||
|
|
|
@ -2,17 +2,23 @@ package net.shadowfacts.phycon.init
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
||||||
import net.minecraft.screen.ScreenHandlerType
|
import net.minecraft.screen.ScreenHandlerType
|
||||||
import net.minecraft.util.Identifier
|
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreenHandler
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||||
|
|
||||||
object PhyScreens {
|
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
|
private set
|
||||||
|
|
||||||
fun init() {
|
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.ActionResult
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.network.DeviceBlock
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.screen.console.DeviceConsoleScreen
|
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
|
package net.shadowfacts.phycon.item
|
||||||
|
|
||||||
|
import net.minecraft.block.Blocks
|
||||||
|
import net.minecraft.entity.ItemEntity
|
||||||
import net.minecraft.item.Item
|
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.minecraft.util.Identifier
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -11,4 +19,33 @@ class ScrewdriverItem: Item(Settings()) {
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "screwdriver")
|
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.PacketByteBufs
|
||||||
import net.fabricmc.fabric.api.networking.v1.PacketSender
|
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.Packet
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.minecraft.server.MinecraftServer
|
import net.minecraft.server.MinecraftServer
|
||||||
import net.minecraft.server.network.ServerPlayNetworkHandler
|
import net.minecraft.server.network.ServerPlayNetworkHandler
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
import net.minecraft.util.Identifier
|
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.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.network.component.ActivationController
|
|
||||||
import net.shadowfacts.phycon.util.ActivationMode
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
object C2SConfigureActivationMode: ServerReceiver {
|
object C2SConfigureDevice: ServerReceiver {
|
||||||
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "configure_activation_mode")
|
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()
|
val buf = PacketByteBufs.create()
|
||||||
|
|
||||||
buf.writeIdentifier(be.world!!.registryKey.value)
|
buf.writeIdentifier(be.world!!.registryKey.value)
|
||||||
buf.writeBlockPos(be.pos)
|
buf.writeBlockPos(be.pos)
|
||||||
buf.writeString(be.controller.activationMode.name)
|
val tag = CompoundTag()
|
||||||
|
be.writeDeviceConfiguration(tag)
|
||||||
|
buf.writeCompoundTag(tag)
|
||||||
|
|
||||||
return createPacket(buf)
|
return createPacket(buf)
|
||||||
}
|
}
|
||||||
|
@ -34,16 +34,16 @@ object C2SConfigureActivationMode: ServerReceiver {
|
||||||
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
val dimID = buf.readIdentifier()
|
val dimID = buf.readIdentifier()
|
||||||
val pos = buf.readBlockPos()
|
val pos = buf.readBlockPos()
|
||||||
val mode = ActivationMode.valueOf(buf.readString())
|
val tag = buf.readCompoundTag() ?: return
|
||||||
|
|
||||||
server.execute {
|
server.execute {
|
||||||
// todo: check the player is close enough
|
// todo: check if the player is close enough
|
||||||
val key = RegistryKey.of(Registry.DIMENSION, dimID)
|
val world = player.world
|
||||||
val world = server.getWorld(key) ?: return@execute
|
if (world.registryKey.value != dimID) return@execute
|
||||||
val device = world.getBlockEntity(pos) ?: return@execute
|
val be = world.getBlockEntity(pos) ?: return@execute
|
||||||
if (device !is ActivationController.ActivatableDevice) return@execute
|
val device = be as? ClientConfigurableDevice ?: return@execute
|
||||||
device.controller.activationMode = mode
|
device.loadDeviceConfiguration(tag)
|
||||||
device.markDirty()
|
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.Registry
|
||||||
import net.minecraft.util.registry.RegistryKey
|
import net.minecraft.util.registry.RegistryKey
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
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
|
* @author shadowfacts
|
||||||
|
@ -30,9 +31,7 @@ object C2STerminalRequestItem: ServerReceiver {
|
||||||
// Force the count of the stack to be 1 before serializing for the network because
|
// 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
|
// PacketByteBuf serializes the stack count as a byte. Otherwise counts > 127 will result in
|
||||||
// an overflow and be negative on the receiving side.
|
// an overflow and be negative on the receiving side.
|
||||||
val stackCopy = stack.copy()
|
buf.writeItemStack(stack.copyWithCount(1))
|
||||||
stackCopy.count = 1
|
|
||||||
buf.writeItemStack(stackCopy)
|
|
||||||
|
|
||||||
buf.writeVarInt(amount)
|
buf.writeVarInt(amount)
|
||||||
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
||||||
|
|
|
@ -10,8 +10,8 @@ import net.minecraft.server.network.ServerPlayNetworkHandler
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||||
import net.shadowfacts.phycon.util.SortMode
|
import net.shadowfacts.phycon.util.SortMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,8 +7,8 @@ import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.network.ClientPlayNetworkHandler
|
import net.minecraft.client.network.ClientPlayNetworkHandler
|
||||||
import net.minecraft.network.Packet
|
import net.minecraft.network.Packet
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
|
||||||
import net.shadowfacts.phycon.util.SortMode
|
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.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
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.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
|
@ -1,4 +1,4 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
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.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
|
@ -1,4 +1,4 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
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.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
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.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
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 alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
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
|
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
|
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.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
|
@ -2,16 +2,14 @@ package net.shadowfacts.phycon.screen.console
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.text.TranslatableText
|
import net.minecraft.text.TranslatableText
|
||||||
import net.shadowfacts.cacao.geometry.Axis
|
|
||||||
import net.shadowfacts.cacao.util.Color
|
import net.shadowfacts.cacao.util.Color
|
||||||
import net.shadowfacts.cacao.view.Label
|
import net.shadowfacts.cacao.view.Label
|
||||||
import net.shadowfacts.cacao.view.StackView
|
|
||||||
import net.shadowfacts.cacao.view.button.EnumButton
|
import net.shadowfacts.cacao.view.button.EnumButton
|
||||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.component.ActivationController
|
import net.shadowfacts.phycon.component.ActivationController
|
||||||
import net.shadowfacts.phycon.networking.C2SConfigureActivationMode
|
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||||
import net.shadowfacts.phycon.util.ActivationMode
|
import net.shadowfacts.phycon.util.ActivationMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +30,7 @@ class ActivatableDeviceViewController<T>(
|
||||||
val mode = EnumButton(device.controller.activationMode, ActivationMode::friendlyName)
|
val mode = EnumButton(device.controller.activationMode, ActivationMode::friendlyName)
|
||||||
mode.handler = {
|
mode.handler = {
|
||||||
device.controller.activationMode = it.value
|
device.controller.activationMode = it.value
|
||||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureActivationMode(device))
|
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||||
}
|
}
|
||||||
view.addSubview(mode)
|
view.addSubview(mode)
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,12 @@ import net.shadowfacts.cacao.viewcontroller.TabViewController
|
||||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||||
import net.shadowfacts.cacao.window.Window
|
import net.shadowfacts.cacao.window.Window
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
|
||||||
import net.shadowfacts.phycon.network.component.ActivationController
|
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
|
import org.lwjgl.glfw.GLFW
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +43,8 @@ class DeviceConsoleScreen(
|
||||||
intrinsicContentSize = Size(16.0, 16.0)
|
intrinsicContentSize = Size(16.0, 16.0)
|
||||||
},
|
},
|
||||||
TranslatableText("gui.phycon.console.remote"),
|
TranslatableText("gui.phycon.console.remote"),
|
||||||
ActivatableDeviceViewController(device)
|
ActivatableDeviceViewController(device),
|
||||||
|
device::canConfigureActivationController
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
if (device is RedstoneControllerBlockEntity) {
|
if (device is RedstoneControllerBlockEntity) {
|
||||||
|
@ -52,7 +56,30 @@ class DeviceConsoleScreen(
|
||||||
RedstoneControllerViewController(device)
|
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)
|
tabController = TabViewController(tabs)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import net.shadowfacts.cacao.view.Label
|
||||||
import net.shadowfacts.cacao.view.StackView
|
import net.shadowfacts.cacao.view.StackView
|
||||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
import net.shadowfacts.cacao.viewcontroller.ViewController
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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.cacao.viewcontroller.ViewController
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
import net.shadowfacts.kiwidsl.dsl
|
||||||
import net.shadowfacts.phycon.api.util.IPAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.block.redstone.RedstoneControllerBlockEntity
|
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
|
||||||
import net.shadowfacts.phycon.networking.C2SConfigureRedstoneController
|
import net.shadowfacts.phycon.networking.C2SConfigureDevice
|
||||||
import net.shadowfacts.phycon.util.RedstoneMode
|
import net.shadowfacts.phycon.util.RedstoneMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,14 +39,14 @@ class RedstoneControllerViewController(val device: RedstoneControllerBlockEntity
|
||||||
val mode = EnumButton(device.redstoneMode, RedstoneMode::friendlyName)
|
val mode = EnumButton(device.redstoneMode, RedstoneMode::friendlyName)
|
||||||
mode.handler = {
|
mode.handler = {
|
||||||
device.redstoneMode = it.value
|
device.redstoneMode = it.value
|
||||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureRedstoneController(device))
|
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
|
||||||
}
|
}
|
||||||
controls.addArrangedSubview(mode)
|
controls.addArrangedSubview(mode)
|
||||||
|
|
||||||
val textFields = (0 until 5).map { i ->
|
val textFields = (0 until 5).map { i ->
|
||||||
TextField(device.managedDevices[i]?.toString() ?: "") {
|
TextField(device.managedDevices[i]?.toString() ?: "") {
|
||||||
device.managedDevices[i] = IPAddress.parse(it.text)
|
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)
|
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.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
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" }
|
"apply": { "model": "phycon:block/cable_center" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": { "facing": "down", "lit": "false" },
|
"when": { "facing": "down", "powered": "false" },
|
||||||
"apply": { "model": "phycon:block/redstone_controller_side_off" }
|
"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 }
|
"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 }
|
"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 }
|
"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 }
|
"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 }
|
"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" }
|
"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 }
|
"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 }
|
"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 }
|
"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 }
|
"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 }
|
"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.terminal": "Terminal",
|
||||||
"block.phycon.cable": "Cable",
|
"block.phycon.cable": "Cable",
|
||||||
"block.phycon.extractor": "Inventory Extractor",
|
"block.phycon.extractor": "Inventory Extractor",
|
||||||
|
"block.phycon.inserter": "Inventory Inserter",
|
||||||
"block.phycon.miner": "Block Miner",
|
"block.phycon.miner": "Block Miner",
|
||||||
"block.phycon.redstone_controller": "Redstone Controller",
|
"block.phycon.redstone_controller": "Redstone Controller",
|
||||||
|
"block.phycon.redstone_emitter": "Redstone Emitter",
|
||||||
|
|
||||||
"item.phycon.screwdriver": "Screwdriver",
|
"item.phycon.screwdriver": "Screwdriver",
|
||||||
"item.phycon.console": "Console",
|
"item.phycon.console": "Console",
|
||||||
|
@ -18,11 +20,24 @@
|
||||||
"gui.phycon.console.redstone.devices": "Managed Devices",
|
"gui.phycon.console.redstone.devices": "Managed Devices",
|
||||||
"gui.phycon.console.remote": "Remote Management",
|
"gui.phycon.console.remote": "Remote Management",
|
||||||
"gui.phycon.console.remote.mode": "Activation Mode",
|
"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.high": "High",
|
||||||
"gui.phycon.redstone_mode.low": "Low",
|
"gui.phycon.redstone_mode.low": "Low",
|
||||||
"gui.phycon.redstone_mode.toggle": "Toggle",
|
"gui.phycon.redstone_mode.toggle": "Toggle",
|
||||||
"gui.phycon.redstone_mode.rising_edge": "Rising Edge",
|
"gui.phycon.redstone_mode.rising_edge": "Rising Edge",
|
||||||
"gui.phycon.redstone_mode.falling_edge": "Falling Edge",
|
"gui.phycon.redstone_mode.falling_edge": "Falling Edge",
|
||||||
"gui.phycon.activation_mode.automatic": "Automatic",
|
"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",
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"cable_side": "phycon:block/cable_straight",
|
||||||
|
"cable_end": "phycon:block/cable_cap_end"
|
||||||
|
},
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"from": [0, 0, 0],
|
"from": [0, 0, 0],
|
||||||
"to": [16, 2, 16],
|
"to": [16, 2, 16],
|
||||||
"faces": {
|
"faces": {
|
||||||
"down": {"texture": "phycon:block/extractor_front"},
|
"down": {"texture": "phycon:block/extractor_front", "cullface": "down"},
|
||||||
"up": {"texture": "phycon:block/extractor_back"},
|
"up": {"texture": "phycon:block/extractor_back"},
|
||||||
"north": {"texture": "phycon:block/extractor_side"},
|
"north": {"texture": "phycon:block/extractor_side"},
|
||||||
"south": {"texture": "phycon:block/extractor_side"},
|
"south": {"texture": "phycon:block/extractor_side"},
|
||||||
|
@ -39,11 +43,11 @@
|
||||||
"from": [6, 6, 6],
|
"from": [6, 6, 6],
|
||||||
"to": [10, 16, 10],
|
"to": [10, 16, 10],
|
||||||
"faces": {
|
"faces": {
|
||||||
"up": {"texture": "phycon:block/cable_side"},
|
"up": {"texture": "#cable_end", "cullface": "up"},
|
||||||
"north": {"texture": "phycon:block/cable_side"},
|
"north": {"texture": "#cable_side"},
|
||||||
"south": {"texture": "phycon:block/cable_side"},
|
"south": {"texture": "#cable_side"},
|
||||||
"west": {"texture": "phycon:block/cable_side"},
|
"west": {"texture": "#cable_side"},
|
||||||
"east": {"texture": "phycon:block/cable_side"}
|
"east": {"texture": "#cable_side"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -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