Add /firm exporthotm to save hotm presets
This commit is contained in:
@@ -65,6 +65,10 @@ object Firmament {
|
|||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
encodeDefaults = true
|
encodeDefaults = true
|
||||||
}
|
}
|
||||||
|
val tightJson = Json(from = json) {
|
||||||
|
prettyPrint = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val httpClient by lazy {
|
val httpClient by lazy {
|
||||||
HttpClient {
|
HttpClient {
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
package moe.nea.firmament.events
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
import net.minecraft.client.texture.Sprite
|
||||||
import net.minecraft.screen.slot.Slot
|
import net.minecraft.screen.slot.Slot
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
|
||||||
interface SlotRenderEvents {
|
interface SlotRenderEvents {
|
||||||
val context: DrawContext
|
val context: DrawContext
|
||||||
@@ -12,6 +15,13 @@ interface SlotRenderEvents {
|
|||||||
val mouseY: Int
|
val mouseY: Int
|
||||||
val delta: Float
|
val delta: Float
|
||||||
|
|
||||||
|
fun highlight(sprite: Sprite) {
|
||||||
|
context.drawSprite(
|
||||||
|
slot.x, slot.y, 0, 16, 16,
|
||||||
|
sprite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
data class Before(
|
data class Before(
|
||||||
override val context: DrawContext, override val slot: Slot,
|
override val context: DrawContext, override val slot: Slot,
|
||||||
override val mouseX: Int,
|
override val mouseX: Int,
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ object CommissionFeatures {
|
|||||||
if (MC.screenName != "Commissions") return
|
if (MC.screenName != "Commissions") return
|
||||||
val stack = event.slot.stack
|
val stack = event.slot.stack
|
||||||
if(stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) {
|
if(stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) {
|
||||||
event.context.drawSprite(
|
event.highlight(
|
||||||
event.slot.x, event.slot.y, 0, 16, 16,
|
|
||||||
MC.guiAtlasManager.getSprite(Identifier.of("firmament:completed_commission_background"))
|
MC.guiAtlasManager.getSprite(Identifier.of("firmament:completed_commission_background"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
241
src/main/kotlin/features/mining/HotmPresets.kt
Normal file
241
src/main/kotlin/features/mining/HotmPresets.kt
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
package moe.nea.firmament.features.mining
|
||||||
|
|
||||||
|
import me.shedaniel.math.Rectangle
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import net.minecraft.block.Blocks
|
||||||
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||||
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
|
import net.minecraft.item.Items
|
||||||
|
import net.minecraft.screen.GenericContainerScreenHandler
|
||||||
|
import net.minecraft.screen.ScreenHandler
|
||||||
|
import net.minecraft.screen.slot.Slot
|
||||||
|
import net.minecraft.screen.slot.SlotActionType
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.annotations.Subscribe
|
||||||
|
import moe.nea.firmament.commands.thenExecute
|
||||||
|
import moe.nea.firmament.events.ChestInventoryUpdateEvent
|
||||||
|
import moe.nea.firmament.events.CommandEvent
|
||||||
|
import moe.nea.firmament.events.ScreenChangeEvent
|
||||||
|
import moe.nea.firmament.events.SlotRenderEvents
|
||||||
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
|
import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
|
||||||
|
import moe.nea.firmament.util.ClipboardUtils
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.TemplateUtil
|
||||||
|
import moe.nea.firmament.util.TimeMark
|
||||||
|
import moe.nea.firmament.util.customgui.CustomGui
|
||||||
|
import moe.nea.firmament.util.customgui.customGui
|
||||||
|
import moe.nea.firmament.util.mc.CommonTextures
|
||||||
|
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||||
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
import moe.nea.firmament.util.useMatch
|
||||||
|
|
||||||
|
object HotmPresets {
|
||||||
|
object Config : ManagedConfig("hotm-presets", Category.MINING) {
|
||||||
|
}
|
||||||
|
|
||||||
|
val SHARE_PREFIX = "FIRMHOTM/"
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HotmPreset(
|
||||||
|
val perks: List<PerkPreset>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PerkPreset(val perkName: String)
|
||||||
|
|
||||||
|
var hotmCommandSent = TimeMark.farPast()
|
||||||
|
val hotmInventoryName = "Heart of the Mountain"
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun onScreenOpen(event: ScreenChangeEvent) {
|
||||||
|
val title = event.new?.title?.unformattedString
|
||||||
|
if (title != hotmInventoryName) return
|
||||||
|
val screen = event.new as? HandledScreen<*> ?: return
|
||||||
|
val oldHandler = (event.old as? HandledScreen<*>)?.customGui
|
||||||
|
if (oldHandler is HotmScrollPrompt) {
|
||||||
|
event.new.customGui = oldHandler
|
||||||
|
oldHandler.setNewScreen(screen)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (hotmCommandSent.passedTime() > 5.seconds) return
|
||||||
|
hotmCommandSent = TimeMark.farPast()
|
||||||
|
screen.customGui = HotmScrollPrompt(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
class HotmScrollPrompt(var screen: HandledScreen<*>) : CustomGui() {
|
||||||
|
var bounds = Rectangle(
|
||||||
|
0, 0, 0, 0
|
||||||
|
)
|
||||||
|
|
||||||
|
fun setNewScreen(screen: HandledScreen<*>) {
|
||||||
|
this.screen = screen
|
||||||
|
onInit()
|
||||||
|
hasScrolled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
|
drawContext.drawGuiTexture(
|
||||||
|
CommonTextures.genericWidget(),
|
||||||
|
bounds.x, bounds.y, 0,
|
||||||
|
bounds.width,
|
||||||
|
bounds.height,
|
||||||
|
)
|
||||||
|
drawContext.drawCenteredTextWithShadow(
|
||||||
|
MC.font,
|
||||||
|
if (hasAll) {
|
||||||
|
Text.translatable("firmament.hotmpreset.copied")
|
||||||
|
} else if (!hasScrolled) {
|
||||||
|
Text.translatable("firmament.hotmpreset.scrollprompt")
|
||||||
|
} else {
|
||||||
|
Text.translatable("firmament.hotmpreset.scrolled")
|
||||||
|
},
|
||||||
|
bounds.centerX,
|
||||||
|
bounds.centerY - 5,
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var hasScrolled = false
|
||||||
|
var hasAll = false
|
||||||
|
|
||||||
|
fun Slot.clickMiddleMouseButton(handler: ScreenHandler) {
|
||||||
|
MC.interactionManager?.clickSlot(
|
||||||
|
handler.syncId,
|
||||||
|
this.id,
|
||||||
|
2,
|
||||||
|
SlotActionType.CLONE,
|
||||||
|
MC.player
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Slot.clickRightMouseButton(handler: ScreenHandler) {
|
||||||
|
MC.interactionManager?.clickSlot(
|
||||||
|
handler.syncId,
|
||||||
|
this.id,
|
||||||
|
1,
|
||||||
|
SlotActionType.PICKUP,
|
||||||
|
MC.player
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClick(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||||
|
if (!hasScrolled) {
|
||||||
|
val slot = screen.screenHandler.getSlot(8)
|
||||||
|
println("Clicking ${slot.stack}")
|
||||||
|
slot.clickRightMouseButton(screen.screenHandler)
|
||||||
|
}
|
||||||
|
hasScrolled = true
|
||||||
|
return super.mouseClick(mouseX, mouseY, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldDrawForeground(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBounds(): List<Rectangle> {
|
||||||
|
return listOf(bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInit() {
|
||||||
|
bounds = Rectangle(
|
||||||
|
screen.width / 2 - 150,
|
||||||
|
screen.height / 2 - 100,
|
||||||
|
300, 200
|
||||||
|
)
|
||||||
|
val screen = screen as AccessorHandledScreen
|
||||||
|
screen.x_Firmament = bounds.x
|
||||||
|
screen.y_Firmament = bounds.y
|
||||||
|
screen.backgroundWidth_Firmament = bounds.width
|
||||||
|
screen.backgroundHeight_Firmament = bounds.height
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun moveSlot(slot: Slot) {
|
||||||
|
slot.x = -10000
|
||||||
|
}
|
||||||
|
|
||||||
|
val coveredRows = mutableSetOf<Int>()
|
||||||
|
val unlockedPerks = mutableSetOf<String>()
|
||||||
|
val allRows = (1..10).toSet()
|
||||||
|
|
||||||
|
fun onNewItems(event: ChestInventoryUpdateEvent) {
|
||||||
|
val handler = screen.screenHandler as? GenericContainerScreenHandler ?: return
|
||||||
|
for (it in handler.slots) {
|
||||||
|
if (it.inventory is PlayerInventory) continue
|
||||||
|
val stack = it.stack
|
||||||
|
val name = stack.displayNameAccordingToNbt.unformattedString
|
||||||
|
tierRegex.useMatch(name) {
|
||||||
|
coveredRows.add(group("tier").toInt())
|
||||||
|
}
|
||||||
|
if (stack.item == Items.DIAMOND
|
||||||
|
|| stack.item == Items.EMERALD
|
||||||
|
|| stack.item == Blocks.EMERALD_BLOCK.asItem()
|
||||||
|
) {
|
||||||
|
unlockedPerks.add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allRows == coveredRows) {
|
||||||
|
ClipboardUtils.setTextContent(TemplateUtil.encodeTemplate(SHARE_PREFIX, HotmPreset(
|
||||||
|
unlockedPerks.map { PerkPreset(it) }
|
||||||
|
)))
|
||||||
|
hasAll = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val tierRegex = "Tier (?<tier>[0-9]+)".toPattern()
|
||||||
|
var highlightedPerks: Set<String> = emptySet()
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun onSlotUpdates(event: ChestInventoryUpdateEvent) {
|
||||||
|
val customGui = (event.inventory as? HandledScreen<*>)?.customGui
|
||||||
|
if (customGui is HotmScrollPrompt) {
|
||||||
|
customGui.onNewItems(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun resetOnScreen(event: ScreenChangeEvent) {
|
||||||
|
if (event.new != null && event.new.title.unformattedString != hotmInventoryName) {
|
||||||
|
highlightedPerks = emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun onSlotRender(event: SlotRenderEvents.Before) {
|
||||||
|
if (hotmInventoryName == MC.screenName
|
||||||
|
&& event.slot.stack.displayNameAccordingToNbt.unformattedString in highlightedPerks
|
||||||
|
) {
|
||||||
|
event.highlight(MC.guiAtlasManager.getSprite(Firmament.identifier("hotm_perk_preset")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun onCommand(event: CommandEvent.SubCommand) {
|
||||||
|
event.subcommand("exporthotm") {
|
||||||
|
thenExecute {
|
||||||
|
hotmCommandSent = TimeMark.now()
|
||||||
|
MC.sendCommand("hotm")
|
||||||
|
source.sendFeedback(Text.translatable("firmament.hotmpreset.openinghotm"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.subcommand("importhotm") {
|
||||||
|
thenExecute {
|
||||||
|
val template =
|
||||||
|
TemplateUtil.maybeDecodeTemplate<HotmPreset>(SHARE_PREFIX, ClipboardUtils.getTextContents())
|
||||||
|
if (template == null) {
|
||||||
|
source.sendFeedback(Text.translatable("firmament.hotmpreset.failedimport"))
|
||||||
|
} else {
|
||||||
|
highlightedPerks = template.perks.mapTo(mutableSetOf()) { it.perkName }
|
||||||
|
source.sendFeedback(Text.translatable("firmament.hotmpreset.okayimport"))
|
||||||
|
MC.sendCommand("hotm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ package moe.nea.firmament.util
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlinx.serialization.DeserializationStrategy
|
import kotlinx.serialization.DeserializationStrategy
|
||||||
import kotlinx.serialization.SerializationStrategy
|
import kotlinx.serialization.SerializationStrategy
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ object TemplateUtil {
|
|||||||
|
|
||||||
fun <T> encodeTemplate(sharePrefix: String, data: T, serializer: SerializationStrategy<T>): String {
|
fun <T> encodeTemplate(sharePrefix: String, data: T, serializer: SerializationStrategy<T>): String {
|
||||||
require(sharePrefix.endsWith("/"))
|
require(sharePrefix.endsWith("/"))
|
||||||
return intoBase64Encoded(sharePrefix + Firmament.json.encodeToString(serializer, data))
|
return intoBase64Encoded(sharePrefix + Firmament.tightJson.encodeToString(serializer, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any> maybeDecodeTemplate(sharePrefix: String, data: String): T? =
|
inline fun <reified T : Any> maybeDecodeTemplate(sharePrefix: String, data: String): T? =
|
||||||
|
|||||||
7
src/main/kotlin/util/mc/CommonTextures.kt
Normal file
7
src/main/kotlin/util/mc/CommonTextures.kt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package moe.nea.firmament.util.mc
|
||||||
|
|
||||||
|
import moe.nea.firmament.Firmament
|
||||||
|
|
||||||
|
object CommonTextures {
|
||||||
|
fun genericWidget() = (Firmament.identifier("generic_vanilla_widget"))
|
||||||
|
}
|
||||||
@@ -94,6 +94,12 @@
|
|||||||
"firmament.config.category.meta": "Meta & Firmament",
|
"firmament.config.category.meta": "Meta & Firmament",
|
||||||
"firmament.config.category.dev": "Developer & Debug",
|
"firmament.config.category.dev": "Developer & Debug",
|
||||||
"firmament.ursa.debugrequest.start": "Ursa request launched",
|
"firmament.ursa.debugrequest.start": "Ursa request launched",
|
||||||
|
"firmament.hotmpreset.openinghotm": "Opening /hotm menu for export.",
|
||||||
|
"firmament.hotmpreset.scrollprompt": "We need to scroll! Please click anywhere to continue.",
|
||||||
|
"firmament.hotmpreset.scrolled": "Just scrolled. Waiting on server to update items.",
|
||||||
|
"firmament.hotmpreset.copied": "Collected all HOTM perks to clipboard. Use /firm importhotm to import.",
|
||||||
|
"firmament.hotmpreset.okayimport": "Imported a HOTM perk preset.",
|
||||||
|
"firmament.hotmpreset.failedimport": "Could not find a HOTM perk preset in your clipboard. You can export your current HOTM perks with /firm exporthotm",
|
||||||
"firmament.ursa.debugrequest.result": "Ursa request succeeded: %s",
|
"firmament.ursa.debugrequest.result": "Ursa request succeeded: %s",
|
||||||
"firmament.sbinfo.nolocraw": "No locraw data available",
|
"firmament.sbinfo.nolocraw": "No locraw data available",
|
||||||
"firmament.sbinfo.profile": "Current profile cutename: %s",
|
"firmament.sbinfo.profile": "Current profile cutename: %s",
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"gui": {
|
||||||
|
"scaling": {
|
||||||
|
"type": "nine_slice",
|
||||||
|
"width": 24,
|
||||||
|
"height": 41,
|
||||||
|
"border": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 558 B |
Reference in New Issue
Block a user