Bulk commit
This commit is contained in:
5
TODO.txt
5
TODO.txt
@@ -1,7 +1,10 @@
|
|||||||
|
Prio 0 (Bugs):
|
||||||
|
- WorldReadyEvent buggy? -> out of date locraw
|
||||||
|
|
||||||
|
Priority 1:
|
||||||
- recipes
|
- recipes
|
||||||
- more recipe categories
|
- more recipe categories
|
||||||
- dfu cache
|
- dfu cache
|
||||||
- replace REI with custom renderer (if needed)
|
|
||||||
- Storage Overlay
|
- Storage Overlay
|
||||||
- PV
|
- PV
|
||||||
- NEU buttons
|
- NEU buttons
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
kotlin("jvm") version "1.8.10"
|
kotlin("jvm") version "1.8.20"
|
||||||
kotlin("plugin.serialization") version "1.8.10"
|
kotlin("plugin.serialization") version "1.8.20"
|
||||||
|
id("com.bnorm.power.kotlin-power-assert") version "0.13.0"
|
||||||
id("dev.architectury.loom") version "1.1.336"
|
id("dev.architectury.loom") version "1.1.336"
|
||||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||||
id("moe.nea.licenseextractificator")
|
id("moe.nea.licenseextractificator")
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ qolify = "1.3.0-1.20"
|
|||||||
citresewn = "1.1.3+1.20"
|
citresewn = "1.1.3+1.20"
|
||||||
hotswap_agent = "1.4.2-SNAPSHOT"
|
hotswap_agent = "1.4.2-SNAPSHOT"
|
||||||
sodium = "mc1.20-0.4.10"
|
sodium = "mc1.20-0.4.10"
|
||||||
|
freecammod = "1.2.0-mc1.20"
|
||||||
ncr = "Fabric-1.20-v2.2.0"
|
ncr = "Fabric-1.20-v2.2.0"
|
||||||
mixinextras = "0.2.0-beta.9"
|
mixinextras = "0.2.0-beta.9"
|
||||||
|
|
||||||
@@ -43,12 +44,14 @@ qolify = { module = "maven.modrinth:qolify", version.ref = "qolify" }
|
|||||||
citresewn = { module = "maven.modrinth:cit-resewn", version.ref = "citresewn" }
|
citresewn = { module = "maven.modrinth:cit-resewn", version.ref = "citresewn" }
|
||||||
ncr = { module = "maven.modrinth:no-chat-reports", version.ref = "ncr" }
|
ncr = { module = "maven.modrinth:no-chat-reports", version.ref = "ncr" }
|
||||||
sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
|
sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
|
||||||
|
freecammod = { module = "maven.modrinth:freecam", version.ref = "freecammod" }
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
dbus = ["dbus_java_core", "dbus_java_unixsocket"]
|
dbus = ["dbus_java_core", "dbus_java_unixsocket"]
|
||||||
runtime_required = ["architectury_fabric", "rei_fabric"]
|
runtime_required = ["architectury_fabric", "rei_fabric"]
|
||||||
runtime_optional = [
|
runtime_optional = [
|
||||||
"devauth",
|
"devauth",
|
||||||
|
"freecammod",
|
||||||
"sodium",
|
"sodium",
|
||||||
"qolify",
|
"qolify",
|
||||||
"citresewn",
|
"citresewn",
|
||||||
|
|||||||
38
src/main/java/moe/nea/firmament/mixins/MixinMouse.java
Normal file
38
src/main/java/moe/nea/firmament/mixins/MixinMouse.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package moe.nea.firmament.mixins;
|
||||||
|
|
||||||
|
import kotlin.Pair;
|
||||||
|
import moe.nea.firmament.features.inventory.SaveCursorPosition;
|
||||||
|
import net.minecraft.client.Mouse;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(Mouse.class)
|
||||||
|
public class MixinMouse {
|
||||||
|
@Shadow
|
||||||
|
private double x;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private double y;
|
||||||
|
|
||||||
|
@Inject(method = "lockCursor", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/Mouse;cursorLocked:Z"))
|
||||||
|
public void onLockCursor(CallbackInfo ci) {
|
||||||
|
SaveCursorPosition.saveCursorOriginal(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "lockCursor", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/Window;getHandle()J"))
|
||||||
|
public void onLockCursorAfter(CallbackInfo ci) {
|
||||||
|
SaveCursorPosition.saveCursorMiddle(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "unlockCursor", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/Window;getHandle()J"))
|
||||||
|
public void onUnlockCursor(CallbackInfo ci) {
|
||||||
|
Pair<Double, Double> cursorPosition = SaveCursorPosition.loadCursor(this.x, this.y);
|
||||||
|
if (cursorPosition == null) return;
|
||||||
|
this.x = cursorPosition.getFirst();
|
||||||
|
this.y = cursorPosition.getSecond();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,25 +19,29 @@
|
|||||||
package moe.nea.firmament.mixins;
|
package moe.nea.firmament.mixins;
|
||||||
|
|
||||||
import moe.nea.firmament.events.WorldRenderLastEvent;
|
import moe.nea.firmament.events.WorldRenderLastEvent;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.*;
|
||||||
import net.minecraft.client.render.GameRenderer;
|
|
||||||
import net.minecraft.client.render.LightmapTextureManager;
|
|
||||||
import net.minecraft.client.render.WorldRenderer;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(WorldRenderer.class)
|
@Mixin(WorldRenderer.class)
|
||||||
public class MixinWorldRenderer {
|
public class MixinWorldRenderer {
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private BufferBuilderStorage bufferBuilders;
|
||||||
|
|
||||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderChunkDebugInfo(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/render/Camera;)V", shift = At.Shift.BEFORE))
|
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderChunkDebugInfo(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/render/Camera;)V", shift = At.Shift.BEFORE))
|
||||||
public void onWorldRenderLast(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f positionMatrix, CallbackInfo ci) {
|
public void onWorldRenderLast(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f positionMatrix, CallbackInfo ci) {
|
||||||
var event = new WorldRenderLastEvent(
|
var event = new WorldRenderLastEvent(
|
||||||
matrices, tickDelta, renderBlockOutline,
|
matrices, tickDelta, renderBlockOutline,
|
||||||
camera, gameRenderer, lightmapTextureManager,
|
camera, gameRenderer, lightmapTextureManager,
|
||||||
positionMatrix
|
positionMatrix,
|
||||||
|
this.bufferBuilders.getEntityVertexConsumers()
|
||||||
);
|
);
|
||||||
WorldRenderLastEvent.Companion.publish(event);
|
WorldRenderLastEvent.Companion.publish(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,15 @@
|
|||||||
package moe.nea.firmament
|
package moe.nea.firmament
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
import io.ktor.client.*
|
import dev.architectury.event.events.client.ClientTickEvent
|
||||||
import io.ktor.client.plugins.*
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.plugins.cache.*
|
import io.ktor.client.plugins.UserAgent
|
||||||
import io.ktor.client.plugins.compression.*
|
import io.ktor.client.plugins.cache.HttpCache
|
||||||
import io.ktor.client.plugins.contentnegotiation.*
|
import io.ktor.client.plugins.compression.ContentEncoding
|
||||||
import io.ktor.client.plugins.logging.*
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.client.plugins.logging.LogLevel
|
||||||
|
import io.ktor.client.plugins.logging.Logging
|
||||||
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
|
||||||
@@ -49,6 +51,7 @@ import net.minecraft.command.CommandRegistryAccess
|
|||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import moe.nea.firmament.commands.registerFirmamentCommand
|
import moe.nea.firmament.commands.registerFirmamentCommand
|
||||||
import moe.nea.firmament.dbus.FirmamentDbusObject
|
import moe.nea.firmament.dbus.FirmamentDbusObject
|
||||||
|
import moe.nea.firmament.events.TickEvent
|
||||||
import moe.nea.firmament.features.FeatureManager
|
import moe.nea.firmament.features.FeatureManager
|
||||||
import moe.nea.firmament.repo.HypixelStaticData
|
import moe.nea.firmament.repo.HypixelStaticData
|
||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
@@ -114,6 +117,10 @@ object Firmament {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun onClientInitialize() {
|
fun onClientInitialize() {
|
||||||
dbusConnection.requestBusName("moe.nea.firmament")
|
dbusConnection.requestBusName("moe.nea.firmament")
|
||||||
|
var tick = 0
|
||||||
|
ClientTickEvent.CLIENT_POST.register(ClientTickEvent.Client { instance ->
|
||||||
|
TickEvent.publish(TickEvent(tick++))
|
||||||
|
})
|
||||||
dbusConnection.exportObject(FirmamentDbusObject)
|
dbusConnection.exportObject(FirmamentDbusObject)
|
||||||
IDataHolder.registerEvents()
|
IDataHolder.registerEvents()
|
||||||
RepoManager.initialize()
|
RepoManager.initialize()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.mojang.brigadier.CommandDispatcher
|
|||||||
import com.mojang.brigadier.arguments.StringArgumentType.string
|
import com.mojang.brigadier.arguments.StringArgumentType.string
|
||||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
|
||||||
import moe.nea.firmament.features.world.FairySouls
|
import moe.nea.firmament.features.world.FairySouls
|
||||||
import moe.nea.firmament.gui.config.AllConfigsGui
|
import moe.nea.firmament.gui.config.AllConfigsGui
|
||||||
import moe.nea.firmament.gui.profileviewer.ProfileViewer
|
import moe.nea.firmament.gui.profileviewer.ProfileViewer
|
||||||
@@ -30,6 +31,7 @@ import moe.nea.firmament.repo.RepoManager
|
|||||||
import moe.nea.firmament.util.FirmFormatters
|
import moe.nea.firmament.util.FirmFormatters
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
import moe.nea.firmament.util.SBData
|
import moe.nea.firmament.util.SBData
|
||||||
|
import moe.nea.firmament.util.ScreenUtil
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
import moe.nea.firmament.util.unformattedString
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
|
||||||
@@ -40,6 +42,12 @@ fun firmamentCommand() = literal("firmament") {
|
|||||||
AllConfigsGui.showAllGuis()
|
AllConfigsGui.showAllGuis()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
thenLiteral("storage") {
|
||||||
|
thenExecute {
|
||||||
|
ScreenUtil.setScreenLater(StorageOverlayScreen())
|
||||||
|
MC.player?.networkHandler?.sendChatCommand("ec")
|
||||||
|
}
|
||||||
|
}
|
||||||
thenLiteral("repo") {
|
thenLiteral("repo") {
|
||||||
thenLiteral("reload") {
|
thenLiteral("reload") {
|
||||||
thenLiteral("fetch") {
|
thenLiteral("fetch") {
|
||||||
|
|||||||
5
src/main/kotlin/moe/nea/firmament/events/TickEvent.kt
Normal file
5
src/main/kotlin/moe/nea/firmament/events/TickEvent.kt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
data class TickEvent(val tickCount: Int) : FirmamentEvent() {
|
||||||
|
companion object : FirmamentEventBus<TickEvent>()
|
||||||
|
}
|
||||||
@@ -21,10 +21,13 @@ package moe.nea.firmament.features
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.features.debug.DebugView
|
||||||
import moe.nea.firmament.features.debug.DeveloperFeatures
|
import moe.nea.firmament.features.debug.DeveloperFeatures
|
||||||
import moe.nea.firmament.features.fishing.FishingWarning
|
import moe.nea.firmament.features.fishing.FishingWarning
|
||||||
import moe.nea.firmament.features.inventory.CraftingOverlay
|
import moe.nea.firmament.features.inventory.CraftingOverlay
|
||||||
|
import moe.nea.firmament.features.inventory.SaveCursorPosition
|
||||||
import moe.nea.firmament.features.inventory.SlotLocking
|
import moe.nea.firmament.features.inventory.SlotLocking
|
||||||
|
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlay
|
||||||
import moe.nea.firmament.features.world.FairySouls
|
import moe.nea.firmament.features.world.FairySouls
|
||||||
import moe.nea.firmament.util.data.DataHolder
|
import moe.nea.firmament.util.data.DataHolder
|
||||||
|
|
||||||
@@ -50,9 +53,13 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
|||||||
loadFeature(FairySouls)
|
loadFeature(FairySouls)
|
||||||
loadFeature(FishingWarning)
|
loadFeature(FishingWarning)
|
||||||
loadFeature(SlotLocking)
|
loadFeature(SlotLocking)
|
||||||
|
loadFeature(StorageOverlay)
|
||||||
loadFeature(CraftingOverlay)
|
loadFeature(CraftingOverlay)
|
||||||
if (Firmament.DEBUG)
|
loadFeature(SaveCursorPosition)
|
||||||
|
if (Firmament.DEBUG) {
|
||||||
loadFeature(DeveloperFeatures)
|
loadFeature(DeveloperFeatures)
|
||||||
|
loadFeature(DebugView)
|
||||||
|
}
|
||||||
hasAutoloaded = true
|
hasAutoloaded = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ package moe.nea.firmament.features
|
|||||||
import moe.nea.firmament.gui.config.ManagedConfig
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
|
|
||||||
interface FirmamentFeature {
|
interface FirmamentFeature {
|
||||||
val name: String
|
|
||||||
val identifier: String
|
val identifier: String
|
||||||
val defaultEnabled: Boolean
|
val defaultEnabled: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package moe.nea.firmament.features.debug
|
||||||
|
|
||||||
|
import io.github.cottonmc.cotton.gui.client.CottonHud
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WBox
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.data.Axis
|
||||||
|
import java.util.Optional
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import net.minecraft.scoreboard.Scoreboard
|
||||||
|
import net.minecraft.scoreboard.Team
|
||||||
|
import net.minecraft.text.StringVisitable
|
||||||
|
import net.minecraft.text.Style
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Formatting
|
||||||
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.events.TickEvent
|
||||||
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.TimeMark
|
||||||
|
|
||||||
|
object DebugView : FirmamentFeature {
|
||||||
|
private data class StoredVariable<T>(
|
||||||
|
val obj: T,
|
||||||
|
val timer: TimeMark,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val storedVariables: MutableMap<String, StoredVariable<*>> = mutableMapOf()
|
||||||
|
override val identifier: String
|
||||||
|
get() = "debug-view"
|
||||||
|
override val defaultEnabled: Boolean
|
||||||
|
get() = Firmament.DEBUG
|
||||||
|
|
||||||
|
fun <T : Any?> showVariable(label: String, obj: T) {
|
||||||
|
synchronized(this) {
|
||||||
|
storedVariables[label] = StoredVariable(obj, TimeMark.now())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val debugWidget = WBox(Axis.VERTICAL)
|
||||||
|
|
||||||
|
|
||||||
|
override fun onLoad() {
|
||||||
|
TickEvent.subscribe {
|
||||||
|
synchronized(this) {
|
||||||
|
storedVariables.entries.removeIf { it.value.timer.passedTime() > 1.seconds }
|
||||||
|
if (storedVariables.isEmpty()) {
|
||||||
|
CottonHud.add(debugWidget, 20, 20)
|
||||||
|
} else {
|
||||||
|
CottonHud.remove(debugWidget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,8 +14,6 @@ import moe.nea.firmament.util.TimeMark
|
|||||||
import moe.nea.firmament.util.iterate
|
import moe.nea.firmament.util.iterate
|
||||||
|
|
||||||
object DeveloperFeatures : FirmamentFeature {
|
object DeveloperFeatures : FirmamentFeature {
|
||||||
override val name: String
|
|
||||||
get() = "developer"
|
|
||||||
override val identifier: String
|
override val identifier: String
|
||||||
get() = "developer"
|
get() = "developer"
|
||||||
override val config: TConfig
|
override val config: TConfig
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package moe.nea.firmament.features.debug
|
||||||
|
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WBox
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WLabel
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WWidget
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.data.Axis
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlin.reflect.KProperty1
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.gui.WSpacer
|
||||||
|
|
||||||
|
class ObjectRenderer(val box: WBox) {
|
||||||
|
var indent = 0
|
||||||
|
|
||||||
|
fun beginObject() {
|
||||||
|
indent++
|
||||||
|
}
|
||||||
|
|
||||||
|
fun endObject() {
|
||||||
|
indent--
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emit(label: String, widget: WWidget) {
|
||||||
|
WSpacer(WBox(Axis.VERTICAL).also {
|
||||||
|
it.add(WWidget())
|
||||||
|
it.add(widget)
|
||||||
|
}, indent * 18)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any?> getDebuggingView(label: String, obj: T) {
|
||||||
|
if (obj == null) {
|
||||||
|
emit(label, WLabel(Text.literal("§cnull")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (obj is String) {
|
||||||
|
emit(label, WLabel(Text.literal(Json.encodeToString(obj))))
|
||||||
|
}
|
||||||
|
getObject(label, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> getObject(label: String, obj: T) {
|
||||||
|
emit(label, WLabel(Text.literal(obj::class.simpleName ?: "<unknown>")))
|
||||||
|
beginObject()
|
||||||
|
for (prop in obj::class.members.filterIsInstance<KProperty1<T, *>>()) {
|
||||||
|
val child = prop.get(obj)
|
||||||
|
getDebuggingView(prop.name, child)
|
||||||
|
}
|
||||||
|
endObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -38,8 +38,6 @@ import moe.nea.firmament.util.TimeMark
|
|||||||
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
||||||
|
|
||||||
object FishingWarning : FirmamentFeature {
|
object FishingWarning : FirmamentFeature {
|
||||||
override val name: String
|
|
||||||
get() = "Fishing Warning"
|
|
||||||
override val identifier: String
|
override val identifier: String
|
||||||
get() = "fishing-warning"
|
get() = "fishing-warning"
|
||||||
|
|
||||||
@@ -137,7 +135,7 @@ object FishingWarning : FirmamentFeature {
|
|||||||
WorldRenderLastEvent.subscribe {
|
WorldRenderLastEvent.subscribe {
|
||||||
recentParticles.removeIf { it.second.passedTime() > 5.seconds }
|
recentParticles.removeIf { it.second.passedTime() > 5.seconds }
|
||||||
recentCandidates.removeIf { it.timeMark.passedTime() > 5.seconds }
|
recentCandidates.removeIf { it.timeMark.passedTime() > 5.seconds }
|
||||||
renderInWorld(it.matrices, it.camera) {
|
renderInWorld(it) {
|
||||||
color(0f, 0f, 1f, 1f)
|
color(0f, 0f, 1f, 1f)
|
||||||
recentParticles.forEach {
|
recentParticles.forEach {
|
||||||
tinyBlock(it.first, 0.1F)
|
tinyBlock(it.first, 0.1F)
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ object CraftingOverlay : FirmamentFeature {
|
|||||||
this.recipe = recipe
|
this.recipe = recipe
|
||||||
}
|
}
|
||||||
|
|
||||||
override val name: String
|
|
||||||
get() = "Crafting Overlay"
|
|
||||||
override val identifier: String
|
override val identifier: String
|
||||||
get() = "crafting-overlay"
|
get() = "crafting-overlay"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package moe.nea.firmament.features.inventory
|
||||||
|
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import net.minecraft.client.util.InputUtil
|
||||||
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.TimeMark
|
||||||
|
import moe.nea.firmament.util.assertNotNullOr
|
||||||
|
|
||||||
|
object SaveCursorPosition : FirmamentFeature {
|
||||||
|
override val identifier: String
|
||||||
|
get() = "save-cursor-position"
|
||||||
|
|
||||||
|
object TConfig : ManagedConfig(identifier) {
|
||||||
|
val enable by toggle("enable") { true }
|
||||||
|
val tolerance by duration("tolerance", 10.milliseconds, 5000.milliseconds) { 500.milliseconds }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val config: TConfig
|
||||||
|
get() = TConfig
|
||||||
|
|
||||||
|
override fun onLoad() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var savedPositionedP1: Pair<Double, Double>? = null
|
||||||
|
var savedPosition: SavedPosition? = null
|
||||||
|
|
||||||
|
data class SavedPosition(
|
||||||
|
val middle: Pair<Double, Double>,
|
||||||
|
val cursor: Pair<Double, Double>,
|
||||||
|
val savedAt: TimeMark = TimeMark.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun saveCursorOriginal(positionedX: Double, positionedY: Double) {
|
||||||
|
savedPositionedP1 = Pair(positionedX, positionedY)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun loadCursor(middleX: Double, middleY: Double): Pair<Double, Double>? {
|
||||||
|
val lastPosition = savedPosition?.takeIf { it.savedAt.passedTime() < 1.seconds }
|
||||||
|
savedPosition = null
|
||||||
|
if (lastPosition != null &&
|
||||||
|
(lastPosition.middle.first - middleX).absoluteValue < 1 &&
|
||||||
|
(lastPosition.middle.second - middleY).absoluteValue < 1
|
||||||
|
) {
|
||||||
|
InputUtil.setCursorParameters(
|
||||||
|
MC.window.handle,
|
||||||
|
InputUtil.GLFW_CURSOR_NORMAL,
|
||||||
|
lastPosition.cursor.first,
|
||||||
|
lastPosition.cursor.second
|
||||||
|
)
|
||||||
|
return lastPosition.cursor
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun saveCursorMiddle(middleX: Double, middleY: Double) {
|
||||||
|
val cursorPos = assertNotNullOr(savedPositionedP1) { return }
|
||||||
|
savedPosition = SavedPosition(Pair(middleX, middleY), cursorPos)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,8 +33,6 @@ import moe.nea.firmament.util.MC
|
|||||||
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
|
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
|
||||||
|
|
||||||
object SlotLocking : FirmamentFeature {
|
object SlotLocking : FirmamentFeature {
|
||||||
override val name: String
|
|
||||||
get() = "Slot Locking"
|
|
||||||
override val identifier: String
|
override val identifier: String
|
||||||
get() = "slot-locking"
|
get() = "slot-locking"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package moe.nea.firmament.features.inventory.storageoverlay
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.screen.Screen
|
||||||
|
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
|
||||||
|
import net.minecraft.screen.GenericContainerScreenHandler
|
||||||
|
import moe.nea.firmament.util.ifMatches
|
||||||
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handle representing the state of the "server side" screens.
|
||||||
|
*/
|
||||||
|
sealed interface StorageBackingHandle {
|
||||||
|
|
||||||
|
sealed interface HasBackingScreen {
|
||||||
|
val handler: GenericContainerScreenHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No open "server side" screen.
|
||||||
|
*/
|
||||||
|
object None : StorageBackingHandle
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main storage overview is open. Clicking on a slot will open that page. This page is accessible via `/storage`
|
||||||
|
*/
|
||||||
|
data class Overview(override val handler: GenericContainerScreenHandler) : StorageBackingHandle, HasBackingScreen
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An individual storage page is open. This may be a backpack or an enderchest page. This page is accessible via
|
||||||
|
* the [Overview] or via `/ec <index + 1>` for enderchest pages.
|
||||||
|
*/
|
||||||
|
data class Page(override val handler: GenericContainerScreenHandler, val storagePageSlot: StoragePageSlot) :
|
||||||
|
StorageBackingHandle, HasBackingScreen
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val enderChestName = "^Ender Chest \\(([1-9])/[1-9]\\)$".toRegex()
|
||||||
|
private val backPackName = "^.+Backpack \\(Slot #([0-9]+)\\)$".toRegex()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a screen into a [StorageBackingHandle]. If this returns null it means that the screen is not
|
||||||
|
* representable as a [StorageBackingHandle], meaning another screen is open, for example the enderchest icon
|
||||||
|
* selection screen.
|
||||||
|
*/
|
||||||
|
fun fromScreen(screen: Screen?): StorageBackingHandle? {
|
||||||
|
if (screen == null) return None
|
||||||
|
if (screen !is GenericContainerScreen) return null
|
||||||
|
val title = screen.title.unformattedString
|
||||||
|
if (title == "Storage") return Overview(screen.screenHandler)
|
||||||
|
return title.ifMatches(enderChestName) {
|
||||||
|
Page(screen.screenHandler, StoragePageSlot.ofEnderChestPage(it.groupValues[1].toInt()))
|
||||||
|
} ?: title.ifMatches(backPackName) {
|
||||||
|
Page(screen.screenHandler, StoragePageSlot.ofBackPackPage(it.groupValues[1].toInt()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package moe.nea.firmament.features.inventory.storageoverlay
|
||||||
|
|
||||||
|
import java.util.SortedMap
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class StorageData(
|
||||||
|
val storageInventories: SortedMap<StoragePageSlot, StorageInventory> = sortedMapOf()
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class StorageInventory(
|
||||||
|
var title: String,
|
||||||
|
val slot: StoragePageSlot,
|
||||||
|
var inventory: VirtualInventory?,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package moe.nea.firmament.features.inventory.storageoverlay
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
|
import moe.nea.firmament.events.ScreenOpenEvent
|
||||||
|
import moe.nea.firmament.events.TickEvent
|
||||||
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
|
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
|
||||||
|
|
||||||
|
object StorageOverlay : FirmamentFeature {
|
||||||
|
|
||||||
|
|
||||||
|
object Data : ProfileSpecificDataHolder<StorageData>(serializer(), "storage-data", ::StorageData)
|
||||||
|
|
||||||
|
override val identifier: String
|
||||||
|
get() = "storage-overlay"
|
||||||
|
|
||||||
|
object TConfig : ManagedConfig(identifier) {
|
||||||
|
val rows by integer("rows", 1, 5) { 3 }
|
||||||
|
val scrollSpeed by integer("scroll-speed", 1, 50) { 10 }
|
||||||
|
val inverseScroll by toggle("inverse-scroll") { false }
|
||||||
|
val padding by integer("padding", 1, 20) { 5 }
|
||||||
|
val margin by integer("margin", 1, 60) { 20 }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val config: TConfig
|
||||||
|
get() = TConfig
|
||||||
|
|
||||||
|
var currentHandler: StorageBackingHandle? = StorageBackingHandle.None
|
||||||
|
|
||||||
|
override fun onLoad() {
|
||||||
|
ScreenOpenEvent.subscribe { event ->
|
||||||
|
currentHandler = StorageBackingHandle.fromScreen(event.new)
|
||||||
|
if (event.old is StorageOverlayScreen && !event.old.isClosing) {
|
||||||
|
event.old.setHandler(currentHandler)
|
||||||
|
if (currentHandler != null)
|
||||||
|
// TODO: Consider instead only replacing rendering? might make a lot of stack handling easier
|
||||||
|
event.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TickEvent.subscribe {
|
||||||
|
rememberContent(currentHandler ?: return@subscribe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rememberContent(handler: StorageBackingHandle) {
|
||||||
|
// TODO: Make all of these functions work on deltas / updates instead of the entire contents
|
||||||
|
val data = Data.data?.storageInventories ?: return
|
||||||
|
when (handler) {
|
||||||
|
StorageBackingHandle.None -> {}
|
||||||
|
is StorageBackingHandle.Overview -> rememberStorageOverview(handler, data)
|
||||||
|
is StorageBackingHandle.Page -> rememberPage(handler, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rememberStorageOverview(
|
||||||
|
handler: StorageBackingHandle.Overview,
|
||||||
|
data: SortedMap<StoragePageSlot, StorageData.StorageInventory>
|
||||||
|
) {
|
||||||
|
for ((index, stack) in handler.handler.stacks.withIndex()) {
|
||||||
|
// Ignore unloaded item stacks
|
||||||
|
if (stack.isEmpty) continue
|
||||||
|
val slot = StoragePageSlot.fromOverviewSlotIndex(index) ?: continue
|
||||||
|
val isEmpty = stack.item in StorageOverlayScreen.emptyStorageSlotItems
|
||||||
|
if (slot in data) {
|
||||||
|
if (isEmpty)
|
||||||
|
data.remove(slot)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (!isEmpty) {
|
||||||
|
data[slot] = StorageData.StorageInventory(slot.defaultName(), slot, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rememberPage(
|
||||||
|
handler: StorageBackingHandle.Page,
|
||||||
|
data: SortedMap<StoragePageSlot, StorageData.StorageInventory>
|
||||||
|
) {
|
||||||
|
// TODO: FIXME: FIXME NOW: Definitely don't copy all of this every tick into persistence
|
||||||
|
val newStacks =
|
||||||
|
VirtualInventory(handler.handler.stacks.take(handler.handler.rows * 9).drop(9).map { it.copy() })
|
||||||
|
data.compute(handler.storagePageSlot) { slot, existingInventory ->
|
||||||
|
(existingInventory ?: StorageData.StorageInventory(
|
||||||
|
slot.defaultName(),
|
||||||
|
slot,
|
||||||
|
null
|
||||||
|
)).also {
|
||||||
|
it.inventory = newStacks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package moe.nea.firmament.features.inventory.storageoverlay
|
||||||
|
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.assertNotNullOr
|
||||||
|
import moe.nea.firmament.util.toShedaniel
|
||||||
|
import net.minecraft.block.Blocks
|
||||||
|
import net.minecraft.client.gui.DrawContext
|
||||||
|
import net.minecraft.client.gui.screen.Screen
|
||||||
|
import net.minecraft.item.Item
|
||||||
|
import net.minecraft.item.Items
|
||||||
|
import net.minecraft.network.packet.c2s.play.CloseHandledScreenC2SPacket
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.DyeColor
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
class StorageOverlayScreen() : Screen(Text.empty()) {
|
||||||
|
companion object {
|
||||||
|
val emptyStorageSlotItems = listOf<Item>(
|
||||||
|
Blocks.RED_STAINED_GLASS_PANE.asItem(),
|
||||||
|
Blocks.BROWN_STAINED_GLASS_PANE.asItem(),
|
||||||
|
Items.GRAY_DYE
|
||||||
|
)
|
||||||
|
val pageWidth get() = 19 * 9
|
||||||
|
}
|
||||||
|
|
||||||
|
private var handler: StorageBackingHandle = StorageBackingHandle.None
|
||||||
|
val content = StorageOverlay.Data.data ?: StorageData()
|
||||||
|
var isClosing = false
|
||||||
|
|
||||||
|
private fun discardOldHandle() {
|
||||||
|
val player = assertNotNullOr(MC.player) { return }
|
||||||
|
val handle = this.handler
|
||||||
|
if (handle is StorageBackingHandle.HasBackingScreen) {
|
||||||
|
player.networkHandler.sendPacket(CloseHandledScreenC2SPacket(handle.handler.syncId))
|
||||||
|
if (player.currentScreenHandler === handle.handler) {
|
||||||
|
player.currentScreenHandler = player.playerScreenHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setHandler(handler: StorageBackingHandle?) {
|
||||||
|
discardOldHandle()
|
||||||
|
if (handler != null)
|
||||||
|
this.handler = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
var scroll = 0
|
||||||
|
var lastRenderedHeight = 0
|
||||||
|
|
||||||
|
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
|
super.render(context, mouseX, mouseY, delta)
|
||||||
|
context.fill(0, 0, width, height, 0x90000000.toInt())
|
||||||
|
layoutedForEach { (key, value), offsetX, offsetY ->
|
||||||
|
context.matrices.push()
|
||||||
|
context.matrices.translate(offsetX.toFloat(), offsetY.toFloat(), 0F)
|
||||||
|
renderStoragePage(context, value, mouseX - offsetX, mouseY - offsetY)
|
||||||
|
context.matrices.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun layoutedForEach(onEach: (data: Pair<StoragePageSlot, StorageData.StorageInventory>, offsetX: Int, offsetY: Int) -> Unit) {
|
||||||
|
var offsetY = 0
|
||||||
|
var currentMaxHeight = StorageOverlay.config.margin - StorageOverlay.config.padding - scroll
|
||||||
|
var totalHeight = -currentMaxHeight
|
||||||
|
content.storageInventories.onEachIndexed { index, (key, value) ->
|
||||||
|
val pageX = (index % StorageOverlay.config.rows)
|
||||||
|
if (pageX == 0) {
|
||||||
|
currentMaxHeight += StorageOverlay.config.padding
|
||||||
|
offsetY += currentMaxHeight
|
||||||
|
totalHeight += currentMaxHeight
|
||||||
|
currentMaxHeight = 0
|
||||||
|
}
|
||||||
|
val xPosition =
|
||||||
|
width / 2 - (StorageOverlay.config.rows * (pageWidth + StorageOverlay.config.padding) - StorageOverlay.config.padding) / 2 + pageX * (pageWidth + StorageOverlay.config.padding)
|
||||||
|
onEach(Pair(key, value), xPosition, offsetY)
|
||||||
|
val height = getStorePageHeight(value)
|
||||||
|
currentMaxHeight = max(currentMaxHeight, height)
|
||||||
|
}
|
||||||
|
lastRenderedHeight = totalHeight + currentMaxHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||||
|
layoutedForEach { (k, p), x, y ->
|
||||||
|
val rx = mouseX - x
|
||||||
|
val ry = mouseY - y
|
||||||
|
if (rx in (0.0..pageWidth.toDouble()) && ry in (0.0..getStorePageHeight(p).toDouble())) {
|
||||||
|
close()
|
||||||
|
k.navigateTo()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.mouseClicked(mouseX, mouseY, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStorePageHeight(page: StorageData.StorageInventory): Int {
|
||||||
|
return page.inventory?.rows?.let { it * 19 + MC.font.fontHeight + 2 } ?: 60
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
|
||||||
|
scroll =
|
||||||
|
(scroll + amount * StorageOverlay.config.scrollSpeed *
|
||||||
|
(if (StorageOverlay.config.inverseScroll) 1 else -1)).toInt()
|
||||||
|
.coerceAtMost(lastRenderedHeight - height + 2 * StorageOverlay.config.margin).coerceAtLeast(0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderStoragePage(context: DrawContext, page: StorageData.StorageInventory, mouseX: Int, mouseY: Int) {
|
||||||
|
context.drawText(MC.font, page.title, 2, 2, -1, true)
|
||||||
|
val inventory = page.inventory
|
||||||
|
if (inventory == null) {
|
||||||
|
// TODO: Missing texture
|
||||||
|
context.fill(0, 0, pageWidth, 60, DyeColor.RED.toShedaniel().darker(4.0).color)
|
||||||
|
context.drawCenteredTextWithShadow(MC.font, Text.literal("Not loaded yet"), pageWidth / 2, 30, -1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((index, stack) in inventory.stacks.withIndex()) {
|
||||||
|
val x = (index % 9) * 19
|
||||||
|
val y = (index / 9) * 19 + MC.font.fontHeight + 2
|
||||||
|
if (((mouseX - x) in 0 until 18) && ((mouseY - y) in 0 until 18)) {
|
||||||
|
context.fill(x, y, x + 18, y + 18, 0x80808080.toInt())
|
||||||
|
} else {
|
||||||
|
context.fill(x, y, x + 18, y + 18, 0x40808080.toInt())
|
||||||
|
}
|
||||||
|
context.drawItem(stack, x + 1, y + 1)
|
||||||
|
context.drawItemInSlot(MC.font, stack, x + 1, y + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
discardOldHandle()
|
||||||
|
isClosing = true
|
||||||
|
super.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package moe.nea.firmament.features.inventory.storageoverlay
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
|
||||||
|
@Serializable(with = StoragePageSlot.Serializer::class)
|
||||||
|
data class StoragePageSlot(val index: Int) : Comparable<StoragePageSlot> {
|
||||||
|
object Serializer : KSerializer<StoragePageSlot> {
|
||||||
|
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("StoragePageSlot", PrimitiveKind.INT)
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): StoragePageSlot {
|
||||||
|
return StoragePageSlot(decoder.decodeInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: StoragePageSlot) {
|
||||||
|
encoder.encodeInt(value.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
assert(index in 0 until (3 * 9))
|
||||||
|
}
|
||||||
|
|
||||||
|
val isEnderChest get() = index < 9
|
||||||
|
val isBackPack get() = !isEnderChest
|
||||||
|
val slotIndexInOverviewPage get() = if (isEnderChest) index + 9 else index + 18
|
||||||
|
fun defaultName(): String = if (isEnderChest) "Ender Chest #${index + 1}" else "Backpack #${index - 9 + 1}"
|
||||||
|
|
||||||
|
fun navigateTo() {
|
||||||
|
if (isBackPack) {
|
||||||
|
MC.sendCommand("backpack ${index - 9 + 1}")
|
||||||
|
} else {
|
||||||
|
MC.sendCommand("enderchest ${index + 1}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromOverviewSlotIndex(slot: Int): StoragePageSlot? {
|
||||||
|
if (slot in 9 until 18) return StoragePageSlot(slot - 9)
|
||||||
|
if (slot in 27 until 45) return StoragePageSlot(slot - 27 + 9)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ofEnderChestPage(slot: Int): StoragePageSlot {
|
||||||
|
assert(slot in 1..9)
|
||||||
|
return StoragePageSlot(slot - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ofBackPackPage(slot: Int): StoragePageSlot {
|
||||||
|
assert(slot in 1..18)
|
||||||
|
return StoragePageSlot(slot - 1 + 9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: StoragePageSlot): Int {
|
||||||
|
return this.index - other.index
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package moe.nea.firmament.features.inventory.storageoverlay
|
||||||
|
|
||||||
|
import io.ktor.util.decodeBase64Bytes
|
||||||
|
import io.ktor.util.encodeBase64
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.nbt.NbtIo
|
||||||
|
import net.minecraft.nbt.NbtList
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
@Serializable(with = VirtualInventory.Serializer::class)
|
||||||
|
data class VirtualInventory(
|
||||||
|
val stacks: List<ItemStack>
|
||||||
|
) {
|
||||||
|
val rows = stacks.size / 9
|
||||||
|
|
||||||
|
init {
|
||||||
|
assert(stacks.size % 9 == 0)
|
||||||
|
assert(stacks.size / 9 in 1..5)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object Serializer : KSerializer<VirtualInventory> {
|
||||||
|
const val INVENTORY = "INVENTORY"
|
||||||
|
override val descriptor: SerialDescriptor
|
||||||
|
get() = PrimitiveSerialDescriptor("VirtualInventory", PrimitiveKind.STRING)
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): VirtualInventory {
|
||||||
|
val s = decoder.decodeString()
|
||||||
|
val n = NbtIo.readCompressed(ByteArrayInputStream(s.decodeBase64Bytes()))
|
||||||
|
val items = n.getList(INVENTORY, NbtCompound.COMPOUND_TYPE.toInt())
|
||||||
|
return VirtualInventory(items.map { ItemStack.fromNbt(it as NbtCompound) })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: VirtualInventory) {
|
||||||
|
val list = NbtList()
|
||||||
|
value.stacks.forEach {
|
||||||
|
list.add(NbtCompound().also(it::writeNbt))
|
||||||
|
}
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
NbtIo.writeCompressed(NbtCompound().also { it.put(INVENTORY, list) }, baos)
|
||||||
|
encoder.encodeString(baos.toByteArray().encodeBase64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,14 @@ package moe.nea.firmament.features.world
|
|||||||
import io.github.moulberry.repo.data.Coordinate
|
import io.github.moulberry.repo.data.Coordinate
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.client.render.RenderLayer
|
||||||
|
import net.minecraft.client.render.RenderLayer.ALWAYS_DEPTH_TEST
|
||||||
|
import net.minecraft.client.render.RenderLayer.MultiPhaseParameters
|
||||||
|
import net.minecraft.client.render.RenderPhase
|
||||||
|
import net.minecraft.client.render.VertexFormat
|
||||||
|
import net.minecraft.client.render.VertexFormats
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.math.Vec3d
|
||||||
import moe.nea.firmament.events.ServerChatLineReceivedEvent
|
import moe.nea.firmament.events.ServerChatLineReceivedEvent
|
||||||
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
||||||
import moe.nea.firmament.events.WorldRenderLastEvent
|
import moe.nea.firmament.events.WorldRenderLastEvent
|
||||||
@@ -32,6 +39,7 @@ import moe.nea.firmament.util.MC
|
|||||||
import moe.nea.firmament.util.SBData
|
import moe.nea.firmament.util.SBData
|
||||||
import moe.nea.firmament.util.blockPos
|
import moe.nea.firmament.util.blockPos
|
||||||
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
|
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
|
||||||
|
import moe.nea.firmament.util.render.RenderInWorldContext
|
||||||
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
||||||
import moe.nea.firmament.util.unformattedString
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
|
||||||
@@ -59,7 +67,6 @@ object FairySouls : FirmamentFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override val name: String get() = "Fairy Souls"
|
|
||||||
override val identifier: String get() = "fairy-souls"
|
override val identifier: String get() = "fairy-souls"
|
||||||
|
|
||||||
val playerReach = 5
|
val playerReach = 5
|
||||||
@@ -107,6 +114,22 @@ object FairySouls : FirmamentFeature {
|
|||||||
updateMissingSouls()
|
updateMissingSouls()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val NODEPTH: RenderLayer = RenderLayer.of(
|
||||||
|
"firmamentnodepth",
|
||||||
|
VertexFormats.POSITION_COLOR_TEXTURE,
|
||||||
|
VertexFormat.DrawMode.QUADS,
|
||||||
|
256,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
MultiPhaseParameters.builder()
|
||||||
|
.program(RenderPhase.COLOR_PROGRAM)
|
||||||
|
.writeMaskState(RenderPhase.COLOR_MASK)
|
||||||
|
.depthTest(ALWAYS_DEPTH_TEST)
|
||||||
|
.cull(RenderPhase.DISABLE_CULLING)
|
||||||
|
.layering(RenderLayer.VIEW_OFFSET_Z_LAYERING)
|
||||||
|
.target(RenderPhase.MAIN_TARGET)
|
||||||
|
.build(true)
|
||||||
|
)
|
||||||
|
|
||||||
override fun onLoad() {
|
override fun onLoad() {
|
||||||
SkyblockServerUpdateEvent.subscribe {
|
SkyblockServerUpdateEvent.subscribe {
|
||||||
@@ -127,7 +150,8 @@ object FairySouls : FirmamentFeature {
|
|||||||
}
|
}
|
||||||
WorldRenderLastEvent.subscribe {
|
WorldRenderLastEvent.subscribe {
|
||||||
if (!TConfig.displaySouls) return@subscribe
|
if (!TConfig.displaySouls) return@subscribe
|
||||||
renderInWorld(it.matrices, it.camera) {
|
renderInWorld(it) {
|
||||||
|
text(Vec3d(0.0, 0.0, 0.0), Text.literal("Test String") , Text.literal("Short"), Text.literal("just lik"), verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM)
|
||||||
color(1F, 1F, 0F, 0.8F)
|
color(1F, 1F, 0F, 0.8F)
|
||||||
currentMissingSouls.forEach {
|
currentMissingSouls.forEach {
|
||||||
block(it.blockPos)
|
block(it.blockPos)
|
||||||
|
|||||||
19
src/main/kotlin/moe/nea/firmament/gui/WSpacer.kt
Normal file
19
src/main/kotlin/moe/nea/firmament/gui/WSpacer.kt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package moe.nea.firmament.gui
|
||||||
|
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WPanel
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WWidget
|
||||||
|
|
||||||
|
class WSpacer(val child: WWidget, val spaceLeft: Int) : WPanel() {
|
||||||
|
init {
|
||||||
|
children.add(child)
|
||||||
|
child.setLocation(spaceLeft, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getWidth(): Int {
|
||||||
|
return child.width + spaceLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getHeight(): Int {
|
||||||
|
return child.height
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,14 +18,11 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.gui.config
|
package moe.nea.firmament.gui.config
|
||||||
|
|
||||||
import io.github.cottonmc.cotton.gui.widget.WLabel
|
|
||||||
import io.github.cottonmc.cotton.gui.widget.WToggleButton
|
import io.github.cottonmc.cotton.gui.widget.WToggleButton
|
||||||
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
|
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import kotlinx.serialization.json.boolean
|
import kotlinx.serialization.json.boolean
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import net.minecraft.text.Text
|
|
||||||
|
|
||||||
class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Boolean> {
|
class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Boolean> {
|
||||||
override fun toJson(element: Boolean): JsonElement? {
|
override fun toJson(element: Boolean): JsonElement? {
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package moe.nea.firmament.gui.config
|
||||||
|
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WLabel
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WSlider
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.data.Axis
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
|
||||||
|
import java.util.function.IntConsumer
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.long
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
import kotlin.time.DurationUnit
|
||||||
|
import kotlin.time.toDuration
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.util.FirmFormatters
|
||||||
|
|
||||||
|
class DurationHandler(val config: ManagedConfig, val min: Duration, val max: Duration) :
|
||||||
|
ManagedConfig.OptionHandler<Duration> {
|
||||||
|
override fun toJson(element: Duration): JsonElement? {
|
||||||
|
return JsonPrimitive(element.inWholeMilliseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromJson(element: JsonElement): Duration {
|
||||||
|
return element.jsonPrimitive.long.toDuration(DurationUnit.MILLISECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun emitGuiElements(opt: ManagedConfig.Option<Duration>, guiAppender: GuiAppender) {
|
||||||
|
val lw = guiAppender.width / 2
|
||||||
|
guiAppender.set(
|
||||||
|
0, 0, lw, 1,
|
||||||
|
WLabel(opt.labelText).setVerticalAlignment(VerticalAlignment.CENTER)
|
||||||
|
)
|
||||||
|
val label =
|
||||||
|
WLabel(Text.literal(FirmFormatters.formatTimespan(opt.value))).setVerticalAlignment(VerticalAlignment.CENTER)
|
||||||
|
guiAppender.set(lw, 0, 2, 1, label)
|
||||||
|
guiAppender.set(
|
||||||
|
lw + 2,
|
||||||
|
0,
|
||||||
|
lw - 2,
|
||||||
|
1,
|
||||||
|
WSlider(min.inWholeMilliseconds.toInt(), max.inWholeMilliseconds.toInt(), Axis.HORIZONTAL).apply {
|
||||||
|
valueChangeListener = IntConsumer {
|
||||||
|
opt.value = it.milliseconds
|
||||||
|
label.text = Text.literal(FirmFormatters.formatTimespan(opt.value))
|
||||||
|
config.save()
|
||||||
|
}
|
||||||
|
guiAppender.onReload {
|
||||||
|
value = opt.value.inWholeMilliseconds.toInt()
|
||||||
|
label.text = Text.literal(FirmFormatters.formatTimespan(opt.value))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
guiAppender.skipRows(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ class GuiAppender(val width: Int) {
|
|||||||
internal val panel = WGridPanel().also { it.setGaps(4, 4) }
|
internal val panel = WGridPanel().also { it.setGaps(4, 4) }
|
||||||
internal val reloadables = mutableListOf<(() -> Unit)>()
|
internal val reloadables = mutableListOf<(() -> Unit)>()
|
||||||
fun set(x: Int, y: Int, w: Int, h: Int, widget: WWidget) {
|
fun set(x: Int, y: Int, w: Int, h: Int, widget: WWidget) {
|
||||||
panel.add(widget, x, y, w, h)
|
panel.add(widget, x, y + row, w, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -50,13 +50,13 @@ class GuiAppender(val width: Int) {
|
|||||||
|
|
||||||
fun appendSplitRow(left: WWidget, right: WWidget) {
|
fun appendSplitRow(left: WWidget, right: WWidget) {
|
||||||
val lw = width / 2
|
val lw = width / 2
|
||||||
set(0, row, lw, 1, left)
|
set(0, 0, lw, 1, left)
|
||||||
set(lw, row, width - lw, 1, right)
|
set(lw, 0, width - lw, 1, right)
|
||||||
skipRows(1)
|
skipRows(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun appendFullRow(widget: WWidget) {
|
fun appendFullRow(widget: WWidget) {
|
||||||
set(0, row, width, 1, widget)
|
set(0, 0, width, 1, widget)
|
||||||
skipRows(1)
|
skipRows(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package moe.nea.firmament.gui.config
|
||||||
|
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WLabel
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.WSlider
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.data.Axis
|
||||||
|
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
|
||||||
|
import java.util.function.IntConsumer
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import kotlinx.serialization.json.int
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
|
class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : ManagedConfig.OptionHandler<Int> {
|
||||||
|
override fun toJson(element: Int): JsonElement? {
|
||||||
|
return JsonPrimitive(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromJson(element: JsonElement): Int {
|
||||||
|
return element.jsonPrimitive.int
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun emitGuiElements(opt: ManagedConfig.Option<Int>, guiAppender: GuiAppender) {
|
||||||
|
val lw = guiAppender.width / 2
|
||||||
|
guiAppender.set(
|
||||||
|
0, 0, lw, 1,
|
||||||
|
WLabel(opt.labelText).setVerticalAlignment(VerticalAlignment.CENTER)
|
||||||
|
)
|
||||||
|
val label =
|
||||||
|
WLabel(Text.literal(opt.value.toString())).setVerticalAlignment(VerticalAlignment.CENTER)
|
||||||
|
guiAppender.set(lw, 0, 2, 1, label)
|
||||||
|
guiAppender.set(
|
||||||
|
lw + 2,
|
||||||
|
0,
|
||||||
|
lw - 2,
|
||||||
|
1,
|
||||||
|
WSlider(min, max, Axis.HORIZONTAL).apply {
|
||||||
|
valueChangeListener = IntConsumer {
|
||||||
|
opt.value = it
|
||||||
|
label.text = Text.literal(opt.value.toString())
|
||||||
|
config.save()
|
||||||
|
}
|
||||||
|
guiAppender.onReload {
|
||||||
|
value = opt.value
|
||||||
|
label.text = Text.literal(opt.value.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
guiAppender.skipRows(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import kotlin.io.path.readText
|
|||||||
import kotlin.io.path.writeText
|
import kotlin.io.path.writeText
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.time.Duration
|
||||||
import net.minecraft.client.gui.screen.Screen
|
import net.minecraft.client.gui.screen.Screen
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
@@ -139,6 +140,25 @@ abstract class ManagedConfig(val name: String) {
|
|||||||
return option(propertyName, default, BooleanHandler(this))
|
return option(propertyName, default, BooleanHandler(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun duration(
|
||||||
|
propertyName: String,
|
||||||
|
min: Duration,
|
||||||
|
max: Duration,
|
||||||
|
default: () -> Duration,
|
||||||
|
): Option<Duration> {
|
||||||
|
return option(propertyName, default, DurationHandler(this, min, max))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected fun integer(
|
||||||
|
propertyName: String,
|
||||||
|
min: Int,
|
||||||
|
max: Int,
|
||||||
|
default: () -> Int,
|
||||||
|
): Option<Int> {
|
||||||
|
return option(propertyName, default, IntegerHandler(this, min, max))
|
||||||
|
}
|
||||||
|
|
||||||
protected fun button(propertyName: String, runnable: () -> Unit): Option<Unit> {
|
protected fun button(propertyName: String, runnable: () -> Unit): Option<Unit> {
|
||||||
return option(propertyName, { }, ClickHandler(this, runnable))
|
return option(propertyName, { }, ClickHandler(this, runnable))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Str
|
|||||||
guiAppender.appendLabeledRow(
|
guiAppender.appendLabeledRow(
|
||||||
opt.labelText,
|
opt.labelText,
|
||||||
WTextField(opt.labelText).apply {
|
WTextField(opt.labelText).apply {
|
||||||
|
maxLength = 1000
|
||||||
suggestion = Text.translatableWithFallback(opt.rawLabelText + ".hint", "")
|
suggestion = Text.translatableWithFallback(opt.rawLabelText + ".hint", "")
|
||||||
guiAppender.onReload { text = opt.value }
|
guiAppender.onReload { text = opt.value }
|
||||||
setChangedListener {
|
setChangedListener {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import moe.nea.firmament.Firmament.logger
|
|||||||
import moe.nea.firmament.gui.config.ManagedConfig
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
import moe.nea.firmament.hud.ProgressBar
|
import moe.nea.firmament.hud.ProgressBar
|
||||||
import moe.nea.firmament.rei.PetData
|
import moe.nea.firmament.rei.PetData
|
||||||
|
import moe.nea.firmament.util.MinecraftDispatcher
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
|
||||||
object RepoManager {
|
object RepoManager {
|
||||||
@@ -63,9 +64,11 @@ object RepoManager {
|
|||||||
registerReloadListener(ItemCache)
|
registerReloadListener(ItemCache)
|
||||||
registerReloadListener(ExpLadders)
|
registerReloadListener(ExpLadders)
|
||||||
registerReloadListener {
|
registerReloadListener {
|
||||||
if (!trySendClientboundUpdateRecipesPacket()) {
|
Firmament.coroutineScope.launch(MinecraftDispatcher) {
|
||||||
logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
|
if (!trySendClientboundUpdateRecipesPacket()) {
|
||||||
recentlyFailedToUpdateItemList = true
|
logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
|
||||||
|
recentlyFailedToUpdateItemList = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package moe.nea.firmament.util
|
|||||||
|
|
||||||
import com.google.common.math.IntMath.pow
|
import com.google.common.math.IntMath.pow
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.time.Duration
|
||||||
|
|
||||||
object FirmFormatters {
|
object FirmFormatters {
|
||||||
fun toString(float: Float, fractionalDigits: Int): String = toString(float.toDouble(), fractionalDigits)
|
fun toString(float: Float, fractionalDigits: Int): String = toString(float.toDouble(), fractionalDigits)
|
||||||
@@ -13,4 +14,8 @@ object FirmFormatters {
|
|||||||
return long.toString() + (if (digits.isEmpty()) "" else ".$digits")
|
return long.toString() + (if (digits.isEmpty()) "" else ".$digits")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun formatTimespan(duration: Duration): String {
|
||||||
|
return duration.toString()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen
|
|||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
|
|
||||||
object MC {
|
object MC {
|
||||||
|
fun sendCommand(command: String) {
|
||||||
|
player?.networkHandler?.sendCommand(command)
|
||||||
|
}
|
||||||
|
|
||||||
inline val font get() = MinecraftClient.getInstance().textRenderer
|
inline val font get() = MinecraftClient.getInstance().textRenderer
|
||||||
inline val soundManager get() = MinecraftClient.getInstance().soundManager
|
inline val soundManager get() = MinecraftClient.getInstance().soundManager
|
||||||
inline val player get() = MinecraftClient.getInstance().player
|
inline val player get() = MinecraftClient.getInstance().player
|
||||||
|
|||||||
38
src/main/kotlin/moe/nea/firmament/util/ScoreboardUtil.kt
Normal file
38
src/main/kotlin/moe/nea/firmament/util/ScoreboardUtil.kt
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import java.util.Optional
|
||||||
|
import net.minecraft.scoreboard.Scoreboard
|
||||||
|
import net.minecraft.scoreboard.Team
|
||||||
|
import net.minecraft.text.StringVisitable
|
||||||
|
import net.minecraft.text.Style
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import net.minecraft.util.Formatting
|
||||||
|
|
||||||
|
fun getScoreboardLines(): List<Text> {
|
||||||
|
val scoreboard = MC.player?.scoreboard ?: return listOf()
|
||||||
|
val activeObjective = scoreboard.getObjectiveForSlot(Scoreboard.SIDEBAR_DISPLAY_SLOT_ID) ?: return listOf()
|
||||||
|
return scoreboard.getAllPlayerScores(activeObjective).reversed().take(15).map {
|
||||||
|
val team = scoreboard.getPlayerTeam(it.playerName)
|
||||||
|
Team.decorateName(team, Text.literal(it.playerName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun Text.formattedString(): String {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
visit(StringVisitable.StyledVisitor<Unit> { style, string ->
|
||||||
|
val c = Formatting.byName(style.color?.name)
|
||||||
|
if (c != null) {
|
||||||
|
sb.append("§${c.code}")
|
||||||
|
}
|
||||||
|
if (style.isUnderlined) {
|
||||||
|
sb.append("§n")
|
||||||
|
}
|
||||||
|
if (style.isBold) {
|
||||||
|
sb.append("§l")
|
||||||
|
}
|
||||||
|
sb.append(string)
|
||||||
|
Optional.empty()
|
||||||
|
}, Style.EMPTY)
|
||||||
|
return sb.toString().replace("§[^a-f0-9]".toRegex(), "")
|
||||||
|
}
|
||||||
18
src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt
Normal file
18
src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package moe.nea.firmament.util.item
|
||||||
|
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.NbtElement
|
||||||
|
import net.minecraft.nbt.NbtString
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
|
||||||
|
val ItemStack.loreAccordingToNbt
|
||||||
|
get() = getOrCreateSubNbt(ItemStack.DISPLAY_KEY).getList(ItemStack.LORE_KEY, NbtElement.STRING_TYPE.toInt())
|
||||||
|
.map { Text.Serializer.fromJson((it as NbtString).asString()) }
|
||||||
|
|
||||||
|
val ItemStack.displayNameAccordingToNbt
|
||||||
|
get() = getOrCreateSubNbt(ItemStack.DISPLAY_KEY).let {
|
||||||
|
if (it.contains(ItemStack.NAME_KEY, NbtElement.STRING_TYPE.toInt()))
|
||||||
|
Text.Serializer.fromJson(it.getString(ItemStack.NAME_KEY))
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
4
src/main/kotlin/moe/nea/firmament/util/regex.kt
Normal file
4
src/main/kotlin/moe/nea/firmament/util/regex.kt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
inline fun <T> String.ifMatches(regex: Regex, block: (MatchResult) -> T): T? =
|
||||||
|
regex.matchEntire(this)?.let(block)
|
||||||
@@ -76,6 +76,10 @@ class RenderInWorldContext private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun waypoint(position: BlockPos, label: Text) {
|
||||||
|
text(position.toCenterPos(), label, Text.literal("§e${MC.player?.pos?.distanceTo(position.toCenterPos())}m"))
|
||||||
|
}
|
||||||
|
|
||||||
fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER) {
|
fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER) {
|
||||||
assertTrueOr(texts.isNotEmpty()) { return@text }
|
assertTrueOr(texts.isNotEmpty()) { return@text }
|
||||||
matrixStack.push()
|
matrixStack.push()
|
||||||
|
|||||||
@@ -57,5 +57,14 @@
|
|||||||
"firmament.pv.skills.total": "Total Exp: %s",
|
"firmament.pv.skills.total": "Total Exp: %s",
|
||||||
"firmament.pv.lookingup": "Looking up %s",
|
"firmament.pv.lookingup": "Looking up %s",
|
||||||
"firmament.pv.noprofile": "%s has no SkyBlock profiles",
|
"firmament.pv.noprofile": "%s has no SkyBlock profiles",
|
||||||
"firmament.pv.noplayer": "%s is not a Minecraft player"
|
"firmament.pv.noplayer": "%s is not a Minecraft player",
|
||||||
|
"firmament.config.save-cursor-position.enable": "Enable",
|
||||||
|
"firmament.config.save-cursor-position.tolerance": "Tolerance",
|
||||||
|
"firmament.config.save-cursor-position": "Save Cursor Position",
|
||||||
|
"firmament.config.storage-overlay": "Storage Overlay",
|
||||||
|
"firmament.config.storage-overlay.rows": "Rows",
|
||||||
|
"firmament.config.storage-overlay.padding": "Padding",
|
||||||
|
"firmament.config.storage-overlay.scroll-speed": "Scroll Speed",
|
||||||
|
"firmament.config.storage-overlay.inverse-scroll": "Invert Scroll",
|
||||||
|
"firmament.config.storage-overlay.margin": "Margin"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user