aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/features/chat
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/features/chat')
-rw-r--r--src/main/kotlin/features/chat/AutoCompletions.kt33
-rw-r--r--src/main/kotlin/features/chat/ChatLinks.kt101
-rw-r--r--src/main/kotlin/features/chat/CopyChat.kt21
-rw-r--r--src/main/kotlin/features/chat/PartyCommands.kt8
-rw-r--r--src/main/kotlin/features/chat/QuickCommands.kt55
5 files changed, 137 insertions, 81 deletions
diff --git a/src/main/kotlin/features/chat/AutoCompletions.kt b/src/main/kotlin/features/chat/AutoCompletions.kt
index 9e0de40..f13fe7e 100644
--- a/src/main/kotlin/features/chat/AutoCompletions.kt
+++ b/src/main/kotlin/features/chat/AutoCompletions.kt
@@ -1,6 +1,15 @@
package moe.nea.firmament.features.chat
+import com.mojang.brigadier.Message
import com.mojang.brigadier.arguments.StringArgumentType.string
+import com.mojang.brigadier.context.CommandContext
+import com.mojang.brigadier.exceptions.BuiltInExceptions
+import com.mojang.brigadier.exceptions.CommandExceptionType
+import com.mojang.brigadier.exceptions.CommandSyntaxException
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType
+import kotlin.concurrent.thread
+import net.minecraft.SharedConstants
+import net.minecraft.commands.BrigadierExceptions
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.get
import moe.nea.firmament.commands.suggestsList
@@ -8,21 +17,21 @@ import moe.nea.firmament.commands.thenArgument
import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.MaskCommands
-import moe.nea.firmament.features.FirmamentFeature
-import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.data.Config
+import moe.nea.firmament.util.data.ManagedConfig
+import moe.nea.firmament.util.tr
-object AutoCompletions : FirmamentFeature {
+object AutoCompletions {
+ @Config
object TConfig : ManagedConfig(identifier, Category.CHAT) {
val provideWarpTabCompletion by toggle("warp-complete") { true }
val replaceWarpIsByWarpIsland by toggle("warp-is") { true }
}
- override val config: ManagedConfig?
- get() = TConfig
- override val identifier: String
+ val identifier: String
get() = "auto-completions"
@Subscribe
@@ -44,12 +53,20 @@ object AutoCompletions : FirmamentFeature {
thenExecute {
val warpName = get(toArg)
if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) {
- MC.sendServerCommand("warp island")
+ MC.sendCommand("warp island")
} else {
- MC.sendServerCommand("warp $warpName")
+ redirectToServer()
}
}
}
}
}
+
+ fun CommandContext<*>.redirectToServer() {
+ val message = tr(
+ "firmament.warp.auto-complete.internal-throw",
+ "This is an internal syntax exception that should not show up in gameplay, used to pass on a command to the server"
+ )
+ throw CommandSyntaxException(CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand(), message)
+ }
}
diff --git a/src/main/kotlin/features/chat/ChatLinks.kt b/src/main/kotlin/features/chat/ChatLinks.kt
index f85825b..aca7af8 100644
--- a/src/main/kotlin/features/chat/ChatLinks.kt
+++ b/src/main/kotlin/features/chat/ChatLinks.kt
@@ -1,47 +1,48 @@
package moe.nea.firmament.features.chat
-import io.ktor.client.request.get
-import io.ktor.client.statement.bodyAsChannel
-import io.ktor.utils.io.jvm.javaio.toInputStream
-import java.net.URL
+import java.net.URI
import java.util.Collections
import java.util.concurrent.atomic.AtomicInteger
-import moe.nea.jarvis.api.Point
+import org.joml.Vector2i
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
+import kotlinx.coroutines.future.await
import kotlin.math.min
-import net.minecraft.client.gui.screen.ChatScreen
-import net.minecraft.client.texture.NativeImage
-import net.minecraft.client.texture.NativeImageBackedTexture
-import net.minecraft.text.ClickEvent
-import net.minecraft.text.HoverEvent
-import net.minecraft.text.Style
-import net.minecraft.text.Text
-import net.minecraft.util.Formatting
-import net.minecraft.util.Identifier
+import net.minecraft.client.gui.screens.ChatScreen
+import com.mojang.blaze3d.platform.NativeImage
+import net.minecraft.client.renderer.texture.DynamicTexture
+import net.minecraft.network.chat.ClickEvent
+import net.minecraft.network.chat.HoverEvent
+import net.minecraft.network.chat.Style
+import net.minecraft.network.chat.Component
+import net.minecraft.ChatFormatting
+import net.minecraft.resources.ResourceLocation
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ModifyChatEvent
import moe.nea.firmament.events.ScreenRenderPostEvent
-import moe.nea.firmament.features.FirmamentFeature
-import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.jarvis.JarvisIntegration
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.data.Config
+import moe.nea.firmament.util.data.ManagedConfig
+import moe.nea.firmament.util.net.HttpUtil
import moe.nea.firmament.util.render.drawTexture
import moe.nea.firmament.util.transformEachRecursively
import moe.nea.firmament.util.unformattedString
-object ChatLinks : FirmamentFeature {
- override val identifier: String
+object ChatLinks {
+ val identifier: String
get() = "chat-links"
+ @Config
object TConfig : ManagedConfig(identifier, Category.CHAT) {
val enableLinks by toggle("links-enabled") { true }
val imageEnabled by toggle("image-enabled") { true }
val allowAllHosts by toggle("allow-all-hosts") { false }
val allowedHosts by string("allowed-hosts") { "cdn.discordapp.com,media.discordapp.com,media.discordapp.net,i.imgur.com" }
val actualAllowedHosts get() = allowedHosts.split(",").map { it.trim() }
- val position by position("position", 16 * 20, 9 * 20) { Point(0.0, 0.0) }
+ val position by position("position", 16 * 20, 9 * 20) { Vector2i(0, 0) }
}
private fun isHostAllowed(host: String) =
@@ -49,12 +50,11 @@ object ChatLinks : FirmamentFeature {
private fun isUrlAllowed(url: String) = isHostAllowed(url.removePrefix("https://").substringBefore("/"))
- override val config get() = TConfig
- val urlRegex = "https://[^. ]+\\.[^ ]+(\\.?( |$))".toRegex()
+ val urlRegex = "https://[^. ]+\\.[^ ]+(\\.?(\\s|$))".toRegex()
val nextTexId = AtomicInteger(0)
data class Image(
- val texture: Identifier,
+ val texture: ResourceLocation,
val width: Int,
val height: Int,
)
@@ -71,18 +71,16 @@ object ChatLinks : FirmamentFeature {
}
imageCache[url] = Firmament.coroutineScope.async {
try {
- val response = Firmament.httpClient.get(URL(url))
- if (response.status.value == 200) {
- val inputStream = response.bodyAsChannel().toInputStream(Firmament.globalJob)
- val image = NativeImage.read(inputStream)
- val texId = Firmament.identifier("dynamic_image_preview${nextTexId.getAndIncrement()}")
- MC.textureManager.registerTexture(
- texId,
- NativeImageBackedTexture(image)
- )
- Image(texId, image.width, image.height)
- } else
- null
+ val inputStream = HttpUtil.request(url)
+ .forInputStream()
+ .await()
+ val image = NativeImage.read(inputStream)
+ val texId = Firmament.identifier("dynamic_image_preview${nextTexId.getAndIncrement()}")
+ MC.textureManager.register(
+ texId,
+ DynamicTexture({ texId.path }, image)
+ )
+ Image(texId, image.width, image.height)
} catch (exc: Exception) {
exc.printStackTrace()
null
@@ -101,19 +99,19 @@ object ChatLinks : FirmamentFeature {
if (!TConfig.imageEnabled) return
if (it.screen !is ChatScreen) return
val hoveredComponent =
- MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return
- val hoverEvent = hoveredComponent.hoverEvent ?: return
- val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return
+ MC.inGameHud.chat.getClickedComponentStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return
+ val hoverEvent = hoveredComponent.hoverEvent as? HoverEvent.ShowText ?: return
+ val value = hoverEvent.value
val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return
if (!isImageUrl(url)) return
val imageFuture = imageCache[url] ?: return
if (!imageFuture.isCompleted) return
val image = imageFuture.getCompleted() ?: return
- it.drawContext.matrices.push()
+ it.drawContext.pose().pushMatrix()
val pos = TConfig.position
- pos.applyTransformations(it.drawContext.matrices)
+ pos.applyTransformations(JarvisIntegration.jarvis, it.drawContext.pose())
val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width))
- it.drawContext.matrices.scale(scale, scale, 1F)
+ it.drawContext.pose().scale(scale, scale)
it.drawContext.drawTexture(
image.texture,
0,
@@ -125,7 +123,7 @@ object ChatLinks : FirmamentFeature {
image.width,
image.height,
)
- it.drawContext.matrices.pop()
+ it.drawContext.pose().popMatrix()
}
@Subscribe
@@ -134,23 +132,24 @@ object ChatLinks : FirmamentFeature {
it.replaceWith = it.replaceWith.transformEachRecursively { child ->
val text = child.string
if ("://" !in text) return@transformEachRecursively child
- val s = Text.empty().setStyle(child.style)
+ val s = Component.empty().setStyle(child.style)
var index = 0
while (index < text.length) {
val nextMatch = urlRegex.find(text, index)
- if (nextMatch == null) {
- s.append(Text.literal(text.substring(index, text.length)))
+ val url = nextMatch?.groupValues[0]
+ val uri = runCatching { url?.let(::URI) }.getOrNull()
+ if (nextMatch == null || url == null || uri == null) {
+ s.append(Component.literal(text.substring(index, text.length)))
break
}
val range = nextMatch.groups[0]!!.range
- val url = nextMatch.groupValues[0]
- s.append(Text.literal(text.substring(index, range.first)))
+ s.append(Component.literal(text.substring(index, range.first)))
s.append(
- Text.literal(url).setStyle(
- Style.EMPTY.withUnderline(true).withColor(
- Formatting.AQUA
- ).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url)))
- .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url))
+ Component.literal(url).setStyle(
+ Style.EMPTY.withUnderlined(true).withColor(
+ ChatFormatting.AQUA
+ ).withHoverEvent(HoverEvent.ShowText(Component.literal(url)))
+ .withClickEvent(ClickEvent.OpenUrl(uri))
)
)
if (isImageUrl(url))
diff --git a/src/main/kotlin/features/chat/CopyChat.kt b/src/main/kotlin/features/chat/CopyChat.kt
new file mode 100644
index 0000000..6bef99f
--- /dev/null
+++ b/src/main/kotlin/features/chat/CopyChat.kt
@@ -0,0 +1,21 @@
+package moe.nea.firmament.features.chat
+
+import net.minecraft.util.FormattedCharSequence
+import moe.nea.firmament.util.data.Config
+import moe.nea.firmament.util.data.ManagedConfig
+import moe.nea.firmament.util.reconstitute
+
+
+object CopyChat {
+ val identifier: String
+ get() = "copy-chat"
+
+ @Config
+ object TConfig : ManagedConfig(identifier, Category.CHAT) {
+ val copyChat by toggle("copy-chat") { false }
+ }
+
+ fun orderedTextToString(orderedText: FormattedCharSequence): String {
+ return orderedText.reconstitute().string
+ }
+}
diff --git a/src/main/kotlin/features/chat/PartyCommands.kt b/src/main/kotlin/features/chat/PartyCommands.kt
index de3a0d9..85daf51 100644
--- a/src/main/kotlin/features/chat/PartyCommands.kt
+++ b/src/main/kotlin/features/chat/PartyCommands.kt
@@ -5,17 +5,18 @@ import com.mojang.brigadier.StringReader
import com.mojang.brigadier.exceptions.CommandSyntaxException
import com.mojang.brigadier.tree.LiteralCommandNode
import kotlin.time.Duration.Companion.seconds
-import net.minecraft.util.math.BlockPos
+import net.minecraft.core.BlockPos
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.CaseInsensitiveLiteralCommandNode
import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.PartyMessageReceivedEvent
import moe.nea.firmament.events.ProcessChatEvent
-import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.TimeMark
+import moe.nea.firmament.util.data.Config
+import moe.nea.firmament.util.data.ManagedConfig
import moe.nea.firmament.util.tr
import moe.nea.firmament.util.useMatch
@@ -79,7 +80,7 @@ object PartyCommands {
register("coords") {
executes {
- val p = MC.player?.blockPos ?: BlockPos.ORIGIN
+ val p = MC.player?.blockPosition() ?: BlockPos.ZERO
MC.sendCommand("pc x: ${p.x}, y: ${p.y}, z: ${p.z}")
0
}
@@ -89,6 +90,7 @@ object PartyCommands {
// TODO: at TPS command
}
+ @Config
object TConfig : ManagedConfig("party-commands", Category.CHAT) {
val enable by toggle("enable") { false }
val cooldown by duration("cooldown", 0.seconds, 20.seconds) { 2.seconds }
diff --git a/src/main/kotlin/features/chat/QuickCommands.kt b/src/main/kotlin/features/chat/QuickCommands.kt
index 7963171..b857f8a 100644
--- a/src/main/kotlin/features/chat/QuickCommands.kt
+++ b/src/main/kotlin/features/chat/QuickCommands.kt
@@ -5,9 +5,9 @@ import com.mojang.brigadier.context.CommandContext
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.fabricmc.fabric.impl.command.client.ClientCommandInternals
-import net.minecraft.command.CommandRegistryAccess
-import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket
-import net.minecraft.text.Text
+import net.minecraft.commands.CommandBuildContext
+import net.minecraft.network.protocol.game.ClientboundCommandsPacket
+import net.minecraft.network.chat.Component
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.DefaultSource
import moe.nea.firmament.commands.RestArgumentType
@@ -15,18 +15,19 @@ import moe.nea.firmament.commands.get
import moe.nea.firmament.commands.thenArgument
import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.events.CommandEvent
-import moe.nea.firmament.features.FirmamentFeature
-import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.gui.config.ManagedOption
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
+import moe.nea.firmament.util.data.Config
+import moe.nea.firmament.util.data.ManagedConfig
import moe.nea.firmament.util.grey
import moe.nea.firmament.util.tr
-object QuickCommands : FirmamentFeature {
- override val identifier: String
+object QuickCommands {
+ val identifier: String
get() = "quick-commands"
+ @Config
object TConfig : ManagedConfig("quick-commands", Category.CHAT) {
val enableJoin by toggle("join") { true }
val enableDh by toggle("dh") { true }
@@ -43,10 +44,14 @@ object QuickCommands : FirmamentFeature {
val dispatcher = CommandDispatcher<FabricClientCommandSource>()
ClientCommandInternals.setActiveDispatcher(dispatcher)
ClientCommandRegistrationCallback.EVENT.invoker()
- .register(dispatcher, CommandRegistryAccess.of(network.combinedDynamicRegistries,
- network.enabledFeatures))
+ .register(
+ dispatcher, CommandBuildContext.simple(
+ network.registryAccess,
+ network.enabledFeatures()
+ )
+ )
ClientCommandInternals.finalizeInit()
- network.onCommandTree(lastPacket)
+ network.handleCommands(lastPacket)
} catch (ex: Exception) {
ClientCommandInternals.setActiveDispatcher(fallback)
throw ex
@@ -64,7 +69,7 @@ object QuickCommands : FirmamentFeature {
return lf
}
- var lastReceivedTreePacket: CommandTreeS2CPacket? = null
+ var lastReceivedTreePacket: ClientboundCommandsPacket? = null
val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL")
val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN")
@@ -98,16 +103,20 @@ object QuickCommands : FirmamentFeature {
}
val joinName = getNameForFloor(what.replace(" ", "").lowercase())
if (joinName == null) {
- source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
+ source.sendFeedback(Component.translatableEscape("firmament.quick-commands.join.unknown", what))
} else {
- source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success",
- joinName))
+ source.sendFeedback(
+ Component.translatableEscape(
+ "firmament.quick-commands.join.success",
+ joinName
+ )
+ )
MC.sendCommand("joininstance $joinName")
}
}
}
thenExecute {
- source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain"))
+ source.sendFeedback(Component.translatable("firmament.quick-commands.join.explain"))
}
}
}
@@ -122,8 +131,12 @@ object QuickCommands : FirmamentFeature {
)
}
if (l !in kuudraLevelNames.indices) {
- source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra",
- kuudraLevel))
+ source.sendFeedback(
+ Component.translatableEscape(
+ "firmament.quick-commands.join.unknown-kuudra",
+ kuudraLevel
+ )
+ )
return null
}
return "KUUDRA_${kuudraLevelNames[l]}"
@@ -143,8 +156,12 @@ object QuickCommands : FirmamentFeature {
return "CATACOMBS_ENTRANCE"
}
if (l !in dungeonLevelNames.indices) {
- source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs",
- kuudraLevel))
+ source.sendFeedback(
+ Component.translatableEscape(
+ "firmament.quick-commands.join.unknown-catacombs",
+ kuudraLevel
+ )
+ )
return null
}
return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}"