diff options
Diffstat (limited to 'src/main/java/de/hysky')
9 files changed, 1070 insertions, 3 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index dca41bd1..edd4241e 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -5,7 +5,9 @@ import com.google.gson.GsonBuilder; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.skyblock.*; +import de.hysky.skyblocker.skyblock.chat.ChatRuleAnnouncementScreen; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; +import de.hysky.skyblocker.skyblock.chat.ChatRulesHandler; import de.hysky.skyblocker.skyblock.dungeon.*; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.dungeon.puzzle.*; @@ -107,6 +109,8 @@ public class SkyblockerMod implements ClientModInitializer { CrystalsLocationsManager.init(); ChatMessageListener.init(); Shortcuts.init(); + ChatRulesHandler.init(); + ChatRuleAnnouncementScreen.init(); DiscordRPCManager.init(); LividColor.init(); FishingHelper.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index 78458291..4a1fe614 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -1192,6 +1192,15 @@ public class SkyblockerConfig { @SerialEntry public ChatFilterResult hideDicer = ChatFilterResult.PASS; + + @SerialEntry + public ChatRuleConfig chatRuleConfig = new ChatRuleConfig(); + } + public static class ChatRuleConfig { + @SerialEntry + public int announcementLength = 60; + @SerialEntry + public int announcementScale = 3; } public enum Info { diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java index acdc8169..0f95bcaa 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java @@ -2,10 +2,12 @@ package de.hysky.skyblocker.config.categories; import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.skyblock.chat.ChatRulesConfigScreen; +import de.hysky.skyblocker.skyblock.dwarven.CrystalsHudConfigScreen; import de.hysky.skyblocker.utils.chat.ChatFilterResult; -import dev.isxander.yacl3.api.ConfigCategory; -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.OptionDescription; +import dev.isxander.yacl3.api.*; +import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder; +import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; public class MessageFilterCategory { @@ -126,6 +128,32 @@ public class MessageFilterCategory { newValue -> config.messages.hideDicer = newValue) .controller(ConfigUtils::createEnumCyclingListController) .build()) + //chat rules options + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules")) + .collapsed(false) + .option(ButtonOption.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen")) + .text(Text.translatable("text.skyblocker.open")) + .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new ChatRulesConfigScreen(screen))) + .build()) + .option(Option.<Integer>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.announcementLength")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.announcementLength.@Tooltip"))) + .binding(defaults.messages.chatRuleConfig.announcementLength, + () -> config.messages.chatRuleConfig.announcementLength, + newValue -> config.messages.chatRuleConfig.announcementLength = newValue) + .controller(opt -> IntegerSliderControllerBuilder.create(opt).range(5, 200).step(1)) + .build()) + .option(Option.<Integer>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.announcementScale")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.announcementScale.@Tooltip"))) + .binding(defaults.messages.chatRuleConfig.announcementScale, + () -> config.messages.chatRuleConfig.announcementScale, + newValue -> config.messages.chatRuleConfig.announcementScale = newValue) + .controller(opt -> IntegerSliderControllerBuilder.create(opt).range(1, 8).step(1)) + .build()) + .build()) .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRule.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRule.java new file mode 100644 index 00000000..4877fdb6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRule.java @@ -0,0 +1,213 @@ +package de.hysky.skyblocker.skyblock.chat; + +import de.hysky.skyblocker.utils.Utils; +import net.minecraft.sound.SoundEvent; + +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * Data class to contain all the settings for a chat rule + */ +public class ChatRule { + + private String name; + + //inputs + private Boolean enabled; + private Boolean isPartialMatch; + private Boolean isRegex; + private Boolean isIgnoreCase; + private String filter; + private String validLocations; + + //output + private Boolean hideMessage; + private Boolean showActionBar; + private Boolean showAnnouncement; + private String replaceMessage; + private SoundEvent customSound; + /** + * Creates a chat rule with default options. + */ + public ChatRule(){ + this.name = "New Rule"; + + this.enabled = true; + this.isPartialMatch = false; + this.isRegex = false; + this.isIgnoreCase = true; + this.filter = ""; + this.validLocations = ""; + + this.hideMessage = true; + this.showActionBar = false; + this.showAnnouncement = false; + this.replaceMessage = null; + this.customSound = null; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getPartialMatch() { + return isPartialMatch; + } + + public void setPartialMatch(Boolean partialMatch) { + isPartialMatch = partialMatch; + } + + public Boolean getRegex() { + return isRegex; + } + + public void setRegex(Boolean regex) { + isRegex = regex; + } + + public Boolean getIgnoreCase() { + return isIgnoreCase; + } + + public void setIgnoreCase(Boolean ignoreCase) { + isIgnoreCase = ignoreCase; + } + + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + this.filter = filter; + } + + public Boolean getHideMessage() { + return hideMessage; + } + + public void setHideMessage(Boolean hideMessage) { + this.hideMessage = hideMessage; + } + + public Boolean getShowActionBar() { + return showActionBar; + } + + public void setShowActionBar(Boolean showActionBar) { + this.showActionBar = showActionBar; + } + + public Boolean getShowAnnouncement() { + return showAnnouncement; + } + + public void setShowAnnouncement(Boolean showAnnouncement) { + this.showAnnouncement = showAnnouncement; + } + + public String getReplaceMessage() { + return replaceMessage; + } + + public void setReplaceMessage(String replaceMessage) { + this.replaceMessage = replaceMessage; + } + + public SoundEvent getCustomSound() { + return customSound; + } + + public void setCustomSound(SoundEvent customSound) { + this.customSound = customSound; + } + + public String getValidLocations() { + return validLocations; + } + + public void setValidLocations(String validLocations) { + this.validLocations = validLocations; + } + + /** + * checks every input option and if the games state and the inputted str matches them returns true. + * @param inputString the chat message to check if fits + * @return if the inputs are all true and the outputs should be performed + */ + public Boolean isMatch(String inputString){ + //enabled + if (!enabled) return false; + + //ignore case + String testString; + String testFilter; + if (isIgnoreCase){ + testString = inputString.toLowerCase(); + testFilter = filter.toLowerCase(); + }else { + testString = inputString; + testFilter = filter; + } + + //filter + if (testFilter.isBlank()) return false; + if(isRegex) { + if (isPartialMatch) { + if (! Pattern.compile(testFilter).matcher(testString).find()) return false; + }else { + if (!testString.matches(testFilter)) return false; + } + } else{ + if (isPartialMatch) { + if (!testString.contains(testFilter)) return false; + }else { + if (!testFilter.equals(testString)) return false; + } + } + + //location + if (validLocations.isBlank()){ //if no locations do not check + return true; + } + String rawLocation = Utils.getLocationRaw(); + Boolean isLocationValid = null; + for (String validLocation : validLocations.replace(" ", "").toLowerCase().split(",")) {//the locations are raw locations split by "," and start with ! if not locations + String rawValidLocation = ChatRulesHandler.locations.get(validLocation.replace("!","")); + if (rawValidLocation == null) continue; + if (validLocation.startsWith("!")) {//not location + if (Objects.equals(rawValidLocation, rawLocation.toLowerCase())) { + isLocationValid = false; + break; + } + } + else { + if (Objects.equals(rawValidLocation, rawLocation.toLowerCase())) { //normal location + isLocationValid = true; + break; + } + } + } + if (isLocationValid != null && isLocationValid){//if location is not in the list at all and is a not a "!" location or and is a normal location + return true; + } + + return false; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} + + + diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java new file mode 100644 index 00000000..2cb6ca5c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleAnnouncementScreen.java @@ -0,0 +1,49 @@ +package de.hysky.skyblocker.skyblock.chat; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; + + +public class ChatRuleAnnouncementScreen { + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + private static float timer; + private static Text text = null; + + public static void init() { + HudRenderCallback.EVENT.register((context, tickDelta) -> { + if (timer <= 0 || text == null) { + return; + } + render(context, tickDelta); + }); + } + + /** + * renders {@link ChatRuleAnnouncementScreen#text} to the middle of the top of the screen. + * @param context render context + * @param tickDelta difference from last render to remove from timer + */ + private static void render(DrawContext context, float tickDelta) { + int scale = SkyblockerConfigManager.get().messages.chatRuleConfig.announcementScale; + //decrement timer + timer -= tickDelta; + //scale text up and center + MatrixStack matrices = context.getMatrices(); + matrices.push(); + matrices.translate(context.getScaledWindowWidth() / 2f, context.getScaledWindowHeight() * 0.3, 0f); + matrices.scale(scale, scale, 0f); + //render text + context.drawCenteredTextWithShadow(CLIENT.textRenderer,text,0, 0, 0xFFFFFF); + + matrices.pop(); + } + + protected static void setText(Text newText) { + text = newText; + timer = SkyblockerConfigManager.get().messages.chatRuleConfig.announcementLength; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleConfigScreen.java new file mode 100644 index 00000000..3adfc6fe --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRuleConfigScreen.java @@ -0,0 +1,326 @@ +package de.hysky.skyblocker.skyblock.chat; + +import it.unimi.dsi.fastutil.ints.IntIntPair; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + + +import java.awt.*; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import static java.util.Map.entry; + +public class ChatRuleConfigScreen extends Screen { + private static final int SPACER_X = 5; + private static final int SPACER_Y = 25; + + private final Map<MutableText, SoundEvent> soundsLookup = Map.ofEntries( + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.pling"), SoundEvents.BLOCK_NOTE_BLOCK_PLING.value()), + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.cave"), SoundEvents.AMBIENT_CAVE.value()), + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.zombie"), SoundEvents.ENTITY_ZOMBIE_AMBIENT), + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.crit"), SoundEvents.ENTITY_PLAYER_ATTACK_CRIT), + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.arrowHit"), SoundEvents.ENTITY_ARROW_HIT_PLAYER), + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.amethyst"), SoundEvents.BLOCK_AMETHYST_BLOCK_HIT), + entry(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.anvil"), SoundEvents.BLOCK_ANVIL_LAND) + ); + + private final int chatRuleIndex; + private final ChatRule chatRule; + private TextFieldWidget nameInput; + private TextFieldWidget filterInput; + private ButtonWidget partialMatchToggle; + private ButtonWidget regexToggle; + private ButtonWidget ignoreCaseToggle; + private TextFieldWidget locationsInput; + private ButtonWidget hideMessageToggle; + private ButtonWidget actionBarToggle; + private ButtonWidget announcementToggle; + private ButtonWidget soundsToggle; + private TextFieldWidget replaceMessageInput; + + //textLocations + private IntIntPair nameLabelTextPos; + private IntIntPair inputsLabelTextPos; + private IntIntPair filterLabelTextPos; + private IntIntPair partialMatchTextPos; + private IntIntPair regexTextPos; + private IntIntPair ignoreCaseTextPos; + private IntIntPair locationLabelTextPos; + private IntIntPair outputsLabelTextPos; + private IntIntPair hideMessageTextPos; + private IntIntPair actionBarTextPos; + private IntIntPair announcementTextPos; + private IntIntPair customSoundLabelTextPos; + private IntIntPair replaceMessageLabelTextPos; + + private int currentSoundIndex; + + private final Screen parent; + + public ChatRuleConfigScreen(Screen parent, int chatRuleIndex) { + super(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen")); + this.chatRuleIndex = chatRuleIndex; + this.chatRule = ChatRulesHandler.chatRuleList.get(chatRuleIndex); + this.parent = parent; + this.currentSoundIndex = getCurrentSoundIndex(); + } + + private int getCurrentSoundIndex() { + List<SoundEvent> soundOptions = soundsLookup.values().stream().toList(); + Identifier ruleSoundId = chatRule.getCustomSound().getId(); + for (int i = 0; i < soundOptions.size(); i++) { + if (soundOptions.get(i).getId().compareTo(ruleSoundId) == 0) { + return i; + } + } + //not found + return -1; + } + + @Override + protected void init() { + super.init(); + if (client == null) return; + //start centered on the X and 1/3 down on the Y + IntIntPair currentPos = IntIntPair.of((this.width - getMaxUsedWidth()) / 2,(int)((this.height -getMaxUsedHeight()) * 0.33)); + int lineXOffset; + + nameLabelTextPos = currentPos; + lineXOffset = client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.name")) + SPACER_X; + nameInput = new TextFieldWidget(MinecraftClient.getInstance().textRenderer, currentPos.leftInt() + lineXOffset, currentPos.rightInt(), 100, 20, Text.of("")); + nameInput.setText(chatRule.getName()); + nameInput.setTooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.name.@Tooltip"))); + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + + inputsLabelTextPos = currentPos; + currentPos = IntIntPair.of(currentPos.leftInt() + 10 ,currentPos.rightInt() + SPACER_Y); + + filterLabelTextPos = currentPos; + lineXOffset = client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.filter")) + SPACER_X; + filterInput = new TextFieldWidget(MinecraftClient.getInstance().textRenderer, currentPos.leftInt() + lineXOffset, currentPos.rightInt(), 200, 20, Text.of("")); + filterInput.setMaxLength(96); + filterInput.setText(chatRule.getFilter()); + filterInput.setTooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.filter.@Tooltip"))); + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + lineXOffset = 0; + + partialMatchTextPos = IntIntPair.of(currentPos.leftInt() + lineXOffset,currentPos.rightInt()); + lineXOffset += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.partialMatch")) + SPACER_X; + partialMatchToggle = ButtonWidget.builder(enabledButtonText(chatRule.getPartialMatch()), a -> { + chatRule.setPartialMatch(!chatRule.getPartialMatch()); + partialMatchToggle.setMessage(enabledButtonText(chatRule.getPartialMatch())); + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(75,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.partialMatch.@Tooltip"))) + .build(); + lineXOffset += 75 + SPACER_X; + regexTextPos = IntIntPair.of(currentPos.leftInt() + lineXOffset,currentPos.rightInt()); + lineXOffset += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.regex")) + SPACER_X; + regexToggle = ButtonWidget.builder(enabledButtonText(chatRule.getRegex()), a -> { + chatRule.setRegex(!chatRule.getRegex()); + regexToggle.setMessage(enabledButtonText(chatRule.getRegex())); + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(75,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.regex.@Tooltip"))) + .build(); + lineXOffset += 75 + SPACER_X; + ignoreCaseTextPos = IntIntPair.of(currentPos.leftInt() + lineXOffset,currentPos.rightInt()); + lineXOffset += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.ignoreCase")) + SPACER_X; + ignoreCaseToggle = ButtonWidget.builder(enabledButtonText(chatRule.getIgnoreCase()), a -> { + chatRule.setIgnoreCase(!chatRule.getIgnoreCase()); + ignoreCaseToggle.setMessage(enabledButtonText(chatRule.getIgnoreCase())); + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(75,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.ignoreCase.@Tooltip"))) + .build(); + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + + locationLabelTextPos = currentPos; + lineXOffset = client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.locations")) + SPACER_X; + locationsInput = new TextFieldWidget(MinecraftClient.getInstance().textRenderer, currentPos.leftInt() + lineXOffset, currentPos.rightInt(), 200, 20, Text.of("")); + locationsInput.setText(chatRule.getValidLocations()); + MutableText locationToolTip = Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.locations.@Tooltip"); + ChatRulesHandler.locationsList.forEach(location -> locationToolTip.append(" " + location + ",\n")); + locationsInput.setTooltip(Tooltip.of(locationToolTip)); + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + + outputsLabelTextPos = IntIntPair.of(currentPos.leftInt() - 10,currentPos.rightInt()); + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + + hideMessageTextPos = currentPos; + lineXOffset = client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.hideMessage")) + SPACER_X; + hideMessageToggle = ButtonWidget.builder(enabledButtonText(chatRule.getHideMessage()), a -> { + chatRule.setHideMessage(!chatRule.getHideMessage()); + hideMessageToggle.setMessage(enabledButtonText(chatRule.getHideMessage())); + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(75,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.hideMessage.@Tooltip"))) + .build(); + lineXOffset += 75 + SPACER_X; + actionBarTextPos = IntIntPair.of(currentPos.leftInt() + lineXOffset,currentPos.rightInt()); + lineXOffset += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.actionBar")) + SPACER_X; + actionBarToggle = ButtonWidget.builder(enabledButtonText(chatRule.getShowActionBar()), a -> { + chatRule.setShowActionBar(!chatRule.getShowActionBar()); + actionBarToggle.setMessage(enabledButtonText(chatRule.getShowActionBar())); + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(75,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.actionBar.@Tooltip"))) + .build(); + lineXOffset = 0; + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + + announcementTextPos = IntIntPair.of(currentPos.leftInt() + lineXOffset,currentPos.rightInt()); + lineXOffset += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.announcement")) + SPACER_X; + announcementToggle = ButtonWidget.builder(enabledButtonText(chatRule.getShowAnnouncement()), a -> { + chatRule.setShowAnnouncement(!chatRule.getShowAnnouncement()); + announcementToggle.setMessage(enabledButtonText(chatRule.getShowAnnouncement())); + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(75,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.announcement.@Tooltip"))) + .build(); + lineXOffset += 75 + SPACER_X; + customSoundLabelTextPos = IntIntPair.of(currentPos.leftInt() + lineXOffset,currentPos.rightInt()); + lineXOffset += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds")) + SPACER_X; + soundsToggle = ButtonWidget.builder(getSoundName(), a -> { + currentSoundIndex += 1; + if (currentSoundIndex == soundsLookup.size()) { + currentSoundIndex = -1; + } + MutableText newText = getSoundName(); + soundsToggle.setMessage(newText); + SoundEvent sound = soundsLookup.get(newText); + chatRule.setCustomSound(sound); + if (client.player != null && sound != null) { + client.player.playSound(sound, 100f, 0.1f); + } + }) + .position(currentPos.leftInt() + lineXOffset, currentPos.rightInt()) + .size(100,20) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.@Tooltip"))) + .build(); + currentPos = IntIntPair.of(currentPos.leftInt(),currentPos.rightInt() + SPACER_Y); + + replaceMessageLabelTextPos = currentPos; + lineXOffset = client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.replace")) + SPACER_X; + replaceMessageInput = new TextFieldWidget(MinecraftClient.getInstance().textRenderer, currentPos.leftInt() + lineXOffset, currentPos.rightInt(), 200, 20, Text.of("")); + replaceMessageInput.setMaxLength(96); + replaceMessageInput.setTooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.replace.@Tooltip"))); + replaceMessageInput.setText(chatRule.getReplaceMessage()); + + ButtonWidget finishButton = ButtonWidget.builder(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.finish"), a -> close()) + .position(this.width - 75 - SPACER_Y, this.height - SPACER_Y) + .size(75, 20) + .build(); + + addDrawableChild(nameInput); + addDrawableChild(filterInput); + addDrawableChild(partialMatchToggle); + addDrawableChild(regexToggle); + addDrawableChild(ignoreCaseToggle); + addDrawableChild(locationsInput); + addDrawableChild(hideMessageToggle); + addDrawableChild(actionBarToggle); + addDrawableChild(announcementToggle); + addDrawableChild(soundsToggle); + addDrawableChild(replaceMessageInput); + addDrawableChild(finishButton); + } + + /** + * Works out the width of the maximum line + * @return the max used width + */ + private int getMaxUsedWidth() { + if (client == null) return 0; + //text + int total = client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.partialMatch")); + total += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.regex")); + total += client.textRenderer.getWidth(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.ignoreCase")); + //space + total += SPACER_X * 6; + //button width + total += 75 * 3; + return total; + } + + /** + * Works out the height used + * @return height used by the gui + */ + private int getMaxUsedHeight() { + //there are 8 rows so just times the spacer by 8 + return SPACER_Y * 8; + } + + private Text enabledButtonText(boolean enabled) { + if (enabled){ + return Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.true").withColor(Color.green.getRGB()); + }else { + return Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.false").withColor(Color.red.getRGB()); + } + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); + + //draw labels ands text + int yOffset = (SPACER_Y - this.textRenderer.fontHeight) / 2; + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.inputs"), inputsLabelTextPos.leftInt(), inputsLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.name"), nameLabelTextPos.leftInt(), nameLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.filter"), filterLabelTextPos.leftInt(), filterLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.partialMatch"), partialMatchTextPos.leftInt(), partialMatchTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.regex"), regexTextPos.leftInt(), regexTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.ignoreCase"), ignoreCaseTextPos.leftInt(), ignoreCaseTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.locations"), locationLabelTextPos.leftInt(), locationLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.outputs"), outputsLabelTextPos.leftInt(), outputsLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.hideMessage"), hideMessageTextPos.leftInt(), hideMessageTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.actionBar"), actionBarTextPos.leftInt(), actionBarTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.announcement"), announcementTextPos.leftInt(), announcementTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds"), customSoundLabelTextPos.leftInt(), customSoundLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + context.drawTextWithShadow(this.textRenderer,Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.replace"), replaceMessageLabelTextPos.leftInt(), replaceMessageLabelTextPos.rightInt() + yOffset, 0xFFFFFF); + } + + @Override + public void close() { + //todo add checks to see if valid rule e.g. has name + //and if valid save a + if (client != null ) { + save(); + client.setScreen(parent); + } + } + private void save(){ + chatRule.setName(nameInput.getText()); + chatRule.setFilter(filterInput.getText()); + chatRule.setReplaceMessage(replaceMessageInput.getText()); + chatRule.setValidLocations(locationsInput.getText()); + + ChatRulesHandler.chatRuleList.set(chatRuleIndex,chatRule); + } + + private MutableText getSoundName() { + if (currentSoundIndex == -1){ + return Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.sounds.none"); + } + return soundsLookup.keySet().stream().toList().get(currentSoundIndex); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java new file mode 100644 index 00000000..c5d7fcc8 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigListWidget.java @@ -0,0 +1,196 @@ +package de.hysky.skyblocker.skyblock.chat; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.screen.narration.NarrationPart; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; + +import java.awt.*; +import java.util.List; + +public class ChatRulesConfigListWidget extends ElementListWidget<ChatRulesConfigListWidget.AbstractChatRuleEntry> { + private final ChatRulesConfigScreen screen; + + private Boolean hasChanged; + + public ChatRulesConfigListWidget(MinecraftClient minecraftClient, ChatRulesConfigScreen screen, int width, int height, int y, int itemHeight) { + super(minecraftClient, width, height, y, itemHeight); + this.screen = screen; + this.hasChanged = false; + //add labels + addEntry(new chatRuleLabelsEntry()); + //add entry fall all existing rules + for (int i = 0; i < (long) ChatRulesHandler.chatRuleList.size(); i++){ + addEntry(new chatRuleConfigEntry(i)); + } + } + + @Override + public int getRowWidth() { + return super.getRowWidth() + 100; + } + + @Override + protected int getScrollbarPositionX() { + return super.getScrollbarPositionX() + 50; + } + + protected void addRuleAfterSelected() { + hasChanged = true; + int newIndex = children().indexOf(getSelectedOrNull()) + 1; + ChatRulesHandler.chatRuleList.add(newIndex, new ChatRule()); + children().add(newIndex + 1, new chatRuleConfigEntry(newIndex)); + } + + protected boolean removeEntry(AbstractChatRuleEntry entry) { + hasChanged = true; + return super.removeEntry(entry); + } + + protected void saveRules() { + hasChanged = false; + ChatRulesHandler.saveChatRules(); + } + + protected boolean hasChanges(){ + return (hasChanged || children().stream().filter(chatRuleConfigEntry.class::isInstance).map(chatRuleConfigEntry.class::cast).anyMatch(chatRuleConfigEntry::isChange)); + } + + protected static abstract class AbstractChatRuleEntry extends Entry<ChatRulesConfigListWidget.AbstractChatRuleEntry> { + } + + private class chatRuleLabelsEntry extends AbstractChatRuleEntry { + + @Override + public List<? extends Selectable> selectableChildren() { + return List.of(); + } + + @Override + public List<? extends Element> children() { + return List.of(); + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + context.drawCenteredTextWithShadow(client.textRenderer, Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleName"), width / 2 - 125, y + 5, 0xFFFFFF); + context.drawCenteredTextWithShadow(client.textRenderer, Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleEnabled"), width / 2, y + 5, 0xFFFFFF); + context.drawCenteredTextWithShadow(client.textRenderer, Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.modify"), width / 2 + 100, y + 5, 0xFFFFFF); + } + } + + private class chatRuleConfigEntry extends AbstractChatRuleEntry { + //data + private final int chatRuleIndex; + private final ChatRule chatRule; + + private final List<? extends Element> children; + + //widgets + private final ButtonWidget enabledButton; + private final ButtonWidget openConfigButton; + private final ButtonWidget deleteButton; + + //text location + private final int nameX = width / 2 - 125; + //saved data + private double oldScrollAmount = 0; + + + public chatRuleConfigEntry(int chatRuleIndex) { + this.chatRuleIndex = chatRuleIndex; + this.chatRule = ChatRulesHandler.chatRuleList.get(chatRuleIndex); + + enabledButton = ButtonWidget.builder(enabledButtonText() , a -> toggleEnabled()) + .size(50,20) + .position(width / 2 - 25,5) + .build(); + + openConfigButton = ButtonWidget.builder(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.editRule"), a -> { + client.setScreen(new ChatRuleConfigScreen(screen, chatRuleIndex)); + }) + .size(50,20) + .position(width / 2 + 45,5) + .tooltip(Tooltip.of(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.editRule.@Tooltip"))) + .build(); + + deleteButton = ButtonWidget.builder(Text.translatable("selectServer.delete"), a -> { + oldScrollAmount = getScrollAmount(); + client.setScreen(new ConfirmScreen(this::deleteEntry, Text.translatable("skyblocker.shortcuts.deleteQuestion"), Text.translatable("skyblocker.shortcuts.deleteWarning", chatRule.getName()), Text.translatable("selectServer.deleteButton"), ScreenTexts.CANCEL)); + }) + .size(50,20) + .position(width / 2 + 105,5) + .build(); + + children = List.of(enabledButton, openConfigButton, deleteButton); + } + + private Text enabledButtonText() { + if (chatRule.getEnabled()){ + return Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.true").withColor(Color.green.getRGB()); + }else { + return Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen.false").withColor(Color.red.getRGB()); + } + } + private void toggleEnabled() { + hasChanged = true; + chatRule.setEnabled(!chatRule.getEnabled()); + enabledButton.setMessage(enabledButtonText()); + } + + private void deleteEntry(boolean confirmedAction) { + if (confirmedAction){ + //delete this + ChatRulesHandler.chatRuleList.remove(chatRuleIndex); + removeEntry(this); + } + client.setScreen(screen); + setScrollAmount(oldScrollAmount); + } + + @Override + public List<? extends Selectable> selectableChildren() { + return List.of(new Selectable() { + @Override + public SelectionType getType() { + return SelectionType.HOVERED; + } + + @Override + public void appendNarrations(NarrationMessageBuilder builder) { + builder.put(NarrationPart.TITLE,chatRule.getName()); + } + }); + } + + @Override + public List<? extends Element> children() { + return children; + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { //todo get strings form en_us.json + //widgets + enabledButton.setY(y); + enabledButton.render(context, mouseX, mouseY, tickDelta); + openConfigButton.setY(y); + openConfigButton.render(context, mouseX, mouseY, tickDelta); + deleteButton.setY(y); + deleteButton.render(context, mouseX, mouseY, tickDelta); + //text + context.drawCenteredTextWithShadow(client.textRenderer, chatRule.getName(), nameX, y + 5, 0xFFFFFF); + } + + public boolean isChange() { + return (!chatRule.getEnabled().equals(ChatRulesHandler.chatRuleList.get(chatRuleIndex).getEnabled())); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigScreen.java new file mode 100644 index 00000000..1a6815dc --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesConfigScreen.java @@ -0,0 +1,75 @@ +package de.hysky.skyblocker.skyblock.chat; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.client.gui.widget.SimplePositioningWidget; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; + +public class ChatRulesConfigScreen extends Screen { + + private ChatRulesConfigListWidget chatRulesConfigListWidget; + private final Screen parent; + + public ChatRulesConfigScreen(Screen parent) { + super(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.ruleScreen")); + this.parent = parent; + } + + @Override + public void setTooltip(Text tooltip) { + super.setTooltip(tooltip); + } + + @Override + protected void init() { + super.init(); + chatRulesConfigListWidget = new ChatRulesConfigListWidget(client, this, width, height - 96, 32, 25); + addDrawableChild(chatRulesConfigListWidget); + GridWidget gridWidget = new GridWidget(); + gridWidget.getMainPositioner().marginX(5).marginY(2); + GridWidget.Adder adder = gridWidget.createAdder(3); + adder.add(ButtonWidget.builder(ScreenTexts.CANCEL, button -> { + if (client != null) { + close(); + } + }).build()); + ButtonWidget buttonNew1 = ButtonWidget.builder(Text.translatable("text.autoconfig.skyblocker.option.messages.chatRules.screen.new"), buttonNew -> chatRulesConfigListWidget.addRuleAfterSelected()).build(); + adder.add(buttonNew1); + ButtonWidget buttonDone = ButtonWidget.builder(ScreenTexts.DONE, button -> { + chatRulesConfigListWidget.saveRules(); + if (client != null) { + close(); + } + }).build(); + adder.add(buttonDone); + gridWidget.refreshPositions(); + SimplePositioningWidget.setPos(gridWidget, 0, this.height - 64, this.width, 64); + gridWidget.forEachChild(this::addDrawableChild); + + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); + } + + @Override + public void close() { + if (client != null && chatRulesConfigListWidget.hasChanges()) { + client.setScreen(new ConfirmScreen(confirmedAction -> { + if (confirmedAction) { + this.client.setScreen(parent); + } else { + client.setScreen(this); + } + }, Text.translatable("text.skyblocker.quit_config"), Text.translatable("text.skyblocker.quit_config_sure"), Text.translatable("text.skyblocker.quit_discard"), ScreenTexts.CANCEL)); + } else { + this.client.setScreen(parent); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java new file mode 100644 index 00000000..bde55aed --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java @@ -0,0 +1,167 @@ +package de.hysky.skyblocker.skyblock.chat; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.Http; +import de.hysky.skyblocker.utils.Utils; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.*; + +public class ChatRulesHandler { + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + private static final Logger LOGGER = LoggerFactory.getLogger(ChatRule.class); + private static final Path CHAT_RULE_FILE = SkyblockerMod.CONFIG_DIR.resolve("chat_rules.json"); + /** + * look up table for the locations input by the users to raw locations + */ + protected static final HashMap<String, String> locations = new HashMap<>(); + /** + * list of possible locations still formatted for the tool tip + */ + protected static final List<String> locationsList = new ArrayList<>(); + + protected static final List<ChatRule> chatRuleList = new ArrayList<>(); + + public static void init() { + loadChatRules(); + loadLocations(); + ClientReceiveMessageEvents.ALLOW_GAME.register(ChatRulesHandler::checkMessage); + } + + private static void loadChatRules() { + try (BufferedReader reader = Files.newBufferedReader(CHAT_RULE_FILE)) { + Type chatRulesType = new TypeToken<Map<String, List<ChatRule>>>() { + }.getType(); + Map<String, List<ChatRule>> chatRules = SkyblockerMod.GSON.fromJson(reader,chatRulesType); + chatRuleList.addAll(chatRules.get("rules")); + + LOGGER.info("[Skyblocker] Loaded chat rules"); + } catch (NoSuchFileException e) { + //todo create default chat rules + LOGGER.warn("[Skyblocker] chat rule file not found, using default rules. This is normal when using for the first time."); + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to load shortcuts file", e); + } + } + + private static void loadLocations() { + try { + String response = Http.sendGetRequest("https://api.hypixel.net/v2/resources/games"); + JsonObject locationsJson = JsonParser.parseString(response).getAsJsonObject().get("games").getAsJsonObject().get("SKYBLOCK").getAsJsonObject().get("modeNames").getAsJsonObject(); + for (Map.Entry<String, JsonElement> entry : locationsJson.entrySet()) { + //fix old naming todo remove when hypixel fix + if (Objects.equals(entry.getKey(), "instanced")) { + locationsList.add(entry.getValue().getAsString()); + locations.put(entry.getValue().getAsString().replace(" ", "").toLowerCase(), "kuudra"); + continue; + } + locationsList.add(entry.getValue().getAsString()); + //add to list in a simplified for so more lenient for user input + locations.put(entry.getValue().getAsString().replace(" ", "").toLowerCase(),entry.getKey()); + } + } + catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to load locations!", e); + } + } + + protected static void saveChatRules() { + JsonObject chatRuleJson = new JsonObject(); + chatRuleJson.add("rules", SkyblockerMod.GSON.toJsonTree(chatRuleList)); + try (BufferedWriter writer = Files.newBufferedWriter(CHAT_RULE_FILE)) { + SkyblockerMod.GSON.toJson(chatRuleJson, writer); + LOGGER.info("[Skyblocker] Saved chat rules file"); + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to save chat rules file", e); + } + } + + /** + * Checks each rule in {@link ChatRulesHandler#chatRuleList} to see if they are a match for the message and if so change outputs based on the options set in the {@link ChatRule}. + * @param message the chat message + * @param overlay if its overlay + */ + private static boolean checkMessage(Text message, Boolean overlay) { + if (!Utils.isOnSkyblock()) return true; //do not work not on skyblock + if (overlay) return true; //ignore messages in overlay + String plain = Formatting.strip(message.getString()); + for (ChatRule rule : chatRuleList) { + if (rule.isMatch(plain)) { + //get a replacement message + Text newMessage; + if (!rule.getReplaceMessage().isBlank()) { + newMessage = formatText(rule.getReplaceMessage()); + } + else { + newMessage = message; + } + + if (rule.getShowAnnouncement()) { + ChatRuleAnnouncementScreen.setText(newMessage); + } + + //show in action bar + if (rule.getShowActionBar() && CLIENT.player != null) { + CLIENT.player.sendMessage(newMessage, true); + } + + //hide message + if (!rule.getHideMessage() && CLIENT.player != null) { + CLIENT.player.sendMessage(newMessage, false); + } + + //play sound + if (rule.getCustomSound() != null && CLIENT.player != null) { + CLIENT.player.playSound(rule.getCustomSound(), 100f, 0.1f); + } + + //do not send original message + return false; + } + } + return true; + } + + /** + * Converts a string with color codes into a formatted Text object + * @param codedString the string with color codes in + * @return formatted text + */ + protected static MutableText formatText(String codedString) { + if (codedString.contains(String.valueOf(Formatting.FORMATTING_CODE_PREFIX)) || codedString.contains("&")){ + MutableText newText = Text.literal(""); + String[] parts = codedString.split("[" + Formatting.FORMATTING_CODE_PREFIX +"&]"); + Style style = Style.EMPTY; + for (String part : parts) { + if (part.isEmpty()) continue; + Formatting formatting = Formatting.byCode(part.charAt(0)); + if (formatting != null){ + style = style.withFormatting(formatting); + Text.literal(part.substring(1)).getWithStyle(style).forEach(newText::append); + } else { + newText.append(Text.of(part)); + } + } + return newText; + } + return Text.literal(codedString); + } +} |