new rack UI
This commit is contained in:
parent
766a9e10ee
commit
1a5a31aafe
16 changed files with 443 additions and 47 deletions
Binary file not shown.
|
|
@ -51,6 +51,22 @@ class DeviceBlockEntity(
|
|||
*/
|
||||
var shelf: UUID? = null
|
||||
|
||||
/**
|
||||
* Order of shelves when the UI is open.
|
||||
*
|
||||
* This is propagated and merged between devices upon the UI being opened.
|
||||
*/
|
||||
val shelfOrder = mutableListOf<UUID>()
|
||||
|
||||
/**
|
||||
* At which position the device should be sorted in the rack. Lower priorities mean earlier
|
||||
* positions.
|
||||
*
|
||||
* Devices start out with the maximum possible priority and no shelf, which means they'll be
|
||||
* appended to the end of the sidebar in an undefined order.
|
||||
*/
|
||||
var sortPriority = Int.MAX_VALUE
|
||||
|
||||
/** NBT compound keys. */
|
||||
private object Nbt {
|
||||
const val controls = "controls"
|
||||
|
|
@ -72,6 +88,8 @@ class DeviceBlockEntity(
|
|||
}
|
||||
|
||||
const val shelf = "shelf"
|
||||
const val shelfOrder = "shelfOrder"
|
||||
const val sortPriority = "sortPriority"
|
||||
}
|
||||
|
||||
override fun readNbt(nbt: NbtCompound) {
|
||||
|
|
@ -131,9 +149,23 @@ class DeviceBlockEntity(
|
|||
outputConnections[port] = blockPosition
|
||||
}
|
||||
|
||||
if (nbt.containsUuid(Nbt.shelf)) {
|
||||
shelf = nbt.getUuid(Nbt.shelf)
|
||||
shelf = if (nbt.containsUuid(Nbt.shelf)) {
|
||||
nbt.getUuid(Nbt.shelf)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val shelfOrderNbt = nbt.getList(Nbt.shelfOrder, NbtElement.INT_ARRAY_TYPE.toInt())
|
||||
shelfOrder.clear()
|
||||
for (i in 0 until shelfOrderNbt.size) {
|
||||
try {
|
||||
val uuid = NbtHelper.toUuid(shelfOrderNbt[i])
|
||||
shelfOrder.add(uuid)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
// toUuid may throw an IllegalArgumentException if the UUID doesn't follow the
|
||||
// expected format. In that case we just ignore the error and move on.
|
||||
}
|
||||
}
|
||||
sortPriority = nbt.getInt(Nbt.sortPriority)
|
||||
}
|
||||
|
||||
override fun writeNbt(nbt: NbtCompound) {
|
||||
|
|
@ -170,6 +202,18 @@ class DeviceBlockEntity(
|
|||
outputConnectionsNbt.add(connectionNbt)
|
||||
}
|
||||
nbt.put(Nbt.outputConnections, outputConnectionsNbt)
|
||||
|
||||
if (shelf != null) {
|
||||
nbt.putUuid(Nbt.shelf, shelf)
|
||||
} else {
|
||||
nbt.remove(Nbt.shelf)
|
||||
}
|
||||
val shelfOrderNbt = NbtList()
|
||||
for (shelfUuid in shelfOrder) {
|
||||
shelfOrderNbt.add(NbtHelper.fromUuid(shelfUuid))
|
||||
}
|
||||
nbt.put(Nbt.shelfOrder, shelfOrderNbt)
|
||||
nbt.putInt(Nbt.sortPriority, sortPriority)
|
||||
}
|
||||
|
||||
override fun onClientLoad(world: ClientWorld) {
|
||||
|
|
|
|||
15
src/main/kotlin/net/liquidev/dawd3/common/lists.kt
Normal file
15
src/main/kotlin/net/liquidev/dawd3/common/lists.kt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package net.liquidev.dawd3.common
|
||||
|
||||
fun <T> moveElement(from: MutableList<T>, fromIndex: Int, to: MutableList<T>, toIndex: Int) {
|
||||
if (from == to && fromIndex != toIndex) {
|
||||
val element = from.removeAt(fromIndex)
|
||||
to.add(
|
||||
if (fromIndex < toIndex) toIndex - 1
|
||||
else toIndex,
|
||||
element,
|
||||
)
|
||||
} else {
|
||||
val element = from.removeAt(fromIndex)
|
||||
to.add(toIndex, element)
|
||||
}
|
||||
}
|
||||
104
src/main/kotlin/net/liquidev/dawd3/net/EditRack.kt
Normal file
104
src/main/kotlin/net/liquidev/dawd3/net/EditRack.kt
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package net.liquidev.dawd3.net
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockEntity
|
||||
import net.liquidev.dawd3.net.serialization.readOptionalUuid
|
||||
import net.liquidev.dawd3.net.serialization.writeOptionalUuid
|
||||
import net.liquidev.dawd3.ui.widget.rack.shelves.ShelfEditing
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Assign a shelf and shelf order to a block at the given position.
|
||||
*
|
||||
* When sent C2S, the data of the device block entity at the given position is modified to write
|
||||
* back its shelf UUID and shelf order. The server then propagates the shelf order to every block
|
||||
* entity in the rack and sends this packet S2C to all witnesses of the propagation.
|
||||
*/
|
||||
data class EditRack(
|
||||
val blockPosition: BlockPos,
|
||||
val shelf: UUID?,
|
||||
val shelfOrder: Array<UUID>,
|
||||
) {
|
||||
companion object {
|
||||
val id = Identifier(Mod.id, "edit_rack")
|
||||
|
||||
fun registerServerReceiver() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(id) { server, player, _, buffer, _ ->
|
||||
val packet = deserialize(buffer)
|
||||
server.execute {
|
||||
val blockState = player.world.getBlockState(packet.blockPosition)
|
||||
val blockEntity =
|
||||
player.world.getBlockEntity(packet.blockPosition) as? DeviceBlockEntity
|
||||
?: return@execute
|
||||
blockEntity.shelf = packet.shelf
|
||||
ShelfEditing.propagateShelfOrderData(
|
||||
player.world,
|
||||
packet.blockPosition,
|
||||
packet.shelfOrder,
|
||||
)
|
||||
blockEntity.markDirty()
|
||||
|
||||
player.world.updateListeners(
|
||||
packet.blockPosition,
|
||||
blockState,
|
||||
blockState,
|
||||
Block.NOTIFY_LISTENERS,
|
||||
)
|
||||
for (witness in PlayerLookup.tracking(blockEntity)) {
|
||||
if (witness != player) {
|
||||
ServerPlayNetworking.send(witness, id, buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun registerClientReceiver() {
|
||||
|
||||
}
|
||||
|
||||
private fun deserialize(buffer: PacketByteBuf) =
|
||||
EditRack(
|
||||
blockPosition = buffer.readBlockPos(),
|
||||
shelf = buffer.readOptionalUuid(),
|
||||
shelfOrder = Array(buffer.readVarInt()) { buffer.readUuid() }
|
||||
)
|
||||
}
|
||||
|
||||
fun serialize(): PacketByteBuf =
|
||||
PacketByteBufs.create()
|
||||
.writeBlockPos(blockPosition)
|
||||
.writeOptionalUuid(shelf)
|
||||
.writeVarInt(shelfOrder.size)
|
||||
.apply {
|
||||
for (shelfUuid in shelfOrder) {
|
||||
writeUuid(shelfUuid)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as EditRack
|
||||
|
||||
if (blockPosition != other.blockPosition) return false
|
||||
if (shelf != other.shelf) return false
|
||||
return shelfOrder.contentEquals(other.shelfOrder)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = blockPosition.hashCode()
|
||||
result = 31 * result + (shelf?.hashCode() ?: 0)
|
||||
result = 31 * result + shelfOrder.contentHashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,5 +11,7 @@ object Packets {
|
|||
fun registerServerReceivers() {
|
||||
TweakControl.registerServerReceiver()
|
||||
ControlTweaked.registerServerReceiver()
|
||||
EditRack.registerServerReceiver()
|
||||
ReorderRack.registerServerReceiver()
|
||||
}
|
||||
}
|
||||
67
src/main/kotlin/net/liquidev/dawd3/net/ReorderRack.kt
Normal file
67
src/main/kotlin/net/liquidev/dawd3/net/ReorderRack.kt
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package net.liquidev.dawd3.net
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
|
||||
import net.liquidev.dawd3.Mod
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockEntity
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
data class ReorderRack(val entries: List<Entry>) {
|
||||
data class Entry(val blockPosition: BlockPos, val sortPriority: Int)
|
||||
|
||||
companion object {
|
||||
val id = Identifier(Mod.id, "reorder_rack")
|
||||
|
||||
fun registerServerReceiver() {
|
||||
ServerPlayNetworking.registerGlobalReceiver(id) { server, player, _, buffer, _ ->
|
||||
val packet = deserialize(buffer)
|
||||
server.execute {
|
||||
for (entry in packet.entries) {
|
||||
val blockEntity =
|
||||
player.world.getBlockEntity(entry.blockPosition) as? DeviceBlockEntity
|
||||
?: continue
|
||||
blockEntity.sortPriority = entry.sortPriority
|
||||
blockEntity.markDirty()
|
||||
|
||||
val blockState = player.world.getBlockState(entry.blockPosition)
|
||||
player.world.updateListeners(
|
||||
entry.blockPosition,
|
||||
blockState,
|
||||
blockState,
|
||||
Block.NOTIFY_LISTENERS
|
||||
)
|
||||
for (witness in PlayerLookup.tracking(blockEntity)) {
|
||||
if (witness != player) {
|
||||
ServerPlayNetworking.send(witness, id, buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserialize(buffer: PacketByteBuf) =
|
||||
ReorderRack(
|
||||
entries = MutableList(buffer.readVarInt()) {
|
||||
Entry(
|
||||
blockPosition = buffer.readBlockPos(),
|
||||
sortPriority = buffer.readVarInt(),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun serialize(): PacketByteBuf {
|
||||
val buffer = PacketByteBufs.create()
|
||||
buffer.writeVarInt(entries.size)
|
||||
for (entry in entries) {
|
||||
buffer.writeBlockPos(entry.blockPosition)
|
||||
buffer.writeVarInt(entry.sortPriority)
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
}
|
||||
24
src/main/kotlin/net/liquidev/dawd3/net/serialization/bin.kt
Normal file
24
src/main/kotlin/net/liquidev/dawd3/net/serialization/bin.kt
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package net.liquidev.dawd3.net.serialization
|
||||
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import java.util.*
|
||||
|
||||
val zeroUuid = UUID(0L, 0L)
|
||||
|
||||
fun PacketByteBuf.readOptionalUuid(): UUID? {
|
||||
val uuid = readUuid()
|
||||
return if (uuid.leastSignificantBits == 0L && uuid.mostSignificantBits == 0L) {
|
||||
null
|
||||
} else {
|
||||
uuid
|
||||
}
|
||||
}
|
||||
|
||||
fun PacketByteBuf.writeOptionalUuid(uuid: UUID?): PacketByteBuf {
|
||||
if (uuid != null) {
|
||||
writeUuid(uuid)
|
||||
} else {
|
||||
writeUuid(zeroUuid)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ object Render {
|
|||
sprite: Sprite,
|
||||
) {
|
||||
RenderSystem.setShaderTexture(0, atlas.asset)
|
||||
RenderSystem.enableBlend()
|
||||
DrawableHelper.drawTexture(
|
||||
matrices,
|
||||
x.toInt(),
|
||||
|
|
@ -166,6 +167,7 @@ object Render {
|
|||
) {
|
||||
// Temporarily defined to just defer to DrawableHelper, later on we should introduce support
|
||||
// for rendering at floating-point coordinates.
|
||||
RenderSystem.enableBlend()
|
||||
DrawableHelper.drawTexture(
|
||||
matrices,
|
||||
x.toInt(),
|
||||
|
|
@ -365,7 +367,7 @@ object Render {
|
|||
tooltip(matrices, x, y, text, atlas, tooltip)
|
||||
}
|
||||
|
||||
inline fun colorized(r: Float, g: Float, b: Float, a: Float, then: () -> Unit) {
|
||||
inline fun colorized(r: Float, g: Float, b: Float, a: Float, crossinline then: () -> Unit) {
|
||||
val (oldR, oldG, oldB, oldA) = RenderSystem.getShaderColor()
|
||||
RenderSystem.setShaderColor(r, g, b, a)
|
||||
RenderSystem.enableBlend() // sigh
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ class RackScreen(
|
|||
shownDevices: Iterable<BlockPos>,
|
||||
) : Screen(Text.translatable("screen.dawd3.rack.title")) {
|
||||
|
||||
private val rootWidget = Rack(width.toFloat(), height.toFloat(), world, shownDevices)
|
||||
private val rootWidget =
|
||||
Rack(width.toFloat(), height.toFloat(), world, shownDevices)
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ abstract class Widget<in C, out M : Message>(var x: Float, var y: Float) {
|
|||
|
||||
abstract fun event(context: C, event: Event): M
|
||||
|
||||
inline fun drawInside(matrices: MatrixStack, draw: () -> Unit) {
|
||||
inline fun drawInside(matrices: MatrixStack, crossinline draw: () -> Unit) {
|
||||
matrices.push()
|
||||
matrices.translate(x.toDouble(), y.toDouble(), 0.0)
|
||||
draw()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package net.liquidev.dawd3.ui.widget.rack
|
||||
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockEntity
|
||||
import net.liquidev.dawd3.common.moveElement
|
||||
import net.liquidev.dawd3.net.EditRack
|
||||
import net.liquidev.dawd3.net.ReorderRack
|
||||
import net.liquidev.dawd3.render.NinePatch
|
||||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.render.TextureStrip
|
||||
|
|
@ -12,6 +16,7 @@ import net.minecraft.client.util.math.MatrixStack
|
|||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import org.lwjgl.glfw.GLFW
|
||||
import java.util.*
|
||||
|
||||
class Rack(
|
||||
override var width: Float,
|
||||
|
|
@ -20,10 +25,10 @@ class Rack(
|
|||
shownDevices: Iterable<BlockPos>,
|
||||
) : Widget<Unit, Message>(0f, 0f) {
|
||||
|
||||
private val sidebar = Sidebar(0f, 0f, 160f, 0f)
|
||||
private val sidebar = Sidebar(0f, 0f, 0f, 0f)
|
||||
private val blockPositionsByWidget = hashMapOf<DeviceWidget, BlockPos>()
|
||||
|
||||
private val shelves = MutableList(10) { Shelf(0f, 0f, width) }
|
||||
private val shelves = mutableListOf<Shelf>()
|
||||
|
||||
enum class DragPlace {
|
||||
Sidebar,
|
||||
|
|
@ -33,6 +38,7 @@ class Rack(
|
|||
data class DraggedWindow(
|
||||
val window: Window,
|
||||
val source: DragPlace,
|
||||
val indexInSource: Int,
|
||||
val byX: Float,
|
||||
val byY: Float,
|
||||
|
||||
|
|
@ -42,14 +48,45 @@ class Rack(
|
|||
private var draggedWindow: DraggedWindow? = null
|
||||
|
||||
init {
|
||||
val shelvesByUuid = hashMapOf<UUID, Shelf>()
|
||||
|
||||
for (blockPosition in shownDevices) {
|
||||
val blockEntity = world.getBlockEntity(blockPosition) as? DeviceBlockEntity ?: continue
|
||||
val widget = blockEntity.descriptor.ui?.open(blockEntity.controls, x = 0f, y = 0f)
|
||||
if (widget != null) {
|
||||
sidebar.windows.add(widget)
|
||||
blockPositionsByWidget[widget] = blockPosition
|
||||
for (shelfUuid in blockEntity.shelfOrder) {
|
||||
if (shelfUuid !in shelvesByUuid) {
|
||||
val shelf = Shelf(0f, 0f, width, shelfUuid)
|
||||
shelves.add(shelf)
|
||||
shelvesByUuid[shelfUuid] = shelf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (blockPosition in shownDevices) {
|
||||
val blockEntity = world.getBlockEntity(blockPosition) as? DeviceBlockEntity ?: continue
|
||||
val window = blockEntity.descriptor.ui?.open(blockEntity.controls, x = 0f, y = 0f)
|
||||
if (window != null) {
|
||||
val shelfUuid = blockEntity.shelf
|
||||
if (shelfUuid != null) {
|
||||
shelvesByUuid[shelfUuid]?.windows?.add(window)
|
||||
} else {
|
||||
sidebar.windows.add(window)
|
||||
}
|
||||
blockPositionsByWidget[window] = blockPosition
|
||||
}
|
||||
}
|
||||
removeEmptyShelvesFromEnd()
|
||||
addEmptyShelfIfNotPresent()
|
||||
|
||||
sortWindowsInContainer(sidebar.windows)
|
||||
shelves.forEach { sortWindowsInContainer(it.windows) }
|
||||
}
|
||||
|
||||
private fun <W : DeviceWidget> sortWindowsInContainer(container: MutableList<W>) {
|
||||
container.sortBy { window ->
|
||||
val blockPosition = blockPositionsByWidget[window]
|
||||
val blockEntity = world.getBlockEntity(blockPosition) as? DeviceBlockEntity
|
||||
blockEntity?.sortPriority ?: Int.MAX_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
private fun <W : DeviceWidget> removeStaleWidgetsFromContainer(container: MutableList<W>) {
|
||||
|
|
@ -67,6 +104,9 @@ class Rack(
|
|||
for (shelf in shelves) {
|
||||
shelf.draw(matrices, mouseX, mouseY, deltaTime)
|
||||
}
|
||||
if (shelves.size == 1 && shelves.last().windows.isEmpty()) {
|
||||
shelves.last().drawUsageHint(matrices)
|
||||
}
|
||||
|
||||
sidebar.draw(matrices, mouseX, mouseY, deltaTime)
|
||||
|
||||
|
|
@ -83,7 +123,6 @@ class Rack(
|
|||
)
|
||||
|
||||
val destination = findDragDestination(mouseX, mouseY)
|
||||
println(destination)
|
||||
when (destination?.place) {
|
||||
DragPlace.Sidebar -> {
|
||||
sidebar.drawInside(matrices) {
|
||||
|
|
@ -91,7 +130,7 @@ class Rack(
|
|||
Sidebar.padding
|
||||
} else if (destination.indexInPlace == sidebar.windows.size) {
|
||||
val window = sidebar.windows.last()
|
||||
window.y + window.height - Sidebar.spacingBetweenWindows / 2f
|
||||
window.y + window.height + Sidebar.spacingBetweenWindows / 2f
|
||||
} else {
|
||||
val window = sidebar.windows[destination.indexInPlace]
|
||||
window.y - Sidebar.spacingBetweenWindows / 2f
|
||||
|
|
@ -143,7 +182,7 @@ class Rack(
|
|||
source: DragPlace,
|
||||
sourceShelfIndex: Int = 0,
|
||||
): Message {
|
||||
for (window in windows) {
|
||||
windows.forEachIndexed { index, window ->
|
||||
val blockPosition = blockPositionsByWidget[window]!!
|
||||
val windowRelativeEvent = event.relativeTo(window.x, window.y)
|
||||
val windowMessage =
|
||||
|
|
@ -153,6 +192,7 @@ class Rack(
|
|||
DraggedWindow(
|
||||
window,
|
||||
source,
|
||||
index,
|
||||
windowMessage.x,
|
||||
windowMessage.y,
|
||||
sourceShelfIndex
|
||||
|
|
@ -192,21 +232,38 @@ class Rack(
|
|||
if (draggedWindow != null) {
|
||||
val destination = findDragDestination(event.mouseX, event.mouseY)
|
||||
if (destination != null) {
|
||||
removeWindowFromSource(
|
||||
draggedWindow.source,
|
||||
draggedWindow.sourceShelfIndex,
|
||||
draggedWindow.window,
|
||||
)
|
||||
when (destination.place) {
|
||||
DragPlace.Sidebar -> sidebar.windows.add(
|
||||
destination.indexInPlace,
|
||||
draggedWindow.window
|
||||
)
|
||||
DragPlace.Shelf -> shelves[destination.shelfIndex].windows.add(
|
||||
destination.indexInPlace,
|
||||
draggedWindow.window
|
||||
)
|
||||
val fromList: MutableList<Window> = when (draggedWindow.source) {
|
||||
DragPlace.Sidebar -> sidebar.windows
|
||||
DragPlace.Shelf -> shelves[draggedWindow.sourceShelfIndex].windows
|
||||
}
|
||||
val toList: MutableList<Window> = when (destination.place) {
|
||||
DragPlace.Sidebar -> sidebar.windows
|
||||
DragPlace.Shelf -> shelves[destination.shelfIndex].windows
|
||||
}
|
||||
moveElement(
|
||||
fromList,
|
||||
fromIndex = draggedWindow.indexInSource,
|
||||
toList,
|
||||
toIndex = destination.indexInPlace
|
||||
)
|
||||
|
||||
val blockPosition = blockPositionsByWidget[draggedWindow.window]
|
||||
if (blockPosition != null) {
|
||||
when (destination.place) {
|
||||
DragPlace.Shelf -> {
|
||||
val shelf = shelves[destination.shelfIndex]
|
||||
updateBlockData(blockPosition, shelf.uuid)
|
||||
}
|
||||
DragPlace.Sidebar -> {
|
||||
updateBlockData(blockPosition, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeEmptyShelvesFromEnd()
|
||||
addEmptyShelfIfNotPresent()
|
||||
updateBlockPriorities(fromList)
|
||||
updateBlockPriorities(toList)
|
||||
reflow()
|
||||
}
|
||||
}
|
||||
|
|
@ -216,6 +273,27 @@ class Rack(
|
|||
return Message.eventIgnored
|
||||
}
|
||||
|
||||
private fun removeEmptyShelvesFromEnd() {
|
||||
while (shelves.size > 1 && shelves.last().windows.isEmpty()) {
|
||||
shelves.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addEmptyShelfIfNotPresent() {
|
||||
if (shelves.size == 0 || shelves.last().windows.isNotEmpty()) {
|
||||
shelves.add(Shelf(0f, 0f, width, UUID.randomUUID()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun <W : DeviceWidget> updateBlockPriorities(windows: MutableList<W>) {
|
||||
val packetEntries = mutableListOf<ReorderRack.Entry>()
|
||||
windows.forEachIndexed { index, window ->
|
||||
val blockPosition = blockPositionsByWidget[window] ?: return@forEachIndexed
|
||||
packetEntries.add(ReorderRack.Entry(blockPosition, index))
|
||||
}
|
||||
ClientPlayNetworking.send(ReorderRack.id, ReorderRack(packetEntries).serialize())
|
||||
}
|
||||
|
||||
internal data class DragDestination(
|
||||
val place: DragPlace,
|
||||
val indexInPlace: Int,
|
||||
|
|
@ -238,22 +316,8 @@ class Rack(
|
|||
return null
|
||||
}
|
||||
|
||||
private fun removeWindowFromSource(
|
||||
source: DragPlace,
|
||||
indexOfSource: Int,
|
||||
window: Window,
|
||||
) {
|
||||
when (source) {
|
||||
DragPlace.Sidebar -> {
|
||||
sidebar.windows.remove(window)
|
||||
}
|
||||
DragPlace.Shelf -> {
|
||||
shelves[indexOfSource].windows.remove(window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun reflow() {
|
||||
sidebar.width = if (sidebar.windows.isNotEmpty()) 160f else 16f
|
||||
sidebar.x = width - sidebar.width
|
||||
sidebar.height = height
|
||||
sidebar.reflow()
|
||||
|
|
@ -262,11 +326,21 @@ class Rack(
|
|||
for (shelf in shelves) {
|
||||
shelf.reflow()
|
||||
shelf.y = dy
|
||||
shelf.width = width
|
||||
shelf.width = width - sidebar.width
|
||||
dy += shelf.height
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateBlockData(editedDevicePosition: BlockPos, newShelfUuid: UUID?) {
|
||||
ClientPlayNetworking.send(
|
||||
EditRack.id, EditRack(
|
||||
editedDevicePosition,
|
||||
shelf = newShelfUuid,
|
||||
shelfOrder = shelves.map { it.uuid }.toTypedArray()
|
||||
).serialize()
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val windowDraggingPreview =
|
||||
NinePatch(u = 48f, v = 0f, width = 8f, height = 8f, border = 2f)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package net.liquidev.dawd3.ui.widget.rack
|
||||
|
||||
import net.liquidev.dawd3.common.rgba
|
||||
import net.liquidev.dawd3.render.Render
|
||||
import net.liquidev.dawd3.render.TextureStrip
|
||||
import net.liquidev.dawd3.ui.Event
|
||||
|
|
@ -8,9 +9,16 @@ import net.liquidev.dawd3.ui.RackScreen
|
|||
import net.liquidev.dawd3.ui.widget.Widget
|
||||
import net.liquidev.dawd3.ui.widget.Window
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.text.Text
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
|
||||
class Shelf(x: Float, y: Float, override var width: Float) : Widget<Nothing, Message>(x, y) {
|
||||
class Shelf(
|
||||
x: Float,
|
||||
y: Float,
|
||||
override var width: Float,
|
||||
val uuid: UUID,
|
||||
) : Widget<Nothing, Message>(x, y) {
|
||||
override var height = 128f
|
||||
private set
|
||||
|
||||
|
|
@ -39,6 +47,20 @@ class Shelf(x: Float, y: Float, override var width: Float) : Widget<Nothing, Mes
|
|||
}
|
||||
}
|
||||
|
||||
fun drawUsageHint(matrices: MatrixStack) {
|
||||
drawInside(matrices) {
|
||||
Render.colorized(1f, 1f, 1f, 0.6f) {
|
||||
Render.textCentered(
|
||||
matrices,
|
||||
width / 2f,
|
||||
height / 2f - 4,
|
||||
Text.translatable("screen.dawd3.rack.shelf_hint"),
|
||||
rgba(255, 255, 255, 127)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Events here are not handled directly by the Shelf, but rather by the parent rack
|
||||
// screen which has extra context that needs to be passed down to windows. Hence this cannot
|
||||
// be called (context is Nothing.)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import net.minecraft.client.util.math.MatrixStack
|
|||
class Sidebar(
|
||||
x: Float,
|
||||
y: Float,
|
||||
override val width: Float,
|
||||
override var width: Float,
|
||||
override var height: Float,
|
||||
) : Widget<Nothing, Message>(x, y) {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package net.liquidev.dawd3.ui.widget.rack.shelves
|
||||
|
||||
import net.liquidev.dawd3.block.device.DeviceBlockEntity
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import java.util.*
|
||||
|
||||
object ShelfEditing {
|
||||
fun propagateShelfOrderData(world: World, from: BlockPos, shelfOrder: Array<UUID>) {
|
||||
propagateShelfOrderDataRec(world, from, HashSet(), shelfOrder)
|
||||
}
|
||||
|
||||
private fun propagateShelfOrderDataRec(
|
||||
world: World,
|
||||
position: BlockPos,
|
||||
traversed: HashSet<BlockPos>,
|
||||
sourceShelfOrder: Array<UUID>,
|
||||
) {
|
||||
val thisBlockEntity = world.getBlockEntity(position) as? DeviceBlockEntity ?: return
|
||||
if (position !in traversed) {
|
||||
traversed.add(position)
|
||||
|
||||
// Maybe not the fastest thing... but I don't want to share a single piece of mutable
|
||||
// data between all the block entities, as that can cause weird bugs later down the line.
|
||||
thisBlockEntity.shelfOrder.clear()
|
||||
thisBlockEntity.shelfOrder.addAll(sourceShelfOrder)
|
||||
thisBlockEntity.markDirty()
|
||||
|
||||
val blockState = world.getBlockState(position)
|
||||
world.updateListeners(position, blockState, blockState, Block.NOTIFY_LISTENERS)
|
||||
|
||||
propagateShelfOrderDataRec(world, position.up(), traversed, sourceShelfOrder)
|
||||
propagateShelfOrderDataRec(world, position.down(), traversed, sourceShelfOrder)
|
||||
propagateShelfOrderDataRec(world, position.north(), traversed, sourceShelfOrder)
|
||||
propagateShelfOrderDataRec(world, position.south(), traversed, sourceShelfOrder)
|
||||
propagateShelfOrderDataRec(world, position.east(), traversed, sourceShelfOrder)
|
||||
propagateShelfOrderDataRec(world, position.west(), traversed, sourceShelfOrder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
"block.dawd3.saw_oscillator": "Saw Oscillator",
|
||||
"block.dawd3.sine_oscillator": "Sine Oscillator",
|
||||
"block.dawd3.triangle_oscillator": "Triangle Oscillator",
|
||||
"screen.dawd3.rack.title": "Rack",
|
||||
"screen.dawd3.rack.shelf_hint": "Drag devices here to organize them",
|
||||
"dawd3.control.dawd3.adsr.attack": "ATT",
|
||||
"dawd3.control.dawd3.adsr.decay": "DEC",
|
||||
"dawd3.control.dawd3.adsr.sustain": "SUS",
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 551 B After Width: | Height: | Size: 548 B |
Reference in a new issue