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) {
BaseBoundsHandler.getInstance().registerExclusionZones(TerminalScreen::class.java) {
val screen = MinecraftClient.getInstance().currentScreen as TerminalScreen
val button = screen.terminalVC.sortMode
val rect = button.convert(button.bounds, to = null)
val view = screen.terminalVC.settingsView
val rect = view.convert(view.bounds, to = null)
listOf(
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
*/
class TextureView(var texture: Texture): View() {
class TextureView(var texture: Texture?): View() {
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.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.PhyBlocks
import net.shadowfacts.phycon.init.PhyItems
@ -27,6 +29,10 @@ object PhysicalConnectivity: ModInitializer {
registerGlobalReceiver(C2STerminalRequestItem)
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
registerGlobalReceiver(C2SConfigureDevice)
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
it.initializePhyCon(PhyConAPIImpl)
}
}
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.networking.ClientReceiver
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
import net.shadowfacts.phycon.util.TerminalSettings
/**
* @author shadowfacts
*/
object PhysicalConnectivityClient: ClientModInitializer {
val terminalSettings = TerminalSettings()
var screenMaterial: RenderMaterial? = null
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
val cachedNetItems = ItemStackCollections.intMap()
// todo: multiple players could have the terminal open simultaneously
var netItemObserver: WeakReference<NetItemObserver>? = null
init {
@ -117,7 +118,9 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
private fun updateAndSync() {
updateNetItems()
// syncs the internal buffer to the client
sync()
// syncs the open container (if any) to the client
netItemObserver?.get()?.netItemsChanged()
}
@ -153,14 +156,6 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
finishable.forEach(::stackLocateRequestCompleted)
}
fun addObserver() {
observers++
}
fun removeObserver() {
observers--
}
override fun tick() {
super.tick()
@ -171,10 +166,6 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
if (counter % 20 == 0L && !world!!.isClient) {
beginInsertions()
if (observers > 0) {
updateAndSync()
}
}
}
@ -197,7 +188,6 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL),
}
player.openHandledScreen(factory)
}
addObserver()
}
fun requestItem(stack: ItemStack, amount: Int = stack.count) {

View File

@ -53,7 +53,6 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
var searchQuery = ""
var scrollPosition = 0.0
var sortMode = SortMode.COUNT_HIGH_FIRST
init {
backgroundWidth = 252
@ -72,7 +71,7 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
fun requestUpdatedItems() {
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) {

View File

@ -10,11 +10,13 @@ import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry
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.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
import net.shadowfacts.phycon.util.copyWithCount
import java.lang.ref.WeakReference
import kotlin.math.ceil
@ -25,7 +27,11 @@ import kotlin.math.roundToInt
/**
* @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 {
companion object {
@ -36,8 +42,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
private val fakeInv = FakeInventory(this)
private var searchQuery: String = ""
var sortMode = SortMode.COUNT_HIGH_FIRST
private set
private var settings = TerminalSettings()
var totalEntries = 0
private set
var scrollPosition = 0f
@ -54,12 +59,17 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
private set
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 {
if (!terminal.world!!.isClient) {
assert(terminal.netItemObserver?.get() === null)
terminal.netItemObserver = WeakReference(this)
netItemsChanged()
// intentionally don't call netItemsChanged immediately, we need to wait for the client to send us its settings
}
// network
@ -107,7 +117,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
totalEntries = filtered.size
val sorted =
when (sortMode) {
when (settings[DefaultPlugin.SORT_MODE]) {
SortMode.COUNT_HIGH_FIRST -> filtered.sortedByDescending { it.intValue }
SortMode.COUNT_LOW_FIRST -> filtered.sortedBy { it.intValue }
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) }
(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 {
@ -139,18 +149,17 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
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.sortMode = sortMode
this.settings = settings
this.scrollPosition = scrollPosition
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)
this.searchQuery = query
this.sortMode = sortMode
this.scrollPosition = scrollPosition
this.totalEntries = totalEntries
itemEntries = entries
@ -163,7 +172,7 @@ class TerminalScreenHandler(syncId: Int, val playerInv: PlayerInventory, val ter
override fun close(player: PlayerEntity) {
super.close(player)
terminal.removeObserver()
terminal.netItemObserver = null
}
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.util.math.MathHelper
import net.shadowfacts.cacao.geometry.Axis
import net.shadowfacts.cacao.geometry.Point
import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.util.MouseButton
import net.shadowfacts.cacao.view.Label
import net.shadowfacts.cacao.view.StackView
import net.shadowfacts.cacao.view.View
import net.shadowfacts.cacao.view.textfield.TextField
import net.shadowfacts.cacao.viewcontroller.ViewController
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
/**
* @author shadowfacts
@ -22,7 +25,7 @@ class TerminalViewController(
): ViewController() {
private lateinit var scrollTrack: ScrollTrackView
lateinit var sortMode: SortModeButton
lateinit var settingsView: View
private set
lateinit var searchField: TextField
private set
@ -84,8 +87,12 @@ class TerminalViewController(
scrollTrack = view.addSubview(ScrollTrackView(::scrollPositionChanged))
sortMode = view.addSubview(SortModeButton(SortMode.COUNT_HIGH_FIRST)).apply {
handler = ::sortModeChanged
val settingsStack = view.addSubview(StackView(Axis.VERTICAL, spacing = 2.0))
settingsView = settingsStack
TerminalSettings.allKeys.forEach { key ->
val button = SettingButton(key)
button.handler = { settingsChanged() }
settingsStack.addArrangedSubview(button)
}
view.solver.dsl {
@ -108,10 +115,8 @@ class TerminalViewController(
scrollTrack.bottomAnchor equalTo (network.bottomAnchor - 1)
scrollTrack.widthAnchor equalTo 12
sortMode.leftAnchor equalTo pane.rightAnchor + 4
sortMode.topAnchor equalTo pane.topAnchor
sortMode.widthAnchor equalTo 20
sortMode.heightAnchor equalTo 20
settingsStack.leftAnchor equalTo (pane.rightAnchor + 4)
settingsStack.topAnchor equalTo pane.topAnchor
}
}
@ -131,8 +136,7 @@ class TerminalViewController(
}
}
private fun sortModeChanged(button: SortModeButton) {
screen.sortMode = button.value
private fun settingsChanged() {
screen.requestUpdatedItems()
}

View File

@ -10,9 +10,11 @@ import net.minecraft.server.network.ServerPlayNetworkHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
/**
* @author shadowfacts
@ -21,14 +23,14 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
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()
buf.writeIdentifier(terminal.world!!.registryKey.value)
buf.writeBlockPos(terminal.pos)
buf.writeString(query)
buf.writeVarInt(sortMode.ordinal)
buf.writeCompoundTag(PhysicalConnectivityClient.terminalSettings.toTag())
buf.writeFloat(scrollPosition)
return ClientPlayNetworking.createC2SPacket(CHANNEL, buf)
@ -38,7 +40,8 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
val dimID = buf.readIdentifier()
val pos = buf.readBlockPos()
val query = buf.readString()
val sortMode = SortMode.values()[buf.readVarInt()]
val settings = TerminalSettings()
settings.fromTag(buf.readCompoundTag()!!)
val scrollPosition = buf.readFloat()
server.execute {
@ -46,7 +49,7 @@ object C2STerminalUpdateDisplayedItems: ServerReceiver {
val screenHandler = player.currentScreenHandler
if (screenHandler !is TerminalScreenHandler) 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.network.Packet
import net.minecraft.network.PacketByteBuf
import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.TerminalBlockEntity
import net.shadowfacts.phycon.block.terminal.TerminalScreenHandler
import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings
import net.shadowfacts.phycon.util.readItemStackWithoutCount
import net.shadowfacts.phycon.util.writeItemStackWithoutCount
@ -19,7 +21,7 @@ import net.shadowfacts.phycon.util.writeItemStackWithoutCount
object S2CTerminalUpdateDisplayedItems: ClientReceiver {
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()
buf.writeIdentifier(terminal.world!!.registryKey.value)
@ -32,7 +34,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
}
buf.writeString(query)
buf.writeVarInt(sortMode.ordinal)
buf.writeCompoundTag(settings.toTag())
buf.writeFloat(scrollPosition)
buf.writeInt(totalEntries)
@ -48,7 +50,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
entries.add(TerminalScreenHandler.Entry(buf.readItemStackWithoutCount(), buf.readVarInt()))
}
val query = buf.readString()
val sortMode = SortMode.values()[buf.readVarInt()]
PhysicalConnectivityClient.terminalSettings.fromTag(buf.readCompoundTag()!!)
val scrollPosition = buf.readFloat()
val totalEntries = buf.readInt()
@ -57,7 +59,7 @@ object S2CTerminalUpdateDisplayedItems: ClientReceiver {
val screenHandler = client.player!!.currentScreenHandler
if (screenHandler !is TerminalScreenHandler) 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.Text
import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.TerminalSetting
/**
* @author shadowfacts
*/
enum class SortMode: RotatableEnum {
enum class SortMode: TerminalSetting {
COUNT_HIGH_FIRST,
COUNT_LOW_FIRST,
ALPHABETICAL;
val tooltip: Text
get() = when (this) {
COUNT_HIGH_FIRST -> LiteralText("Count, highest first")
COUNT_LOW_FIRST -> LiteralText("Count, lowest first")
ALPHABETICAL -> LiteralText("Name")
}
override fun getIconTexture() = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
override fun getUV() = when (this) {
COUNT_HIGH_FIRST -> intArrayOf(0, 230)
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",
"value": "net.shadowfacts.phycon.PhysicalConnectivityClient"
}
],
"phycon": [
{
"adapter": "kotlin",
"value": "net.shadowfacts.phycon.DefaultPlugin"
}
]
},
"mixins": [