Add terminal settings API

This commit is contained in:
Shadowfacts 2021-03-24 17:28:03 -04:00
parent e41c9e3ccb
commit 28e14ae8bf
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
21 changed files with 339 additions and 112 deletions

View File

@ -34,8 +34,8 @@ object PhyConPlugin: ClientModInitializer, REIPluginV0 {
override fun registerBounds(helper: DisplayHelper) { override fun registerBounds(helper: DisplayHelper) {
BaseBoundsHandler.getInstance().registerExclusionZones(TerminalScreen::class.java) { BaseBoundsHandler.getInstance().registerExclusionZones(TerminalScreen::class.java) {
val screen = MinecraftClient.getInstance().currentScreen as TerminalScreen val screen = MinecraftClient.getInstance().currentScreen as TerminalScreen
val button = screen.terminalVC.sortMode val view = screen.terminalVC.settingsView
val rect = button.convert(button.bounds, to = null) val rect = view.convert(view.bounds, to = null)
listOf( listOf(
Rectangle(rect.left.toInt(), rect.top.toInt(), 20, 20) Rectangle(rect.left.toInt(), rect.top.toInt(), 20, 20)
) )

View File

@ -0,0 +1,14 @@
package net.shadowfacts.phycon.api;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
/**
* @author shadowfacts
*/
public interface PhyConAPI {
@NotNull
<E extends Enum<E> & TerminalSetting> TerminalSettingKey<E> registerTerminalSetting(Identifier id, E defaultValue);
}

View File

@ -0,0 +1,10 @@
package net.shadowfacts.phycon.api;
/**
* @author shadowfacts
*/
public interface PhyConPlugin {
void initializePhyCon(PhyConAPI api);
}

View File

@ -0,0 +1,18 @@
package net.shadowfacts.phycon.api;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
/**
* @author shadowfacts
*/
public interface TerminalSetting {
Identifier getIconTexture();
int[] getUV();
@Nullable Text getTooltip();
}

View File

@ -0,0 +1,14 @@
package net.shadowfacts.phycon.api;
import net.minecraft.util.Identifier;
/**
* @author shadowfacts
*/
public interface TerminalSettingKey<E extends Enum<E> & TerminalSetting> {
Identifier getID();
E getValue();
}

View File

@ -11,10 +11,12 @@ import net.shadowfacts.cacao.util.texture.Texture
* *
* @author shadowfacts * @author shadowfacts
*/ */
class TextureView(var texture: Texture): View() { class TextureView(var texture: Texture?): View() {
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) { override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
RenderHelper.draw(matrixStack, bounds, texture) texture?.also {
RenderHelper.draw(matrixStack, bounds, it)
}
} }
} }

View File

@ -0,0 +1,21 @@
package net.shadowfacts.phycon
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.api.PhyConAPI
import net.shadowfacts.phycon.api.PhyConPlugin
import net.shadowfacts.phycon.api.TerminalSettingKey
import net.shadowfacts.phycon.util.SortMode
/**
* @author shadowfacts
*/
object DefaultPlugin: PhyConPlugin {
lateinit var SORT_MODE: TerminalSettingKey<SortMode>
private set
override fun initializePhyCon(api: PhyConAPI) {
SORT_MODE = api.registerTerminalSetting(Identifier(PhysicalConnectivity.MODID, "sort"), SortMode.COUNT_HIGH_FIRST)
}
}

View File

@ -0,0 +1,18 @@
package net.shadowfacts.phycon
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.api.PhyConAPI
import net.shadowfacts.phycon.api.TerminalSetting
import net.shadowfacts.phycon.api.TerminalSettingKey
import net.shadowfacts.phycon.util.TerminalSettings
/**
* @author shadowfacts
*/
object PhyConAPIImpl: PhyConAPI {
override fun <E> registerTerminalSetting(id: Identifier, defaultValue: E): TerminalSettingKey<E> where E: Enum<E>, E: TerminalSetting? {
return TerminalSettings.register(id, defaultValue)
}
}

View File

@ -2,6 +2,8 @@ package net.shadowfacts.phycon
import net.fabricmc.api.ModInitializer import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.fabricmc.loader.api.FabricLoader
import net.shadowfacts.phycon.api.PhyConPlugin
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyItems import net.shadowfacts.phycon.init.PhyItems
@ -27,6 +29,10 @@ object PhysicalConnectivity: ModInitializer {
registerGlobalReceiver(C2STerminalRequestItem) registerGlobalReceiver(C2STerminalRequestItem)
registerGlobalReceiver(C2STerminalUpdateDisplayedItems) registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
registerGlobalReceiver(C2SConfigureDevice) registerGlobalReceiver(C2SConfigureDevice)
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
it.initializePhyCon(PhyConAPIImpl)
}
} }
private fun registerGlobalReceiver(receiver: ServerReceiver) { private fun registerGlobalReceiver(receiver: ServerReceiver) {

View File

@ -14,12 +14,15 @@ import net.shadowfacts.phycon.client.PhyExtendedModelProvider
import net.shadowfacts.phycon.client.PhyModelProvider import net.shadowfacts.phycon.client.PhyModelProvider
import net.shadowfacts.phycon.networking.ClientReceiver import net.shadowfacts.phycon.networking.ClientReceiver
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
import net.shadowfacts.phycon.util.TerminalSettings
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
object PhysicalConnectivityClient: ClientModInitializer { object PhysicalConnectivityClient: ClientModInitializer {
val terminalSettings = TerminalSettings()
var screenMaterial: RenderMaterial? = null var screenMaterial: RenderMaterial? = null
private set private set

View File

@ -0,0 +1,72 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.client.util.math.MatrixStack
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.geometry.Size
import net.shadowfacts.cacao.util.EnumHelper
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.util.texture.Texture
import net.shadowfacts.cacao.view.TextureView
import net.shadowfacts.cacao.view.button.AbstractButton
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.api.TerminalSetting
import net.shadowfacts.phycon.util.TerminalSettings
import java.util.EnumMap
/**
* @author shadowfacts
*/
class SettingButton<E>(
val key: TerminalSettings.SettingKey<E>,
): AbstractButton<SettingButton<E>>(
TextureView(null).apply {
intrinsicContentSize = Size(16.0, 16.0)
},
padding = 2.0
) where E: Enum<E>, E: TerminalSetting {
private val textureCache = EnumMap<E, Texture>(key.clazz)
private val textureView: TextureView
get() = content as TextureView
init {
updateTexture()
}
private fun updateTexture() {
textureView.texture = textureCache.getOrPut(key.value) {
val uv = key.value.uv
Texture(key.value.iconTexture, uv[0], uv[1])
}
}
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
if (!disabled) {
val newValue = when (mouseButton) {
MouseButton.LEFT -> EnumHelper.next(key.value)
MouseButton.RIGHT -> EnumHelper.previous(key.value)
else -> {
return false
}
}
PhysicalConnectivityClient.terminalSettings[key] = newValue
updateTexture()
}
return super.mouseClicked(point, mouseButton)
}
override fun draw(matrixStack: MatrixStack, mouse: Point, delta: Float) {
super.draw(matrixStack, mouse, delta)
if (mouse in bounds) {
key.value.tooltip?.also {
window!!.drawTooltip(listOf(it))
}
}
}
}

View File

@ -1,57 +0,0 @@
package net.shadowfacts.phycon.block.terminal
import net.minecraft.util.Identifier
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.geometry.Size
import net.shadowfacts.cacao.util.EnumHelper
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.util.texture.Texture
import net.shadowfacts.cacao.view.TextureView
import net.shadowfacts.cacao.view.button.AbstractButton
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.util.SortMode
/**
* @author shadowfacts
*/
class SortModeButton(
initialValue: SortMode,
): AbstractButton<SortModeButton>(
TextureView(TEXTURES[initialValue]!!).apply {
intrinsicContentSize = Size(16.0, 16.0)
}
) {
companion object {
private val ID = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
private val TEXTURES = mapOf(
SortMode.COUNT_HIGH_FIRST to Texture(ID, 0, 230),
SortMode.COUNT_LOW_FIRST to Texture(ID, 16, 230),
SortMode.ALPHABETICAL to Texture(ID, 32, 230),
)
}
private val textureView: TextureView
get() = content as TextureView
var value: SortMode = initialValue
set(value) {
field = value
textureView.texture = TEXTURES[value]!!
}
override fun mouseClicked(point: Point, mouseButton: MouseButton): Boolean {
if (!disabled) {
value = when (mouseButton) {
MouseButton.LEFT -> EnumHelper.next(value)
MouseButton.RIGHT -> EnumHelper.previous(value)
else -> {
return false
}
}
}
return super.mouseClicked(point, mouseButton)
}
}

View File

@ -57,6 +57,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
private var observers = 0 private var observers = 0
val cachedNetItems = ItemStackCollections.intMap() val cachedNetItems = ItemStackCollections.intMap()
// todo: multiple players could have the terminal open simultaneously
var netItemObserver: WeakReference<NetItemObserver>? = null var netItemObserver: WeakReference<NetItemObserver>? = null
init { init {
@ -117,7 +118,9 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
private fun updateAndSync() { private fun updateAndSync() {
updateNetItems() updateNetItems()
// syncs the internal buffer to the client
sync() sync()
// syncs the open container (if any) to the client
netItemObserver?.get()?.netItemsChanged() netItemObserver?.get()?.netItemsChanged()
} }
@ -153,14 +156,6 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
finishable.forEach(::stackLocateRequestCompleted) finishable.forEach(::stackLocateRequestCompleted)
} }
fun addObserver() {
observers++
}
fun removeObserver() {
observers--
}
override fun tick() { override fun tick() {
super.tick() super.tick()
@ -171,10 +166,6 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
if (counter % 20 == 0L && !world!!.isClient) { if (counter % 20 == 0L && !world!!.isClient) {
beginInsertions() beginInsertions()
if (observers > 0) {
updateAndSync()
}
} }
} }
@ -197,7 +188,6 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
} }
player.openHandledScreen(factory) player.openHandledScreen(factory)
} }
addObserver()
} }
fun requestItem(stack: ItemStack, amount: Int = stack.count) { fun requestItem(stack: ItemStack, amount: Int = stack.count) {

View File

@ -53,7 +53,6 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
var searchQuery = "" var searchQuery = ""
var scrollPosition = 0.0 var scrollPosition = 0.0
var sortMode = SortMode.COUNT_HIGH_FIRST
init { init {
backgroundWidth = 252 backgroundWidth = 252
@ -72,7 +71,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
fun requestUpdatedItems() { fun requestUpdatedItems() {
val player = MinecraftClient.getInstance().player!! val player = MinecraftClient.getInstance().player!!
player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchQuery, sortMode, scrollPosition.toFloat())) player.networkHandler.sendPacket(C2STerminalUpdateDisplayedItems(handler.terminal, searchQuery, scrollPosition.toFloat()))
} }
private fun showRequestAmountDialog(stack: ItemStack) { private fun showRequestAmountDialog(stack: ItemStack) {

View File

@ -10,11 +10,13 @@ import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.DefaultPlugin
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyScreens import net.shadowfacts.phycon.init.PhyScreens
import net.shadowfacts.phycon.networking.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.copyWithCount import net.shadowfacts.phycon.util.copyWithCount
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.math.ceil import kotlin.math.ceil
@ -25,7 +27,11 @@ import kotlin.math.roundToInt
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL, syncId), class TerminalScreenHandler(
syncId: Int,
val playerInv: PlayerInventory,
val terminal: TerminalBlockEntity,
): ScreenHandler(PhyScreens.TERMINAL, syncId),
TerminalBlockEntity.NetItemObserver { TerminalBlockEntity.NetItemObserver {
companion object { companion object {
@ -36,8 +42,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
private val fakeInv = FakeInventory(this) private val fakeInv = FakeInventory(this)
private var searchQuery: String = "" private var searchQuery: String = ""
var sortMode = SortMode.COUNT_HIGH_FIRST private var settings = TerminalSettings()
private set
var totalEntries = 0 var totalEntries = 0
private set private set
var scrollPosition = 0f var scrollPosition = 0f
@ -54,12 +59,17 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
private set private set
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf): constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!) this(
syncId,
playerInv,
PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!
)
init { init {
if (!terminal.world!!.isClient) { if (!terminal.world!!.isClient) {
assert(terminal.netItemObserver?.get() === null)
terminal.netItemObserver = WeakReference(this) terminal.netItemObserver = WeakReference(this)
netItemsChanged() // intentionally don't call netItemsChanged immediately, we need to wait for the client to send us its settings
} }
// network // network
@ -107,7 +117,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
totalEntries = filtered.size totalEntries = filtered.size
val sorted = val sorted =
when (sortMode) { when (settings[DefaultPlugin.SORT_MODE]) {
SortMode.COUNT_HIGH_FIRST -> filtered.sortedByDescending { it.intValue } SortMode.COUNT_HIGH_FIRST -> filtered.sortedByDescending { it.intValue }
SortMode.COUNT_LOW_FIRST -> filtered.sortedBy { it.intValue } SortMode.COUNT_LOW_FIRST -> filtered.sortedBy { it.intValue }
SortMode.ALPHABETICAL -> filtered.sortedBy { it.key.name.string } SortMode.ALPHABETICAL -> filtered.sortedBy { it.key.name.string }
@ -120,7 +130,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
// itemEntries = sorted.map { Entry(it.key, it.intValue) } // itemEntries = sorted.map { Entry(it.key, it.intValue) }
(player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, sortMode, scrollPosition, totalEntries)) (player as ServerPlayerEntity).networkHandler.sendPacket(S2CTerminalUpdateDisplayedItems(terminal, itemEntries, searchQuery, settings, scrollPosition, totalEntries))
} }
fun totalRows(): Int { fun totalRows(): Int {
@ -139,18 +149,17 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
return currentScrollOffsetInRows() * 9 return currentScrollOffsetInRows() * 9
} }
fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, sortMode: SortMode, scrollPosition: Float) { fun sendUpdatedItemsToClient(player: ServerPlayerEntity, query: String, settings: TerminalSettings, scrollPosition: Float) {
this.searchQuery = query this.searchQuery = query
this.sortMode = sortMode this.settings = settings
this.scrollPosition = scrollPosition this.scrollPosition = scrollPosition
netItemsChanged() netItemsChanged()
} }
fun receivedUpdatedItemsFromServer(entries: List<Entry>, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int) { fun receivedUpdatedItemsFromServer(entries: List<Entry>, query: String, scrollPosition: Float, totalEntries: Int) {
assert(playerInv.player.world.isClient) assert(playerInv.player.world.isClient)
this.searchQuery = query this.searchQuery = query
this.sortMode = sortMode
this.scrollPosition = scrollPosition this.scrollPosition = scrollPosition
this.totalEntries = totalEntries this.totalEntries = totalEntries
itemEntries = entries itemEntries = entries
@ -163,7 +172,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
override fun close(player: PlayerEntity) { override fun close(player: PlayerEntity) {
super.close(player) super.close(player)
terminal.removeObserver() terminal.netItemObserver = null
} }
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack { override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {

View File

@ -2,15 +2,18 @@ package net.shadowfacts.phycon.block.terminal
import net.minecraft.text.TranslatableText import net.minecraft.text.TranslatableText
import net.minecraft.util.math.MathHelper import net.minecraft.util.math.MathHelper
import net.shadowfacts.cacao.geometry.Axis
import net.shadowfacts.cacao.geometry.Point import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.util.Color import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.util.MouseButton import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.view.Label import net.shadowfacts.cacao.view.Label
import net.shadowfacts.cacao.view.StackView
import net.shadowfacts.cacao.view.View import net.shadowfacts.cacao.view.View
import net.shadowfacts.cacao.view.textfield.TextField import net.shadowfacts.cacao.view.textfield.TextField
import net.shadowfacts.cacao.viewcontroller.ViewController import net.shadowfacts.cacao.viewcontroller.ViewController
import net.shadowfacts.kiwidsl.dsl import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.util.SortMode import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
/** /**
* @author shadowfacts * @author shadowfacts
@ -22,7 +25,7 @@ class TerminalViewController(
): ViewController() { ): ViewController() {
private lateinit var scrollTrack: ScrollTrackView private lateinit var scrollTrack: ScrollTrackView
lateinit var sortMode: SortModeButton lateinit var settingsView: View
private set private set
lateinit var searchField: TextField lateinit var searchField: TextField
private set private set
@ -84,8 +87,12 @@ class TerminalViewController(
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged)) scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
sortMode = view.addSubview(SortModeButton(SortMode.COUNT_HIGH_FIRST)).apply { val settingsStack = view.addSubview(StackView(Axis.VERTICAL, spacing = 2.0))
handler = ::sortModeChanged settingsView = settingsStack
TerminalSettings.allKeys.forEach { key ->
val button = SettingButton(key)
button.handler = { settingsChanged() }
settingsStack.addArrangedSubview(button)
} }
view.solver.dsl { view.solver.dsl {
@ -108,10 +115,8 @@ class TerminalViewController(
scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1) scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1)
scrollTrack.widthAnchor equalTo 12 scrollTrack.widthAnchor equalTo 12
sortMode.leftAnchor equalTo pane.rightAnchor + 4 settingsStack.leftAnchor equalTo (pane.rightAnchor + 4)
sortMode.topAnchor equalTo pane.topAnchor settingsStack.topAnchor equalTo pane.topAnchor
sortMode.widthAnchor equalTo 20
sortMode.heightAnchor equalTo 20
} }
} }
@ -131,8 +136,7 @@ class TerminalViewController(
} }
} }
private fun sortModeChanged(button: SortModeButton) { private fun settingsChanged() {
screen.sortMode = button.value
screen.requestUpdatedItems() screen.requestUpdatedItems()
} }

View File

@ -10,9 +10,11 @@ import net.minecraft.server.network.ServerPlayNetworkHandler
import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
import net.shadowfacts.phycon.util.SortMode import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
/** /**
* @author shadowfacts * @author shadowfacts
@ -21,14 +23,14 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "terminal_update_displayed") override val CHANNEL = Identifier(PhysicalConnectivity.MODID, "terminal_update_displayed")
operator fun invoke(terminal: TerminalBlockEntity, query: String, sortMode: SortMode, scrollPosition: Float): Packet<*> { operator fun invoke(terminal: TerminalBlockEntity, query: String, scrollPosition: Float): Packet<*> {
val buf = PacketByteBufs.create() val buf = PacketByteBufs.create()
buf.writeIdentifier(terminal.world!!.registryKey.value) buf.writeIdentifier(terminal.world!!.registryKey.value)
buf.writeBlockPos(terminal.pos) buf.writeBlockPos(terminal.pos)
buf.writeString(query) buf.writeString(query)
buf.writeVarInt(sortMode.ordinal) buf.writeCompoundTag(PhysicalConnectivityClient.terminalSettings.toTag())
buf.writeFloat(scrollPosition) buf.writeFloat(scrollPosition)
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf) return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
@ -38,7 +40,8 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
val dimID = buf.readIdentifier() val dimID = buf.readIdentifier()
val pos = buf.readBlockPos() val pos = buf.readBlockPos()
val query = buf.readString() val query = buf.readString()
val sortMode = SortMode.values()[buf.readVarInt()] val settings = TerminalSettings()
settings.fromTag(buf.readCompoundTag()!!)
val scrollPosition = buf.readFloat() val scrollPosition = buf.readFloat()
server.execute { server.execute {
@ -46,7 +49,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
val screenHandler = player.currentScreenHandler val screenHandler = player.currentScreenHandler
if (screenHandler !is TerminalScreenHandler) return@execute if (screenHandler !is TerminalScreenHandler) return@execute
if (screenHandler.terminal.pos != pos) return@execute if (screenHandler.terminal.pos != pos) return@execute
screenHandler.sendUpdatedItemsToClient(player, query, sortMode, scrollPosition) screenHandler.sendUpdatedItemsToClient(player, query, settings, scrollPosition)
} }
} }
} }

View File

@ -7,9 +7,11 @@ import net.minecraft.client.MinecraftClient
import net.minecraft.client.network.ClientPlayNetworkHandler import net.minecraft.client.network.ClientPlayNetworkHandler
import net.minecraft.network.Packet import net.minecraft.network.Packet
import net.minecraft.network.PacketByteBuf import net.minecraft.network.PacketByteBuf
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
import net.shadowfacts.phycon.util.SortMode import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
import net.shadowfacts.phycon.util.readItemStackWithoutCount import net.shadowfacts.phycon.util.readItemStackWithoutCount
import net.shadowfacts.phycon.util.writeItemStackWithoutCount import net.shadowfacts.phycon.util.writeItemStackWithoutCount
@ -19,7 +21,7 @@ import net.shadowfacts.phycon.util.writeItemStackWithoutCount
object S2CTerminalUpdateDisplayedItems: ClientReceiver { object S2CTerminalUpdateDisplayedItems: ClientReceiver {
override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL override val CHANNEL = C2STerminalUpdateDisplayedItems.CHANNEL
operator fun invoke(terminal: TerminalBlockEntity, entries: List<TerminalScreenHandler.Entry>, query: String, sortMode: SortMode, scrollPosition: Float, totalEntries: Int): Packet<*> { operator fun invoke(terminal: TerminalBlockEntity, entries: List<TerminalScreenHandler.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)
@ -32,7 +34,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
} }
buf.writeString(query) buf.writeString(query)
buf.writeVarInt(sortMode.ordinal) buf.writeCompoundTag(settings.toTag())
buf.writeFloat(scrollPosition) buf.writeFloat(scrollPosition)
buf.writeInt(totalEntries) buf.writeInt(totalEntries)
@ -48,7 +50,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
entries.add(TerminalScreenHandler.Entry(buf.readItemStackWithoutCount(), buf.readVarInt())) entries.add(TerminalScreenHandler.Entry(buf.readItemStackWithoutCount(), buf.readVarInt()))
} }
val query = buf.readString() val query = buf.readString()
val sortMode = SortMode.values()[buf.readVarInt()] PhysicalConnectivityClient.terminalSettings.fromTag(buf.readCompoundTag()!!)
val scrollPosition = buf.readFloat() val scrollPosition = buf.readFloat()
val totalEntries = buf.readInt() val totalEntries = buf.readInt()
@ -57,7 +59,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
val screenHandler = client.player!!.currentScreenHandler val screenHandler = client.player!!.currentScreenHandler
if (screenHandler !is TerminalScreenHandler) return@execute if (screenHandler !is TerminalScreenHandler) return@execute
if (screenHandler.terminal.pos != pos) return@execute if (screenHandler.terminal.pos != pos) return@execute
screenHandler.receivedUpdatedItemsFromServer(entries, query, sortMode, scrollPosition, totalEntries) screenHandler.receivedUpdatedItemsFromServer(entries, query, scrollPosition, totalEntries)
} }
} }
} }

View File

@ -2,20 +2,30 @@ package net.shadowfacts.phycon.util
import net.minecraft.text.LiteralText import net.minecraft.text.LiteralText
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.TerminalSetting
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
enum class SortMode: RotatableEnum { enum class SortMode: TerminalSetting {
COUNT_HIGH_FIRST, COUNT_HIGH_FIRST,
COUNT_LOW_FIRST, COUNT_LOW_FIRST,
ALPHABETICAL; ALPHABETICAL;
val tooltip: Text override fun getIconTexture() = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
get() = when (this) {
COUNT_HIGH_FIRST -> LiteralText("Count, highest first") override fun getUV() = when (this) {
COUNT_LOW_FIRST -> LiteralText("Count, lowest first") COUNT_HIGH_FIRST -> intArrayOf(0, 230)
ALPHABETICAL -> LiteralText("Name") COUNT_LOW_FIRST -> intArrayOf(16, 230)
} ALPHABETICAL -> intArrayOf(32, 230)
}
override fun getTooltip() = when (this) {
COUNT_HIGH_FIRST -> LiteralText("Count, highest first")
COUNT_LOW_FIRST -> LiteralText("Count, lowest first")
ALPHABETICAL -> LiteralText("Name")
}
} }

View File

@ -0,0 +1,83 @@
package net.shadowfacts.phycon.util
import net.minecraft.nbt.CompoundTag
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.api.TerminalSettingKey
import net.shadowfacts.phycon.api.TerminalSetting
/**
* @author shadowfacts
*/
class TerminalSettings {
companion object {
private val SETTINGS = mutableMapOf<Identifier, SettingKey<*>>()
private val DEFAULTS = mutableMapOf<TerminalSettingKey<*>, Enum<*>>()
val allKeys: Collection<SettingKey<*>>
get() = SETTINGS.values
fun <E> register(id: Identifier, defaultValue: E): SettingKey<E> where E: Enum<E>, E: TerminalSetting {
val setting = SettingKey(id, defaultValue.javaClass)
SETTINGS[id] = setting
DEFAULTS[setting] = defaultValue
return setting
}
fun <E> getDefault(setting: TerminalSettingKey<E>): E where E: Enum<E>, E: TerminalSetting {
@Suppress("UNCHECKED_CAST")
return DEFAULTS[setting] as E
}
}
class SettingKey<E>(
val id: Identifier,
val clazz: Class<E>,
): TerminalSettingKey<E> where E: Enum<E>, E: TerminalSetting {
fun value(ordinal: Int): E? {
@Suppress("UNCHECKED_CAST")
return if (clazz.enumConstants.size <= ordinal) null
else clazz.enumConstants[ordinal] as E
}
override fun getID() = id
override fun getValue() = PhysicalConnectivityClient.terminalSettings[this]
}
private val settings = mutableMapOf<TerminalSettingKey<*>, Enum<*>>()
operator fun <E> get(key: TerminalSettingKey<E>): E where E: Enum<E>, E: TerminalSetting {
@Suppress("UNCHECKED_CAST")
return settings[key] as? E ?: getDefault(key)
}
operator fun <E> set(key: SettingKey<E>, value: E) where E: Enum<E>, E: TerminalSetting {
settings[key] = value
}
fun toTag(): CompoundTag {
return CompoundTag().also {
settings.forEach { (s, v) ->
it.putInt(s.id.toString(), v.ordinal)
}
}
}
fun fromTag(tag: CompoundTag) {
settings.clear()
tag.keys.forEach { k ->
val id = Identifier.tryParse(k) ?: return@forEach
val setting = SETTINGS[id] ?: return@forEach
setValueFromOrdinal(setting, tag.getInt(k))
}
}
private fun <E> setValueFromOrdinal(setting: SettingKey<E>, ordinal: Int) where E: Enum<E>, E: TerminalSetting {
val value = setting.value(ordinal)
if (value != null) {
this[setting] = value
}
}
}

View File

@ -35,6 +35,12 @@
"adapter": "kotlin", "adapter": "kotlin",
"value": "net.shadowfacts.phycon.PhysicalConnectivityClient" "value": "net.shadowfacts.phycon.PhysicalConnectivityClient"
} }
],
"phycon": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.DefaultPlugin"
}
] ]
}, },
"mixins": [ "mixins": [