Compare commits
No commits in common. "future" and "main" have entirely different histories.
|
@ -1,2 +0,0 @@
|
||||||
# reformat
|
|
||||||
f6f4c12d0304c945c03ab70556048ee8d78e4019
|
|
|
@ -1,7 +1,7 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "fabric-loom" version "0.12.9"
|
id "fabric-loom" version "0.12.9"
|
||||||
id "maven-publish"
|
id "maven-publish"
|
||||||
id "org.jetbrains.kotlin.jvm" version "1.7.10"
|
id "org.jetbrains.kotlin.jvm" version "1.6.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
archivesBaseName = project.archives_base_name
|
archivesBaseName = project.archives_base_name
|
||||||
|
@ -79,9 +79,9 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||||
// You may need to force-disable transitiveness on them.
|
// You may need to force-disable transitiveness on them.
|
||||||
// modImplementation "alexiil.mc.lib:libblockattributes-all:${project.libblockattributes_version}"
|
modImplementation "alexiil.mc.lib:libblockattributes-all:${project.libblockattributes_version}"
|
||||||
// include "alexiil.mc.lib:libblockattributes-core:${project.libblockattributes_version}"
|
include "alexiil.mc.lib:libblockattributes-core:${project.libblockattributes_version}"
|
||||||
// include "alexiil.mc.lib:libblockattributes-items:${project.libblockattributes_version}"
|
include "alexiil.mc.lib:libblockattributes-items:${project.libblockattributes_version}"
|
||||||
|
|
||||||
implementation project(":kiwi-java")
|
implementation project(":kiwi-java")
|
||||||
include project(":kiwi-java")
|
include project(":kiwi-java")
|
||||||
|
|
|
@ -39,8 +39,7 @@ object PhyConPluginClient : ClientModInitializer, REIClientPlugin, AbstractTermi
|
||||||
AbstractTerminalScreen.searchQueryListener = this
|
AbstractTerminalScreen.searchQueryListener = this
|
||||||
try {
|
try {
|
||||||
val clazz = Class.forName("me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField")
|
val clazz = Class.forName("me.shedaniel.rei.impl.client.gui.widget.search.OverlaySearchField")
|
||||||
isHighlightingHandle =
|
isHighlightingHandle = MethodHandles.publicLookup().findStaticGetter(clazz, "isHighlighting", Boolean::class.java)
|
||||||
MethodHandles.publicLookup().findStaticGetter(clazz, "isHighlighting", Boolean::class.java)
|
|
||||||
} catch (e: ReflectiveOperationException) {
|
} catch (e: ReflectiveOperationException) {
|
||||||
logger.warn("Unable to find OverlaySearchField.isHighlighting, highlight sync will be disabled", e)
|
logger.warn("Unable to find OverlaySearchField.isHighlighting, highlight sync will be disabled", e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,7 @@ object PhyConPluginCommon : REIServerPlugin, PhyConPlugin {
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override fun registerMenuInfo(registry: MenuInfoRegistry) {
|
override fun registerMenuInfo(registry: MenuInfoRegistry) {
|
||||||
registry.register(
|
registry.register(CategoryIdentifier.of("minecraft", "plugins/crafting"), CraftingTerminalScreenHandler::class.java, SimpleMenuInfoProvider.of(::TerminalInfo))
|
||||||
CategoryIdentifier.of("minecraft", "plugins/crafting"),
|
|
||||||
CraftingTerminalScreenHandler::class.java,
|
|
||||||
SimpleMenuInfoProvider.of(::TerminalInfo)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initializePhyCon(api: PhyConAPI) {
|
override fun initializePhyCon(api: PhyConAPI) {
|
||||||
|
|
|
@ -18,20 +18,11 @@ object PhyConTR : ModInitializer {
|
||||||
|
|
||||||
override fun onInitialize() {
|
override fun onInitialize() {
|
||||||
TRContent.StorageUnit.values().forEach {
|
TRContent.StorageUnit.values().forEach {
|
||||||
ItemAttributes.GROUPED_INV.setBlockAdder(
|
ItemAttributes.GROUPED_INV.setBlockAdder(AttributeSourceType.COMPAT_WRAPPER, it.block, ::addStorageUnitGroupedInv)
|
||||||
AttributeSourceType.COMPAT_WRAPPER,
|
|
||||||
it.block,
|
|
||||||
::addStorageUnitGroupedInv
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addStorageUnitGroupedInv(
|
private fun addStorageUnitGroupedInv(world: World, pos: BlockPos, state: BlockState, to: AttributeList<GroupedItemInv>) {
|
||||||
world: World,
|
|
||||||
pos: BlockPos,
|
|
||||||
state: BlockState,
|
|
||||||
to: AttributeList<GroupedItemInv>
|
|
||||||
) {
|
|
||||||
(world.getBlockEntity(pos) as? StorageUnitBaseBlockEntity)?.also { su ->
|
(world.getBlockEntity(pos) as? StorageUnitBaseBlockEntity)?.also { su ->
|
||||||
to.offer(StorageUnitWrapper(su))
|
to.offer(StorageUnitWrapper(su))
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ public interface Interface {
|
||||||
|
|
||||||
void send(@NotNull EthernetFrame frame);
|
void send(@NotNull EthernetFrame frame);
|
||||||
|
|
||||||
default void cableDisconnected() {
|
default void cableDisconnected() {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ public interface NetworkDevice {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IP address of this device.
|
* The IP address of this device.
|
||||||
* <p>
|
*
|
||||||
* If a device has not been assigned an address by a DHCP server, it may self-assign a randomly generated one.
|
* If a device has not been assigned an address by a DHCP server, it may self-assign a randomly generated one.
|
||||||
* <p>
|
*
|
||||||
* The address of a network device should never be the broadcast address.
|
* The address of a network device should never be the broadcast address.
|
||||||
*
|
*
|
||||||
* @return The IP address of this device.
|
* @return The IP address of this device.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package net.shadowfacts.phycon.api;
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.Attribute;
|
||||||
|
import alexiil.mc.lib.attributes.Attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
public class PhyAttributes {
|
||||||
|
|
||||||
|
public static final Attribute<PacketSink> PACKET_SINK = Attributes.create(PacketSink.class);
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ public interface TerminalSetting {
|
||||||
|
|
||||||
int[] getUV();
|
int[] getUV();
|
||||||
|
|
||||||
@Nullable
|
@Nullable Text getTooltip();
|
||||||
Text getTooltip();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,12 @@ public final class IPAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Random ipAddressRandom = new Random();
|
private static final Random ipAddressRandom = new Random();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static IPAddress random() {
|
public static IPAddress random() {
|
||||||
return random(ipAddressRandom);
|
return random(ipAddressRandom);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern IP_PATTERN = Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
|
private static final Pattern IP_PATTERN = Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$");
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static IPAddress parse(String s) {
|
public static IPAddress parse(String s) {
|
||||||
Matcher matcher = IP_PATTERN.matcher(s);
|
Matcher matcher = IP_PATTERN.matcher(s);
|
||||||
|
|
|
@ -22,7 +22,6 @@ public final class MACAddress {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Random macAddressRandom = new Random();
|
private static final Random macAddressRandom = new Random();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static MACAddress random() {
|
public static MACAddress random() {
|
||||||
return random(macAddressRandom);
|
return random(macAddressRandom);
|
||||||
|
|
|
@ -24,7 +24,6 @@ open class CacaoScreen(title: Text = LiteralText("CacaoScreen")) : Screen(title)
|
||||||
|
|
||||||
// _windows is the internal, mutable object, since we only want it to by mutated by the add/removeWindow methods.
|
// _windows is the internal, mutable object, since we only want it to by mutated by the add/removeWindow methods.
|
||||||
private val _windows = LinkedList<Window>()
|
private val _windows = LinkedList<Window>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of windows that belong to this screen.
|
* The list of windows that belong to this screen.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
# Cacao
|
# Cacao
|
||||||
|
|
||||||
Cacao is a UI framework for Fabric/Minecraft mods based on Apple's [Cocoa](https://en.wikipedia.org/wiki/Cocoa_(API)
|
Cacao is a UI framework for Fabric/Minecraft mods based on Apple's [Cocoa](https://en.wikipedia.org/wiki/Cocoa_(API)
|
||||||
UI toolkit.
|
UI toolkit.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### Screen
|
### Screen
|
||||||
|
|
||||||
A [CacaoScreen][] is the object that acts as the interface between Minecraft GUI code and the Cacao framework.
|
A [CacaoScreen][] is the object that acts as the interface between Minecraft GUI code and the Cacao framework.
|
||||||
|
|
||||||
The CacaoScreen draws Cacao views on screen and passes Minecraft input events to the appropriate Views. The CacaoScreen
|
The CacaoScreen draws Cacao views on screen and passes Minecraft input events to the appropriate Views. The CacaoScreen
|
||||||
|
@ -15,7 +12,6 @@ owns a group of [Window](#window) objects which are displayed on screen, one on
|
||||||
[CacaoScreen]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt
|
[CacaoScreen]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/CacaoScreen.kt
|
||||||
|
|
||||||
### Window
|
### Window
|
||||||
|
|
||||||
A [Window][] object has a root [View Controller](#view-controller) that it displays on screen.
|
A [Window][] object has a root [View Controller](#view-controller) that it displays on screen.
|
||||||
|
|
||||||
The Window occupies the entire screen space and translates events from the screen to the root View Controller's View.
|
The Window occupies the entire screen space and translates events from the screen to the root View Controller's View.
|
||||||
|
@ -25,7 +21,6 @@ view hierarchy.
|
||||||
[Window]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/Window.kt
|
[Window]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/Window.kt
|
||||||
|
|
||||||
### View Controller
|
### View Controller
|
||||||
|
|
||||||
A [ViewController][] object owns a view, receives lifecycle events for it, and is generally used to control the view.
|
A [ViewController][] object owns a view, receives lifecycle events for it, and is generally used to control the view.
|
||||||
|
|
||||||
Each View Controller has a single root [View](#view) which in turn may have subviews.
|
Each View Controller has a single root [View](#view) which in turn may have subviews.
|
||||||
|
@ -33,7 +28,6 @@ Each View Controller has a single root [View](#view) which in turn may have subv
|
||||||
[ViewController]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/viewcontroller/ViewController.kt
|
[ViewController]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/viewcontroller/ViewController.kt
|
||||||
|
|
||||||
### View
|
### View
|
||||||
|
|
||||||
A [View][] object represents a single view on screen. It handles drawing, positioning, and directly handles input.
|
A [View][] object represents a single view on screen. It handles drawing, positioning, and directly handles input.
|
||||||
|
|
||||||
[View]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/view/View.kt
|
[View]: https://git.shadowfacts.net/minecraft/ASMR/src/branch/master/src/main/kotlin/net/shadowfacts/cacao/view/View.kt
|
||||||
|
|
|
@ -10,12 +10,10 @@ enum class AxisPosition {
|
||||||
* Top for vertical, left for horizontal.
|
* Top for vertical, left for horizontal.
|
||||||
*/
|
*/
|
||||||
LEADING,
|
LEADING,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Center X/Y.
|
* Center X/Y.
|
||||||
*/
|
*/
|
||||||
CENTER,
|
CENTER,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bottom for vertical, right for horizontal.
|
* Bottom for vertical, right for horizontal.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -28,11 +28,6 @@ class LayoutGuide(
|
||||||
val centerYAnchor: LayoutVariable = LayoutVariable(this, "centerY")
|
val centerYAnchor: LayoutVariable = LayoutVariable(this, "centerY")
|
||||||
|
|
||||||
val frame: Rect
|
val frame: Rect
|
||||||
get() = Rect(
|
get() = Rect(leftAnchor.value - owningView.leftAnchor.value, topAnchor.value - owningView.topAnchor.value, widthAnchor.value, heightAnchor.value)
|
||||||
leftAnchor.value - owningView.leftAnchor.value,
|
|
||||||
topAnchor.value - owningView.topAnchor.value,
|
|
||||||
widthAnchor.value,
|
|
||||||
heightAnchor.value
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,27 +48,13 @@ object RenderHelper : DrawableHelper() {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||||
RenderSystem.setShaderTexture(0, texture.location)
|
RenderSystem.setShaderTexture(0, texture.location)
|
||||||
draw(
|
draw(matrixStack, rect.left, rect.top, texture.u, texture.v, rect.width, rect.height, texture.width, texture.height)
|
||||||
matrixStack,
|
|
||||||
rect.left,
|
|
||||||
rect.top,
|
|
||||||
texture.u,
|
|
||||||
texture.v,
|
|
||||||
rect.width,
|
|
||||||
rect.height,
|
|
||||||
texture.width,
|
|
||||||
texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun drawLine(start: Point, end: Point, z: Double, width: Float, color: Color) {
|
fun drawLine(start: Point, end: Point, z: Double, width: Float, color: Color) {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
|
|
||||||
RenderSystem.lineWidth(width)
|
RenderSystem.lineWidth(width)
|
||||||
RenderSystem.enableBlend()
|
|
||||||
RenderSystem.disableTexture()
|
|
||||||
RenderSystem.defaultBlendFunc()
|
|
||||||
RenderSystem.setShader(GameRenderer::getPositionColorShader)
|
|
||||||
val tessellator = Tessellator.getInstance()
|
val tessellator = Tessellator.getInstance()
|
||||||
val buffer = tessellator.buffer
|
val buffer = tessellator.buffer
|
||||||
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.POSITION_COLOR)
|
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.POSITION_COLOR)
|
||||||
|
@ -80,50 +66,18 @@ object RenderHelper : DrawableHelper() {
|
||||||
/**
|
/**
|
||||||
* Draws the bound texture with the given screen and texture position and size.
|
* Draws the bound texture with the given screen and texture position and size.
|
||||||
*/
|
*/
|
||||||
fun draw(
|
fun draw(matrixStack: MatrixStack, x: Double, y: Double, u: Int, v: Int, width: Double, height: Double, textureWidth: Int, textureHeight: Int) {
|
||||||
matrixStack: MatrixStack,
|
|
||||||
x: Double,
|
|
||||||
y: Double,
|
|
||||||
u: Int,
|
|
||||||
v: Int,
|
|
||||||
width: Double,
|
|
||||||
height: Double,
|
|
||||||
textureWidth: Int,
|
|
||||||
textureHeight: Int
|
|
||||||
) {
|
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
val uStart = u.toFloat() / textureWidth
|
val uStart = u.toFloat() / textureWidth
|
||||||
val uEnd = (u + width).toFloat() / textureWidth
|
val uEnd = (u + width).toFloat() / textureWidth
|
||||||
val vStart = v.toFloat() / textureHeight
|
val vStart = v.toFloat() / textureHeight
|
||||||
val vEnd = (v + height).toFloat() / textureHeight
|
val vEnd = (v + height).toFloat() / textureHeight
|
||||||
drawTexturedQuad(
|
drawTexturedQuad(matrixStack.peek().positionMatrix, x, x + width, y, y + height, 0.0, uStart, uEnd, vStart, vEnd)
|
||||||
matrixStack.peek().positionMatrix,
|
|
||||||
x,
|
|
||||||
x + width,
|
|
||||||
y,
|
|
||||||
y + height,
|
|
||||||
0.0,
|
|
||||||
uStart,
|
|
||||||
uEnd,
|
|
||||||
vStart,
|
|
||||||
vEnd
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from net.minecraft.client.gui.DrawableHelper
|
// Copied from net.minecraft.client.gui.DrawableHelper
|
||||||
// TODO: use an access transformer to just call minecraft's impl
|
// TODO: use an access transformer to just call minecraft's impl
|
||||||
private fun drawTexturedQuad(
|
private fun drawTexturedQuad(matrix: Matrix4f, x0: Double, x1: Double, y0: Double, y1: Double, z: Double, u0: Float, u1: Float, v0: Float, v1: Float) {
|
||||||
matrix: Matrix4f,
|
|
||||||
x0: Double,
|
|
||||||
x1: Double,
|
|
||||||
y0: Double,
|
|
||||||
y1: Double,
|
|
||||||
z: Double,
|
|
||||||
u0: Float,
|
|
||||||
u1: Float,
|
|
||||||
v0: Float,
|
|
||||||
v1: Float
|
|
||||||
) {
|
|
||||||
val bufferBuilder = Tessellator.getInstance().buffer
|
val bufferBuilder = Tessellator.getInstance().buffer
|
||||||
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE)
|
bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE)
|
||||||
bufferBuilder.vertex(matrix, x0.toFloat(), y1.toFloat(), z.toFloat()).texture(u0, v1).next()
|
bufferBuilder.vertex(matrix, x0.toFloat(), y1.toFloat(), z.toFloat()).texture(u0, v1).next()
|
||||||
|
|
|
@ -15,13 +15,7 @@ import net.minecraft.util.Identifier
|
||||||
* @param centerWidth The width of the center patch.
|
* @param centerWidth The width of the center patch.
|
||||||
* @param centerHeight The height of the center patch.
|
* @param centerHeight The height of the center patch.
|
||||||
*/
|
*/
|
||||||
data class NinePatchTexture(
|
data class NinePatchTexture(val texture: Texture, val cornerWidth: Int, val cornerHeight: Int, val centerWidth: Int, val centerHeight: Int) {
|
||||||
val texture: Texture,
|
|
||||||
val cornerWidth: Int,
|
|
||||||
val cornerHeight: Int,
|
|
||||||
val centerWidth: Int,
|
|
||||||
val centerHeight: Int
|
|
||||||
) {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val PANEL_BG = NinePatchTexture(Texture(Identifier("textures/gui/demo_background.png"), 0, 0), 5, 5, 238, 156)
|
val PANEL_BG = NinePatchTexture(Texture(Identifier("textures/gui/demo_background.png"), 0, 0), 5, 5, 238, 156)
|
||||||
|
|
|
@ -26,44 +26,24 @@ open class NinePatchView(val ninePatch: NinePatchTexture) : View() {
|
||||||
protected open val topLeft by topLeftDelegate
|
protected open val topLeft by topLeftDelegate
|
||||||
|
|
||||||
private val topRightDelegate = ResettableLazyProperty {
|
private val topRightDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(bounds.width - ninePatch.cornerWidth, 0.0, ninePatch.cornerWidth.toDouble(), ninePatch.cornerHeight.toDouble())
|
||||||
bounds.width - ninePatch.cornerWidth,
|
|
||||||
0.0,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
ninePatch.cornerHeight.toDouble()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
protected open val topRight by topRightDelegate
|
protected open val topRight by topRightDelegate
|
||||||
|
|
||||||
private val bottomLeftDelegate = ResettableLazyProperty {
|
private val bottomLeftDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(0.0, bounds.height - ninePatch.cornerHeight, ninePatch.cornerWidth.toDouble(), ninePatch.cornerHeight.toDouble())
|
||||||
0.0,
|
|
||||||
bounds.height - ninePatch.cornerHeight,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
ninePatch.cornerHeight.toDouble()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
protected open val bottomLeft by bottomLeftDelegate
|
protected open val bottomLeft by bottomLeftDelegate
|
||||||
|
|
||||||
private val bottomRightDelegate = ResettableLazyProperty {
|
private val bottomRightDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(bounds.width - ninePatch.cornerWidth, bounds.height - ninePatch.cornerHeight, ninePatch.cornerWidth.toDouble(), ninePatch.cornerHeight.toDouble())
|
||||||
bounds.width - ninePatch.cornerWidth,
|
|
||||||
bounds.height - ninePatch.cornerHeight,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
ninePatch.cornerHeight.toDouble()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
protected open val bottomRight by bottomRightDelegate
|
protected open val bottomRight by bottomRightDelegate
|
||||||
|
|
||||||
|
|
||||||
// Edges
|
// Edges
|
||||||
private val topMiddleDelegate = ResettableLazyProperty {
|
private val topMiddleDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(ninePatch.cornerWidth.toDouble(), topLeft.top, bounds.width - 2 * ninePatch.cornerWidth, ninePatch.cornerHeight.toDouble())
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
topLeft.top,
|
|
||||||
bounds.width - 2 * ninePatch.cornerWidth,
|
|
||||||
ninePatch.cornerHeight.toDouble()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
protected open val topMiddle by topMiddleDelegate
|
protected open val topMiddle by topMiddleDelegate
|
||||||
|
|
||||||
|
@ -73,12 +53,7 @@ open class NinePatchView(val ninePatch: NinePatchTexture) : View() {
|
||||||
protected open val bottomMiddle by bottomMiddleDelegate
|
protected open val bottomMiddle by bottomMiddleDelegate
|
||||||
|
|
||||||
private val leftMiddleDelegate = ResettableLazyProperty {
|
private val leftMiddleDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(topLeft.left, ninePatch.cornerHeight.toDouble(), ninePatch.cornerWidth.toDouble(), bounds.height - 2 * ninePatch.cornerHeight)
|
||||||
topLeft.left,
|
|
||||||
ninePatch.cornerHeight.toDouble(),
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
bounds.height - 2 * ninePatch.cornerHeight
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
protected open val leftMiddle by leftMiddleDelegate
|
protected open val leftMiddle by leftMiddleDelegate
|
||||||
|
|
||||||
|
@ -94,17 +69,7 @@ open class NinePatchView(val ninePatch: NinePatchTexture) : View() {
|
||||||
}
|
}
|
||||||
protected open val center by centerDelegate
|
protected open val center by centerDelegate
|
||||||
|
|
||||||
private val delegates = listOf(
|
private val delegates = listOf(topLeftDelegate, topRightDelegate, bottomLeftDelegate, bottomRightDelegate, topMiddleDelegate, bottomMiddleDelegate, leftMiddleDelegate, rightMiddleDelegate, centerDelegate)
|
||||||
topLeftDelegate,
|
|
||||||
topRightDelegate,
|
|
||||||
bottomLeftDelegate,
|
|
||||||
bottomRightDelegate,
|
|
||||||
topMiddleDelegate,
|
|
||||||
bottomMiddleDelegate,
|
|
||||||
leftMiddleDelegate,
|
|
||||||
rightMiddleDelegate,
|
|
||||||
centerDelegate
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun didLayout() {
|
override fun didLayout() {
|
||||||
super.didLayout()
|
super.didLayout()
|
||||||
|
@ -128,114 +93,30 @@ open class NinePatchView(val ninePatch: NinePatchTexture) : View() {
|
||||||
private fun drawEdges(matrixStack: MatrixStack) {
|
private fun drawEdges(matrixStack: MatrixStack) {
|
||||||
// Horizontal
|
// Horizontal
|
||||||
for (i in 0 until (topMiddle.width.roundToInt() / ninePatch.centerWidth)) {
|
for (i in 0 until (topMiddle.width.roundToInt() / ninePatch.centerWidth)) {
|
||||||
RenderHelper.draw(
|
RenderHelper.draw(matrixStack, topMiddle.left + i * ninePatch.centerWidth, topMiddle.top, ninePatch.topMiddle.u, ninePatch.topMiddle.v, ninePatch.centerWidth.toDouble(), topMiddle.height, ninePatch.texture.width, ninePatch.texture.height)
|
||||||
matrixStack,
|
RenderHelper.draw(matrixStack, bottomMiddle.left + i * ninePatch.centerWidth, bottomMiddle.top, ninePatch.bottomMiddle.u, ninePatch.bottomMiddle.v, ninePatch.centerWidth.toDouble(), bottomMiddle.height, ninePatch.texture.width, ninePatch.texture.height)
|
||||||
topMiddle.left + i * ninePatch.centerWidth,
|
|
||||||
topMiddle.top,
|
|
||||||
ninePatch.topMiddle.u,
|
|
||||||
ninePatch.topMiddle.v,
|
|
||||||
ninePatch.centerWidth.toDouble(),
|
|
||||||
topMiddle.height,
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
RenderHelper.draw(
|
|
||||||
matrixStack,
|
|
||||||
bottomMiddle.left + i * ninePatch.centerWidth,
|
|
||||||
bottomMiddle.top,
|
|
||||||
ninePatch.bottomMiddle.u,
|
|
||||||
ninePatch.bottomMiddle.v,
|
|
||||||
ninePatch.centerWidth.toDouble(),
|
|
||||||
bottomMiddle.height,
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val remWidth = topMiddle.width.roundToInt() % ninePatch.centerWidth
|
val remWidth = topMiddle.width.roundToInt() % ninePatch.centerWidth
|
||||||
if (remWidth > 0) {
|
if (remWidth > 0) {
|
||||||
RenderHelper.draw(
|
RenderHelper.draw(matrixStack, topMiddle.right - remWidth, topMiddle.top, ninePatch.topMiddle.u, ninePatch.topMiddle.v, remWidth.toDouble(), ninePatch.cornerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
|
||||||
matrixStack,
|
RenderHelper.draw(matrixStack, bottomMiddle.right - remWidth, bottomMiddle.top, ninePatch.bottomMiddle.u, ninePatch.bottomMiddle.v, remWidth.toDouble(), ninePatch.cornerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
|
||||||
topMiddle.right - remWidth,
|
|
||||||
topMiddle.top,
|
|
||||||
ninePatch.topMiddle.u,
|
|
||||||
ninePatch.topMiddle.v,
|
|
||||||
remWidth.toDouble(),
|
|
||||||
ninePatch.cornerHeight.toDouble(),
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
RenderHelper.draw(
|
|
||||||
matrixStack,
|
|
||||||
bottomMiddle.right - remWidth,
|
|
||||||
bottomMiddle.top,
|
|
||||||
ninePatch.bottomMiddle.u,
|
|
||||||
ninePatch.bottomMiddle.v,
|
|
||||||
remWidth.toDouble(),
|
|
||||||
ninePatch.cornerHeight.toDouble(),
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical
|
// Vertical
|
||||||
for (i in 0 until (leftMiddle.height.roundToInt() / ninePatch.centerHeight)) {
|
for (i in 0 until (leftMiddle.height.roundToInt() / ninePatch.centerHeight)) {
|
||||||
RenderHelper.draw(
|
RenderHelper.draw(matrixStack, leftMiddle.left, leftMiddle.top + i * ninePatch.centerHeight, ninePatch.leftMiddle.u, ninePatch.leftMiddle.v, ninePatch.cornerWidth.toDouble(), ninePatch.centerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
|
||||||
matrixStack,
|
RenderHelper.draw(matrixStack, rightMiddle.left, rightMiddle.top + i * ninePatch.centerHeight, ninePatch.rightMiddle.u, ninePatch.rightMiddle.v, ninePatch.cornerWidth.toDouble(), ninePatch.centerHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
|
||||||
leftMiddle.left,
|
|
||||||
leftMiddle.top + i * ninePatch.centerHeight,
|
|
||||||
ninePatch.leftMiddle.u,
|
|
||||||
ninePatch.leftMiddle.v,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
ninePatch.centerHeight.toDouble(),
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
RenderHelper.draw(
|
|
||||||
matrixStack,
|
|
||||||
rightMiddle.left,
|
|
||||||
rightMiddle.top + i * ninePatch.centerHeight,
|
|
||||||
ninePatch.rightMiddle.u,
|
|
||||||
ninePatch.rightMiddle.v,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
ninePatch.centerHeight.toDouble(),
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val remHeight = leftMiddle.height.roundToInt() % ninePatch.centerHeight
|
val remHeight = leftMiddle.height.roundToInt() % ninePatch.centerHeight
|
||||||
if (remHeight > 0) {
|
if (remHeight > 0) {
|
||||||
RenderHelper.draw(
|
RenderHelper.draw(matrixStack, leftMiddle.left, leftMiddle.bottom - remHeight, ninePatch.leftMiddle.u, ninePatch.leftMiddle.v, ninePatch.cornerWidth.toDouble(), remHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
|
||||||
matrixStack,
|
RenderHelper.draw(matrixStack, rightMiddle.left, rightMiddle.bottom - remHeight, ninePatch.rightMiddle.u, ninePatch.rightMiddle.v, ninePatch.cornerWidth.toDouble(), remHeight.toDouble(), ninePatch.texture.width, ninePatch.texture.height)
|
||||||
leftMiddle.left,
|
|
||||||
leftMiddle.bottom - remHeight,
|
|
||||||
ninePatch.leftMiddle.u,
|
|
||||||
ninePatch.leftMiddle.v,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
remHeight.toDouble(),
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
RenderHelper.draw(
|
|
||||||
matrixStack,
|
|
||||||
rightMiddle.left,
|
|
||||||
rightMiddle.bottom - remHeight,
|
|
||||||
ninePatch.rightMiddle.u,
|
|
||||||
ninePatch.rightMiddle.v,
|
|
||||||
ninePatch.cornerWidth.toDouble(),
|
|
||||||
remHeight.toDouble(),
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun drawCenter(matrixStack: MatrixStack) {
|
private fun drawCenter(matrixStack: MatrixStack) {
|
||||||
for (i in 0 until (center.height.roundToInt() / ninePatch.centerHeight)) {
|
for (i in 0 until (center.height.roundToInt() / ninePatch.centerHeight)) {
|
||||||
drawCenterRow(
|
drawCenterRow(matrixStack, center.top + i * ninePatch.centerHeight.toDouble(), ninePatch.centerHeight.toDouble())
|
||||||
matrixStack,
|
|
||||||
center.top + i * ninePatch.centerHeight.toDouble(),
|
|
||||||
ninePatch.centerHeight.toDouble()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val remHeight = center.height.roundToInt() % ninePatch.centerHeight
|
val remHeight = center.height.roundToInt() % ninePatch.centerHeight
|
||||||
if (remHeight > 0) {
|
if (remHeight > 0) {
|
||||||
|
@ -245,31 +126,11 @@ open class NinePatchView(val ninePatch: NinePatchTexture) : View() {
|
||||||
|
|
||||||
private fun drawCenterRow(matrixStack: MatrixStack, y: Double, height: Double) {
|
private fun drawCenterRow(matrixStack: MatrixStack, y: Double, height: Double) {
|
||||||
for (i in 0 until (center.width.roundToInt() / ninePatch.centerWidth)) {
|
for (i in 0 until (center.width.roundToInt() / ninePatch.centerWidth)) {
|
||||||
RenderHelper.draw(
|
RenderHelper.draw(matrixStack, center.left + i * ninePatch.centerWidth, y, ninePatch.center.u, ninePatch.center.v, ninePatch.centerWidth.toDouble(), height, ninePatch.texture.width, ninePatch.texture.height)
|
||||||
matrixStack,
|
|
||||||
center.left + i * ninePatch.centerWidth,
|
|
||||||
y,
|
|
||||||
ninePatch.center.u,
|
|
||||||
ninePatch.center.v,
|
|
||||||
ninePatch.centerWidth.toDouble(),
|
|
||||||
height,
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val remWidth = center.width.roundToInt() % ninePatch.centerWidth
|
val remWidth = center.width.roundToInt() % ninePatch.centerWidth
|
||||||
if (remWidth > 0) {
|
if (remWidth > 0) {
|
||||||
RenderHelper.draw(
|
RenderHelper.draw(matrixStack, center.right - remWidth, y, ninePatch.center.u, ninePatch.center.v, remWidth.toDouble(), height, ninePatch.texture.width, ninePatch.texture.height)
|
||||||
matrixStack,
|
|
||||||
center.right - remWidth,
|
|
||||||
y,
|
|
||||||
ninePatch.center.u,
|
|
||||||
ninePatch.center.v,
|
|
||||||
remWidth.toDouble(),
|
|
||||||
height,
|
|
||||||
ninePatch.texture.width,
|
|
||||||
ninePatch.texture.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ open class StackView(
|
||||||
|
|
||||||
// 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.
|
||||||
* This list should never be mutated directly, only be calling the [addArrangedSubview]/[removeArrangedSubview]
|
* This list should never be mutated directly, only be calling the [addArrangedSubview]/[removeArrangedSubview]
|
||||||
|
@ -140,16 +139,10 @@ open class StackView(
|
||||||
val previous = arrangedSubviews.getOrNull(index - 1)
|
val previous = arrangedSubviews.getOrNull(index - 1)
|
||||||
val next = arrangedSubviews.getOrNull(index + 1)
|
val next = arrangedSubviews.getOrNull(index + 1)
|
||||||
if (next != null) {
|
if (next != null) {
|
||||||
arrangedSubviewConnections.add(
|
arrangedSubviewConnections.add(index, anchor(TRAILING, view) equalTo (anchor(LEADING, next) + spacing))
|
||||||
index,
|
|
||||||
anchor(TRAILING, view) equalTo (anchor(LEADING, next) + spacing)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
arrangedSubviewConnections.add(
|
arrangedSubviewConnections.add(index - 1, anchor(TRAILING, previous) equalTo (anchor(LEADING, view) - spacing))
|
||||||
index - 1,
|
|
||||||
anchor(TRAILING, previous) equalTo (anchor(LEADING, view) - spacing)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,15 +150,12 @@ open class StackView(
|
||||||
when (distribution) {
|
when (distribution) {
|
||||||
Distribution.LEADING ->
|
Distribution.LEADING ->
|
||||||
perpAnchor(LEADING) equalTo perpAnchor(LEADING, view)
|
perpAnchor(LEADING) equalTo perpAnchor(LEADING, view)
|
||||||
|
|
||||||
Distribution.TRAILING ->
|
Distribution.TRAILING ->
|
||||||
perpAnchor(TRAILING) equalTo perpAnchor(TRAILING, view)
|
perpAnchor(TRAILING) equalTo perpAnchor(TRAILING, view)
|
||||||
|
|
||||||
Distribution.FILL -> {
|
Distribution.FILL -> {
|
||||||
perpAnchor(LEADING) equalTo perpAnchor(LEADING, view)
|
perpAnchor(LEADING) equalTo perpAnchor(LEADING, view)
|
||||||
perpAnchor(TRAILING) equalTo perpAnchor(TRAILING, view)
|
perpAnchor(TRAILING) equalTo perpAnchor(TRAILING, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
Distribution.CENTER ->
|
Distribution.CENTER ->
|
||||||
perpAnchor(CENTER) equalTo perpAnchor(CENTER, view)
|
perpAnchor(CENTER) equalTo perpAnchor(CENTER, view)
|
||||||
}
|
}
|
||||||
|
@ -175,7 +165,6 @@ open class StackView(
|
||||||
private fun anchor(position: AxisPosition, view: View = this): LayoutVariable {
|
private fun anchor(position: AxisPosition, view: View = this): LayoutVariable {
|
||||||
return view.getAnchor(axis, position)
|
return view.getAnchor(axis, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun perpAnchor(position: AxisPosition, view: View = this): LayoutVariable {
|
private fun perpAnchor(position: AxisPosition, view: View = this): LayoutVariable {
|
||||||
return view.getAnchor(axis.perpendicular, position)
|
return view.getAnchor(axis.perpendicular, position)
|
||||||
}
|
}
|
||||||
|
@ -210,7 +199,6 @@ open class StackView(
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
LEADING,
|
LEADING,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The centers of the arranged subviews are pinned to the center of the stack view.
|
* The centers of the arranged subviews are pinned to the center of the stack view.
|
||||||
* ```
|
* ```
|
||||||
|
@ -234,7 +222,6 @@ open class StackView(
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
CENTER,
|
CENTER,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The trailing edges of arranged subviews are pinned to the leading edge of the stack view.
|
* The trailing edges of arranged subviews are pinned to the leading edge of the stack view.
|
||||||
* ```
|
* ```
|
||||||
|
@ -258,7 +245,6 @@ open class StackView(
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
TRAILING,
|
TRAILING,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The arranged subviews fill the perpendicular axis of the stack view.
|
* The arranged subviews fill the perpendicular axis of the stack view.
|
||||||
* ```
|
* ```
|
||||||
|
|
|
@ -42,7 +42,6 @@ open class View() : Responder {
|
||||||
v.solver = it
|
v.solver = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The constraint solver used by the [Window] this view belongs to.
|
* The constraint solver used by the [Window] this view belongs to.
|
||||||
* Not initialized until [wasAdded] called, using it before that will throw a runtime exception.
|
* Not initialized until [wasAdded] called, using it before that will throw a runtime exception.
|
||||||
|
@ -56,37 +55,30 @@ open class View() : Responder {
|
||||||
* Layout anchor for the left edge of this view in the window's coordinate system.
|
* Layout anchor for the left edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val leftAnchor = LayoutVariable(this, "left")
|
val leftAnchor = LayoutVariable(this, "left")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the right edge of this view in the window's coordinate system.
|
* Layout anchor for the right edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val rightAnchor = LayoutVariable(this, "right")
|
val rightAnchor = LayoutVariable(this, "right")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the top edge of this view in the window's coordinate system.
|
* Layout anchor for the top edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val topAnchor = LayoutVariable(this, "top")
|
val topAnchor = LayoutVariable(this, "top")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the bottom edge of this view in the window's coordinate system.
|
* Layout anchor for the bottom edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val bottomAnchor = LayoutVariable(this, "bottom")
|
val bottomAnchor = LayoutVariable(this, "bottom")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the width of this view in the window's coordinate system.
|
* Layout anchor for the width of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val widthAnchor = LayoutVariable(this, "width")
|
val widthAnchor = LayoutVariable(this, "width")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the height of this view in the window's coordinate system.
|
* Layout anchor for the height of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val heightAnchor = LayoutVariable(this, "height")
|
val heightAnchor = LayoutVariable(this, "height")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the center X position of this view in the window's coordinate system.
|
* Layout anchor for the center X position of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val centerXAnchor = LayoutVariable(this, "centerX")
|
val centerXAnchor = LayoutVariable(this, "centerX")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the center Y position of this view in the window's coordinate system.
|
* Layout anchor for the center Y position of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
|
@ -163,7 +155,6 @@ open class View() : Responder {
|
||||||
* This view's parent view. If `null`, this view is a top-level view in the [Window].
|
* This view's parent view. If `null`, this view is a top-level view in the [Window].
|
||||||
*/
|
*/
|
||||||
var superview: View? = null
|
var superview: View? = null
|
||||||
|
|
||||||
// _subviews is the internal, mutable object since we only want it to be mutated by the add/removeSubview methods
|
// _subviews is the internal, mutable object since we only want it to be mutated by the add/removeSubview methods
|
||||||
private val _subviews = LinkedList<View>()
|
private val _subviews = LinkedList<View>()
|
||||||
private var subviewsSortedByZIndex: List<View> = listOf()
|
private var subviewsSortedByZIndex: List<View> = listOf()
|
||||||
|
@ -190,7 +181,6 @@ open class View() : Responder {
|
||||||
AxisPosition.CENTER -> centerXAnchor
|
AxisPosition.CENTER -> centerXAnchor
|
||||||
AxisPosition.TRAILING -> rightAnchor
|
AxisPosition.TRAILING -> rightAnchor
|
||||||
}
|
}
|
||||||
|
|
||||||
Axis.VERTICAL ->
|
Axis.VERTICAL ->
|
||||||
when (position) {
|
when (position) {
|
||||||
AxisPosition.LEADING -> topAnchor
|
AxisPosition.LEADING -> topAnchor
|
||||||
|
@ -250,11 +240,7 @@ open class View() : Responder {
|
||||||
for (b in a + 1 until variables.size) {
|
for (b in a + 1 until variables.size) {
|
||||||
// if the variable views have no common ancestor after the removed view's superview is unset,
|
// if the variable views have no common ancestor after the removed view's superview is unset,
|
||||||
// the constraint crossed the this<->view boundary and should be removed
|
// the constraint crossed the this<->view boundary and should be removed
|
||||||
val ancestor = LowestCommonAncestor.find(
|
val ancestor = LowestCommonAncestor.find(variables[a].viewOrLayoutGuideView, variables[b].viewOrLayoutGuideView, View::superview)
|
||||||
variables[a].viewOrLayoutGuideView,
|
|
||||||
variables[b].viewOrLayoutGuideView,
|
|
||||||
View::superview
|
|
||||||
)
|
|
||||||
if (ancestor == null) {
|
if (ancestor == null) {
|
||||||
return@filter true
|
return@filter true
|
||||||
}
|
}
|
||||||
|
@ -364,12 +350,7 @@ open class View() : Responder {
|
||||||
if (usesConstraintBasedLayout) {
|
if (usesConstraintBasedLayout) {
|
||||||
val superviewLeft = superview?.leftAnchor?.value ?: 0.0
|
val superviewLeft = superview?.leftAnchor?.value ?: 0.0
|
||||||
val superviewTop = superview?.topAnchor?.value ?: 0.0
|
val superviewTop = superview?.topAnchor?.value ?: 0.0
|
||||||
frame = Rect(
|
frame = Rect(leftAnchor.value - superviewLeft, topAnchor.value - superviewTop, widthAnchor.value, heightAnchor.value)
|
||||||
leftAnchor.value - superviewLeft,
|
|
||||||
topAnchor.value - superviewTop,
|
|
||||||
widthAnchor.value,
|
|
||||||
heightAnchor.value
|
|
||||||
)
|
|
||||||
bounds = Rect(0.0, 0.0, widthAnchor.value, heightAnchor.value)
|
bounds = Rect(0.0, 0.0, widthAnchor.value, heightAnchor.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ abstract class AbstractButton<Impl : AbstractButton<Impl>>(val content: View, va
|
||||||
field = value
|
field = value
|
||||||
value?.also(::addBackground)
|
value?.also(::addBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The background to draw when the button is hovered over by the mouse.
|
* The background to draw when the button is hovered over by the mouse.
|
||||||
* If `null`, the normal [background] will be used.
|
* If `null`, the normal [background] will be used.
|
||||||
|
@ -63,7 +62,6 @@ abstract class AbstractButton<Impl : AbstractButton<Impl>>(val content: View, va
|
||||||
field = value
|
field = value
|
||||||
value?.also(::addBackground)
|
value?.also(::addBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The background to draw when the button is [disabled].
|
* The background to draw when the button is [disabled].
|
||||||
* If `null`, the normal [background] will be used.
|
* If `null`, the normal [background] will be used.
|
||||||
|
|
|
@ -159,12 +159,7 @@ private class DropdownItemBackgroundView(
|
||||||
override val topRight by topRightDelegate
|
override val topRight by topRightDelegate
|
||||||
|
|
||||||
private val bottomLeftDelegate = ResettableLazyProperty {
|
private val bottomLeftDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(topLeft.left, bounds.height - ninePatch.cornerHeight, topLeft.width, if (last) ninePatch.cornerHeight.toDouble() else 0.0)
|
||||||
topLeft.left,
|
|
||||||
bounds.height - ninePatch.cornerHeight,
|
|
||||||
topLeft.width,
|
|
||||||
if (last) ninePatch.cornerHeight.toDouble() else 0.0
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
override val bottomLeft by bottomLeftDelegate
|
override val bottomLeft by bottomLeftDelegate
|
||||||
|
|
||||||
|
@ -185,12 +180,7 @@ private class DropdownItemBackgroundView(
|
||||||
override val bottomMiddle by bottomMiddleDelegate
|
override val bottomMiddle by bottomMiddleDelegate
|
||||||
|
|
||||||
private val leftMiddleDelegate = ResettableLazyProperty {
|
private val leftMiddleDelegate = ResettableLazyProperty {
|
||||||
Rect(
|
Rect(topLeft.left, topLeft.bottom, topLeft.width, bounds.height - (if (first && last) 2 else if (first || last) 1 else 0) * ninePatch.cornerHeight)
|
||||||
topLeft.left,
|
|
||||||
topLeft.bottom,
|
|
||||||
topLeft.width,
|
|
||||||
bounds.height - (if (first && last) 2 else if (first || last) 1 else 0) * ninePatch.cornerHeight
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
override val leftMiddle by leftMiddleDelegate
|
override val leftMiddle by leftMiddleDelegate
|
||||||
|
|
||||||
|
@ -205,17 +195,7 @@ private class DropdownItemBackgroundView(
|
||||||
}
|
}
|
||||||
override val center by centerDelegate
|
override val center by centerDelegate
|
||||||
|
|
||||||
private val delegates = listOf(
|
private val delegates = listOf(topLeftDelegate, topRightDelegate, bottomLeftDelegate, bottomRightDelegate, topMiddleDelegate, bottomMiddleDelegate, leftMiddleDelegate, rightMiddleDelegate, centerDelegate)
|
||||||
topLeftDelegate,
|
|
||||||
topRightDelegate,
|
|
||||||
bottomLeftDelegate,
|
|
||||||
bottomRightDelegate,
|
|
||||||
topMiddleDelegate,
|
|
||||||
bottomMiddleDelegate,
|
|
||||||
leftMiddleDelegate,
|
|
||||||
rightMiddleDelegate,
|
|
||||||
centerDelegate
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun didLayout() {
|
override fun didLayout() {
|
||||||
super.didLayout()
|
super.didLayout()
|
||||||
|
|
|
@ -166,8 +166,7 @@ abstract class AbstractTextField<Impl : AbstractTextField<Impl>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: label for the TextFieldWidget?
|
// todo: label for the TextFieldWidget?
|
||||||
private class ProxyWidget :
|
private class ProxyWidget: TextFieldWidget(MinecraftClient.getInstance().textRenderer, 0, 0, 0, 0, LiteralText("")) {
|
||||||
TextFieldWidget(MinecraftClient.getInstance().textRenderer, 0, 0, 0, 0, LiteralText("")) {
|
|
||||||
// AbstractButtonWidget.height is protected
|
// AbstractButtonWidget.height is protected
|
||||||
fun setHeight(height: Int) {
|
fun setHeight(height: Int) {
|
||||||
this.height = height
|
this.height = height
|
||||||
|
|
|
@ -99,7 +99,6 @@ class TabViewController<T : TabViewController.Tab>(
|
||||||
private lateinit var outerStack: StackView
|
private lateinit var outerStack: StackView
|
||||||
private lateinit var tabStack: StackView
|
private lateinit var tabStack: StackView
|
||||||
private lateinit var currentTabController: ViewController
|
private lateinit var currentTabController: ViewController
|
||||||
|
|
||||||
// todo: this shouldn't be public, use layout guides
|
// todo: this shouldn't be public, use layout guides
|
||||||
lateinit var tabVCContainer: View
|
lateinit var tabVCContainer: View
|
||||||
private set
|
private set
|
||||||
|
|
|
@ -58,7 +58,6 @@ abstract class ViewController {
|
||||||
|
|
||||||
// _children is the internal, mutable object since we only want it to be mutated by the embed/removeChild methods
|
// _children is the internal, mutable object since we only want it to be mutated by the embed/removeChild methods
|
||||||
private var _children = LinkedList<ViewController>()
|
private var _children = LinkedList<ViewController>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of all the child VCs of this view controller.
|
* The list of all the child VCs of this view controller.
|
||||||
* This list should never be mutated directly, only by the [embedChild]/[removeChild] methods.
|
* This list should never be mutated directly, only by the [embedChild]/[removeChild] methods.
|
||||||
|
|
|
@ -48,37 +48,30 @@ open class Window(
|
||||||
* Layout anchor for the left edge of this view in the window's coordinate system.
|
* Layout anchor for the left edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val leftAnchor = Variable("left")
|
val leftAnchor = Variable("left")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the right edge of this view in the window's coordinate system.
|
* Layout anchor for the right edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val rightAnchor = Variable("right")
|
val rightAnchor = Variable("right")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the top edge of this view in the window's coordinate system.
|
* Layout anchor for the top edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val topAnchor = Variable("top")
|
val topAnchor = Variable("top")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the bottom edge of this view in the window's coordinate system.
|
* Layout anchor for the bottom edge of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val bottomAnchor = Variable("bottom")
|
val bottomAnchor = Variable("bottom")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the width of this view in the window's coordinate system.
|
* Layout anchor for the width of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val widthAnchor = Variable("width")
|
val widthAnchor = Variable("width")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the height of this view in the window's coordinate system.
|
* Layout anchor for the height of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val heightAnchor = Variable("height")
|
val heightAnchor = Variable("height")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the center X position of this view in the window's coordinate system.
|
* Layout anchor for the center X position of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
val centerXAnchor = Variable("centerX")
|
val centerXAnchor = Variable("centerX")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout anchor for the center Y position of this view in the window's coordinate system.
|
* Layout anchor for the center Y position of this view in the window's coordinate system.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -17,8 +17,7 @@ class KiwiContext(val solver: Solver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExpressionConvertible.equalTo(other: ExpressionConvertible, strength: Double): Constraint {
|
fun ExpressionConvertible.equalTo(other: ExpressionConvertible, strength: Double): Constraint {
|
||||||
return Symbolics.equals(this.toExpression(), other.toExpression()).setStrength(strength)
|
return Symbolics.equals(this.toExpression(), other.toExpression()).setStrength(strength).apply(solver::addConstraint)
|
||||||
.apply(solver::addConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun ExpressionConvertible.equalTo(constant: Number): Constraint {
|
infix fun ExpressionConvertible.equalTo(constant: Number): Constraint {
|
||||||
|
@ -26,8 +25,7 @@ class KiwiContext(val solver: Solver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExpressionConvertible.equalTo(constant: Number, strength: Double): Constraint {
|
fun ExpressionConvertible.equalTo(constant: Number, strength: Double): Constraint {
|
||||||
return Symbolics.equals(this.toExpression(), constant.toDouble()).setStrength(strength)
|
return Symbolics.equals(this.toExpression(), constant.toDouble()).setStrength(strength).apply(solver::addConstraint)
|
||||||
.apply(solver::addConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun ExpressionConvertible.lessThanOrEqualTo(other: ExpressionConvertible): Constraint {
|
infix fun ExpressionConvertible.lessThanOrEqualTo(other: ExpressionConvertible): Constraint {
|
||||||
|
@ -35,8 +33,7 @@ class KiwiContext(val solver: Solver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExpressionConvertible.lessThanOrEqualTo(other: ExpressionConvertible, strength: Double): Constraint {
|
fun ExpressionConvertible.lessThanOrEqualTo(other: ExpressionConvertible, strength: Double): Constraint {
|
||||||
return Symbolics.lessThanOrEqualTo(this.toExpression(), other.toExpression()).setStrength(strength)
|
return Symbolics.lessThanOrEqualTo(this.toExpression(), other.toExpression()).setStrength(strength).apply(solver::addConstraint)
|
||||||
.apply(solver::addConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun ExpressionConvertible.lessThanOrEqualTo(constant: Number): Constraint {
|
infix fun ExpressionConvertible.lessThanOrEqualTo(constant: Number): Constraint {
|
||||||
|
@ -44,8 +41,7 @@ class KiwiContext(val solver: Solver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExpressionConvertible.lessThanOrEqualTo(constant: Number, strength: Double): Constraint {
|
fun ExpressionConvertible.lessThanOrEqualTo(constant: Number, strength: Double): Constraint {
|
||||||
return Symbolics.lessThanOrEqualTo(this.toExpression(), constant.toDouble()).setStrength(strength)
|
return Symbolics.lessThanOrEqualTo(this.toExpression(), constant.toDouble()).setStrength(strength).apply(solver::addConstraint)
|
||||||
.apply(solver::addConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun ExpressionConvertible.greaterThanOrEqualTo(other: ExpressionConvertible): Constraint {
|
infix fun ExpressionConvertible.greaterThanOrEqualTo(other: ExpressionConvertible): Constraint {
|
||||||
|
@ -53,8 +49,7 @@ class KiwiContext(val solver: Solver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExpressionConvertible.greaterThanOrEqualTo(other: ExpressionConvertible, strength: Double): Constraint {
|
fun ExpressionConvertible.greaterThanOrEqualTo(other: ExpressionConvertible, strength: Double): Constraint {
|
||||||
return Symbolics.greaterThanOrEqualTo(this.toExpression(), other.toExpression()).setStrength(strength)
|
return Symbolics.greaterThanOrEqualTo(this.toExpression(), other.toExpression()).setStrength(strength).apply(solver::addConstraint)
|
||||||
.apply(solver::addConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun ExpressionConvertible.greaterThanOrEqualTo(constant: Number): Constraint {
|
infix fun ExpressionConvertible.greaterThanOrEqualTo(constant: Number): Constraint {
|
||||||
|
@ -62,8 +57,7 @@ class KiwiContext(val solver: Solver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ExpressionConvertible.greaterThanOrEqualTo(constant: Number, strength: Double): Constraint {
|
fun ExpressionConvertible.greaterThanOrEqualTo(constant: Number, strength: Double): Constraint {
|
||||||
return Symbolics.greaterThanOrEqualTo(this.toExpression(), constant.toDouble()).setStrength(strength)
|
return Symbolics.greaterThanOrEqualTo(this.toExpression(), constant.toDouble()).setStrength(strength).apply(solver::addConstraint)
|
||||||
.apply(solver::addConstraint)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addition
|
// Addition
|
||||||
|
|
|
@ -15,8 +15,7 @@ object DefaultPlugin : PhyConPlugin {
|
||||||
private set
|
private set
|
||||||
|
|
||||||
override fun initializePhyCon(api: PhyConAPI) {
|
override fun initializePhyCon(api: PhyConAPI) {
|
||||||
SORT_MODE =
|
SORT_MODE = api.registerTerminalSetting(Identifier(PhysicalConnectivity.MODID, "sort"), SortMode.COUNT_HIGH_FIRST)
|
||||||
api.registerTerminalSetting(Identifier(PhysicalConnectivity.MODID, "sort"), SortMode.COUNT_HIGH_FIRST)
|
|
||||||
SORT_MODE.setPriority(Int.MAX_VALUE)
|
SORT_MODE.setPriority(Int.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,7 @@ import net.shadowfacts.phycon.util.TerminalSettings
|
||||||
*/
|
*/
|
||||||
object PhyConAPIImpl: PhyConAPI {
|
object PhyConAPIImpl: PhyConAPI {
|
||||||
|
|
||||||
override fun <E> registerTerminalSetting(
|
override fun <E> registerTerminalSetting(id: Identifier, defaultValue: E): TerminalSettingKey<E> where E: Enum<E>, E: TerminalSetting? {
|
||||||
id: Identifier,
|
|
||||||
defaultValue: E
|
|
||||||
): TerminalSettingKey<E> where E : Enum<E>, E : TerminalSetting? {
|
|
||||||
return TerminalSettings.register(id, defaultValue)
|
return TerminalSettings.register(id, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,7 @@ object PhysicalConnectivity : ModInitializer {
|
||||||
registerGlobalReceiver(C2STerminalRequestItem)
|
registerGlobalReceiver(C2STerminalRequestItem)
|
||||||
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
|
||||||
|
|
||||||
ItemStorage.SIDED.registerForBlockEntity(
|
ItemStorage.SIDED.registerForBlockEntity(P2PReceiverBlockEntity::provideItemStorage, PhyBlockEntities.P2P_RECEIVER)
|
||||||
P2PReceiverBlockEntity::provideItemStorage,
|
|
||||||
PhyBlockEntities.P2P_RECEIVER
|
|
||||||
)
|
|
||||||
|
|
||||||
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
|
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
|
||||||
it.initializePhyCon(PhyConAPIImpl)
|
it.initializePhyCon(PhyConAPIImpl)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
|
||||||
import net.fabricmc.fabric.api.renderer.v1.RendererAccess
|
import net.fabricmc.fabric.api.renderer.v1.RendererAccess
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial
|
||||||
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
import net.shadowfacts.phycon.block.inserter.InserterScreen
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchConsoleScreen
|
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreen
|
||||||
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreen
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreen
|
||||||
import net.shadowfacts.phycon.init.PhyScreens
|
import net.shadowfacts.phycon.init.PhyScreens
|
||||||
|
@ -45,7 +44,6 @@ object PhysicalConnectivityClient : ClientModInitializer {
|
||||||
ScreenRegistry.register(PhyScreens.CRAFTING_TERMINAL, ::CraftingTerminalScreen)
|
ScreenRegistry.register(PhyScreens.CRAFTING_TERMINAL, ::CraftingTerminalScreen)
|
||||||
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
ScreenRegistry.register(PhyScreens.INSERTER, ::InserterScreen)
|
||||||
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
ScreenRegistry.register(PhyScreens.REDSTONE_EMITTER, ::RedstoneEmitterScreen)
|
||||||
ScreenRegistry.register(PhyScreens.SWITCH_CONSOLE, ::SwitchConsoleScreen)
|
|
||||||
|
|
||||||
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
|
registerGlobalReceiver(S2CTerminalUpdateDisplayedItems)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,21 +15,11 @@ import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class DeviceBlock<T : DeviceBlockEntity>(settings: Settings) : BlockWithEntity<T>(settings),
|
abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings), NetworkComponentBlock {
|
||||||
NetworkComponentBlock {
|
|
||||||
|
|
||||||
abstract override fun getNetworkConnectedSides(
|
abstract override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction>
|
||||||
state: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos
|
|
||||||
): Collection<Direction>
|
|
||||||
|
|
||||||
override fun getNetworkInterfaceForSide(
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||||
side: Direction,
|
|
||||||
state: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos
|
|
||||||
): Interface? {
|
|
||||||
return getBlockEntity(world, pos)!!
|
return getBlockEntity(world, pos)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,11 +28,7 @@ abstract class DeviceBlock<T : DeviceBlockEntity>(settings: Settings) : BlockWit
|
||||||
getBlockEntity(world, pos)!!.onBreak()
|
getBlockEntity(world, pos)!!.onBreak()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : BlockEntity> getTicker(
|
override fun <T: BlockEntity> getTicker(world: World, state: BlockState, type: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||||
world: World,
|
|
||||||
state: BlockState,
|
|
||||||
type: BlockEntityType<T>
|
|
||||||
): BlockEntityTicker<T>? {
|
|
||||||
return if (world.isClient) {
|
return if (world.isClient) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -28,8 +28,7 @@ import java.util.*
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState) :
|
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state),
|
||||||
BlockEntity(type, pos, state),
|
|
||||||
PacketSink,
|
PacketSink,
|
||||||
PacketSource,
|
PacketSource,
|
||||||
Interface {
|
Interface {
|
||||||
|
@ -61,7 +60,6 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
|
||||||
is DeviceRemovedPacket -> {
|
is DeviceRemovedPacket -> {
|
||||||
arpTable.remove(packet.source)
|
arpTable.remove(packet.source)
|
||||||
}
|
}
|
||||||
|
|
||||||
is PingPacket -> {
|
is PingPacket -> {
|
||||||
sendPacket(PongPacket(ipAddress, packet.source))
|
sendPacket(PongPacket(ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
|
@ -74,14 +72,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receive(frame: EthernetFrame) {
|
override fun receive(frame: EthernetFrame) {
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug(
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) received frame from {}: {}", this, ipAddress, macAddress, frame.source, frame)
|
||||||
"{} ({}, {}) received frame from {}: {}",
|
|
||||||
this,
|
|
||||||
ipAddress,
|
|
||||||
macAddress,
|
|
||||||
frame.source,
|
|
||||||
frame
|
|
||||||
)
|
|
||||||
when (frame) {
|
when (frame) {
|
||||||
is ARPQueryFrame -> handleARPQuery(frame)
|
is ARPQueryFrame -> handleARPQuery(frame)
|
||||||
is ARPResponseFrame -> handleARPResponse(frame)
|
is ARPResponseFrame -> handleARPResponse(frame)
|
||||||
|
@ -98,26 +89,14 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug("{}, ({}), received ARP query for {}", this, ipAddress, frame.queryIP)
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{}, ({}), received ARP query for {}", this, ipAddress, frame.queryIP)
|
||||||
arpTable[frame.sourceIP] = frame.source
|
arpTable[frame.sourceIP] = frame.source
|
||||||
if (frame.queryIP == ipAddress) {
|
if (frame.queryIP == ipAddress) {
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug(
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}) sending ARP response to {} with {}", this, ipAddress, frame.sourceIP, macAddress)
|
||||||
"{} ({}) sending ARP response to {} with {}",
|
|
||||||
this,
|
|
||||||
ipAddress,
|
|
||||||
frame.sourceIP,
|
|
||||||
macAddress
|
|
||||||
)
|
|
||||||
send(ARPResponseFrame(ipAddress, macAddress, frame.source))
|
send(ARPResponseFrame(ipAddress, macAddress, frame.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleARPResponse(frame: ARPResponseFrame) {
|
private fun handleARPResponse(frame: ARPResponseFrame) {
|
||||||
arpTable[frame.query] = frame.source
|
arpTable[frame.query] = frame.source
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug(
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{}, ({}) received ARP response for {} with {}", this, ipAddress, frame.query, frame.source)
|
||||||
"{}, ({}) received ARP response for {} with {}",
|
|
||||||
this,
|
|
||||||
ipAddress,
|
|
||||||
frame.query,
|
|
||||||
frame.source
|
|
||||||
)
|
|
||||||
|
|
||||||
val toRemove = packetQueue.filter { (packet, _) ->
|
val toRemove = packetQueue.filter { (packet, _) ->
|
||||||
if (packet.destination == frame.query) {
|
if (packet.destination == frame.query) {
|
||||||
|
@ -143,12 +122,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
|
||||||
} else {
|
} else {
|
||||||
packetQueue.add(PendingPacket(packet, counter))
|
packetQueue.add(PendingPacket(packet, counter))
|
||||||
|
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug(
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}) sending ARP query for {}", this, ipAddress, packet.destination)
|
||||||
"{} ({}) sending ARP query for {}",
|
|
||||||
this,
|
|
||||||
ipAddress,
|
|
||||||
packet.destination
|
|
||||||
)
|
|
||||||
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
|
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,7 +141,6 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
|
||||||
this.cachedDestination = WeakReference(it)
|
this.cachedDestination = WeakReference(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,11 +82,7 @@ abstract class FaceDeviceBlock<T : DeviceBlockEntity>(settings: Settings) : Devi
|
||||||
if (cableConnection == FaceCableConnection.NONE) {
|
if (cableConnection == FaceCableConnection.NONE) {
|
||||||
VoxelShapes.union(faceShapes[facing], centerShapes[facing])
|
VoxelShapes.union(faceShapes[facing], centerShapes[facing])
|
||||||
} else {
|
} else {
|
||||||
VoxelShapes.union(
|
VoxelShapes.union(faceShapes[facing], centerShapes[facing], CableBlock.SIDE_SHAPES[cableConnection.direction])
|
||||||
faceShapes[facing],
|
|
||||||
centerShapes[facing],
|
|
||||||
CableBlock.SIDE_SHAPES[cableConnection.direction]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,12 +92,7 @@ abstract class FaceDeviceBlock<T : DeviceBlockEntity>(settings: Settings) : Devi
|
||||||
return if (direction != null) EnumSet.of(direction) else setOf()
|
return if (direction != null) EnumSet.of(direction) else setOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNetworkInterfaceForSide(
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||||
side: Direction,
|
|
||||||
state: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos
|
|
||||||
): Interface? {
|
|
||||||
return if (side == state[FACING]) {
|
return if (side == state[FACING]) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
|
@ -117,22 +108,15 @@ abstract class FaceDeviceBlock<T : DeviceBlockEntity>(settings: Settings) : Devi
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
val facing =
|
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
||||||
if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
|
|
||||||
// todo: this should never be called
|
// todo: this should never be called
|
||||||
val cableConnection =
|
val cableConnection = FaceCableConnection.from(getCableConnectedSide(context.world, context.blockPos, facing, DyeColor.BLUE))
|
||||||
FaceCableConnection.from(getCableConnectedSide(context.world, context.blockPos, facing, DyeColor.BLUE))
|
|
||||||
return defaultState
|
return defaultState
|
||||||
.with(FACING, facing)
|
.with(FACING, facing)
|
||||||
.with(CABLE_CONNECTION, cableConnection)
|
.with(CABLE_CONNECTION, cableConnection)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCableConnectedSide(
|
private fun getCableConnectedSide(world: WorldAccess, pos: BlockPos, facing: Direction, color: DyeColor): Direction? {
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos,
|
|
||||||
facing: Direction,
|
|
||||||
color: DyeColor
|
|
||||||
): Direction? {
|
|
||||||
for (side in Direction.values()) {
|
for (side in Direction.values()) {
|
||||||
if (side == facing) {
|
if (side == facing) {
|
||||||
continue
|
continue
|
||||||
|
@ -146,32 +130,18 @@ abstract class FaceDeviceBlock<T : DeviceBlockEntity>(settings: Settings) : Devi
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canConnectTo(
|
private fun canConnectTo(world: WorldAccess, side: Direction, candidateState: BlockState, candidatePos: BlockPos, myColor: DyeColor): Boolean {
|
||||||
world: WorldAccess,
|
|
||||||
side: Direction,
|
|
||||||
candidateState: BlockState,
|
|
||||||
candidatePos: BlockPos,
|
|
||||||
myColor: DyeColor
|
|
||||||
): Boolean {
|
|
||||||
val block = candidateState.block
|
val block = candidateState.block
|
||||||
return if (block is FaceDeviceBlock<*> && candidateState[COLOR] == myColor) {
|
return if (block is FaceDeviceBlock<*> && candidateState[COLOR] == myColor) {
|
||||||
true
|
true
|
||||||
} else if (block is CableBlock && block.color == myColor) {
|
} else if (block is CableBlock && block.color == myColor) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
block is NetworkComponentBlock && block.getNetworkConnectedSides(candidateState, world, candidatePos)
|
block is NetworkComponentBlock && block.getNetworkConnectedSides(candidateState, world, candidatePos).contains(side.opposite)
|
||||||
.contains(side.opposite)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStateForNeighborUpdate(
|
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
|
||||||
state: BlockState,
|
|
||||||
side: Direction,
|
|
||||||
neighborState: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos,
|
|
||||||
neighborPos: BlockPos
|
|
||||||
): BlockState {
|
|
||||||
val current = state[CABLE_CONNECTION]
|
val current = state[CABLE_CONNECTION]
|
||||||
var newConnection = current
|
var newConnection = current
|
||||||
|
|
||||||
|
@ -189,12 +159,7 @@ abstract class FaceDeviceBlock<T : DeviceBlockEntity>(settings: Settings) : Devi
|
||||||
return state.with(CABLE_CONNECTION, newConnection)
|
return state.with(CABLE_CONNECTION, newConnection)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getOutlineShape(
|
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||||
state: BlockState,
|
|
||||||
world: BlockView,
|
|
||||||
pos: BlockPos,
|
|
||||||
context: ShapeContext
|
|
||||||
): VoxelShape {
|
|
||||||
return getShape(state[FACING], state[CABLE_CONNECTION])
|
return getShape(state[FACING], state[CABLE_CONNECTION])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,7 @@ class CableBlock(
|
||||||
VoxelShapes.union(acc, SIDE_SHAPES[side])
|
VoxelShapes.union(acc, SIDE_SHAPES[side])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val CONNECTIONS: Map<Direction, EnumProperty<CableConnection>> =
|
val CONNECTIONS: Map<Direction, EnumProperty<CableConnection>> = Direction.values().associate { it to EnumProperty.of(it.name.toLowerCase(), CableConnection::class.java) }
|
||||||
Direction.values().associate { it to EnumProperty.of(it.name.toLowerCase(), CableConnection::class.java) }
|
|
||||||
|
|
||||||
fun getShape(state: BlockState): VoxelShape {
|
fun getShape(state: BlockState): VoxelShape {
|
||||||
val key = Direction.values().foldIndexed(0) { i, acc, dir ->
|
val key = Direction.values().foldIndexed(0) { i, acc, dir ->
|
||||||
|
@ -111,14 +110,7 @@ class CableBlock(
|
||||||
return getInitialState(context.world, context.blockPos)
|
return getInitialState(context.world, context.blockPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStateForNeighborUpdate(
|
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, blockPos_1: BlockPos, blockPos_2: BlockPos): BlockState {
|
||||||
state: BlockState,
|
|
||||||
side: Direction,
|
|
||||||
neighborState: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
blockPos_1: BlockPos,
|
|
||||||
blockPos_2: BlockPos
|
|
||||||
): BlockState {
|
|
||||||
val prop = CONNECTIONS[side]
|
val prop = CONNECTIONS[side]
|
||||||
val current = state[prop]
|
val current = state[prop]
|
||||||
return when (current) {
|
return when (current) {
|
||||||
|
@ -127,11 +119,7 @@ class CableBlock(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getConnectionStateInDirection(
|
private fun getConnectionStateInDirection(world: WorldAccess, pos: BlockPos, direction: Direction): CableConnection {
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos,
|
|
||||||
direction: Direction
|
|
||||||
): CableConnection {
|
|
||||||
val offsetPos = pos.offset(direction)
|
val offsetPos = pos.offset(direction)
|
||||||
val state = world.getBlockState(offsetPos)
|
val state = world.getBlockState(offsetPos)
|
||||||
val block = state.block
|
val block = state.block
|
||||||
|
@ -152,12 +140,7 @@ class CableBlock(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNetworkInterfaceForSide(
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||||
side: Direction,
|
|
||||||
state: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos
|
|
||||||
): Interface? {
|
|
||||||
// cables don't have network interfaces
|
// cables don't have network interfaces
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -186,18 +169,11 @@ class CableBlock(
|
||||||
val connectedToPos = pos.offset(side)
|
val connectedToPos = pos.offset(side)
|
||||||
val connectedTo = world.getBlockState(connectedToPos)
|
val connectedTo = world.getBlockState(connectedToPos)
|
||||||
if (connectedTo.block == this && connectedTo[CONNECTIONS[side.opposite]] == CableConnection.DISABLED) {
|
if (connectedTo.block == this && connectedTo[CONNECTIONS[side.opposite]] == CableConnection.DISABLED) {
|
||||||
world.setBlockState(
|
world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON))
|
||||||
connectedToPos,
|
|
||||||
connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.with(
|
state.with(prop, if (connectedTo.block is NetworkComponentBlock) CableConnection.ON else CableConnection.OFF)
|
||||||
prop,
|
|
||||||
if (connectedTo.block is NetworkComponentBlock) CableConnection.ON else CableConnection.OFF
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> state.with(prop, CableConnection.DISABLED)
|
else -> state.with(prop, CableConnection.DISABLED)
|
||||||
}
|
}
|
||||||
world.setBlockState(pos, newState)
|
world.setBlockState(pos, newState)
|
||||||
|
@ -219,12 +195,7 @@ class CableBlock(
|
||||||
// return false
|
// return false
|
||||||
// }
|
// }
|
||||||
|
|
||||||
override fun getOutlineShape(
|
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||||
state: BlockState,
|
|
||||||
world: BlockView,
|
|
||||||
pos: BlockPos,
|
|
||||||
context: ShapeContext
|
|
||||||
): VoxelShape {
|
|
||||||
return getShape(state)
|
return getShape(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,14 +59,7 @@ class ExtractorBlock : FaceDeviceBlock<ExtractorBlockEntity>(
|
||||||
arr[i] = 16.0 - arr[i]
|
arr[i] = 16.0 - arr[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createCuboidShape(
|
createCuboidShape(min(arr[0], arr[3]), min(arr[1], arr[4]), min(arr[2], arr[5]), max(arr[0], arr[3]), max(arr[1], arr[4]), max(arr[2], arr[5]))
|
||||||
min(arr[0], arr[3]),
|
|
||||||
min(arr[1], arr[4]),
|
|
||||||
min(arr[2], arr[5]),
|
|
||||||
max(arr[0], arr[3]),
|
|
||||||
max(arr[1], arr[4]),
|
|
||||||
max(arr[2], arr[5])
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
EXTRACTOR_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
EXTRACTOR_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
||||||
}
|
}
|
||||||
|
@ -78,4 +71,16 @@ class ExtractorBlock : FaceDeviceBlock<ExtractorBlockEntity>(
|
||||||
|
|
||||||
override fun createBlockEntity(pos: BlockPos, state: BlockState) = ExtractorBlockEntity(pos, state)
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = ExtractorBlockEntity(pos, state)
|
||||||
|
|
||||||
|
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, neighbor: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
getBlockEntity(world, pos)!!.updateInventory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
package net.shadowfacts.phycon.block.extractor
|
package net.shadowfacts.phycon.block.extractor
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiCache
|
import alexiil.mc.lib.attributes.SearchOptions
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
|
import alexiil.mc.lib.attributes.Simulation
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
import alexiil.mc.lib.attributes.item.FixedItemInv
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction
|
import alexiil.mc.lib.attributes.item.filter.ExactItemStackFilter
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.server.world.ServerWorld
|
|
||||||
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.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
|
@ -24,15 +23,12 @@ import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import net.shadowfacts.phycon.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 net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.util.copyWithCount
|
|
||||||
import kotlin.math.min
|
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ExtractorBlockEntity(pos: BlockPos, state: BlockState) :
|
class ExtractorBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.EXTRACTOR, pos, state),
|
||||||
DeviceBlockEntity(PhyBlockEntities.EXTRACTOR, pos, state),
|
|
||||||
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
NetworkStackDispatcher<ExtractorBlockEntity.PendingInsertion>,
|
||||||
ActivationController.ActivatableDevice,
|
ActivationController.ActivatableDevice,
|
||||||
ClientConfigurableDevice {
|
ClientConfigurableDevice {
|
||||||
|
@ -44,19 +40,20 @@ class ExtractorBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = cachedState[FaceDeviceBlock.FACING]
|
get() = cachedState[FaceDeviceBlock.FACING]
|
||||||
|
|
||||||
private var inventory: Pair<BlockState, BlockApiCache<Storage<ItemVariant>, Direction>>? = null
|
private var inventory: FixedItemInv? = null
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = 1L
|
override val dispatchStackTimeout = 1L
|
||||||
override val controller = ActivationController(SLEEP_TIME, this)
|
override val controller = ActivationController(SLEEP_TIME, this)
|
||||||
|
|
||||||
private fun getInventory(): Storage<ItemVariant>? {
|
fun updateInventory() {
|
||||||
if (inventory == null) {
|
|
||||||
val offsetPos = pos.offset(facing)
|
val offsetPos = pos.offset(facing)
|
||||||
val cachedFacedBlock = world!!.getBlockState(offsetPos)
|
val option = SearchOptions.inDirection(facing)
|
||||||
val inventory = BlockApiCache.create(ItemStorage.SIDED, world!! as ServerWorld, offsetPos)
|
inventory = ItemAttributes.FIXED_INV.getFirstOrNull(world, offsetPos, option)
|
||||||
this.inventory = Pair(cachedFacedBlock, inventory)
|
|
||||||
}
|
}
|
||||||
return inventory!!.second.find(inventory!!.first, facing.opposite)
|
|
||||||
|
private fun getInventory(): FixedItemInv? {
|
||||||
|
if (inventory == null) updateInventory()
|
||||||
|
return inventory
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
|
@ -78,15 +75,10 @@ class ExtractorBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
val inventory = getInventory() ?: return insertion.stack
|
val inventory = getInventory() ?: return insertion.stack
|
||||||
// if the inventory has changed, the old slot index is meaningless
|
// if the inventory has changed, the old slot index is meaningless
|
||||||
if (inventory !== insertion.inventory) return insertion.stack
|
if (inventory !== insertion.inventory) return insertion.stack
|
||||||
val transaction = Transaction.openOuter()
|
val extracted = inventory.extractStack(insertion.inventorySlot, ExactItemStackFilter(insertion.stack), ItemStack.EMPTY, insertion.totalCapacity, Simulation.ACTION)
|
||||||
val extractedAmount = inventory.extract(ItemVariant.of(insertion.stack), insertion.stack.count.toLong(), transaction).toInt()
|
if (extracted.isEmpty) return insertion.stack
|
||||||
transaction.commit()
|
|
||||||
if (extractedAmount == 0) {
|
|
||||||
return insertion.stack
|
|
||||||
} else if (extractedAmount != insertion.stack.count) {
|
|
||||||
// if we extracted less than expected, make sure super.finishInsertion doesn't send more than we actually have
|
// if we extracted less than expected, make sure super.finishInsertion doesn't send more than we actually have
|
||||||
insertion.stack = insertion.stack.copyWithCount(extractedAmount)
|
insertion.stack = extracted
|
||||||
}
|
|
||||||
return super.finishInsertion(insertion)
|
return super.finishInsertion(insertion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,15 +94,14 @@ class ExtractorBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
|
|
||||||
override fun activate(): Boolean {
|
override fun activate(): Boolean {
|
||||||
val inventory = getInventory() ?: return false
|
val inventory = getInventory() ?: return false
|
||||||
for (view in inventory.iterator(null)) {
|
for (slot in 0 until inventory.slotCount) {
|
||||||
if (view.amount <= 0) continue
|
val slotStack = inventory.getInvStack(slot)
|
||||||
val transaction = Transaction.openOuter()
|
if (slotStack.isEmpty) continue
|
||||||
var extractableAmount = inventory.simulateExtract(view.resource, view.amount, transaction).toInt()
|
val extractable = inventory.extractStack(slot, ExactItemStackFilter(slotStack), ItemStack.EMPTY, slotStack.count, Simulation.SIMULATE)
|
||||||
transaction.close()
|
if (extractable.isEmpty) continue
|
||||||
if (extractableAmount <= 0) continue
|
dispatchItemStack(extractable) { insertion ->
|
||||||
extractableAmount = min(extractableAmount, view.resource.item.maxCount)
|
|
||||||
dispatchItemStack(view.resource.toStack(extractableAmount)) { insertion ->
|
|
||||||
insertion.inventory = inventory
|
insertion.inventory = inventory
|
||||||
|
insertion.inventorySlot = slot
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -135,9 +126,8 @@ class ExtractorBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
controller.activationMode = ActivationMode.valueOf(tag.getString("ActivationMode"))
|
||||||
}
|
}
|
||||||
|
|
||||||
class PendingInsertion(stack: ItemStack, timestamp: Long) :
|
class PendingInsertion(stack: ItemStack, timestamp: Long): NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
|
||||||
NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
|
lateinit var inventory: FixedItemInv
|
||||||
lateinit var inventory: Storage<ItemVariant>
|
|
||||||
var inventorySlot by Delegates.notNull<Int>()
|
var inventorySlot by Delegates.notNull<Int>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,14 +68,7 @@ class InserterBlock : FaceDeviceBlock<InserterBlockEntity>(
|
||||||
arr[i] = 16.0 - arr[i]
|
arr[i] = 16.0 - arr[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createCuboidShape(
|
createCuboidShape(min(arr[0], arr[3]), min(arr[1], arr[4]), min(arr[2], arr[5]), max(arr[0], arr[3]), max(arr[1], arr[4]), max(arr[2], arr[5]))
|
||||||
min(arr[0], arr[3]),
|
|
||||||
min(arr[1], arr[4]),
|
|
||||||
min(arr[2], arr[5]),
|
|
||||||
max(arr[0], arr[3]),
|
|
||||||
max(arr[1], arr[4]),
|
|
||||||
max(arr[2], arr[5])
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
INSERTER_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
INSERTER_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
||||||
}
|
}
|
||||||
|
@ -87,14 +80,19 @@ class InserterBlock : FaceDeviceBlock<InserterBlockEntity>(
|
||||||
|
|
||||||
override fun createBlockEntity(pos: BlockPos, state: BlockState) = InserterBlockEntity(pos, state)
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = InserterBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun onUse(
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
||||||
state: BlockState,
|
if (!world.isClient) {
|
||||||
world: World,
|
getBlockEntity(world, pos)!!.updateInventory()
|
||||||
pos: BlockPos,
|
}
|
||||||
player: PlayerEntity,
|
}
|
||||||
hand: Hand,
|
|
||||||
hitResult: BlockHitResult
|
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||||
): ActionResult {
|
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) {
|
if (!world.isClient) {
|
||||||
val be = getBlockEntity(world, pos)!!
|
val be = getBlockEntity(world, pos)!!
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
package net.shadowfacts.phycon.block.inserter
|
package net.shadowfacts.phycon.block.inserter
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiCache
|
import alexiil.mc.lib.attributes.SearchOptions
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
|
import alexiil.mc.lib.attributes.Simulation
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
import alexiil.mc.lib.attributes.item.ItemInsertable
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.server.world.ServerWorld
|
|
||||||
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.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
|
@ -20,7 +19,9 @@ import net.shadowfacts.phycon.component.NetworkStackProvider
|
||||||
import net.shadowfacts.phycon.component.handleItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
import net.shadowfacts.phycon.util.*
|
import net.shadowfacts.phycon.util.ActivationMode
|
||||||
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
|
import net.shadowfacts.phycon.util.GhostInv
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,25 +41,24 @@ class InserterBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = cachedState[FaceDeviceBlock.FACING]
|
get() = cachedState[FaceDeviceBlock.FACING]
|
||||||
|
|
||||||
private var inventory: Pair<BlockState, BlockApiCache<Storage<ItemVariant>, Direction>>? = null
|
private var inventory: ItemInsertable? = null
|
||||||
private var currentRequest: PendingExtractRequest? = null
|
private var currentRequest: PendingExtractRequest? = null
|
||||||
var stackToExtract: ItemStack = ItemStack.EMPTY
|
var stackToExtract: ItemStack = ItemStack.EMPTY
|
||||||
override var ghostSlotStack: ItemStack
|
override var ghostSlotStack: ItemStack
|
||||||
get() = stackToExtract
|
get() = stackToExtract
|
||||||
set(value) {
|
set(value) { stackToExtract = value }
|
||||||
stackToExtract = value
|
|
||||||
}
|
|
||||||
var amountToExtract = 1
|
var amountToExtract = 1
|
||||||
override val controller = ActivationController(SLEEP_TIME, this)
|
override val controller = ActivationController(SLEEP_TIME, this)
|
||||||
|
|
||||||
private fun getInventory(): Storage<ItemVariant>? {
|
fun updateInventory() {
|
||||||
if (inventory == null) {
|
|
||||||
val offsetPos = pos.offset(facing)
|
val offsetPos = pos.offset(facing)
|
||||||
val cachedFacedBlock = world!!.getBlockState(offsetPos)
|
val option = SearchOptions.inDirection(facing)
|
||||||
val inventory = BlockApiCache.create(ItemStorage.SIDED, world!! as ServerWorld, offsetPos)
|
inventory = ItemAttributes.INSERTABLE.getFirstOrNull(world, offsetPos, option)
|
||||||
this.inventory = Pair(cachedFacedBlock, inventory)
|
|
||||||
}
|
}
|
||||||
return inventory!!.second.find(inventory!!.first, facing.opposite)
|
|
||||||
|
private fun getInventory(): ItemInsertable? {
|
||||||
|
if (inventory == null) updateInventory()
|
||||||
|
return inventory
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
|
@ -71,26 +71,17 @@ class InserterBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(
|
||||||
|
|
||||||
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||||
val inventory = getInventory()
|
val inventory = getInventory()
|
||||||
if (inventory != null) {
|
return if (inventory != null) {
|
||||||
val transaction = Transaction.openOuter()
|
inventory.attemptInsertion(packet.stack, Simulation.ACTION)
|
||||||
val inserted = inventory.insert(ItemVariant.of(packet.stack), packet.stack.count.toLong(), transaction).toInt()
|
|
||||||
transaction.commit()
|
|
||||||
return if (inserted == 0) {
|
|
||||||
packet.stack
|
|
||||||
} else if (inserted == packet.stack.count) {
|
|
||||||
ItemStack.EMPTY
|
|
||||||
} else {
|
|
||||||
packet.stack.copyWithCount(packet.stack.count - inserted)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// no inventory, entire stack remains
|
// no inventory, entire stack remains
|
||||||
return packet.stack
|
packet.stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleStackLocation(packet: StackLocationPacket) {
|
private fun handleStackLocation(packet: StackLocationPacket) {
|
||||||
val request = currentRequest
|
val request = currentRequest
|
||||||
if (request != null && request.stack.equalsIgnoringAmount(packet.stack)) {
|
if (request != null && ItemStackUtil.areEqualIgnoreAmounts(request.stack, packet.stack)) {
|
||||||
request.results.add(packet.amount to packet.stackProvider)
|
request.results.add(packet.amount to packet.stackProvider)
|
||||||
if (request.isFinishable(counter)) {
|
if (request.isFinishable(counter)) {
|
||||||
finishRequest()
|
finishRequest()
|
||||||
|
|
|
@ -38,12 +38,7 @@ class MinerBlock : DeviceBlock<MinerBlockEntity>(
|
||||||
return EnumSet.of(state[FACING].opposite)
|
return EnumSet.of(state[FACING].opposite)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNetworkInterfaceForSide(
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||||
side: Direction,
|
|
||||||
state: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos
|
|
||||||
): Interface? {
|
|
||||||
return if (side == state[FACING]) {
|
return if (side == state[FACING]) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
|
@ -69,14 +64,7 @@ class MinerBlock : DeviceBlock<MinerBlockEntity>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun neighborUpdate(
|
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighbor: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||||
state: BlockState,
|
|
||||||
world: World,
|
|
||||||
pos: BlockPos,
|
|
||||||
neighbor: Block,
|
|
||||||
neighborPos: BlockPos,
|
|
||||||
bl: Boolean
|
|
||||||
) {
|
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
// getBlockEntity(world, pos)!!.updateBlockToMine()
|
// getBlockEntity(world, pos)!!.updateBlockToMine()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package net.shadowfacts.phycon.block.miner
|
package net.shadowfacts.phycon.block.miner
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.base.ExtractionOnlyStorage
|
import alexiil.mc.lib.attributes.item.filter.ItemFilter
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant
|
|
||||||
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
|
||||||
|
@ -24,7 +22,6 @@ import net.shadowfacts.phycon.packet.*
|
||||||
import net.shadowfacts.phycon.util.ActivationMode
|
import net.shadowfacts.phycon.util.ActivationMode
|
||||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.util.copyWithCount
|
import net.shadowfacts.phycon.util.copyWithCount
|
||||||
import net.shadowfacts.phycon.util.equalsIgnoringAmount
|
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +36,7 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = cachedState[MinerBlock.FACING]
|
get() = cachedState[MinerBlock.FACING]
|
||||||
|
|
||||||
private val invProxy = MinerStorageProxy(this)
|
private val invProxy = MinerInvProxy(this)
|
||||||
|
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = AbstractTerminalBlockEntity.INSERTION_TIMEOUT
|
override val dispatchStackTimeout = AbstractTerminalBlockEntity.INSERTION_TIMEOUT
|
||||||
|
@ -63,16 +60,16 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
|
||||||
if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) {
|
if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sendPacket(ReadItemStoragePacket(invProxy, ipAddress, packet.source))
|
sendPacket(ReadGroupedInventoryPacket(invProxy, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||||
if (minerMode != MinerMode.ON_DEMAND) {
|
if (minerMode != MinerMode.ON_DEMAND) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val amount = invProxy.simulateExtract(ItemVariant.of(packet.stack), Long.MAX_VALUE, null)
|
val amount = invProxy.getAmount(packet.stack)
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
sendPacket(StackLocationPacket(packet.stack, amount.toInt(), this, ipAddress, packet.source))
|
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +80,7 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
|
||||||
|
|
||||||
// always recalculate immediately before breaking
|
// always recalculate immediately before breaking
|
||||||
val drops = invProxy.getDrops(recalculate = true)
|
val drops = invProxy.getDrops(recalculate = true)
|
||||||
val amount = invProxy.simulateExtract(ItemVariant.of(packet.stack), packet.amount.toLong(), null)
|
if (invProxy.getAmount(packet.stack) > 0) {
|
||||||
if (amount > 0) {
|
|
||||||
world!!.breakBlock(pos.offset(facing), false)
|
world!!.breakBlock(pos.offset(facing), false)
|
||||||
|
|
||||||
// send the requested amount back to the requester
|
// send the requested amount back to the requester
|
||||||
|
@ -93,7 +89,7 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
|
||||||
if (remaining <= 0) {
|
if (remaining <= 0) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (!droppedStack.equalsIgnoringAmount(packet.stack)) {
|
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,15 +184,13 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
|
||||||
val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.lowercase()}")
|
val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.lowercase()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
class MinerStorageProxy(val miner: MinerBlockEntity) :
|
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
|
||||||
SnapshotParticipant<Pair<BlockState, List<ItemStack>>?>(),
|
|
||||||
ExtractionOnlyStorage<ItemVariant>
|
|
||||||
{
|
|
||||||
companion object {
|
companion object {
|
||||||
val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
|
val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cache: Pair<BlockState, List<ItemStack>>? = null
|
private var cachedState: BlockState? = null
|
||||||
|
private var cachedDrops: List<ItemStack>? = null
|
||||||
|
|
||||||
private val world: World
|
private val world: World
|
||||||
get() = miner.world!!
|
get() = miner.world!!
|
||||||
|
@ -208,78 +202,39 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
|
||||||
fun getDrops(recalculate: Boolean = false): List<ItemStack> {
|
fun getDrops(recalculate: Boolean = false): List<ItemStack> {
|
||||||
val targetPos = pos.offset(facing)
|
val targetPos = pos.offset(facing)
|
||||||
val realState = world.getBlockState(targetPos)
|
val realState = world.getBlockState(targetPos)
|
||||||
val cache = this.cache
|
|
||||||
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
|
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
|
||||||
if (cache == null || realState != cache.first || recalculate) {
|
if (cachedDrops == null || realState != cachedState || recalculate) {
|
||||||
|
cachedState = realState
|
||||||
|
|
||||||
val be = if (realState.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
val be = if (realState.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
||||||
val drops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL)
|
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL)
|
||||||
this.cache = Pair(realState, drops)
|
|
||||||
return drops
|
|
||||||
}
|
}
|
||||||
return cache.second
|
return cachedDrops!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSnapshot(): Pair<BlockState, List<ItemStack>>? {
|
override fun getStoredStacks(): Set<ItemStack> {
|
||||||
return cache
|
if (miner.minerMode != MinerMode.ON_DEMAND) {
|
||||||
|
return setOf()
|
||||||
|
}
|
||||||
|
return getDrops().toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readSnapshot(snapshot: Pair<BlockState, List<ItemStack>>?) {
|
override fun getTotalCapacity(): Int {
|
||||||
cache = snapshot
|
return Int.MAX_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun extract(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long {
|
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
|
||||||
val drops = getDrops()
|
var totalCount = 0
|
||||||
val (matched, unmatched) = drops.partition { resource.matches(it) }
|
for (s in storedStacks) {
|
||||||
if (matched.isEmpty()) {
|
if (filter.matches(s)) {
|
||||||
return 0
|
totalCount += s.count
|
||||||
}
|
|
||||||
val matchedCount = matched.sumOf { it.count }.toLong()
|
|
||||||
val extracted = min(maxAmount, matchedCount)
|
|
||||||
transaction.addCloseCallback { context, result ->
|
|
||||||
if (result.wasCommitted()) {
|
|
||||||
world.breakBlock(pos.offset(facing), false)
|
|
||||||
// send any un-extracted drops to the network
|
|
||||||
if (matchedCount > extracted) {
|
|
||||||
miner.dispatchItemStack(resource.toStack().copyWithCount((matchedCount - extracted).toInt()))
|
|
||||||
}
|
|
||||||
for (stack in unmatched) {
|
|
||||||
miner.dispatchItemStack(stack)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return GroupedItemInvView.ItemInvStatistic(filter, totalCount, 0, Int.MAX_VALUE)
|
||||||
return extracted
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator(transaction: TransactionContext): Iterator<StorageView<ItemVariant>> {
|
|
||||||
return getDrops().map { View(it, this) }.iterator()
|
|
||||||
}
|
|
||||||
|
|
||||||
class View(val stack: ItemStack, val proxy: MinerStorageProxy) : StorageView<ItemVariant> {
|
|
||||||
override fun extract(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long {
|
|
||||||
return proxy.extract(resource, maxAmount, transaction)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isResourceBlank(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getResource(): ItemVariant {
|
|
||||||
return ItemVariant.of(stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAmount(): Long {
|
|
||||||
return stack.count.toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCapacity(): Long {
|
|
||||||
// TODO: ehh? we have stuff stored, but nothing can be inserted, so...
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PendingInsertion(stack: ItemStack, timestamp: Long) :
|
class PendingInsertion(stack: ItemStack, timestamp: Long): NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
|
||||||
NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package net.shadowfacts.phycon.block.netinterface
|
package net.shadowfacts.phycon.block.netinterface
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.AttributeList
|
||||||
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.*
|
import net.minecraft.block.*
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
@ -21,7 +23,8 @@ class InterfaceBlock : FaceDeviceBlock<InterfaceBlockEntity>(
|
||||||
.strength(1.5f)
|
.strength(1.5f)
|
||||||
.sounds(BlockSoundGroup.METAL)
|
.sounds(BlockSoundGroup.METAL)
|
||||||
),
|
),
|
||||||
NetworkComponentBlock {
|
NetworkComponentBlock,
|
||||||
|
AttributeProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
|
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
|
||||||
|
@ -39,4 +42,20 @@ class InterfaceBlock : FaceDeviceBlock<InterfaceBlockEntity>(
|
||||||
|
|
||||||
override fun createBlockEntity(pos: BlockPos, state: BlockState) = InterfaceBlockEntity(pos, state)
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = InterfaceBlockEntity(pos, state)
|
||||||
|
|
||||||
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
getBlockEntity(world, pos)!!.updateInventory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
getBlockEntity(world, pos)!!.updateInventory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||||
|
to.offer(getBlockEntity(world, pos))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package net.shadowfacts.phycon.block.netinterface
|
package net.shadowfacts.phycon.block.netinterface
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiCache
|
import alexiil.mc.lib.attributes.SearchOptions
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
|
import alexiil.mc.lib.attributes.Simulation
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.server.world.ServerWorld
|
|
||||||
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.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
|
@ -21,14 +19,13 @@ import net.shadowfacts.phycon.component.NetworkStackReceiver
|
||||||
import net.shadowfacts.phycon.component.handleItemStack
|
import net.shadowfacts.phycon.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.util.copyWithCount
|
import java.lang.ref.WeakReference
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class InterfaceBlockEntity(pos: BlockPos, state: BlockState) :
|
class InterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.INTERFACE, pos, state),
|
||||||
DeviceBlockEntity(PhyBlockEntities.INTERFACE, pos, state),
|
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
NetworkStackProvider,
|
NetworkStackProvider,
|
||||||
NetworkStackReceiver,
|
NetworkStackReceiver,
|
||||||
|
@ -41,17 +38,21 @@ class InterfaceBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
override var receiverPriority = 0
|
override var receiverPriority = 0
|
||||||
var syncPriorities = true
|
var syncPriorities = true
|
||||||
|
|
||||||
private var cachedFacedBlock: BlockState? = null
|
private var inventory: WeakReference<GroupedItemInv>? = null
|
||||||
private var inventoryCache: BlockApiCache<Storage<ItemVariant>, Direction>? = null
|
|
||||||
|
|
||||||
private fun getInventory(): Storage<ItemVariant>? {
|
fun updateInventory() {
|
||||||
if (cachedFacedBlock == null) {
|
val offsetPos = pos.offset(facing)
|
||||||
cachedFacedBlock = world!!.getBlockState(pos.offset(facing))
|
val option = SearchOptions.inDirection(facing)
|
||||||
|
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option).let {
|
||||||
|
WeakReference(it)
|
||||||
}
|
}
|
||||||
if (inventoryCache == null) {
|
|
||||||
inventoryCache = BlockApiCache.create(ItemStorage.SIDED, world!! as ServerWorld, pos.offset(facing))
|
|
||||||
}
|
}
|
||||||
return inventoryCache!!.find(cachedFacedBlock!!, facing.opposite)
|
|
||||||
|
private fun getInventory(): GroupedItemInv? {
|
||||||
|
// if we don't have an inventory, try to get one
|
||||||
|
// this happens when readAll is called before a neighbor state changes, such as immediately after world load
|
||||||
|
if (inventory?.get() == null) updateInventory()
|
||||||
|
return inventory?.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
|
@ -69,50 +70,46 @@ class InterfaceBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
sendPacket(ReadItemStoragePacket(inv, ipAddress, packet.source))
|
sendPacket(ReadGroupedInventoryPacket(inv, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
val transaction = Transaction.openOuter()
|
val amount = inv.getAmount(packet.stack)
|
||||||
val amount = inv.simulateExtract(ItemVariant.of(packet.stack), Long.MAX_VALUE, transaction);
|
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||||
transaction.close()
|
|
||||||
sendPacket(StackLocationPacket(packet.stack, amount.toInt(), this, ipAddress, packet.source))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleExtractStack(packet: ExtractStackPacket) {
|
private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
var remaining = packet.amount
|
var amount = packet.amount
|
||||||
while (remaining > 0) {
|
while (amount > 0) {
|
||||||
val toExtract = min(remaining, packet.stack.maxCount)
|
val extracted = inv.extract(packet.stack, min(amount, packet.stack.maxCount))
|
||||||
val transaction = Transaction.openOuter()
|
if (extracted.isEmpty) {
|
||||||
val extracted = inv.extract(ItemVariant.of(packet.stack), toExtract.toLong(), transaction)
|
break
|
||||||
transaction.commit()
|
} else {
|
||||||
remaining -= extracted.toInt()
|
amount -= extracted.count
|
||||||
sendPacket(ItemStackPacket(packet.stack.copyWithCount(extracted.toInt()), ipAddress, packet.source))
|
sendPacket(ItemStackPacket(extracted, ipAddress, packet.source))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleCheckCapacity(packet: CheckCapacityPacket) {
|
private fun handleCheckCapacity(packet: CheckCapacityPacket) {
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
val transaction = Transaction.openOuter()
|
val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE)
|
||||||
val inserted = inv.simulateInsert(ItemVariant.of(packet.stack), packet.stack.count.toLong(), transaction)
|
val couldAccept = packet.stack.count - remaining.count
|
||||||
transaction.close()
|
sendPacket(CapacityPacket(packet.stack, couldAccept, this, ipAddress, packet.source))
|
||||||
sendPacket(CapacityPacket(packet.stack, inserted.toInt(), this, ipAddress, packet.source))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||||
val inventory = getInventory()
|
val inventory = getInventory()
|
||||||
if (inventory != null) {
|
if (inventory != null) {
|
||||||
val transaction = Transaction.openOuter()
|
val remaining = inventory.insert(packet.stack)
|
||||||
val inserted = inventory.insert(ItemVariant.of(packet.stack), packet.stack.count.toLong(), transaction)
|
// whatever could not be inserted will be sent back to the packet's source
|
||||||
transaction.commit()
|
return remaining
|
||||||
val remaining = packet.stack.count - inserted.toInt()
|
|
||||||
return packet.stack.copyWithCount(remaining)
|
|
||||||
} else {
|
} else {
|
||||||
return packet.stack
|
return packet.stack
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package net.shadowfacts.phycon.block.netswitch
|
package net.shadowfacts.phycon.block.netswitch
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.AttributeList
|
||||||
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.Material
|
import net.minecraft.block.Material
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
|
@ -9,6 +11,7 @@ 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
|
||||||
|
import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
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
|
||||||
|
@ -25,7 +28,8 @@ class SwitchBlock : BlockWithEntity<SwitchBlockEntity>(
|
||||||
.strength(1.5f)
|
.strength(1.5f)
|
||||||
.sounds(BlockSoundGroup.METAL)
|
.sounds(BlockSoundGroup.METAL)
|
||||||
),
|
),
|
||||||
NetworkComponentBlock {
|
NetworkComponentBlock,
|
||||||
|
AttributeProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "switch")
|
val ID = Identifier(PhysicalConnectivity.MODID, "switch")
|
||||||
|
@ -35,22 +39,13 @@ class SwitchBlock : BlockWithEntity<SwitchBlockEntity>(
|
||||||
return EnumSet.allOf(Direction::class.java)
|
return EnumSet.allOf(Direction::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNetworkInterfaceForSide(
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
|
||||||
side: Direction,
|
|
||||||
state: BlockState,
|
|
||||||
world: WorldAccess,
|
|
||||||
pos: BlockPos
|
|
||||||
): Interface? {
|
|
||||||
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
|
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(pos: BlockPos, state: BlockState) = SwitchBlockEntity(pos, state)
|
override fun createBlockEntity(pos: BlockPos, state: BlockState) = SwitchBlockEntity(pos, state)
|
||||||
|
|
||||||
override fun <T : BlockEntity> getTicker(
|
override fun <T: BlockEntity> getTicker(world: World, state: BlockState, type: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||||
world: World,
|
|
||||||
state: BlockState,
|
|
||||||
type: BlockEntityType<T>
|
|
||||||
): BlockEntityTicker<T>? {
|
|
||||||
return if (world.isClient) {
|
return if (world.isClient) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,4 +54,8 @@ class SwitchBlock : BlockWithEntity<SwitchBlockEntity>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||||
|
to.offer(getBlockEntity(world, pos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import net.shadowfacts.phycon.frame.BasePacketFrame
|
||||||
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import net.shadowfacts.phycon.util.IntRingBuffer
|
|
||||||
import net.shadowfacts.phycon.util.NetworkUtil
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.Deque
|
import java.util.Deque
|
||||||
|
@ -39,13 +38,9 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(PhyBlock
|
||||||
|
|
||||||
private val macTable = mutableMapOf<MACAddress, Direction>()
|
private val macTable = mutableMapOf<MACAddress, Direction>()
|
||||||
private val destinationCache = Array<WeakReference<Interface>?>(6) { null }
|
private val destinationCache = Array<WeakReference<Interface>?>(6) { null }
|
||||||
val packetStatistics = IntRingBuffer(60) // 1 minute's worth
|
|
||||||
private val currentSecondPacketStatistics = IntRingBuffer(20)
|
|
||||||
private var packetsHandledThisTick = 0
|
private var packetsHandledThisTick = 0
|
||||||
private var delayedPackets: Deque<Pair<PacketFrame, SwitchInterface>> = LinkedList()
|
private var delayedPackets: Deque<Pair<PacketFrame, SwitchInterface>> = LinkedList()
|
||||||
|
|
||||||
var statisticsObserver: (() -> Unit)? = null
|
|
||||||
|
|
||||||
fun interfaceForSide(side: Direction): SwitchInterface {
|
fun interfaceForSide(side: Direction): SwitchInterface {
|
||||||
return interfaces.find { it.side == side }!!
|
return interfaces.find { it.side == side }!!
|
||||||
}
|
}
|
||||||
|
@ -69,14 +64,7 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(PhyBlock
|
||||||
private fun resend(frame: EthernetFrame, fromItf: SwitchInterface) {
|
private fun resend(frame: EthernetFrame, fromItf: SwitchInterface) {
|
||||||
if (frame.destination.type != MACAddress.Type.BROADCAST && macTable.containsKey(frame.destination)) {
|
if (frame.destination.type != MACAddress.Type.BROADCAST && macTable.containsKey(frame.destination)) {
|
||||||
val dir = macTable[frame.destination]!!
|
val dir = macTable[frame.destination]!!
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug(
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) forwarding {} to side {}", this, fromItf.side, fromItf.macAddress, frame, dir)
|
||||||
"{} ({}, {}) forwarding {} to side {}",
|
|
||||||
this,
|
|
||||||
fromItf.side,
|
|
||||||
fromItf.macAddress,
|
|
||||||
frame,
|
|
||||||
dir
|
|
||||||
)
|
|
||||||
interfaceForSide(dir).send(frame)
|
interfaceForSide(dir).send(frame)
|
||||||
} else {
|
} else {
|
||||||
flood(frame, fromItf)
|
flood(frame, fromItf)
|
||||||
|
@ -84,13 +72,7 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(PhyBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flood(frame: EthernetFrame, source: SwitchInterface) {
|
private fun flood(frame: EthernetFrame, source: SwitchInterface) {
|
||||||
PhysicalConnectivity.NETWORK_LOGGER.debug(
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) flooding {}", this, source.side, source.macAddress, frame)
|
||||||
"{} ({}, {}) flooding {}",
|
|
||||||
this,
|
|
||||||
source.side,
|
|
||||||
source.macAddress,
|
|
||||||
frame
|
|
||||||
)
|
|
||||||
for (itf in interfaces) {
|
for (itf in interfaces) {
|
||||||
if (source == itf) continue
|
if (source == itf) continue
|
||||||
itf.send(frame)
|
itf.send(frame)
|
||||||
|
@ -116,16 +98,6 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(PhyBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tick() {
|
fun tick() {
|
||||||
if (statisticsObserver != null) {
|
|
||||||
if (currentSecondPacketStatistics.size == 20) {
|
|
||||||
packetStatistics.add(currentSecondPacketStatistics.sum())
|
|
||||||
currentSecondPacketStatistics.clear()
|
|
||||||
statisticsObserver?.invoke()
|
|
||||||
} else {
|
|
||||||
currentSecondPacketStatistics.add(packetsHandledThisTick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
packetsHandledThisTick = 0
|
packetsHandledThisTick = 0
|
||||||
|
|
||||||
while (delayedPackets.isNotEmpty() && packetsHandledThisTick <= SWITCHING_CAPACITY) {
|
while (delayedPackets.isNotEmpty() && packetsHandledThisTick <= SWITCHING_CAPACITY) {
|
||||||
|
@ -175,11 +147,6 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(PhyBlock
|
||||||
delayedPackets.addLast(frame to fromItf)
|
delayedPackets.addLast(frame to fromItf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tag.getIntArray("PacketStatistics")?.also { statistics ->
|
|
||||||
if (statistics.isNotEmpty()) {
|
|
||||||
packetStatistics.replace(statistics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
|
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
|
||||||
|
@ -189,7 +156,6 @@ class SwitchBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(PhyBlock
|
||||||
override fun toInitialChunkDataNbt(): NbtCompound {
|
override fun toInitialChunkDataNbt(): NbtCompound {
|
||||||
val tag = NbtCompound()
|
val tag = NbtCompound()
|
||||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||||
tag.putIntArray("PacketStatistics", packetStatistics.asContiguousArray())
|
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
package net.shadowfacts.phycon.block.netswitch
|
|
||||||
|
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
|
||||||
import net.minecraft.text.LiteralText
|
|
||||||
import net.minecraft.text.Text
|
|
||||||
import net.shadowfacts.cacao.CacaoHandledScreen
|
|
||||||
import net.shadowfacts.cacao.geometry.Point
|
|
||||||
import net.shadowfacts.cacao.geometry.Rect
|
|
||||||
import net.shadowfacts.cacao.geometry.Size
|
|
||||||
import net.shadowfacts.cacao.util.Color
|
|
||||||
import net.shadowfacts.cacao.util.RenderHelper
|
|
||||||
import net.shadowfacts.cacao.view.Label
|
|
||||||
import net.shadowfacts.cacao.view.View
|
|
||||||
import net.shadowfacts.cacao.viewcontroller.ViewController
|
|
||||||
import net.shadowfacts.cacao.window.ScreenHandlerWindow
|
|
||||||
import net.shadowfacts.kiwidsl.dsl
|
|
||||||
import org.lwjgl.glfw.GLFW
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
class SwitchConsoleScreen(
|
|
||||||
handler: SwitchConsoleScreenHandler,
|
|
||||||
playerInventory: PlayerInventory,
|
|
||||||
title: Text,
|
|
||||||
) : CacaoHandledScreen<SwitchConsoleScreenHandler>(
|
|
||||||
handler,
|
|
||||||
playerInventory,
|
|
||||||
title,
|
|
||||||
) {
|
|
||||||
|
|
||||||
val root = SwitchConsoleViewController(handler.switch)
|
|
||||||
|
|
||||||
init {
|
|
||||||
addWindow(ScreenHandlerWindow(handler, root))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun shouldPause() = false
|
|
||||||
|
|
||||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
|
||||||
if (keyCode == GLFW.GLFW_KEY_E) {
|
|
||||||
close()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return super.keyPressed(keyCode, scanCode, modifiers)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class SwitchConsoleViewController(val switch: SwitchBlockEntity) : ViewController() {
|
|
||||||
override fun viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
val stats = SwitchPacketStatisticsView(switch)
|
|
||||||
view.addSubview(stats)
|
|
||||||
view.solver.dsl {
|
|
||||||
stats.centerXAnchor equalTo (view.centerXAnchor + 50)
|
|
||||||
stats.centerYAnchor equalTo (view.centerYAnchor + 50)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SwitchPacketStatisticsView(val switch: SwitchBlockEntity) : View() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
intrinsicContentSize = Size(180.0, 90.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
|
||||||
RenderHelper.fill(matrixStack, bounds, Color.BLACK)
|
|
||||||
if (switch.packetStatistics.size == 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO: drawLine isn't working for some reason
|
|
||||||
RenderHelper.drawLine(
|
|
||||||
Point(bounds.left, bounds.top),
|
|
||||||
Point(bounds.right, bounds.bottom),
|
|
||||||
1.0,
|
|
||||||
2f,
|
|
||||||
Color.MAGENTA
|
|
||||||
)
|
|
||||||
return
|
|
||||||
val maxPackets = switch.packetStatistics.maxOf { it }
|
|
||||||
val maxDataPointsCount = 60
|
|
||||||
var lastPoint: Point? = null
|
|
||||||
val size = Size(3.0, 3.0)
|
|
||||||
for ((index, packets) in switch.packetStatistics.withIndex()) {
|
|
||||||
val x = (1 - (switch.packetStatistics.size - index).toDouble() / maxDataPointsCount) * bounds.width
|
|
||||||
val y = (1 - (packets.toDouble() / maxPackets)) * (bounds.height)
|
|
||||||
val point = Point(x, y)
|
|
||||||
if (lastPoint != null) {
|
|
||||||
// RenderHelper.fill(matrixStack, Rect(lastPoint, 3.0, 3.0), Color.RED)
|
|
||||||
RenderHelper.drawLine(lastPoint, point, 1.0, 2f, Color.RED)
|
|
||||||
}
|
|
||||||
lastPoint = point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package net.shadowfacts.phycon.block.netswitch
|
|
||||||
|
|
||||||
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.util.Identifier
|
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
|
||||||
import net.shadowfacts.phycon.init.PhyScreens
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
class SwitchConsoleScreenHandler(
|
|
||||||
syncId: Int,
|
|
||||||
val switch: SwitchBlockEntity,
|
|
||||||
) : ScreenHandler(PhyScreens.SWITCH_CONSOLE, syncId) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "switch_console")
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf) :
|
|
||||||
this(
|
|
||||||
syncId,
|
|
||||||
PhyBlocks.SWITCH.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!
|
|
||||||
)
|
|
||||||
|
|
||||||
init {
|
|
||||||
switch.statisticsObserver = {
|
|
||||||
switch.world!!.updateListeners(switch.pos, switch.cachedState, switch.cachedState, 3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canUse(player: PlayerEntity): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close(player: PlayerEntity) {
|
|
||||||
super.close(player)
|
|
||||||
|
|
||||||
switch.statisticsObserver = null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -15,8 +15,7 @@ import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class P2PInterfaceBlockEntity(pos: BlockPos, state: BlockState) :
|
class P2PInterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.P2P_INTERFACE, pos, state) {
|
||||||
DeviceBlockEntity(PhyBlockEntities.P2P_INTERFACE, pos, state) {
|
|
||||||
|
|
||||||
private var inventory: Storage<ItemVariant>? = null
|
private var inventory: Storage<ItemVariant>? = null
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,7 @@ import java.lang.ref.WeakReference
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class P2PReceiverBlockEntity(pos: BlockPos, state: BlockState) :
|
class P2PReceiverBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.P2P_RECEIVER, pos, state),
|
||||||
DeviceBlockEntity(PhyBlockEntities.P2P_RECEIVER, pos, state),
|
|
||||||
ClientConfigurableDevice {
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
enum class Status {
|
enum class Status {
|
||||||
|
|
|
@ -51,14 +51,7 @@ class RedstoneControllerBlock : FaceDeviceBlock<RedstoneControllerBlockEntity>(
|
||||||
return state.with(POWERED, isPowered(context.world, context.blockPos, state[FACING]))
|
return state.with(POWERED, isPowered(context.world, context.blockPos, state[FACING]))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun neighborUpdate(
|
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||||
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[POWERED]
|
val wasLit = state[POWERED]
|
||||||
|
|
|
@ -14,8 +14,7 @@ import net.shadowfacts.phycon.util.RedstoneMode
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RedstoneControllerBlockEntity(pos: BlockPos, state: BlockState) :
|
class RedstoneControllerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER, pos, state),
|
||||||
DeviceBlockEntity(PhyBlockEntities.REDSTONE_CONTROLLER, pos, state),
|
|
||||||
ClientConfigurableDevice {
|
ClientConfigurableDevice {
|
||||||
|
|
||||||
var managedDevices = Array<IPAddress?>(5) { null }
|
var managedDevices = Array<IPAddress?>(5) { null }
|
||||||
|
|
|
@ -51,12 +51,7 @@ class RedstoneEmitterBlock : FaceDeviceBlock<RedstoneEmitterBlockEntity>(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStrongRedstonePower(
|
override fun getStrongRedstonePower(state: BlockState, world: BlockView, pos: BlockPos, receivingSide: Direction): Int {
|
||||||
state: BlockState,
|
|
||||||
world: BlockView,
|
|
||||||
pos: BlockPos,
|
|
||||||
receivingSide: Direction
|
|
||||||
): Int {
|
|
||||||
return if (receivingSide.opposite == state[FACING]) {
|
return if (receivingSide.opposite == state[FACING]) {
|
||||||
getBlockEntity(world, pos)!!.cachedEmittedPower
|
getBlockEntity(world, pos)!!.cachedEmittedPower
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,23 +59,11 @@ class RedstoneEmitterBlock : FaceDeviceBlock<RedstoneEmitterBlockEntity>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getWeakRedstonePower(
|
override fun getWeakRedstonePower(state: BlockState, world: BlockView, pos: BlockPos, receivingSide: Direction): Int {
|
||||||
state: BlockState,
|
|
||||||
world: BlockView,
|
|
||||||
pos: BlockPos,
|
|
||||||
receivingSide: Direction
|
|
||||||
): Int {
|
|
||||||
return getStrongRedstonePower(state, world, pos, receivingSide)
|
return getStrongRedstonePower(state, world, pos, receivingSide)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUse(
|
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, result: BlockHitResult): ActionResult {
|
||||||
state: BlockState,
|
|
||||||
world: World,
|
|
||||||
pos: BlockPos,
|
|
||||||
player: PlayerEntity,
|
|
||||||
hand: Hand,
|
|
||||||
result: BlockHitResult
|
|
||||||
): ActionResult {
|
|
||||||
if (!world.isClient) {
|
if (!world.isClient) {
|
||||||
val be = getBlockEntity(world, pos)!!
|
val be = getBlockEntity(world, pos)!!
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package net.shadowfacts.phycon.block.redstone_emitter
|
package net.shadowfacts.phycon.block.redstone_emitter
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
@ -13,29 +12,27 @@ import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
import net.shadowfacts.phycon.block.FaceDeviceBlock
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.DeviceRemovedPacket
|
import net.shadowfacts.phycon.packet.DeviceRemovedPacket
|
||||||
import net.shadowfacts.phycon.packet.ReadItemStoragePacket
|
import net.shadowfacts.phycon.packet.ReadGroupedInventoryPacket
|
||||||
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
import net.shadowfacts.phycon.util.ClientConfigurableDevice
|
||||||
import net.shadowfacts.phycon.util.GhostInv
|
import net.shadowfacts.phycon.util.GhostInv
|
||||||
|
import kotlin.math.round
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState) :
|
class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER, pos, state),
|
||||||
DeviceBlockEntity(PhyBlockEntities.REDSTONE_EMITTER, pos, state),
|
|
||||||
ClientConfigurableDevice,
|
ClientConfigurableDevice,
|
||||||
GhostInv {
|
GhostInv {
|
||||||
|
|
||||||
private val inventoryCache = mutableMapOf<IPAddress, Storage<ItemVariant>>()
|
private val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||||
var cachedEmittedPower: Int = 0
|
var cachedEmittedPower: Int = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var stackToMonitor: ItemStack = ItemStack.EMPTY
|
var stackToMonitor: ItemStack = ItemStack.EMPTY
|
||||||
override var ghostSlotStack: ItemStack
|
override var ghostSlotStack: ItemStack
|
||||||
get() = stackToMonitor
|
get() = stackToMonitor
|
||||||
set(value) {
|
set(value) { stackToMonitor = value }
|
||||||
stackToMonitor = value
|
|
||||||
}
|
|
||||||
var maxAmount = 64
|
var maxAmount = 64
|
||||||
var mode = Mode.ANALOG
|
var mode = Mode.ANALOG
|
||||||
set(value) {
|
set(value) {
|
||||||
|
@ -45,12 +42,12 @@ class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ReadItemStoragePacket -> handleReadItemStorage(packet)
|
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
|
||||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadItemStorage(packet: ReadItemStoragePacket) {
|
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
|
||||||
inventoryCache[packet.source] = packet.inventory
|
inventoryCache[packet.source] = packet.inventory
|
||||||
recalculateRedstone()
|
recalculateRedstone()
|
||||||
}
|
}
|
||||||
|
@ -66,10 +63,11 @@ class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
if (!world!!.isClient && counter % 20 == 0L) {
|
if (!world!!.isClient && counter % 20 == 0L) {
|
||||||
if (counter % 80 == 0L) {
|
if (counter % 80 == 0L) {
|
||||||
updateInventories()
|
updateInventories()
|
||||||
}
|
} else if (counter % 20 == 0L) {
|
||||||
recalculateRedstone()
|
recalculateRedstone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateInventories() {
|
private fun updateInventories() {
|
||||||
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
|
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
|
||||||
|
@ -83,18 +81,16 @@ class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
updateWorld()
|
updateWorld()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val variant = ItemVariant.of(stackToMonitor)
|
|
||||||
val networkAmount = inventoryCache.values.fold(0) { acc, inv ->
|
val networkAmount = inventoryCache.values.fold(0) { acc, inv ->
|
||||||
acc + inv.simulateExtract(variant, Long.MAX_VALUE, null).toInt()
|
acc + inv.getAmount(stackToMonitor)
|
||||||
}
|
}
|
||||||
cachedEmittedPower =
|
cachedEmittedPower =
|
||||||
when (mode) {
|
when (mode) {
|
||||||
Mode.ANALOG -> if (networkAmount == 0) {
|
Mode.ANALOG -> if (networkAmount == 0) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
1 + (networkAmount / maxAmount.toDouble() * 14).toInt()
|
1 + round(networkAmount / maxAmount.toDouble() * 14).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
Mode.DIGITAL -> if (networkAmount >= maxAmount) 15 else 0
|
Mode.DIGITAL -> if (networkAmount >= maxAmount) 15 else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,12 +90,7 @@ class RedstoneEmitterScreen(
|
||||||
view.addSubview(hStack)
|
view.addSubview(hStack)
|
||||||
|
|
||||||
val zeroStack = hStack.addArrangedSubview(StackView(Axis.VERTICAL))
|
val zeroStack = hStack.addArrangedSubview(StackView(Axis.VERTICAL))
|
||||||
zeroStack.addArrangedSubview(
|
zeroStack.addArrangedSubview(Label(TranslatableText("gui.phycon.emitter.count", 0), textAlignment = Label.TextAlignment.CENTER)).apply {
|
||||||
Label(
|
|
||||||
TranslatableText("gui.phycon.emitter.count", 0),
|
|
||||||
textAlignment = Label.TextAlignment.CENTER
|
|
||||||
)
|
|
||||||
).apply {
|
|
||||||
textColor = Color.TEXT
|
textColor = Color.TEXT
|
||||||
}
|
}
|
||||||
zeroStack.addArrangedSubview(View())
|
zeroStack.addArrangedSubview(View())
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.AttributeList
|
||||||
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.Material
|
import net.minecraft.block.Material
|
||||||
|
@ -10,11 +12,15 @@ import net.minecraft.state.StateManager
|
||||||
import net.minecraft.state.property.Properties
|
import net.minecraft.state.property.Properties
|
||||||
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.ItemScatterer
|
||||||
import net.minecraft.util.hit.BlockHitResult
|
import net.minecraft.util.hit.BlockHitResult
|
||||||
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.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.block.DeviceBlock
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
import java.util.EnumSet
|
import java.util.EnumSet
|
||||||
|
@ -27,7 +33,8 @@ abstract class AbstractTerminalBlock<T : AbstractTerminalBlockEntity> : DeviceBl
|
||||||
.strength(1.5f)
|
.strength(1.5f)
|
||||||
.sounds(BlockSoundGroup.METAL)
|
.sounds(BlockSoundGroup.METAL)
|
||||||
),
|
),
|
||||||
NetworkComponentBlock {
|
NetworkComponentBlock,
|
||||||
|
AttributeProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val FACING = Properties.FACING
|
val FACING = Properties.FACING
|
||||||
|
@ -48,14 +55,7 @@ abstract class AbstractTerminalBlock<T : AbstractTerminalBlockEntity> : DeviceBl
|
||||||
return defaultState.with(FACING, context.playerLookDirection.opposite)
|
return defaultState.with(FACING, context.playerLookDirection.opposite)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUse(
|
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
||||||
state: BlockState,
|
|
||||||
world: World,
|
|
||||||
pos: BlockPos,
|
|
||||||
player: PlayerEntity,
|
|
||||||
hand: Hand,
|
|
||||||
hitResult: BlockHitResult
|
|
||||||
): ActionResult {
|
|
||||||
getBlockEntity(world, pos)!!.onActivate(player)
|
getBlockEntity(world, pos)!!.onActivate(player)
|
||||||
return ActionResult.SUCCESS
|
return ActionResult.SUCCESS
|
||||||
}
|
}
|
||||||
|
@ -68,4 +68,8 @@ abstract class AbstractTerminalBlock<T : AbstractTerminalBlockEntity> : DeviceBl
|
||||||
super.onStateReplaced(state, world, pos, newState, moved)
|
super.onStateReplaced(state, world, pos, newState, moved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||||
|
to.offer(getBlockEntity(world, pos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||||
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction
|
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
@ -19,9 +18,9 @@ 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.block.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.component.*
|
import net.shadowfacts.phycon.component.*
|
||||||
|
import net.shadowfacts.phycon.frame.NetworkSplitFrame
|
||||||
import net.shadowfacts.phycon.packet.*
|
import net.shadowfacts.phycon.packet.*
|
||||||
import net.shadowfacts.phycon.util.NetworkUtil
|
import net.shadowfacts.phycon.util.NetworkUtil
|
||||||
import net.shadowfacts.phycon.util.equalsIgnoringAmount
|
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.function.IntBinaryOperator
|
import java.util.function.IntBinaryOperator
|
||||||
|
@ -31,8 +30,7 @@ import kotlin.properties.Delegates
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState) :
|
abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): DeviceBlockEntity(type, pos, state),
|
||||||
DeviceBlockEntity(type, pos, state),
|
|
||||||
InventoryChangedListener,
|
InventoryChangedListener,
|
||||||
ItemStackPacketHandler,
|
ItemStackPacketHandler,
|
||||||
NetworkStackDispatcher<AbstractTerminalBlockEntity.PendingInsertion> {
|
NetworkStackDispatcher<AbstractTerminalBlockEntity.PendingInsertion> {
|
||||||
|
@ -45,14 +43,14 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
|
||||||
val REQUEST_INVENTORY_TIMEOUT: Long = 1 // ticks
|
val REQUEST_INVENTORY_TIMEOUT: Long = 1 // ticks
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val inventoryCache = mutableMapOf<IPAddress, Storage<ItemVariant>>()
|
protected val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||||
val internalBuffer = TerminalBufferInventory(18)
|
val internalBuffer = TerminalBufferInventory(18)
|
||||||
|
|
||||||
protected val pendingRequests = LinkedList<StackLocateRequest>()
|
protected val pendingRequests = LinkedList<StackLocateRequest>()
|
||||||
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
override val pendingInsertions = mutableListOf<PendingInsertion>()
|
||||||
override val dispatchStackTimeout = INSERTION_TIMEOUT
|
override val dispatchStackTimeout = INSERTION_TIMEOUT
|
||||||
|
|
||||||
val cachedNetItems = Object2IntOpenHashMap<ItemVariant>()
|
val cachedNetItems = ItemStackCollections.intMap()
|
||||||
private var requestInventoryTimestamp: Long? = null
|
private var requestInventoryTimestamp: Long? = null
|
||||||
|
|
||||||
// todo: multiple players could have the terminal open simultaneously
|
// todo: multiple players could have the terminal open simultaneously
|
||||||
|
@ -79,7 +77,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ReadItemStoragePacket -> handleReadItemStorage(packet)
|
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
|
||||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||||
is StackLocationPacket -> handleStackLocation(packet)
|
is StackLocationPacket -> handleStackLocation(packet)
|
||||||
is ItemStackPacket -> handleItemStack(packet)
|
is ItemStackPacket -> handleItemStack(packet)
|
||||||
|
@ -87,7 +85,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadItemStorage(packet: ReadItemStoragePacket) {
|
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
|
||||||
inventoryCache[packet.source] = packet.inventory
|
inventoryCache[packet.source] = packet.inventory
|
||||||
updateAndSync()
|
updateAndSync()
|
||||||
}
|
}
|
||||||
|
@ -99,7 +97,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
|
||||||
|
|
||||||
private fun handleStackLocation(packet: StackLocationPacket) {
|
private fun handleStackLocation(packet: StackLocationPacket) {
|
||||||
val request = pendingRequests.firstOrNull {
|
val request = pendingRequests.firstOrNull {
|
||||||
it.stack.equalsIgnoringAmount(packet.stack)
|
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
|
||||||
}
|
}
|
||||||
if (request != null) {
|
if (request != null) {
|
||||||
request.results.add(packet.amount to packet.stackProvider)
|
request.results.add(packet.amount to packet.stackProvider)
|
||||||
|
@ -138,12 +136,10 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
|
||||||
private fun updateNetItems() {
|
private fun updateNetItems() {
|
||||||
cachedNetItems.clear()
|
cachedNetItems.clear()
|
||||||
for (inventory in inventoryCache.values) {
|
for (inventory in inventoryCache.values) {
|
||||||
val transaction = Transaction.openOuter()
|
for (stack in inventory.storedStacks) {
|
||||||
for (view in inventory.iterator(transaction)) {
|
val amount = inventory.getAmount(stack)
|
||||||
val amount = view.amount.toInt()
|
cachedNetItems.mergeInt(stack, amount, IntBinaryOperator { a, b -> a + b })
|
||||||
cachedNetItems.mergeInt(view.resource, amount, IntBinaryOperator { a, b -> a + b })
|
|
||||||
}
|
}
|
||||||
transaction.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,8 +259,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
|
||||||
fun netItemsChanged()
|
fun netItemsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
class PendingInsertion(stack: ItemStack, timestamp: Long) :
|
class PendingInsertion(stack: ItemStack, timestamp: Long): NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
|
||||||
NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
|
|
||||||
var bufferSlot by Delegates.notNull<Int>()
|
var bufferSlot by Delegates.notNull<Int>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,13 +80,7 @@ abstract class AbstractTerminalScreen<BE : AbstractTerminalBlockEntity, T : Abst
|
||||||
|
|
||||||
fun requestUpdatedItems() {
|
fun requestUpdatedItems() {
|
||||||
val player = MinecraftClient.getInstance().player!!
|
val player = MinecraftClient.getInstance().player!!
|
||||||
player.networkHandler.sendPacket(
|
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchQuery, scrollPosition.toFloat()))
|
||||||
C2STerminalUpdateDisplayedItems(
|
|
||||||
handler.terminal,
|
|
||||||
searchQuery,
|
|
||||||
scrollPosition.toFloat()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showRequestAmountDialog(stack: ItemStack) {
|
private fun showRequestAmountDialog(stack: ItemStack) {
|
||||||
|
@ -121,12 +115,10 @@ abstract class AbstractTerminalScreen<BE : AbstractTerminalBlockEntity, T : Abst
|
||||||
val format = if (amount < 10_000) DECIMAL_FORMAT else FORMAT
|
val format = if (amount < 10_000) DECIMAL_FORMAT else FORMAT
|
||||||
format.format(amount / 1_000.0) + "K"
|
format.format(amount / 1_000.0) + "K"
|
||||||
}
|
}
|
||||||
|
|
||||||
amount < 1_000_000_000 -> {
|
amount < 1_000_000_000 -> {
|
||||||
val format = if (amount < 10_000_000) DECIMAL_FORMAT else FORMAT
|
val format = if (amount < 10_000_000) DECIMAL_FORMAT else FORMAT
|
||||||
format.format(amount / 1_000_000.0) + "M"
|
format.format(amount / 1_000_000.0) + "M"
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
DECIMAL_FORMAT.format(amount / 1000000000.0).toString() + "B"
|
DECIMAL_FORMAT.format(amount / 1000000000.0).toString() + "B"
|
||||||
}
|
}
|
||||||
|
@ -144,18 +136,7 @@ abstract class AbstractTerminalScreen<BE : AbstractTerminalBlockEntity, T : Abst
|
||||||
val immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().buffer)
|
val immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().buffer)
|
||||||
val textX = (1 / scale * 18) - textRenderer.getWidth(s).toFloat() - 3
|
val textX = (1 / scale * 18) - textRenderer.getWidth(s).toFloat() - 3
|
||||||
val textY = (1 / scale * 18) - 11
|
val textY = (1 / scale * 18) - 11
|
||||||
textRenderer.draw(
|
textRenderer.draw(s, textX, textY, 0xffffff, true, matrixStack.peek().positionMatrix, immediate, false, 0, 0xF000F0)
|
||||||
s,
|
|
||||||
textX,
|
|
||||||
textY,
|
|
||||||
0xffffff,
|
|
||||||
true,
|
|
||||||
matrixStack.peek().positionMatrix,
|
|
||||||
immediate,
|
|
||||||
false,
|
|
||||||
0,
|
|
||||||
0xF000F0
|
|
||||||
)
|
|
||||||
RenderSystem.enableDepthTest()
|
RenderSystem.enableDepthTest()
|
||||||
immediate.draw()
|
immediate.draw()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
|
||||||
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
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.minecraft.screen.ScreenHandler
|
import net.minecraft.screen.ScreenHandler
|
||||||
import net.minecraft.screen.ScreenHandlerType
|
import net.minecraft.screen.ScreenHandlerType
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
import net.shadowfacts.phycon.DefaultPlugin
|
import net.shadowfacts.phycon.DefaultPlugin
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.init.PhyBlocks
|
||||||
|
import net.shadowfacts.phycon.init.PhyScreens
|
||||||
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.TerminalSettings
|
import net.shadowfacts.phycon.util.TerminalSettings
|
||||||
import net.shadowfacts.phycon.util.name
|
import net.shadowfacts.phycon.util.copyWithCount
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
@ -45,7 +49,7 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
field = value
|
field = value
|
||||||
if (terminal.world!!.isClient) {
|
if (terminal.world!!.isClient) {
|
||||||
itemsForDisplay = value.map {
|
itemsForDisplay = value.map {
|
||||||
it.variant.toStack(it.amount)
|
it.stack.copyWithCount(it.amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,8 +106,6 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
return@filter true
|
return@filter true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: this is happening on the logical server, won't work with localization
|
|
||||||
// should filtering happen on the client?
|
|
||||||
it.key.name.string.contains(searchQuery, true)
|
it.key.name.string.contains(searchQuery, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,16 +125,7 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
|
|
||||||
// itemEntries = sorted.map { Entry(it.key, it.intValue) }
|
// itemEntries = sorted.map { Entry(it.key, it.intValue) }
|
||||||
|
|
||||||
(player as ServerPlayerEntity).networkHandler.sendPacket(
|
(player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, settings, scrollPosition, totalEntries))
|
||||||
S2CTerminalUpdateDisplayedItems(
|
|
||||||
terminal,
|
|
||||||
itemEntries,
|
|
||||||
searchQuery,
|
|
||||||
settings,
|
|
||||||
scrollPosition,
|
|
||||||
totalEntries
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun totalRows(): Int {
|
fun totalRows(): Int {
|
||||||
|
@ -151,12 +144,7 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
return currentScrollOffsetInRows() * 9
|
return currentScrollOffsetInRows() * 9
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendUpdatedItemsToClient(
|
fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, settings: TerminalSettings, scrollPosition: Float) {
|
||||||
player: ServerPlayerEntity,
|
|
||||||
query: String,
|
|
||||||
settings: TerminalSettings,
|
|
||||||
scrollPosition: Float
|
|
||||||
) {
|
|
||||||
this.searchQuery = query
|
this.searchQuery = query
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.scrollPosition = scrollPosition
|
this.scrollPosition = scrollPosition
|
||||||
|
@ -187,8 +175,7 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
// todo: why does this think it's quick_craft sometimes?
|
// todo: why does this think it's quick_craft sometimes?
|
||||||
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !cursorStack.isEmpty) {
|
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !cursorStack.isEmpty) {
|
||||||
// placing cursor stack into buffer
|
// placing cursor stack into buffer
|
||||||
val bufferSlot =
|
val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
|
||||||
slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
|
|
||||||
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,16 +203,8 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED)
|
terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED)
|
||||||
}
|
}
|
||||||
} else if (isPlayerSlot(slotId)) {
|
} else if (isPlayerSlot(slotId)) {
|
||||||
val slotsInsertedInto = tryInsertItem(
|
val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
|
||||||
slot.stack,
|
slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
|
||||||
bufferSlotsStart until playerSlotsStart
|
|
||||||
) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
|
|
||||||
slotsInsertedInto.forEach {
|
|
||||||
terminal.internalBuffer.markSlot(
|
|
||||||
it - bufferSlotsStart,
|
|
||||||
TerminalBufferInventory.Mode.TO_NETWORK
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (slotsInsertedInto.isEmpty()) {
|
if (slotsInsertedInto.isEmpty()) {
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
}
|
}
|
||||||
|
@ -271,5 +250,5 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
|
||||||
fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
|
fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
|
||||||
fun isPlayerSlot(id: Int) = id >= playerSlotsStart
|
fun isPlayerSlot(id: Int) = id >= playerSlotsStart
|
||||||
|
|
||||||
data class Entry(val variant: ItemVariant, val amount: Int)
|
data class Entry(val stack: ItemStack, val amount: Int)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntBinaryOperator
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
|
||||||
import net.minecraft.block.BlockState
|
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
|
||||||
|
@ -18,16 +17,16 @@ import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import net.shadowfacts.phycon.packet.LocateStackPacket
|
import net.shadowfacts.phycon.packet.LocateStackPacket
|
||||||
import net.shadowfacts.phycon.util.equalsIgnoringAmount
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
import net.shadowfacts.phycon.util.fromTag
|
import net.shadowfacts.phycon.util.fromTag
|
||||||
import net.shadowfacts.phycon.util.toTag
|
import net.shadowfacts.phycon.util.toTag
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
|
class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlockEntity(PhyBlockEntities.CRAFTING_TERMINAL, pos, state) {
|
||||||
AbstractTerminalBlockEntity(PhyBlockEntities.CRAFTING_TERMINAL, pos, state) {
|
|
||||||
|
|
||||||
val craftingInv = SimpleInventory(9)
|
val craftingInv = SimpleInventory(9)
|
||||||
|
|
||||||
|
@ -53,23 +52,20 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestItemsForCrafting(maxAmount: Int) {
|
fun requestItemsForCrafting(maxAmount: Int) {
|
||||||
// use an array map because we have at most 9 items
|
val amounts = ItemStackCollections.map<IntArray>()
|
||||||
// values are bitfields of which slots contain the item
|
|
||||||
val stackToSlotsMap = Object2IntArrayMap<ItemVariant>()
|
|
||||||
|
|
||||||
val or = IntBinaryOperator { a, b -> a or b }
|
|
||||||
for (i in 0 until craftingInv.size()) {
|
for (i in 0 until craftingInv.size()) {
|
||||||
val craftingInvStack = craftingInv.getStack(i)
|
val craftingInvStack = craftingInv.getStack(i)
|
||||||
if (craftingInvStack.isEmpty) continue
|
if (craftingInvStack.isEmpty) continue
|
||||||
if (craftingInvStack.count >= craftingInvStack.maxCount) continue
|
if (craftingInvStack.count >= craftingInvStack.maxCount) continue
|
||||||
|
|
||||||
stackToSlotsMap.mergeInt(ItemVariant.of(craftingInvStack), 1 shl i, or)
|
if (craftingInvStack !in amounts) amounts[craftingInvStack] = IntArray(9) { 0 }
|
||||||
|
amounts[craftingInvStack]!![i] = min(maxAmount, craftingInvStack.maxCount - craftingInvStack.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((variant, slots) in stackToSlotsMap) {
|
for ((stack, amountPerSlot) in amounts) {
|
||||||
val total = slots.countOneBits()
|
val total = amountPerSlot.sum()
|
||||||
val stack = variant.toStack()
|
val request = CraftingStackLocateRequest(stack, total, counter, amountPerSlot)
|
||||||
val request = CraftingStackLocateRequest(stack, total, counter, slots)
|
|
||||||
pendingRequests.add(request)
|
pendingRequests.add(request)
|
||||||
sendPacket(LocateStackPacket(stack, ipAddress))
|
sendPacket(LocateStackPacket(stack, ipAddress))
|
||||||
}
|
}
|
||||||
|
@ -84,29 +80,27 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||||
val craftingReq =
|
val craftingReq = completedCraftingStackRequests.find { ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) }
|
||||||
completedCraftingStackRequests.find { it.stack.equalsIgnoringAmount(packet.stack) }
|
|
||||||
if (craftingReq != null) {
|
if (craftingReq != null) {
|
||||||
var remaining = packet.stack.copy()
|
var remaining = packet.stack.copy()
|
||||||
|
|
||||||
for (i in 0 until craftingInv.size()) {
|
for (i in 0 until craftingInv.size()) {
|
||||||
val currentStack = craftingInv.getStack(i)
|
val currentStack = craftingInv.getStack(i)
|
||||||
if (currentStack.count >= currentStack.maxCount) continue
|
if (currentStack.count >= currentStack.maxCount) continue
|
||||||
if (!currentStack.equalsIgnoringAmount(remaining)) continue
|
if (!ItemStackUtil.areEqualIgnoreAmounts(currentStack, remaining)) continue
|
||||||
|
|
||||||
currentStack.count += 1
|
val toInsert = minOf(remaining.count, currentStack.maxCount - currentStack.count, craftingReq.amountPerSlot[i])
|
||||||
remaining.count -= 1
|
currentStack.count += toInsert
|
||||||
|
remaining.count -= toInsert
|
||||||
craftingReq.slots = craftingReq.slots and (1 shl i).inv()
|
craftingReq.amountPerSlot[i] -= toInsert
|
||||||
craftingReq.received += 1
|
craftingReq.received += toInsert
|
||||||
|
|
||||||
if (remaining.isEmpty) {
|
if (remaining.isEmpty) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if slots == 0, there are no more slots needing items for this request
|
if (craftingReq.amountPerSlot.sum() == 0 || craftingReq.received >= craftingReq.totalResultAmount) {
|
||||||
if (craftingReq.slots == 0 || craftingReq.received >= craftingReq.totalResultAmount) {
|
|
||||||
completedCraftingStackRequests.remove(craftingReq)
|
completedCraftingStackRequests.remove(craftingReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,10 +130,7 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
|
||||||
stack: ItemStack,
|
stack: ItemStack,
|
||||||
amount: Int,
|
amount: Int,
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
/**
|
val amountPerSlot: IntArray,
|
||||||
* Values are bitfields of which slots in the crafting inventory this request is for.
|
|
||||||
*/
|
|
||||||
var slots: Int,
|
|
||||||
): StackLocateRequest(stack, amount, timestamp) {
|
): StackLocateRequest(stack, amount, timestamp) {
|
||||||
var received: Int = 0
|
var received: Int = 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,7 @@ class CraftingTerminalScreenHandler(
|
||||||
syncId: Int,
|
syncId: Int,
|
||||||
playerInv: PlayerInventory,
|
playerInv: PlayerInventory,
|
||||||
terminal: CraftingTerminalBlockEntity,
|
terminal: CraftingTerminalBlockEntity,
|
||||||
) : AbstractTerminalScreenHandler<CraftingTerminalBlockEntity>(
|
): AbstractTerminalScreenHandler<CraftingTerminalBlockEntity>(PhyScreens.CRAFTING_TERMINAL, syncId, playerInv, terminal) {
|
||||||
PhyScreens.CRAFTING_TERMINAL,
|
|
||||||
syncId,
|
|
||||||
playerInv,
|
|
||||||
terminal
|
|
||||||
) {
|
|
||||||
|
|
||||||
val craftingInv = CraftingInv(this)
|
val craftingInv = CraftingInv(this)
|
||||||
val result = CraftingResultInventory()
|
val result = CraftingResultInventory()
|
||||||
|
@ -78,14 +73,7 @@ class CraftingTerminalScreenHandler(
|
||||||
ItemStack.EMPTY
|
ItemStack.EMPTY
|
||||||
}
|
}
|
||||||
result.setStack(0, resultStack)
|
result.setStack(0, resultStack)
|
||||||
player.networkHandler.sendPacket(
|
player.networkHandler.sendPacket(ScreenHandlerSlotUpdateS2CPacket(syncId, nextRevision(), resultSlot.id, resultStack))
|
||||||
ScreenHandlerSlotUpdateS2CPacket(
|
|
||||||
syncId,
|
|
||||||
nextRevision(),
|
|
||||||
resultSlot.id,
|
|
||||||
resultStack
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,12 +84,7 @@ class CraftingTerminalViewController(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearPressed(button: Button) {
|
private fun clearPressed(button: Button) {
|
||||||
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(
|
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2STerminalCraftingButton(terminal, C2STerminalCraftingButton.Action.CLEAR_GRID))
|
||||||
C2STerminalCraftingButton(
|
|
||||||
terminal,
|
|
||||||
C2STerminalCraftingButton.Action.CLEAR_GRID
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun plusPressed(button: Button) {
|
private fun plusPressed(button: Button) {
|
||||||
|
|
|
@ -10,12 +10,12 @@ import net.minecraft.server.network.ServerPlayerEntity
|
||||||
import net.minecraft.text.TranslatableText
|
import net.minecraft.text.TranslatableText
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class TerminalBlockEntity(pos: BlockPos, state: BlockState) :
|
class TerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlockEntity(PhyBlockEntities.TERMINAL, pos, state) {
|
||||||
AbstractTerminalBlockEntity(PhyBlockEntities.TERMINAL, pos, state) {
|
|
||||||
|
|
||||||
override fun onActivate(player: PlayerEntity) {
|
override fun onActivate(player: PlayerEntity) {
|
||||||
super.onActivate(player)
|
super.onActivate(player)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package net.shadowfacts.phycon.block.terminal
|
package net.shadowfacts.phycon.block.terminal
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.inventory.SimpleInventory
|
import net.minecraft.inventory.SimpleInventory
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.nbt.NbtIntArray
|
import net.minecraft.nbt.NbtIntArray
|
||||||
import net.shadowfacts.phycon.util.equalsIgnoringAmount
|
|
||||||
import net.shadowfacts.phycon.util.fromTag
|
import net.shadowfacts.phycon.util.fromTag
|
||||||
import net.shadowfacts.phycon.util.toTag
|
import net.shadowfacts.phycon.util.toTag
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
@ -54,7 +54,7 @@ class TerminalBufferInventory(size: Int) : SimpleInventory(size) {
|
||||||
setStack(slot, stack)
|
setStack(slot, stack)
|
||||||
markSlot(slot, mode)
|
markSlot(slot, mode)
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
} else if (stack.equalsIgnoringAmount(current)) {
|
} else if (ItemStackUtil.areEqualIgnoreAmounts(stack, current)) {
|
||||||
val toTransfer = min(current.maxCount - current.count, stack.count)
|
val toTransfer = min(current.maxCount - current.count, stack.count)
|
||||||
current.count += toTransfer
|
current.count += toTransfer
|
||||||
stack.count -= toTransfer
|
stack.count -= toTransfer
|
||||||
|
|
|
@ -24,8 +24,7 @@ class TerminalRequestAmountViewController(
|
||||||
): ViewController() {
|
): ViewController() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val BACKGROUND =
|
private val BACKGROUND = Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal_amount.png"), 0, 0)
|
||||||
Texture(Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal_amount.png"), 0, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var field: NumberField
|
lateinit var field: NumberField
|
||||||
|
|
|
@ -86,12 +86,7 @@ class ColoredCableModel(
|
||||||
rotationContainer: ModelBakeSettings,
|
rotationContainer: ModelBakeSettings,
|
||||||
modelId: Identifier
|
modelId: Identifier
|
||||||
): BakedModel {
|
): BakedModel {
|
||||||
centerSprite = textureGetter.apply(
|
centerSprite = textureGetter.apply(SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/cable/${color.getName()}/straight")))
|
||||||
SpriteIdentifier(
|
|
||||||
PlayerScreenHandler.BLOCK_ATLAS_TEXTURE,
|
|
||||||
Identifier(PhysicalConnectivity.MODID, "block/cable/${color.getName()}/straight")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
sideRotations.forEach { (side, rot) ->
|
sideRotations.forEach { (side, rot) ->
|
||||||
this.side[side.ordinal] = loader.bakeRecoloredCable(SIDE, rot, textureGetter, color)
|
this.side[side.ordinal] = loader.bakeRecoloredCable(SIDE, rot, textureGetter, color)
|
||||||
|
|
|
@ -23,7 +23,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
private val interfaceCableCornerID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner")
|
private val interfaceCableCornerID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner")
|
||||||
private val interfaceCableCorner2ID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner_2")
|
private val interfaceCableCorner2ID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_corner_2")
|
||||||
private val interfaceCableCapID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_cap")
|
private val interfaceCableCapID = Identifier(PhysicalConnectivity.MODID, "block/interface_cable_cap")
|
||||||
|
|
||||||
// private var interfaceCableStraight = Array<BakedModel?>(6) { null }
|
// private var interfaceCableStraight = Array<BakedModel?>(6) { null }
|
||||||
// private var interfaceCableCap = Array<BakedModel?>(6) { null }
|
// private var interfaceCableCap = Array<BakedModel?>(6) { null }
|
||||||
// private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>()
|
// private var interfaceCableCorner = mutableMapOf<ModelRotation, BakedModel>()
|
||||||
|
@ -66,8 +65,7 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
for (tex in depTextures) {
|
for (tex in depTextures) {
|
||||||
if (tex.textureId.namespace == PhysicalConnectivity.MODID && tex.textureId.path.startsWith("block/cable/color/")) {
|
if (tex.textureId.namespace == PhysicalConnectivity.MODID && tex.textureId.path.startsWith("block/cable/color/")) {
|
||||||
for (color in DyeColor.values()) {
|
for (color in DyeColor.values()) {
|
||||||
val newPath =
|
val newPath = tex.textureId.path.replace("block/cable/color/", "block/cable/${color.getName()}/")
|
||||||
tex.textureId.path.replace("block/cable/color/", "block/cable/${color.getName()}/")
|
|
||||||
val substituted = SpriteIdentifier(tex.atlasId, Identifier(PhysicalConnectivity.MODID, newPath))
|
val substituted = SpriteIdentifier(tex.atlasId, Identifier(PhysicalConnectivity.MODID, newPath))
|
||||||
textures.add(substituted)
|
textures.add(substituted)
|
||||||
}
|
}
|
||||||
|
@ -79,12 +77,7 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
return textures
|
return textures
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bake(
|
override fun bake(loader: ModelLoader, textureGetter: Function<SpriteIdentifier, Sprite>, rotationContainer: ModelBakeSettings, modelId: Identifier): BakedModel {
|
||||||
loader: ModelLoader,
|
|
||||||
textureGetter: Function<SpriteIdentifier, Sprite>,
|
|
||||||
rotationContainer: ModelBakeSettings,
|
|
||||||
modelId: Identifier
|
|
||||||
): BakedModel {
|
|
||||||
bakeSideModels(loader, textureGetter)
|
bakeSideModels(loader, textureGetter)
|
||||||
|
|
||||||
DyeColor.values().forEach { color ->
|
DyeColor.values().forEach { color ->
|
||||||
|
@ -139,7 +132,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
FaceCableConnection.WEST -> interfaceCableCorner[color]!![ModelRotation.X0_Y270]
|
FaceCableConnection.WEST -> interfaceCableCorner[color]!![ModelRotation.X0_Y270]
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction.UP -> when (connection) {
|
Direction.UP -> when (connection) {
|
||||||
FaceCableConnection.NORTH -> interfaceCableCorner[color]!![ModelRotation.X180_Y180]
|
FaceCableConnection.NORTH -> interfaceCableCorner[color]!![ModelRotation.X180_Y180]
|
||||||
FaceCableConnection.EAST -> interfaceCableCorner[color]!![ModelRotation.X180_Y270]
|
FaceCableConnection.EAST -> interfaceCableCorner[color]!![ModelRotation.X180_Y270]
|
||||||
|
@ -147,7 +139,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
FaceCableConnection.WEST -> interfaceCableCorner[color]!![ModelRotation.X180_Y90]
|
FaceCableConnection.WEST -> interfaceCableCorner[color]!![ModelRotation.X180_Y90]
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction.NORTH -> when (connection) {
|
Direction.NORTH -> when (connection) {
|
||||||
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y0]
|
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y0]
|
||||||
FaceCableConnection.EAST -> interfaceCableCorner2[color]!![ModelRotation.X180_Y180]
|
FaceCableConnection.EAST -> interfaceCableCorner2[color]!![ModelRotation.X180_Y180]
|
||||||
|
@ -155,7 +146,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
FaceCableConnection.WEST -> interfaceCableCorner2[color]!![ModelRotation.X0_Y0]
|
FaceCableConnection.WEST -> interfaceCableCorner2[color]!![ModelRotation.X0_Y0]
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction.SOUTH -> when (connection) {
|
Direction.SOUTH -> when (connection) {
|
||||||
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y180]
|
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y180]
|
||||||
FaceCableConnection.WEST -> interfaceCableCorner2[color]!![ModelRotation.X180_Y0]
|
FaceCableConnection.WEST -> interfaceCableCorner2[color]!![ModelRotation.X180_Y0]
|
||||||
|
@ -163,7 +153,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
FaceCableConnection.EAST -> interfaceCableCorner2[color]!![ModelRotation.X0_Y180]
|
FaceCableConnection.EAST -> interfaceCableCorner2[color]!![ModelRotation.X0_Y180]
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction.WEST -> when (connection) {
|
Direction.WEST -> when (connection) {
|
||||||
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y270]
|
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y270]
|
||||||
FaceCableConnection.NORTH -> interfaceCableCorner2[color]!![ModelRotation.X180_Y90]
|
FaceCableConnection.NORTH -> interfaceCableCorner2[color]!![ModelRotation.X180_Y90]
|
||||||
|
@ -171,7 +160,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
FaceCableConnection.SOUTH -> interfaceCableCorner2[color]!![ModelRotation.X0_Y270]
|
FaceCableConnection.SOUTH -> interfaceCableCorner2[color]!![ModelRotation.X0_Y270]
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction.EAST -> when (connection) {
|
Direction.EAST -> when (connection) {
|
||||||
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y90]
|
FaceCableConnection.UP -> interfaceCableCorner[color]!![ModelRotation.X270_Y90]
|
||||||
FaceCableConnection.SOUTH -> interfaceCableCorner2[color]!![ModelRotation.X180_Y270]
|
FaceCableConnection.SOUTH -> interfaceCableCorner2[color]!![ModelRotation.X180_Y270]
|
||||||
|
@ -179,7 +167,6 @@ abstract class FaceDeviceModel : UnbakedModel, BakedModel {
|
||||||
FaceCableConnection.NORTH -> interfaceCableCorner2[color]!![ModelRotation.X0_Y90]
|
FaceCableConnection.NORTH -> interfaceCableCorner2[color]!![ModelRotation.X0_Y90]
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
model?.getQuads(state, face, random) ?: listOf()
|
model?.getQuads(state, face, random) ?: listOf()
|
||||||
|
|
|
@ -33,10 +33,7 @@ class ScreenDeviceModel(
|
||||||
): UnbakedModel, BakedModel, FabricBakedModel {
|
): UnbakedModel, BakedModel, FabricBakedModel {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val CASING = SpriteIdentifier(
|
private val CASING = SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, Identifier(PhysicalConnectivity.MODID, "block/casing"))
|
||||||
PlayerScreenHandler.BLOCK_ATLAS_TEXTURE,
|
|
||||||
Identifier(PhysicalConnectivity.MODID, "block/casing")
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val screenTexture = SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, screenTexture)
|
private val screenTexture = SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, screenTexture)
|
||||||
|
|
|
@ -40,79 +40,65 @@ class DeviceConsoleScreen(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (device is ActivationController.ActivatableDevice) {
|
if (device is ActivationController.ActivatableDevice) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
TextureView(Texture(Identifier("textures/item/ender_pearl.png"), 0, 0, 16, 16)).apply {
|
TextureView(Texture(Identifier("textures/item/ender_pearl.png"), 0, 0, 16, 16)).apply {
|
||||||
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
|
device::canConfigureActivationController
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (device is RedstoneControllerBlockEntity) {
|
if (device is RedstoneControllerBlockEntity) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
TextureView(Texture(Identifier("textures/block/redstone_torch.png"), 0, 0, 16, 16)).apply {
|
TextureView(Texture(Identifier("textures/block/redstone_torch.png"), 0, 0, 16, 16)).apply {
|
||||||
intrinsicContentSize = Size(16.0, 16.0)
|
intrinsicContentSize = Size(16.0, 16.0)
|
||||||
},
|
},
|
||||||
TranslatableText("block.phycon.redstone_controller"),
|
TranslatableText("block.phycon.redstone_controller"),
|
||||||
RedstoneControllerViewController(device)
|
RedstoneControllerViewController(device)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (device is MinerBlockEntity) {
|
if (device is MinerBlockEntity) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
TextureView(Texture(Identifier("textures/item/diamond_pickaxe.png"), 0, 0, 16, 16)).apply {
|
TextureView(Texture(Identifier("textures/item/diamond_pickaxe.png"), 0, 0, 16, 16)).apply {
|
||||||
intrinsicContentSize = Size(16.0, 16.0)
|
intrinsicContentSize = Size(16.0, 16.0)
|
||||||
},
|
},
|
||||||
TranslatableText("block.phycon.miner"),
|
TranslatableText("block.phycon.miner"),
|
||||||
MinerViewController(device)
|
MinerViewController(device)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (device is NetworkStackProvider) {
|
if (device is NetworkStackProvider) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
Label("P").apply { textColor = Color.TEXT },
|
Label("P").apply { textColor = Color.TEXT },
|
||||||
TranslatableText("gui.phycon.console.provider"),
|
TranslatableText("gui.phycon.console.provider"),
|
||||||
ProviderViewController(device),
|
ProviderViewController(device),
|
||||||
device::canConfigureProviderPriority
|
device::canConfigureProviderPriority
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (device is NetworkStackReceiver) {
|
if (device is NetworkStackReceiver) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
Label("R").apply { textColor = Color.TEXT },
|
Label("R").apply { textColor = Color.TEXT },
|
||||||
TranslatableText("gui.phycon.console.receiver"),
|
TranslatableText("gui.phycon.console.receiver"),
|
||||||
ReceiverViewController(device),
|
ReceiverViewController(device),
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (device is RedstoneEmitterBlockEntity) {
|
if (device is RedstoneEmitterBlockEntity) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
TextureView(Texture(Identifier("textures/item/redstone.png"), 0, 0, 16, 16)).apply {
|
TextureView(Texture(Identifier("textures/item/redstone.png"), 0, 0, 16, 16)).apply {
|
||||||
intrinsicContentSize = Size(16.0, 16.0)
|
intrinsicContentSize = Size(16.0, 16.0)
|
||||||
},
|
},
|
||||||
TranslatableText("block.phycon.redstone_emitter"),
|
TranslatableText("block.phycon.redstone_emitter"),
|
||||||
RedstoneEmitterViewController(device)
|
RedstoneEmitterViewController(device)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (device is P2PReceiverBlockEntity) {
|
if (device is P2PReceiverBlockEntity) {
|
||||||
tabs.add(
|
tabs.add(TabViewController.SimpleTab(
|
||||||
TabViewController.SimpleTab(
|
|
||||||
TextureView(Texture(Identifier("textures/item/ender_pearl.png"), 0, 0, 16, 16)).apply {
|
TextureView(Texture(Identifier("textures/item/ender_pearl.png"), 0, 0, 16, 16)).apply {
|
||||||
intrinsicContentSize = Size(16.0, 16.0)
|
intrinsicContentSize = Size(16.0, 16.0)
|
||||||
},
|
},
|
||||||
TranslatableText("block.phycon.p2p_receiver"),
|
TranslatableText("block.phycon.p2p_receiver"),
|
||||||
P2PReceiverViewController(device)
|
P2PReceiverViewController(device)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tabController = TabViewController(tabs)
|
tabController = TabViewController(tabs)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.shadowfacts.phycon.component
|
package net.shadowfacts.phycon.component
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -7,15 +8,12 @@ import net.shadowfacts.phycon.packet.CapacityPacket
|
||||||
import net.shadowfacts.phycon.packet.CheckCapacityPacket
|
import net.shadowfacts.phycon.packet.CheckCapacityPacket
|
||||||
import net.shadowfacts.phycon.packet.ItemStackPacket
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
||||||
import net.shadowfacts.phycon.util.copyWithCount
|
import net.shadowfacts.phycon.util.copyWithCount
|
||||||
import net.shadowfacts.phycon.util.equalsIgnoringAmount
|
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
// TODO: use Transfer API transactions for this
|
interface NetworkStackDispatcher<Insertion: NetworkStackDispatcher.PendingInsertion<Insertion>>: ItemStackPacketHandler {
|
||||||
interface NetworkStackDispatcher<Insertion : NetworkStackDispatcher.PendingInsertion<Insertion>> :
|
|
||||||
ItemStackPacketHandler {
|
|
||||||
|
|
||||||
val counter: Long
|
val counter: Long
|
||||||
val dispatchStackTimeout: Long
|
val dispatchStackTimeout: Long
|
||||||
|
@ -32,7 +30,7 @@ interface NetworkStackDispatcher<Insertion : NetworkStackDispatcher.PendingInser
|
||||||
|
|
||||||
fun handleCapacity(packet: CapacityPacket) {
|
fun handleCapacity(packet: CapacityPacket) {
|
||||||
pendingInsertions.firstOrNull { insertion ->
|
pendingInsertions.firstOrNull { insertion ->
|
||||||
packet.stack.equalsIgnoringAmount(insertion.stack) &&
|
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, insertion.stack) &&
|
||||||
insertion.results.none { it.second.ipAddress == packet.source }
|
insertion.results.none { it.second.ipAddress == packet.source }
|
||||||
}?.also { insertion ->
|
}?.also { insertion ->
|
||||||
insertion.results.add(packet.capacity to packet.stackReceiver)
|
insertion.results.add(packet.capacity to packet.stackReceiver)
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
package net.shadowfacts.phycon.init
|
package net.shadowfacts.phycon.init
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType.ExtendedFactory
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
||||||
import net.minecraft.screen.ScreenHandler
|
|
||||||
import net.minecraft.screen.ScreenHandlerType
|
import net.minecraft.screen.ScreenHandlerType
|
||||||
import net.minecraft.util.Identifier
|
|
||||||
import net.minecraft.util.registry.Registry
|
|
||||||
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
import net.shadowfacts.phycon.block.inserter.InserterScreenHandler
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchConsoleScreenHandler
|
|
||||||
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreenHandler
|
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterScreenHandler
|
||||||
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
|
||||||
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreenHandler
|
import net.shadowfacts.phycon.block.terminal.CraftingTerminalScreenHandler
|
||||||
|
@ -25,19 +19,12 @@ object PhyScreens {
|
||||||
private set
|
private set
|
||||||
lateinit var REDSTONE_EMITTER: ScreenHandlerType<RedstoneEmitterScreenHandler>
|
lateinit var REDSTONE_EMITTER: ScreenHandlerType<RedstoneEmitterScreenHandler>
|
||||||
private set
|
private set
|
||||||
lateinit var SWITCH_CONSOLE: ScreenHandlerType<SwitchConsoleScreenHandler>
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
TERMINAL = register(TerminalBlock.ID, ::TerminalScreenHandler)
|
TERMINAL = ScreenHandlerRegistry.registerExtended(TerminalBlock.ID, ::TerminalScreenHandler)
|
||||||
CRAFTING_TERMINAL = register(CraftingTerminalBlock.ID, ::CraftingTerminalScreenHandler)
|
CRAFTING_TERMINAL = ScreenHandlerRegistry.registerExtended(CraftingTerminalBlock.ID, ::CraftingTerminalScreenHandler)
|
||||||
INSERTER = register(InserterScreenHandler.ID, ::InserterScreenHandler)
|
INSERTER = ScreenHandlerRegistry.registerExtended(InserterScreenHandler.ID, ::InserterScreenHandler)
|
||||||
REDSTONE_EMITTER = register(RedstoneEmitterScreenHandler.ID, ::RedstoneEmitterScreenHandler)
|
REDSTONE_EMITTER = ScreenHandlerRegistry.registerExtended(RedstoneEmitterScreenHandler.ID, ::RedstoneEmitterScreenHandler)
|
||||||
SWITCH_CONSOLE = register(SwitchConsoleScreenHandler.ID, ::SwitchConsoleScreenHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : ScreenHandler> register(id: Identifier, factory: ExtendedFactory<T>): ScreenHandlerType<T> {
|
|
||||||
return Registry.register(Registry.SCREEN_HANDLER, id, ExtendedScreenHandlerType(factory))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,14 @@
|
||||||
package net.shadowfacts.phycon.item
|
package net.shadowfacts.phycon.item
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
|
||||||
import net.minecraft.item.Item
|
import net.minecraft.item.Item
|
||||||
import net.minecraft.item.ItemUsageContext
|
import net.minecraft.item.ItemUsageContext
|
||||||
import net.minecraft.network.PacketByteBuf
|
|
||||||
import net.minecraft.screen.ScreenHandler
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
|
||||||
import net.minecraft.text.Text
|
|
||||||
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.block.DeviceBlock
|
import net.shadowfacts.phycon.block.DeviceBlock
|
||||||
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchBlockEntity
|
|
||||||
import net.shadowfacts.phycon.client.screen.console.DeviceConsoleScreen
|
import net.shadowfacts.phycon.client.screen.console.DeviceConsoleScreen
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchConsoleScreen
|
|
||||||
import net.shadowfacts.phycon.block.netswitch.SwitchConsoleScreenHandler
|
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -42,14 +31,6 @@ class ConsoleItem : Item(Settings().maxCount(1)) {
|
||||||
}
|
}
|
||||||
return ActionResult.SUCCESS
|
return ActionResult.SUCCESS
|
||||||
}
|
}
|
||||||
} else if (block === PhyBlocks.SWITCH) {
|
|
||||||
val be = block.getBlockEntity(context.world, context.blockPos)
|
|
||||||
if (be != null) {
|
|
||||||
if (!context.world.isClient && context.player != null) {
|
|
||||||
openScreen(be, context.player!!)
|
|
||||||
}
|
|
||||||
return ActionResult.SUCCESS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ActionResult.PASS
|
return ActionResult.PASS
|
||||||
}
|
}
|
||||||
|
@ -60,19 +41,4 @@ class ConsoleItem : Item(Settings().maxCount(1)) {
|
||||||
MinecraftClient.getInstance().setScreen(screen)
|
MinecraftClient.getInstance().setScreen(screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openScreen(be: SwitchBlockEntity, player: PlayerEntity) {
|
|
||||||
val factory = object : ExtendedScreenHandlerFactory {
|
|
||||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
|
|
||||||
return SwitchConsoleScreenHandler(syncId, be)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getDisplayName() = PhyBlocks.SWITCH.name
|
|
||||||
|
|
||||||
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
|
||||||
buf.writeBlockPos(be.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
player.openHandledScreen(factory)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,18 +14,14 @@ import kotlin.math.roundToInt
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settings()) :
|
class FaceDeviceBlockItem(block: FaceDeviceBlock<*>, settings: Settings = Settings()): DeviceBlockItem(block, settings) {
|
||||||
DeviceBlockItem(block, settings) {
|
|
||||||
|
|
||||||
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
|
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
|
||||||
val hitState = context.world.getBlockState(context.blockPos)
|
val hitState = context.world.getBlockState(context.blockPos)
|
||||||
val hitBlock = hitState.block
|
val hitBlock = hitState.block
|
||||||
if (hitBlock is CableBlock) {
|
if (hitBlock is CableBlock) {
|
||||||
val hitBlockEdge = context.hitPos.getComponentAlongAxis(context.side.axis) % 1 == 0.0
|
val hitBlockEdge = context.hitPos.getComponentAlongAxis(context.side.axis) % 1 == 0.0
|
||||||
val hitBlockBeingPlacedIn =
|
val hitBlockBeingPlacedIn = floor(context.hitPos.getComponentAlongAxis(context.side.axis)).toInt() == context.blockPos.getComponentAlongAxis(context.side.axis)
|
||||||
floor(context.hitPos.getComponentAlongAxis(context.side.axis)).toInt() == context.blockPos.getComponentAlongAxis(
|
|
||||||
context.side.axis
|
|
||||||
)
|
|
||||||
|
|
||||||
val placementSide: Direction =
|
val placementSide: Direction =
|
||||||
if (hitBlockEdge xor hitBlockBeingPlacedIn) {
|
if (hitBlockEdge xor hitBlockBeingPlacedIn) {
|
||||||
|
|
|
@ -42,25 +42,14 @@ class ScrewdriverItem : Item(Settings().maxCount(1)) {
|
||||||
|
|
||||||
if (newState != null) {
|
if (newState != null) {
|
||||||
context.world.setBlockState(context.blockPos, newState)
|
context.world.setBlockState(context.blockPos, newState)
|
||||||
context.world.playSound(
|
context.world.playSound(context.player, context.blockPos, SoundEvents.BLOCK_METAL_PLACE, SoundCategory.BLOCKS, 0.8f, 0.65f)
|
||||||
context.player,
|
|
||||||
context.blockPos,
|
|
||||||
SoundEvents.BLOCK_METAL_PLACE,
|
|
||||||
SoundCategory.BLOCKS,
|
|
||||||
0.8f,
|
|
||||||
0.65f
|
|
||||||
)
|
|
||||||
return ActionResult.SUCCESS
|
return ActionResult.SUCCESS
|
||||||
} else {
|
} else {
|
||||||
return ActionResult.PASS
|
return ActionResult.PASS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun screwdriverDeviceBlock(
|
private fun screwdriverDeviceBlock(context: ItemUsageContext, state: BlockState, block: DeviceBlock<*>): BlockState? {
|
||||||
context: ItemUsageContext,
|
|
||||||
state: BlockState,
|
|
||||||
block: DeviceBlock<*>
|
|
||||||
): BlockState? {
|
|
||||||
if (!context.world.isClient) {
|
if (!context.world.isClient) {
|
||||||
val be = block.getBlockEntity(context.world, context.blockPos)!!
|
val be = block.getBlockEntity(context.world, context.blockPos)!!
|
||||||
|
|
||||||
|
@ -77,13 +66,7 @@ class ScrewdriverItem : Item(Settings().maxCount(1)) {
|
||||||
beTag.remove("InternalBuffer")
|
beTag.remove("InternalBuffer")
|
||||||
}
|
}
|
||||||
|
|
||||||
val entity = ItemEntity(
|
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), stack)
|
||||||
context.world,
|
|
||||||
context.blockPos.x.toDouble(),
|
|
||||||
context.blockPos.y.toDouble(),
|
|
||||||
context.blockPos.z.toDouble(),
|
|
||||||
stack
|
|
||||||
)
|
|
||||||
context.world.spawnEntity(entity)
|
context.world.spawnEntity(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,16 +77,8 @@ class ScrewdriverItem : Item(Settings().maxCount(1)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun screwdriverFaceDeviceBlock(
|
private fun screwdriverFaceDeviceBlock(context: ItemUsageContext, state: BlockState, block: FaceDeviceBlock<*>): BlockState? {
|
||||||
context: ItemUsageContext,
|
val hitInsideBlock = Vec3d(context.hitPos.x - context.blockPos.x, context.hitPos.y - context.blockPos.y, context.hitPos.z - context.blockPos.z)
|
||||||
state: BlockState,
|
|
||||||
block: FaceDeviceBlock<*>
|
|
||||||
): BlockState? {
|
|
||||||
val hitInsideBlock = Vec3d(
|
|
||||||
context.hitPos.x - context.blockPos.x,
|
|
||||||
context.hitPos.y - context.blockPos.y,
|
|
||||||
context.hitPos.z - context.blockPos.z
|
|
||||||
)
|
|
||||||
val faceShape = block.faceShapes[state[FaceDeviceBlock.FACING]]!!
|
val faceShape = block.faceShapes[state[FaceDeviceBlock.FACING]]!!
|
||||||
// if we hit the face part of block, leave the cable behind
|
// if we hit the face part of block, leave the cable behind
|
||||||
if (faceShape.boundingBox.containsInclusive(hitInsideBlock)) {
|
if (faceShape.boundingBox.containsInclusive(hitInsideBlock)) {
|
||||||
|
@ -111,13 +86,7 @@ class ScrewdriverItem : Item(Settings().maxCount(1)) {
|
||||||
return cableBlock.getInitialState(context.world, context.blockPos)
|
return cableBlock.getInitialState(context.world, context.blockPos)
|
||||||
} else {
|
} else {
|
||||||
if (!context.world.isClient) {
|
if (!context.world.isClient) {
|
||||||
val cable = ItemEntity(
|
val cable = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(state.block))
|
||||||
context.world,
|
|
||||||
context.blockPos.x.toDouble(),
|
|
||||||
context.blockPos.y.toDouble(),
|
|
||||||
context.blockPos.z.toDouble(),
|
|
||||||
ItemStack(state.block)
|
|
||||||
)
|
|
||||||
context.world.spawnEntity(cable)
|
context.world.spawnEntity(cable)
|
||||||
}
|
}
|
||||||
return Blocks.AIR.defaultState
|
return Blocks.AIR.defaultState
|
||||||
|
@ -126,13 +95,7 @@ class ScrewdriverItem : Item(Settings().maxCount(1)) {
|
||||||
|
|
||||||
private fun screwdriverCableBlock(context: ItemUsageContext, state: BlockState): BlockState? {
|
private fun screwdriverCableBlock(context: ItemUsageContext, state: BlockState): BlockState? {
|
||||||
if (!context.world.isClient) {
|
if (!context.world.isClient) {
|
||||||
val entity = ItemEntity(
|
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(state.block))
|
||||||
context.world,
|
|
||||||
context.blockPos.x.toDouble(),
|
|
||||||
context.blockPos.y.toDouble(),
|
|
||||||
context.blockPos.z.toDouble(),
|
|
||||||
ItemStack(state.block)
|
|
||||||
)
|
|
||||||
context.world.spawnEntity(entity)
|
context.world.spawnEntity(entity)
|
||||||
}
|
}
|
||||||
return Blocks.AIR.defaultState
|
return Blocks.AIR.defaultState
|
||||||
|
@ -140,13 +103,7 @@ class ScrewdriverItem : Item(Settings().maxCount(1)) {
|
||||||
|
|
||||||
private fun screwdriverSwitchBlock(context: ItemUsageContext): BlockState? {
|
private fun screwdriverSwitchBlock(context: ItemUsageContext): BlockState? {
|
||||||
if (!context.world.isClient) {
|
if (!context.world.isClient) {
|
||||||
val entity = ItemEntity(
|
val entity = ItemEntity(context.world, context.blockPos.x.toDouble(), context.blockPos.y.toDouble(), context.blockPos.z.toDouble(), ItemStack(PhyBlocks.SWITCH))
|
||||||
context.world,
|
|
||||||
context.blockPos.x.toDouble(),
|
|
||||||
context.blockPos.y.toDouble(),
|
|
||||||
context.blockPos.z.toDouble(),
|
|
||||||
ItemStack(PhyBlocks.SWITCH)
|
|
||||||
)
|
|
||||||
context.world.spawnEntity(entity)
|
context.world.spawnEntity(entity)
|
||||||
}
|
}
|
||||||
return Blocks.AIR.defaultState
|
return Blocks.AIR.defaultState
|
||||||
|
|
|
@ -31,13 +31,7 @@ object C2SConfigureDevice : ServerReceiver {
|
||||||
return createPacket(buf)
|
return createPacket(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receive(
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
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 tag = buf.readNbt() ?: return
|
val tag = buf.readNbt() ?: return
|
||||||
|
|
|
@ -36,13 +36,7 @@ object C2STerminalCraftingButton : ServerReceiver {
|
||||||
return createPacket(buf)
|
return createPacket(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receive(
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
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 action = Action.values()[buf.readByte().toInt()]
|
val action = Action.values()[buf.readByte().toInt()]
|
||||||
|
|
|
@ -38,13 +38,7 @@ object C2STerminalRequestItem : ServerReceiver {
|
||||||
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receive(
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
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 stack = buf.readItemStackWithoutCount()
|
val stack = buf.readItemStackWithoutCount()
|
||||||
|
|
|
@ -35,13 +35,7 @@ object C2STerminalUpdateDisplayedItems : ServerReceiver {
|
||||||
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receive(
|
override fun receive(server: MinecraftServer, player: ServerPlayerEntity, handler: ServerPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
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 query = buf.readString()
|
val query = buf.readString()
|
||||||
|
|
|
@ -10,7 +10,9 @@ import net.minecraft.network.PacketByteBuf
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivityClient
|
import net.shadowfacts.phycon.PhysicalConnectivityClient
|
||||||
import net.shadowfacts.phycon.block.terminal.AbstractTerminalBlockEntity
|
import net.shadowfacts.phycon.block.terminal.AbstractTerminalBlockEntity
|
||||||
import net.shadowfacts.phycon.block.terminal.AbstractTerminalScreenHandler
|
import net.shadowfacts.phycon.block.terminal.AbstractTerminalScreenHandler
|
||||||
import net.shadowfacts.phycon.util.*
|
import net.shadowfacts.phycon.util.TerminalSettings
|
||||||
|
import net.shadowfacts.phycon.util.readItemStackWithoutCount
|
||||||
|
import net.shadowfacts.phycon.util.writeItemStackWithoutCount
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -18,14 +20,7 @@ import net.shadowfacts.phycon.util.*
|
||||||
object S2CTerminalUpdateDisplayedItems: ClientReceiver {
|
object S2CTerminalUpdateDisplayedItems: ClientReceiver {
|
||||||
override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL
|
override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL
|
||||||
|
|
||||||
operator fun invoke(
|
operator fun invoke(terminal: AbstractTerminalBlockEntity, entries: List<AbstractTerminalScreenHandler.Entry>, query: String, settings: TerminalSettings, scrollPosition: Float, totalEntries: Int): Packet<*> {
|
||||||
terminal: AbstractTerminalBlockEntity,
|
|
||||||
entries: List<AbstractTerminalScreenHandler.Entry>,
|
|
||||||
query: String,
|
|
||||||
settings: TerminalSettings,
|
|
||||||
scrollPosition: Float,
|
|
||||||
totalEntries: Int
|
|
||||||
): Packet<*> {
|
|
||||||
val buf = PacketByteBufs.create()
|
val buf = PacketByteBufs.create()
|
||||||
|
|
||||||
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
buf.writeIdentifier(terminal.world!!.registryKey.value)
|
||||||
|
@ -33,7 +28,7 @@ object S2CTerminalUpdateDisplayedItems : ClientReceiver {
|
||||||
|
|
||||||
buf.writeVarInt(entries.size)
|
buf.writeVarInt(entries.size)
|
||||||
for (e in entries) {
|
for (e in entries) {
|
||||||
buf.writeItemVariant(e.variant)
|
buf.writeItemStackWithoutCount(e.stack)
|
||||||
buf.writeVarInt(e.amount)
|
buf.writeVarInt(e.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,18 +40,13 @@ object S2CTerminalUpdateDisplayedItems : ClientReceiver {
|
||||||
return ServerPlayNetworking.createS2CPacket(CHANNEL, buf)
|
return ServerPlayNetworking.createS2CPacket(CHANNEL, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun receive(
|
override fun receive(client: MinecraftClient, handler: ClientPlayNetworkHandler, buf: PacketByteBuf, responseSender: PacketSender) {
|
||||||
client: MinecraftClient,
|
|
||||||
handler: ClientPlayNetworkHandler,
|
|
||||||
buf: PacketByteBuf,
|
|
||||||
responseSender: PacketSender
|
|
||||||
) {
|
|
||||||
val dimID = buf.readIdentifier()
|
val dimID = buf.readIdentifier()
|
||||||
val pos = buf.readBlockPos()
|
val pos = buf.readBlockPos()
|
||||||
val entryCount = buf.readVarInt()
|
val entryCount = buf.readVarInt()
|
||||||
val entries = ArrayList<AbstractTerminalScreenHandler.Entry>(entryCount)
|
val entries = ArrayList<AbstractTerminalScreenHandler.Entry>(entryCount)
|
||||||
for (i in 0 until entryCount) {
|
for (i in 0 until entryCount) {
|
||||||
entries.add(AbstractTerminalScreenHandler.Entry(buf.readItemVariant(), buf.readVarInt()))
|
entries.add(AbstractTerminalScreenHandler.Entry(buf.readItemStackWithoutCount(), buf.readVarInt()))
|
||||||
}
|
}
|
||||||
val query = buf.readString()
|
val query = buf.readString()
|
||||||
PhysicalConnectivityClient.terminalSettings.fromTag(buf.readNbt()!!)
|
PhysicalConnectivityClient.terminalSettings.fromTag(buf.readNbt()!!)
|
||||||
|
|
|
@ -6,6 +6,5 @@ import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class CheckCapacityPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress) :
|
class CheckCapacityPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
BasePacket(source, destination) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import net.shadowfacts.phycon.block.DeviceBlockEntity
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class DeviceRemovedPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST) :
|
class DeviceRemovedPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
|
||||||
BasePacket(source, destination) {
|
|
||||||
constructor(device: DeviceBlockEntity): this(device.ipAddress)
|
constructor(device: DeviceBlockEntity): this(device.ipAddress)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,5 @@ import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: IPAddress, destination: IPAddress) :
|
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
BasePacket(source, destination) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: IPAddress, destination: IPAddress) :
|
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
BasePacket(source, destination) {
|
|
||||||
constructor(stack: ItemStack, source: IPAddress, destination: IPAddress): this(stack, 0, source, destination)
|
constructor(stack: ItemStack, source: IPAddress, destination: IPAddress): this(stack, 0, source, destination)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,5 @@ import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class LocateStackPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress = IPAddress.BROADCAST) :
|
class LocateStackPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
|
||||||
BasePacket(source, destination) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package net.shadowfacts.phycon.packet
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class ReadGroupedInventoryPacket(
|
||||||
|
val inventory: GroupedItemInvView,
|
||||||
|
source: IPAddress,
|
||||||
|
destination: IPAddress
|
||||||
|
): BasePacket(source, destination)
|
|
@ -5,8 +5,7 @@ import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RemoteActivationPacket(val mode: Mode, source: IPAddress, destination: IPAddress) :
|
class RemoteActivationPacket(val mode: Mode, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
BasePacket(source, destination) {
|
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
SINGLE,
|
SINGLE,
|
||||||
ENABLE,
|
ENABLE,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.shadowfacts.phycon.util
|
package net.shadowfacts.phycon.util
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import net.minecraft.inventory.SimpleInventory
|
import net.minecraft.inventory.SimpleInventory
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
@ -44,7 +45,7 @@ fun SimpleInventory.insert(stack: ItemStack, slot: Int): ItemStack {
|
||||||
if (current.isEmpty) {
|
if (current.isEmpty) {
|
||||||
setStack(slot, stack)
|
setStack(slot, stack)
|
||||||
return ItemStack.EMPTY
|
return ItemStack.EMPTY
|
||||||
} else if (stack.equalsIgnoringAmount(current)) {
|
} else if (ItemStackUtil.areEqualIgnoreAmounts(stack, current)) {
|
||||||
val toTransfer = min(current.maxCount - current.count, stack.count)
|
val toTransfer = min(current.maxCount - current.count, stack.count)
|
||||||
current.count += toTransfer
|
current.count += toTransfer
|
||||||
stack.count -= toTransfer
|
stack.count -= toTransfer
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package net.shadowfacts.phycon.util
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
sealed class Either<Left, Right> {
|
|
||||||
class Left<Left, Right>(val left: Left) : Either<Left, Right>()
|
|
||||||
|
|
||||||
class Right<Left, Right>(val right: Right) : Either<Left, Right>()
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
package net.shadowfacts.phycon.util
|
|
||||||
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
class IntRingBuffer(size: Int) : Iterable<Int> {
|
|
||||||
private val array = IntArray(size)
|
|
||||||
private var next = 0
|
|
||||||
private var wrapped = false
|
|
||||||
|
|
||||||
val size: Int
|
|
||||||
get() = if (wrapped) array.size else next
|
|
||||||
|
|
||||||
fun add(value: Int) {
|
|
||||||
array[next] = value
|
|
||||||
next = (next + 1) % array.size
|
|
||||||
wrapped = wrapped || next == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun asContiguousArray(): IntArray {
|
|
||||||
if (wrapped) {
|
|
||||||
val array = IntArray(array.size)
|
|
||||||
this.array.copyInto(array, destinationOffset = array.size - next, startIndex = 0, endIndex = next)
|
|
||||||
this.array.copyInto(array, destinationOffset = 0, startIndex = next, endIndex = array.size)
|
|
||||||
return array
|
|
||||||
} else {
|
|
||||||
return this.array.copyOfRange(0, next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun replace(array: IntArray) {
|
|
||||||
val count = min(array.size, this.array.size)
|
|
||||||
array.copyInto(this.array, destinationOffset = 0, startIndex = array.size - count, endIndex = count)
|
|
||||||
next = (count + 1) % this.array.size
|
|
||||||
wrapped = array.size >= this.array.size
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clear() {
|
|
||||||
next = 0
|
|
||||||
wrapped = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun iterator() = Iterator(this)
|
|
||||||
|
|
||||||
class Iterator(private val ringBuffer: IntRingBuffer) : IntIterator() {
|
|
||||||
private var nextIndex = if (ringBuffer.wrapped) ringBuffer.next else 0
|
|
||||||
private var wrapped = false
|
|
||||||
|
|
||||||
override fun nextInt(): Int {
|
|
||||||
val res = ringBuffer.array[nextIndex]
|
|
||||||
nextIndex += 1
|
|
||||||
if (nextIndex >= ringBuffer.array.size) {
|
|
||||||
wrapped = true
|
|
||||||
nextIndex = 0
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return if (ringBuffer.wrapped) {
|
|
||||||
!wrapped || nextIndex < ringBuffer.next
|
|
||||||
} else {
|
|
||||||
nextIndex < ringBuffer.next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,17 +0,0 @@
|
||||||
package net.shadowfacts.phycon.util
|
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
|
|
||||||
fun ItemStack.copyWithCount(count: Int): ItemStack {
|
|
||||||
return copy().also { it.count = count }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ItemStack.equalsIgnoringAmount(other: ItemStack): Boolean {
|
|
||||||
if (this.isEmpty) return other.isEmpty
|
|
||||||
if (other.isEmpty) return false
|
|
||||||
return this.item === other.item && this.nbt == other.nbt;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package net.shadowfacts.phycon.util
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
|
||||||
import net.minecraft.item.ItemStack
|
|
||||||
import net.minecraft.text.Text
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
|
|
||||||
val ItemVariant.name: Text
|
|
||||||
get() {
|
|
||||||
// don't use toStack because that copies the NBT
|
|
||||||
// we assume that items don't mutate NBT in getName
|
|
||||||
val stack = ItemStack(this.item, 1)
|
|
||||||
stack.nbt = this.nbt
|
|
||||||
return item.getName(stack)
|
|
||||||
}
|
|
|
@ -37,7 +37,6 @@ object NetworkUtil {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> {
|
fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> {
|
||||||
val results = LinkedList<PacketSink>()
|
val results = LinkedList<PacketSink>()
|
||||||
val visited = hashSetOf(startPos)
|
val visited = hashSetOf(startPos)
|
||||||
|
@ -63,15 +62,8 @@ object NetworkUtil {
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
private fun findEdges(
|
private fun findEdges(queue: MutableList<BlockPos>, visited: Set<BlockPos>, world: World, pos: BlockPos, includeNonCables: Boolean = false) {
|
||||||
queue: MutableList<BlockPos>,
|
|
||||||
visited: Set<BlockPos>,
|
|
||||||
world: World,
|
|
||||||
pos: BlockPos,
|
|
||||||
includeNonCables: Boolean = false
|
|
||||||
) {
|
|
||||||
val state = world.getBlockState(pos)
|
val state = world.getBlockState(pos)
|
||||||
val block = state.block
|
val block = state.block
|
||||||
if (block is NetworkComponentBlock && (includeNonCables || block is NetworkCableBlock)) {
|
if (block is NetworkComponentBlock && (includeNonCables || block is NetworkCableBlock)) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package net.shadowfacts.phycon.util
|
package net.shadowfacts.phycon.util
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
|
|
||||||
import net.minecraft.item.Item
|
import net.minecraft.item.Item
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
@ -36,11 +35,3 @@ fun PacketByteBuf.readItemStackWithoutCount(): ItemStack {
|
||||||
stack
|
stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PacketByteBuf.writeItemVariant(variant: ItemVariant) {
|
|
||||||
variant.toPacket(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun PacketByteBuf.readItemVariant(): ItemVariant {
|
|
||||||
return ItemVariant.fromPacket(this)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
package net.shadowfacts.phycon.util
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.Assertions.assertArrayEquals
|
|
||||||
import org.junit.jupiter.api.Assertions.assertFalse
|
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
class IntRingBufferTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testEmpty() {
|
|
||||||
assertArrayEquals(intArrayOf(), IntRingBuffer(4).asContiguousArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testAsContiguousArray() {
|
|
||||||
val buffer = IntRingBuffer(4)
|
|
||||||
buffer.add(0)
|
|
||||||
buffer.add(1)
|
|
||||||
assertArrayEquals(intArrayOf(0, 1), buffer.asContiguousArray())
|
|
||||||
|
|
||||||
buffer.add(2)
|
|
||||||
buffer.add(3)
|
|
||||||
buffer.add(4)
|
|
||||||
assertArrayEquals(intArrayOf(1, 2, 3, 4), buffer.asContiguousArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testIterator() {
|
|
||||||
val buffer = IntRingBuffer(4)
|
|
||||||
|
|
||||||
val iterator = buffer.iterator()
|
|
||||||
assertFalse(iterator.hasNext())
|
|
||||||
|
|
||||||
buffer.add(0)
|
|
||||||
buffer.add(1)
|
|
||||||
assertEquals(listOf(0, 1), buffer.toList())
|
|
||||||
|
|
||||||
buffer.add(2)
|
|
||||||
buffer.add(3)
|
|
||||||
buffer.add(4)
|
|
||||||
assertEquals(listOf(1, 2, 3, 4), buffer.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue