diff --git a/build.gradle.kts b/build.gradle.kts index 4ed61d0..d8cbf24 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,15 +58,15 @@ afterEvaluate { } java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 withSourcesJar() } kotlin { compilerOptions { - jvmTarget.set(JvmTarget.JVM_17) + jvmTarget.set(JvmTarget.JVM_21) } } @@ -76,9 +76,7 @@ tasks { filesMatching("fabric.mod.json") { expand( - "version" to modVersion, - "minecraft_version" to libs.versions.minecraft.get(), - "kotlin_loader_version" to libs.versions.fabric.kotlin.get() + "version" to modVersion ) } } @@ -91,7 +89,7 @@ tasks { /* Thanks to https://github.com/jakobkmar for original script */ fun DependencyHandlerScope.includeTransitive( dependencies: Set, - minecraftDependencies: Set, + minecraftLibs: Set, kotlinDependency: ResolvedDependency, checkedDependencies: MutableSet = HashSet() ) { @@ -100,7 +98,7 @@ fun DependencyHandlerScope.includeTransitive( if (kotlinDependency.children.any { dep -> dep.name == it.name }) { println("Skipping -> ${it.name} (already in fabric-language-kotlin)") - } else if (minecraftDependencies.any { dep -> dep.moduleGroup == it.moduleGroup && dep.moduleName == it.moduleName }) { + } else if (minecraftLibs.any { dep -> dep.moduleGroup == it.moduleGroup && dep.moduleName == it.moduleName }) { println("Skipping -> ${it.name} (already in minecraft)") } else { include(it.name) @@ -108,7 +106,7 @@ fun DependencyHandlerScope.includeTransitive( } checkedDependencies += it - includeTransitive(it.children, minecraftDependencies, kotlinDependency, checkedDependencies) + includeTransitive(it.children, minecraftLibs, kotlinDependency, checkedDependencies) } } diff --git a/src/main/java/ua/mei/minekord/mixin/PlayerAdvancementTrackerMixin.java b/src/main/java/ua/mei/minekord/mixin/PlayerAdvancementTrackerMixin.java index d3f1464..6c0880a 100644 --- a/src/main/java/ua/mei/minekord/mixin/PlayerAdvancementTrackerMixin.java +++ b/src/main/java/ua/mei/minekord/mixin/PlayerAdvancementTrackerMixin.java @@ -1,13 +1,14 @@ package ua.mei.minekord.mixin; -import net.minecraft.advancement.Advancement; +import net.minecraft.advancement.AdvancementDisplay; +import net.minecraft.advancement.AdvancementEntry; import net.minecraft.advancement.PlayerAdvancementTracker; import net.minecraft.server.network.ServerPlayerEntity; 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.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import ua.mei.minekord.event.AdvancementGrantEvent; @Mixin(PlayerAdvancementTracker.class) @@ -15,8 +16,8 @@ public abstract class PlayerAdvancementTrackerMixin { @Shadow private ServerPlayerEntity owner; - @Inject(method = "grantCriterion", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V")) - public void minekord$callEvent(Advancement advancement, String string, CallbackInfoReturnable cir) { - AdvancementGrantEvent.Companion.getEVENT().invoker().grant(owner, advancement); + @Inject(method = "method_53637", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V")) + public void minekord$callEvent(AdvancementEntry advancementEntry, AdvancementDisplay advancementDisplay, CallbackInfo ci) { + AdvancementGrantEvent.Companion.getEVENT().invoker().grant(owner, advancementEntry.value()); } } diff --git a/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java b/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java index e019418..8a17eaf 100644 --- a/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java +++ b/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java @@ -39,14 +39,14 @@ public abstract class ServerLoginNetworkHandlerMixin { @Shadow @Nullable - GameProfile profile; + private GameProfile profile; @Shadow @Final MinecraftServer server; @Shadow - ServerLoginNetworkHandler.State state; + private ServerLoginNetworkHandler.State state; @Shadow @Final @@ -111,11 +111,11 @@ public void run() { if (ServerLoginNetworkHandlerMixin.this.profile != null) { LOGGER.info("Snowflake based UUID of player {} is {}", ServerLoginNetworkHandlerMixin.this.profile.getName(), ServerLoginNetworkHandlerMixin.this.profile.getId()); - ServerLoginNetworkHandlerMixin.this.state = ServerLoginNetworkHandler.State.READY_TO_ACCEPT; + ServerLoginNetworkHandlerMixin.this.state = ServerLoginNetworkHandler.State.PROTOCOL_SWITCHING; } else if (ServerLoginNetworkHandlerMixin.this.server.isSingleplayer()) { LOGGER.warn("Failed to verify username but will let them in anyway!"); ServerLoginNetworkHandlerMixin.this.profile = gameProfile; - ServerLoginNetworkHandlerMixin.this.state = ServerLoginNetworkHandler.State.READY_TO_ACCEPT; + ServerLoginNetworkHandlerMixin.this.state = ServerLoginNetworkHandler.State.PROTOCOL_SWITCHING; } else { ServerLoginNetworkHandlerMixin.this.disconnect(Text.translatable("multiplayer.disconnect.unverified_username")); LOGGER.error("Username '{}' tried to join with an invalid session", gameProfile.getName()); diff --git a/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt b/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt index 70afaf0..0eddd16 100644 --- a/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt +++ b/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt @@ -29,6 +29,7 @@ import ua.mei.minekord.utils.literal import ua.mei.minekord.utils.native import ua.mei.minekord.utils.summary import ua.mei.minekord.utils.toText +import kotlin.jvm.optionals.getOrNull class MessagesExtension : MinekordExtension() { override val name: String = "minekord.messages" @@ -43,13 +44,13 @@ class MessagesExtension : MinekordExtension() { val sender: Member = event.member ?: return@action var content: Text = if (Chat.convertMarkdown) { - MinecraftSerializer.INSTANCE.serialize(message.content, MinekordBot.minecraftOptions).native() + MinecraftSerializer.INSTANCE.serialize(message.content, MinekordBot.minecraftOptions).native(server.registryManager) } else { message.content.literal() } if (message.referencedMessage != null) { - val replyContent: Text = MinecraftSerializer.INSTANCE.serialize(message.referencedMessage!!.content, MinekordBot.minecraftOptions).native() + val replyContent: Text = MinecraftSerializer.INSTANCE.serialize(message.referencedMessage!!.content, MinekordBot.minecraftOptions).native(server.registryManager) val reply: Text = Chat.Minecraft.replyFormat.toText(server) { "sender" to (message.referencedMessage!!.author?.effectiveName ?: message.referencedMessage!!.data.author.username).literal() @@ -75,7 +76,7 @@ class MessagesExtension : MinekordExtension() { username = sender.name avatarUrl = sender.avatarUrl - content = DiscordSerializer.INSTANCE.serialize(message.adventure(), MinekordBot.discordOptions).let { + content = DiscordSerializer.INSTANCE.serialize(message.adventure(server.registryManager), MinekordBot.discordOptions).let { if (Chat.convertMentions) { SerializerUtils.convertMentions(it) } else { @@ -86,7 +87,7 @@ class MessagesExtension : MinekordExtension() { } override suspend fun onAdvancementGrant(player: ServerPlayerEntity, advancement: Advancement) { - val display: AdvancementDisplay = advancement.display ?: return + val display: AdvancementDisplay = advancement.comp_1913.getOrNull() ?: return val frame: AdvancementFrame = display.frame val message = when (frame) { diff --git a/src/main/kotlin/ua/mei/minekord/bot/extension/PlayerListExtension.kt b/src/main/kotlin/ua/mei/minekord/bot/extension/PlayerListExtension.kt index 4cda310..3139b5f 100644 --- a/src/main/kotlin/ua/mei/minekord/bot/extension/PlayerListExtension.kt +++ b/src/main/kotlin/ua/mei/minekord/bot/extension/PlayerListExtension.kt @@ -25,9 +25,9 @@ class PlayerListExtension : MinekordExtension() { embed { title = Commands.PlayerList.title.toText(server).string color = Colors.green - description = server.playerManager.playerList.map { + description = server.playerManager.playerList.joinToString("\n") { Commands.PlayerList.format.toText(it).string - }.joinToString("\n") + } } } } diff --git a/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt b/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt index f2361ef..1d63251 100644 --- a/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt +++ b/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt @@ -4,16 +4,15 @@ import com.uchuhimo.konf.Config import com.uchuhimo.konf.source.toml import dev.kord.common.Color import eu.pb4.placeholders.api.ParserContext -import eu.pb4.placeholders.api.Placeholders +import eu.pb4.placeholders.api.node.DynamicTextNode import eu.pb4.placeholders.api.node.EmptyNode import eu.pb4.placeholders.api.node.TextNode import eu.pb4.placeholders.api.parsers.NodeParser -import eu.pb4.placeholders.api.parsers.PatternPlaceholderParser -import eu.pb4.placeholders.api.parsers.StaticPreParser -import eu.pb4.placeholders.api.parsers.TextParserV1 +import eu.pb4.placeholders.api.parsers.TagLikeParser import net.fabricmc.loader.api.FabricLoader import net.kyori.adventure.text.format.TextColor import net.minecraft.text.Text +import ua.mei.minekord.Minekord import ua.mei.minekord.config.spec.AuthSpec import ua.mei.minekord.config.spec.ChatSpec import ua.mei.minekord.config.spec.ColorsSpec @@ -25,15 +24,20 @@ import ua.mei.minekord.config.spec.PresenceSpec import ua.mei.minekord.utils.MinekordActivityType import ua.mei.minekord.utils.toColor +import java.util.function.Function as JavaFunction + object MinekordConfig { const val CONFIG_PATH: String = "minekord.toml" - private val parser: NodeParser = NodeParser.merge( - TextParserV1.DEFAULT, - Placeholders.DEFAULT_PLACEHOLDER_PARSER, - PatternPlaceholderParser(PatternPlaceholderParser.ALT_PLACEHOLDER_PATTERN_CUSTOM, DynamicNode.Companion::of), - StaticPreParser.INSTANCE - ) + val dynamicKey: ParserContext.Key> = DynamicTextNode.key(Minekord.MOD_ID) + val parser: NodeParser = NodeParser.builder() + .simplifiedTextFormat() + .quickText() + .globalPlaceholders() + .placeholders(TagLikeParser.PLACEHOLDER_ALTERNATIVE, dynamicKey) + .staticPreParsing() + .build() + private lateinit var config: Config fun load() { @@ -288,22 +292,4 @@ object MinekordConfig { ipUnblockedTitle = config[MessagesSpec.ipUnblockedTitle] } } - - data class DynamicNode(val key: String, val text: Text) : TextNode { - companion object { - fun of(key: String): DynamicNode { - return DynamicNode(key, Text.literal("{$key}")) - } - - val NODES = ParserContext.Key>("minekord:dynamic", null) - } - - override fun toText(context: ParserContext, removeBackslashes: Boolean): Text { - return context.get(NODES)?.getOrDefault(this.key, text) ?: text - } - - override fun isDynamic(): Boolean { - return true - } - } } diff --git a/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt b/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt index 31ee69d..900f680 100644 --- a/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt +++ b/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt @@ -9,22 +9,25 @@ import eu.pb4.placeholders.api.node.EmptyNode import eu.pb4.placeholders.api.node.TextNode import net.kyori.adventure.text.Component import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.minecraft.registry.RegistryWrapper import net.minecraft.server.MinecraftServer import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.text.MutableText import net.minecraft.text.Text +import ua.mei.minekord.config.MinekordConfig import ua.mei.minekord.config.MinekordConfig.Chat -import ua.mei.minekord.config.MinekordConfig.DynamicNode import java.util.Base64 +import java.util.function.Function as JavaFunction + fun String.literal(): MutableText = Text.literal(this) -fun Component.native(): MutableText { - return Text.Serializer.fromJson(GsonComponentSerializer.gson().serialize(this)) ?: Text.empty() +fun Component.native(wrapperLookup: RegistryWrapper.WrapperLookup): MutableText { + return Text.Serialization.fromJson(GsonComponentSerializer.gson().serialize(this), wrapperLookup) ?: Text.empty() } -fun Text.adventure(): Component { - return GsonComponentSerializer.gson().deserialize(Text.Serializer.toJson(this)) +fun Text.adventure(wrapperLookup: RegistryWrapper.WrapperLookup): Component { + return GsonComponentSerializer.gson().deserialize(Text.Serialization.toJsonString(this, wrapperLookup)) } fun String.adventure(): Component = Component.text(this) @@ -40,11 +43,11 @@ fun String.summary(): String { fun GameProfile.texture(): String { return try { JsonParser.parseString(Base64.getDecoder().decode(this.properties.get("textures").firstOrNull()?.value ?: "").toString(Charsets.UTF_8)) - .getAsJsonObject() + .asJsonObject .getAsJsonObject("textures") .getAsJsonObject("SKIN") .getAsJsonPrimitive("url") - .getAsString() + .asString .let { it.substring(it.lastIndexOf('/') + 1) } .takeIf { it.isNotBlank() } ?: "" } catch (_: Throwable) { @@ -56,7 +59,10 @@ fun String.toColor(): Color = Color(this.removePrefix("#").toInt(16)) fun TextNode.toText(context: PlaceholderContext, placeholders: PlaceholderBuilder.() -> Unit): Text { if (this == EmptyNode.INSTANCE) return Text.empty() - return this.toText(context.asParserContext().with(DynamicNode.NODES, PlaceholderBuilder().apply(placeholders).map)) + + val map = PlaceholderBuilder().apply(placeholders).map + + return this.toText(context.asParserContext().with(MinekordConfig.dynamicKey, JavaFunction { map[it] })) } fun TextNode.toText(player: ServerPlayerEntity, placeholders: PlaceholderBuilder.() -> Unit = {}): Text {