From 5dc54f0fe918ea571345e2ac1dad9e1800106c3a Mon Sep 17 00:00:00 2001 From: Cam Walter Date: Tue, 26 Mar 2024 16:51:48 -0500 Subject: [PATCH] Scoreboard: Completely revamp the API Adds mutability to Scoreboard.Score among these other changes: (added unless otherwise stated) Team: - getColor - setColor Scoreboard: - addLine - createTeam - removeIndex - removeScores Scoreboard.Score: - getNumberFormat - getTeam - remove - setName - setNumberFormat - setPoints - setTeam --- api/ctjs.api | 31 ++- docs/MIGRATION.md | 10 +- .../internal/mixins/MinecraftClientMixin.java | 6 +- .../internal/mixins/Scoreboard$1Accessor.java | 15 ++ .../mixins/ScoreboardObjectiveMixin.java | 19 ++ src/main/kotlin/com/chattriggers/ctjs/CTJS.kt | 2 + .../com/chattriggers/ctjs/api/entity/Team.kt | 21 ++ .../ctjs/api/message/TextComponent.kt | 4 +- .../chattriggers/ctjs/api/world/Scoreboard.kt | 235 ++++++++++++++++-- .../internal/console/ConsoleHostProcess.kt | 2 +- src/main/resources/chattriggers.mixins.json | 38 +-- 11 files changed, 330 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/chattriggers/ctjs/internal/mixins/Scoreboard$1Accessor.java create mode 100644 src/main/java/com/chattriggers/ctjs/internal/mixins/ScoreboardObjectiveMixin.java diff --git a/api/ctjs.api b/api/ctjs.api index 295bbf0e..d8afafd8 100644 --- a/api/ctjs.api +++ b/api/ctjs.api @@ -1013,6 +1013,7 @@ public final class com/chattriggers/ctjs/api/entity/PlayerMP : com/chattriggers/ public final class com/chattriggers/ctjs/api/entity/Team : com/chattriggers/ctjs/api/CTWrapper { public fun (Lnet/minecraft/scoreboard/Team;)V public final fun canSeeInvisibleTeammates ()Z + public final fun getColor ()Ljava/lang/String; public final fun getDeathMessageVisibility ()Lcom/chattriggers/ctjs/api/entity/Team$Visibility; public final fun getFriendlyFire ()Z public synthetic fun getMcValue ()Ljava/lang/Object; @@ -1023,6 +1024,7 @@ public final class com/chattriggers/ctjs/api/entity/Team : com/chattriggers/ctjs public final fun getPrefix ()Ljava/lang/String; public final fun getRegisteredName ()Ljava/lang/String; public final fun getSuffix ()Ljava/lang/String; + public final fun setColor (Ljava/lang/Object;)Lcom/chattriggers/ctjs/api/entity/Team; public final fun setName (Lcom/chattriggers/ctjs/api/message/TextComponent;)Lcom/chattriggers/ctjs/api/entity/Team; public final fun setName (Ljava/lang/String;)Lcom/chattriggers/ctjs/api/entity/Team; public final fun setPrefix (Lcom/chattriggers/ctjs/api/message/TextComponent;)Lcom/chattriggers/ctjs/api/entity/Team; @@ -1033,6 +1035,10 @@ public final class com/chattriggers/ctjs/api/entity/Team : com/chattriggers/ctjs public fun toMC ()Lnet/minecraft/scoreboard/Team; } +public synthetic class com/chattriggers/ctjs/api/entity/Team$EntriesMappings { + public static final synthetic field entries$0 Lkotlin/enums/EnumEntries; +} + public final class com/chattriggers/ctjs/api/entity/Team$Visibility : java/lang/Enum, com/chattriggers/ctjs/api/CTWrapper { public static final field ALWAYS Lcom/chattriggers/ctjs/api/entity/Team$Visibility; public static final field Companion Lcom/chattriggers/ctjs/api/entity/Team$Visibility$Companion; @@ -2314,6 +2320,9 @@ public final class com/chattriggers/ctjs/api/world/PotionEffectType { public final class com/chattriggers/ctjs/api/world/Scoreboard { public static final field INSTANCE Lcom/chattriggers/ctjs/api/world/Scoreboard; + public static final fun addLine (ILcom/chattriggers/ctjs/api/message/TextComponent;)V + public static final fun addLine (ILjava/lang/String;)V + public static final fun createTeam (Ljava/lang/String;)Lcom/chattriggers/ctjs/api/entity/Team; public static final fun getLineByIndex (I)Lcom/chattriggers/ctjs/api/world/Scoreboard$Score; public static final fun getLines ()Ljava/util/List; public static final fun getLines (Z)Ljava/util/List; @@ -2323,6 +2332,10 @@ public final class com/chattriggers/ctjs/api/world/Scoreboard { public static final fun getShouldRender ()Z public static final fun getSidebar ()Lnet/minecraft/scoreboard/ScoreboardObjective; public static final fun getTitle ()Lcom/chattriggers/ctjs/api/message/TextComponent; + public static final fun removeIndex (I)V + public static final fun removeIndex (IZ)V + public static synthetic fun removeIndex$default (IZILjava/lang/Object;)V + public static final fun removeScores (I)V public static final fun setLine (ILcom/chattriggers/ctjs/api/message/TextComponent;)V public static final fun setLine (ILcom/chattriggers/ctjs/api/message/TextComponent;Z)V public static final fun setLine (ILjava/lang/String;)V @@ -2335,11 +2348,21 @@ public final class com/chattriggers/ctjs/api/world/Scoreboard { public static final fun toMC ()Lnet/minecraft/scoreboard/Scoreboard; } -public final class com/chattriggers/ctjs/api/world/Scoreboard$Score { - public fun (Lnet/minecraft/scoreboard/ScoreboardEntry;)V +public final class com/chattriggers/ctjs/api/world/Scoreboard$Score : com/chattriggers/ctjs/api/CTWrapper { + public fun (Lnet/minecraft/scoreboard/ScoreAccess;)V + public synthetic fun getMcValue ()Ljava/lang/Object; + public fun getMcValue ()Lnet/minecraft/scoreboard/ScoreAccess; public final fun getName ()Lcom/chattriggers/ctjs/api/message/TextComponent; - public final fun getPoints ()I - public final fun toMC ()Lnet/minecraft/scoreboard/ScoreboardEntry; + public final fun getNumberFormat ()Lnet/minecraft/scoreboard/number/NumberFormat; + public final fun getScore ()I + public final fun getTeam ()Lcom/chattriggers/ctjs/api/entity/Team; + public final fun remove ()V + public final fun setName (Lcom/chattriggers/ctjs/api/message/TextComponent;)Lcom/chattriggers/ctjs/api/world/Scoreboard$Score; + public final fun setNumberFormat (Ljava/lang/Object;)Lcom/chattriggers/ctjs/api/world/Scoreboard$Score; + public final fun setScore (I)Lcom/chattriggers/ctjs/api/world/Scoreboard$Score; + public final fun setTeam (Lcom/chattriggers/ctjs/api/entity/Team;)Lcom/chattriggers/ctjs/api/world/Scoreboard$Score; + public synthetic fun toMC ()Ljava/lang/Object; + public fun toMC ()Lnet/minecraft/scoreboard/ScoreAccess; public fun toString ()Ljava/lang/String; } diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 89c7b799..89da0bb8 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -134,7 +134,11 @@ Here is a list of targeted changes for various different APIs: - `Scoreboard` - Remove `Scoreboard.getScoreboardTitle()` in favor of the less verbose `Scoreboard.getTitle()` - `Scoreboard.getTitle()` now returns `TextComponent` instead of `String` - - `Score.getName()` now returns `TextComponent` instead of `String` + - `Score` + - is now mutable. You can now edit the score, name, number format, and team + - `getPoints`/`setPoints` are renamed to `getScore`/`setScore` + - Added `addLine()`, `createTeam()`, `removeIndex()`, `removeScores()` methods + - `getLines` now actually sorts by descending instead of ascending - `Book` now uses `TextComponent` instead of `Message` - `Settings` - Renamed all methods in the `skin` object to indicate they return whether the part is enabled, not the actual part themselves (i.e. `getCape()` -> `isCapeEnabled()`) @@ -195,7 +199,9 @@ Here is a list of targeted changes for various different APIs: - `TabList` - Renamed `getHeaderMessage()` to `getHeaderComponent()`, and it now returns a `TextComponent` instead of a `Message` - Renamed `getFooterMessage()` to `getFooterComponent()`, and it now returns a `TextComponent` instead of a `Message` -- `Team.getNameTagVisibility()` and `Team.getDeathMessageVisibility()` now return a `Team.Visibility` instead of a string +- `Team` + - `Team.getNameTagVisibility()` and `Team.getDeathMessageVisibility()` now return a `Team.Visibility` instead of a string + - Added `setColor()` - `Client` - `getChatGUI` was renamed to `getChatGui` to match the naming of `getTabGui` - Removed `Config.modulesFolder`. Use `ChatTriggers.MODULES_FOLDER` or the string `"./config/ChatTriggers/modules"` diff --git a/src/main/java/com/chattriggers/ctjs/internal/mixins/MinecraftClientMixin.java b/src/main/java/com/chattriggers/ctjs/internal/mixins/MinecraftClientMixin.java index 7ed706f6..c42ccf3b 100644 --- a/src/main/java/com/chattriggers/ctjs/internal/mixins/MinecraftClientMixin.java +++ b/src/main/java/com/chattriggers/ctjs/internal/mixins/MinecraftClientMixin.java @@ -1,5 +1,6 @@ package com.chattriggers.ctjs.internal.mixins; +import com.chattriggers.ctjs.api.world.Scoreboard; import com.chattriggers.ctjs.internal.engine.CTEvents; import com.chattriggers.ctjs.api.triggers.TriggerType; import com.chattriggers.ctjs.internal.engine.module.ModuleManager; @@ -29,8 +30,10 @@ private void injectWorldUnload(ClientWorld world, CallbackInfo ci) { TriggerType.SERVER_DISCONNECT.triggerAll(); } - if (this.world != null) + if (this.world != null) { TriggerType.WORLD_UNLOAD.triggerAll(); + Scoreboard.INSTANCE.clearCustom$ctjs(); + } } @Inject(method = "joinWorld", at = @At("TAIL")) @@ -46,6 +49,7 @@ private void injectDisconnect(Screen screen, CallbackInfo ci) { if (this.isIntegratedServerRunning() || this.getCurrentServerEntry() != null) { TriggerType.WORLD_UNLOAD.triggerAll(); TriggerType.SERVER_DISCONNECT.triggerAll(); + Scoreboard.INSTANCE.clearCustom$ctjs(); } } diff --git a/src/main/java/com/chattriggers/ctjs/internal/mixins/Scoreboard$1Accessor.java b/src/main/java/com/chattriggers/ctjs/internal/mixins/Scoreboard$1Accessor.java new file mode 100644 index 00000000..3c9124bd --- /dev/null +++ b/src/main/java/com/chattriggers/ctjs/internal/mixins/Scoreboard$1Accessor.java @@ -0,0 +1,15 @@ +package com.chattriggers.ctjs.internal.mixins; + +import net.minecraft.scoreboard.ScoreHolder; +import net.minecraft.scoreboard.ScoreboardScore; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(targets = "net.minecraft.scoreboard.Scoreboard$1") +public interface Scoreboard$1Accessor { + @Accessor("field_47543") + ScoreboardScore getScore(); + + @Accessor("field_47547") + ScoreHolder getHolder(); +} diff --git a/src/main/java/com/chattriggers/ctjs/internal/mixins/ScoreboardObjectiveMixin.java b/src/main/java/com/chattriggers/ctjs/internal/mixins/ScoreboardObjectiveMixin.java new file mode 100644 index 00000000..f8b2cffa --- /dev/null +++ b/src/main/java/com/chattriggers/ctjs/internal/mixins/ScoreboardObjectiveMixin.java @@ -0,0 +1,19 @@ +package com.chattriggers.ctjs.internal.mixins; + +import com.chattriggers.ctjs.api.world.Scoreboard; +import net.minecraft.scoreboard.ScoreboardObjective; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ScoreboardObjective.class) +public class ScoreboardObjectiveMixin { + @Inject(method = "setDisplayName", at = @At("HEAD"), cancellable = true) + private void chattriggers$keepCustomName(Text name, CallbackInfo ci) { + if (Scoreboard.INSTANCE.getCustomTitle$ctjs()) { + ci.cancel(); + } + } +} diff --git a/src/main/kotlin/com/chattriggers/ctjs/CTJS.kt b/src/main/kotlin/com/chattriggers/ctjs/CTJS.kt index 47a3d14d..7513994d 100644 --- a/src/main/kotlin/com/chattriggers/ctjs/CTJS.kt +++ b/src/main/kotlin/com/chattriggers/ctjs/CTJS.kt @@ -9,6 +9,7 @@ import com.chattriggers.ctjs.api.commands.DynamicCommands import com.chattriggers.ctjs.api.message.ChatLib import com.chattriggers.ctjs.api.render.Image import com.chattriggers.ctjs.api.triggers.TriggerType +import com.chattriggers.ctjs.api.world.Scoreboard import com.chattriggers.ctjs.api.world.World import com.chattriggers.ctjs.engine.Console import com.chattriggers.ctjs.engine.Register @@ -85,6 +86,7 @@ class CTJS : ClientModInitializer { fun unload(asCommand: Boolean = true) { TriggerType.WORLD_UNLOAD.triggerAll() TriggerType.GAME_UNLOAD.triggerAll() + Scoreboard.clearCustom() isLoaded = false diff --git a/src/main/kotlin/com/chattriggers/ctjs/api/entity/Team.kt b/src/main/kotlin/com/chattriggers/ctjs/api/entity/Team.kt index 54f817c1..76f04cd7 100644 --- a/src/main/kotlin/com/chattriggers/ctjs/api/entity/Team.kt +++ b/src/main/kotlin/com/chattriggers/ctjs/api/entity/Team.kt @@ -3,7 +3,10 @@ package com.chattriggers.ctjs.api.entity import com.chattriggers.ctjs.api.CTWrapper import com.chattriggers.ctjs.api.message.TextComponent import com.chattriggers.ctjs.MCTeam +import com.chattriggers.ctjs.api.message.ChatLib import net.minecraft.scoreboard.AbstractTeam +import net.minecraft.text.TextColor +import net.minecraft.util.Formatting class Team(override val mcValue: MCTeam) : CTWrapper { /** @@ -79,6 +82,24 @@ class Team(override val mcValue: MCTeam) : CTWrapper { */ fun setSuffix(suffix: String) = setSuffix(TextComponent(suffix)) + fun getColor() = mcValue.color.toString() + + /** + * Sets the team color + * @param color a string format of a [Formatting], or a hex value + * @return the team for method chaining + */ + fun setColor(color: Any?) = apply { + mcValue.color = when (color) { + is Number -> Formatting.byColorIndex(color.toInt()) + is CharSequence -> Formatting.entries.find { + it.toString() == ChatLib.addColor(color.toString()) + } ?: Formatting.RESET + null -> Formatting.RESET + else -> throw IllegalArgumentException("Could not convert type ${color::class.simpleName} to a Formatting") + } + } + /** * Gets the team's friendly fire setting */ diff --git a/src/main/kotlin/com/chattriggers/ctjs/api/message/TextComponent.kt b/src/main/kotlin/com/chattriggers/ctjs/api/message/TextComponent.kt index fb26d6ed..48e746ea 100644 --- a/src/main/kotlin/com/chattriggers/ctjs/api/message/TextComponent.kt +++ b/src/main/kotlin/com/chattriggers/ctjs/api/message/TextComponent.kt @@ -399,12 +399,12 @@ class TextComponent private constructor( } } - private companion object { + internal companion object { private val colorToFormatChar = Formatting.entries.mapNotNull { format -> TextColor.fromFormatting(format)?.let { it to format } }.toMap() - private fun jsObjectToStyle(obj: NativeObject): Style { + internal fun jsObjectToStyle(obj: NativeObject): Style { return Style.EMPTY .withColor(obj["color"]?.let { color -> when (color) { diff --git a/src/main/kotlin/com/chattriggers/ctjs/api/world/Scoreboard.kt b/src/main/kotlin/com/chattriggers/ctjs/api/world/Scoreboard.kt index 9d718de7..be866833 100644 --- a/src/main/kotlin/com/chattriggers/ctjs/api/world/Scoreboard.kt +++ b/src/main/kotlin/com/chattriggers/ctjs/api/world/Scoreboard.kt @@ -1,16 +1,27 @@ package com.chattriggers.ctjs.api.world -import com.chattriggers.ctjs.api.message.TextComponent import com.chattriggers.ctjs.MCTeam -import net.minecraft.scoreboard.ScoreboardEntry +import com.chattriggers.ctjs.api.CTWrapper +import com.chattriggers.ctjs.api.entity.Team +import com.chattriggers.ctjs.api.message.TextComponent +import com.chattriggers.ctjs.internal.mixins.`Scoreboard$1Accessor` +import com.chattriggers.ctjs.internal.utils.asMixin +import gg.essential.elementa.state.BasicState +import net.minecraft.scoreboard.ScoreAccess +import net.minecraft.scoreboard.ScoreboardDisplaySlot import net.minecraft.scoreboard.ScoreboardObjective import net.minecraft.scoreboard.ScoreboardScore +import net.minecraft.scoreboard.number.NumberFormat +import net.minecraft.scoreboard.number.StyledNumberFormat +import net.minecraft.text.Style +import org.mozilla.javascript.NativeObject object Scoreboard { private var needsUpdate = true private var scoreboardNames = mutableListOf() private var scoreboardTitle = TextComponent("") private var shouldRender = true + internal var customTitle = false @JvmStatic fun toMC() = World.toMC()?.scoreboard @@ -20,7 +31,7 @@ object Scoreboard { fun getScoreboard() = toMC() @JvmStatic - fun getSidebar(): ScoreboardObjective? = toMC()?.objectives?.firstOrNull() + fun getSidebar(): ScoreboardObjective? = toMC()?.getObjectiveForSlot(ScoreboardDisplaySlot.SIDEBAR) /** * Gets the top-most string which is displayed on the scoreboard. (doesn't have a score on the side). @@ -46,7 +57,10 @@ object Scoreboard { */ @JvmStatic fun setTitle(title: TextComponent) { + customTitle = false getSidebar()?.displayName = title + scoreboardTitle = title + customTitle = true } @JvmStatic @@ -89,14 +103,14 @@ object Scoreboard { */ @JvmStatic fun getLinesByScore(score: Int): List = getLines().filter { - it.getPoints() == score + it.getScore() == score } /** * Sets a line in the scoreboard to the specified name and score. * * @param score the score value for this item - * @param line the string to display on said line + * @param line the [TextComponent] to display on said line * @param override whether to remove old lines with the same score */ @JvmStatic @@ -106,17 +120,16 @@ object Scoreboard { val sidebarObjective = getSidebar() ?: return if (override) { - scoreboard.getScoreboardEntries(sidebarObjective).filter { - it.value == score - }.forEach { - scoreboard.removeScore({ it.owner }, sidebarObjective) - } + removeScores(score) + addLine(score, line) + return } scoreboard.knownScoreHolders.forEach { val scoreboardScore = scoreboard.getScore({ it.nameForScoreboard }, sidebarObjective) as? ScoreboardScore - if (scoreboardScore?.score == score) + if (scoreboardScore?.score == score) { scoreboardScore.displayText = line + } } } @@ -124,6 +137,50 @@ object Scoreboard { @JvmOverloads fun setLine(score: Int, line: String, override: Boolean = false) = setLine(score, TextComponent(line), override) + /** + * Adds a line to the scoreboard + * + * @param score the score value for this item + * @param line the [TextComponent] to display on said line + */ + @JvmStatic + fun addLine(score: Int, line: TextComponent) { + val scoreboard = toMC() ?: return + val sidebarObjective = getSidebar() ?: return + + val newLine = scoreboard.getOrCreateScore({ Math.random().toString() }, sidebarObjective, true) + newLine.displayText = line + newLine.score = score + + updateNames() + } + + @JvmStatic + fun addLine(score: Int, line: String) = addLine(score, TextComponent(line)) + + /** + * Removes all lines from the scoreboard matching with a certain score + * + * @param score the score of the lines to remove + */ + @JvmStatic + fun removeScores(score: Int) { + getLinesByScore(score).forEach(Score::remove) + } + + /** + * Removes the line at a certain index + * + * @param index the index of the line to remove + */ + @JvmStatic + @JvmOverloads + fun removeIndex(index: Int, descending: Boolean = true) { + val names = if (descending) scoreboardNames else scoreboardNames.asReversed() + val line = names.removeAt(index) + line.remove() + } + @JvmStatic fun setShouldRender(shouldRender: Boolean) { Scoreboard.shouldRender = shouldRender @@ -132,45 +189,171 @@ object Scoreboard { @JvmStatic fun getShouldRender() = shouldRender + /** + * Creates or gets a [Team] with a given name + * + * @param name the name of the team + */ + @JvmStatic + fun createTeam(name: String): Team = Team(toMC()!!.addTeam(name)) + private fun updateNames() { scoreboardNames.clear() - scoreboardTitle = TextComponent("") + + if (!customTitle) + scoreboardTitle = TextComponent("") val scoreboard = toMC() ?: return - val objective = scoreboard.objectives.singleOrNull() ?: return + val objective = getSidebar() ?: return + + if (!customTitle) + scoreboardTitle = TextComponent(objective.displayName) + + val newScores = scoreboard.knownScoreHolders.asSequence().filter { + objective in scoreboard.getScoreHolderObjectives(it) + }.map { + scoreboard.getOrCreateScore(it, objective, true) + }.mapTo(mutableListOf(), ::Score) - scoreboardTitle = TextComponent(objective.displayName) - scoreboardNames = scoreboard.getScoreboardEntries(objective).filter { - it.owner != null && !it.owner.startsWith("#") - }.map(::Score).sortedBy { it.getPoints() }.toMutableList() + scoreboardNames = newScores.sortedWith(compareBy { + it.getScore() + }.reversed().thenBy { + it.getName().formattedText.lowercase() + }).toMutableList() } internal fun resetCache() { needsUpdate = true } - class Score(private val mcValue: ScoreboardEntry) { - fun toMC() = mcValue + internal fun clearCustom() { + scoreboardNames.clear() + customTitle = false + scoreboardTitle = TextComponent("") + } + + class Score(override val mcValue: ScoreAccess) : CTWrapper { + private val scoreState = BasicState(mcValue.score) + private val nameState = BasicState(mcValue.displayText) + private val formatState = BasicState(mcValue.asMixin<`Scoreboard$1Accessor`>().score.numberFormat) + private val teamState = run { + val scoreboard = Scoreboard.toMC()!! + val name = mcValue.asMixin<`Scoreboard$1Accessor`>().holder.nameForScoreboard + + BasicState(scoreboard.getScoreHolderTeam(name)) + } + + /** + * Gets the team associated with this score, if it exists + * + * @return the team, or null if it does not exist + */ + fun getTeam(): Team? = teamState.get()?.let(::Team) + + /** + * Sets the team associated with this score + * + * @param team the new team to set for this line. Custom teams can be created using [createTeam] + * @return the score to allow for method chaining + */ + fun setTeam(team: Team?) = apply { + val scoreboard = Scoreboard.toMC()!! + val name = mcValue.asMixin<`Scoreboard$1Accessor`>().holder.nameForScoreboard + + if (team == null) { + scoreboard.clearTeam(name) + } else { + scoreboard.addScoreHolderToTeam(name, team.toMC()) + } + + teamState.set(team?.toMC()) + } /** - * Gets the score point value for this score, + * Gets the score value for this score, * i.e. the number on the right of the board * * @return the actual point value */ - fun getPoints(): Int = mcValue.value + fun getScore(): Int = scoreState.get() + + /** + * Sets the score value for this score + * + * @param score the new point value + * @return the score to allow for method chaining + */ + fun setScore(score: Int) = apply { + scoreState.set(score) + mcValue.score = score + } /** * Gets the display string of this score * * @return the display name */ - fun getName() = TextComponent( - MCTeam.decorateName( - Scoreboard.toMC()!!.getScoreHolderTeam(mcValue.owner), - TextComponent(mcValue.owner), + fun getName(): TextComponent { + val name = mcValue.asMixin<`Scoreboard$1Accessor`>().holder.nameForScoreboard + + return TextComponent( + MCTeam.decorateName( + getTeam()?.mcValue, + TextComponent(nameState.get() ?: name), + ) ) - ) + } + + /** + * Sets the name of this score + * + * @param name the new name + * @return the score to allow for method chaining + */ + fun setName(name: TextComponent?) = apply { + nameState.set(name) + mcValue.displayText = name + } + + /** + * Gets the number format of this score + * + * @return the number format + */ + fun getNumberFormat(): NumberFormat? = formatState.get() + + /** + * Sets the number format of this score + * + * @param format either a formatting string, i.e. "&6", style in the form of an object, see [TextComponent], a + * [NumberFormat], or hex value + * @return the score to allow for method chaining + * + * @see [TextComponent] + */ + fun setNumberFormat(format: Any?) = apply { + val style = when (format) { + is CharSequence -> StyledNumberFormat(TextComponent(format.toString()).style) + is NativeObject -> StyledNumberFormat(TextComponent.jsObjectToStyle(format)) + is NumberFormat -> format + is Number -> StyledNumberFormat(Style.EMPTY.withColor(format.toInt())) + else -> null + } + + formatState.set(style) + mcValue.setNumberFormat(style) + } + + /** + * Removes this score from the scoreboard + */ + fun remove() { + val scoreboard = Scoreboard.toMC() ?: return + val sidebarObjective = getSidebar() ?: return + + scoreboard.removeScore(toMC().asMixin<`Scoreboard$1Accessor`>().holder, sidebarObjective) + updateNames() + } override fun toString(): String = getName().formattedText } diff --git a/src/main/kotlin/com/chattriggers/ctjs/internal/console/ConsoleHostProcess.kt b/src/main/kotlin/com/chattriggers/ctjs/internal/console/ConsoleHostProcess.kt index 479db26f..9954d38c 100644 --- a/src/main/kotlin/com/chattriggers/ctjs/internal/console/ConsoleHostProcess.kt +++ b/src/main/kotlin/com/chattriggers/ctjs/internal/console/ConsoleHostProcess.kt @@ -130,7 +130,7 @@ object ConsoleHostProcess : Initializer { when (val message = Json.decodeFromString(messageText)) { is EvalTextMessage -> { - val result = JSLoader.eval(message.string) + val result = JSLoader.eval(message.string) ?: continue trySendMessage(EvalResultMessage(message.id, result)) } is FontSizeMessage -> { diff --git a/src/main/resources/chattriggers.mixins.json b/src/main/resources/chattriggers.mixins.json index ad44393f..487cb788 100644 --- a/src/main/resources/chattriggers.mixins.json +++ b/src/main/resources/chattriggers.mixins.json @@ -11,11 +11,9 @@ "ChatHudAccessor", "ChatHudMixin", "ChatScreenAccessor", - "ChunkAccessor", "ClickableWidgetAccessor", "ClientChunkManagerAccessor", "ClientChunkMapAccessor", - "ClientConnectionMixin", "ClientPlayerEntityMixin", "ClientPlayerInteractionManagerMixin", "ClientWorldAccessor", @@ -27,37 +25,43 @@ "HandledScreenAccessor", "HandledScreenMixin", "InGameHudMixin", - "ItemStackMixin", "KeyBindingAccessor", - "LivingEntityMixin", "MinecraftClientMixin", "MouseMixin", - "NbtCompoundAccessor", "ParticleAccessor", "ParticleManagerMixin", - "PlayerEntityMixin", "PlayerListHudAccessor", "PlayerListHudMixin", - "PlayerScreenHandlerMixin", "RenderTickCounterMixin", - "ScreenHandlerMixin", - "SystemDetailsMixin", "commands.ClientCommandSourceMixin", "commands.ClientPlayNetworkHandlerMixin", - "commands.CommandContextAccessor", - "commands.CommandDispatcherMixin", - "commands.CommandNodeAccessor", - "commands.EntitySelectorAccessor", "sound.SoundAccessor", "sound.SoundManagerAccessor", "sound.SoundSystemAccessor", "sound.SoundSystemMixin", - "sound.SourceAccessor", - "stdio.BootstrapMixin", - "stdio.LoggerPrintStreamMixin" + "sound.SourceAccessor" ], "injectors": { "defaultRequire": 1 }, - "plugin": "com.chattriggers.ctjs.internal.launch.CTMixinPlugin" + "plugin": "com.chattriggers.ctjs.internal.launch.CTMixinPlugin", + "mixins": [ + "ChunkAccessor", + "ClientConnectionMixin", + "ItemStackMixin", + "LivingEntityMixin", + "NbtCompoundAccessor", + "PlayerEntityMixin", + "PlayerScreenHandlerMixin", + "Scoreboard$1Accessor", + "ScoreboardObjectiveMixin", + "ScreenHandlerMixin", + "SystemDetailsMixin", + "commands.CommandContextAccessor", + "commands.CommandDispatcherMixin", + "commands.CommandNodeAccessor", + "commands.EntitySelectorAccessor", + "stdio.BootstrapMixin", + "stdio.LoggerPrintStreamMixin" + ] }