diff options
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java')
-rw-r--r-- | src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java | 182 |
1 files changed, 182 insertions, 0 deletions
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..13115bee --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chat/ChatRulesHandler.java @@ -0,0 +1,182 @@ +package de.hysky.skyblocker.skyblock.chat; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; + +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.sound.SoundEvents; +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.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +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"); + private static final Codec<Map<String, List<ChatRule>>> MAP_CODEC = Codec.unboundedMap(Codec.STRING, ChatRule.LIST_CODEC); + /** + * 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() { + CompletableFuture.runAsync(ChatRulesHandler::loadChatRules); + CompletableFuture.runAsync(ChatRulesHandler::loadLocations); + ClientReceiveMessageEvents.ALLOW_GAME.register(ChatRulesHandler::checkMessage); + } + + private static void loadChatRules() { + try (BufferedReader reader = Files.newBufferedReader(CHAT_RULE_FILE)) { + Map<String, List<ChatRule>> chatRules = MAP_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow(); + LOGGER.info("[Sky: " + chatRules.toString()); + + chatRuleList.addAll(chatRules.get("rules")); + + LOGGER.info("[Skyblocker] Loaded chat rules"); + } catch (NoSuchFileException e) { + registerDefaultChatRules(); + LOGGER.warn("[Skyblocker] chat rule file not found, using default rules. This is normal when using for the first time."); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to load shortcuts file", e); + } + } + + private static void registerDefaultChatRules() { + //clean hub chat + ChatRule cleanHubRule = new ChatRule("Clean Hub Chat", false, true, true, true, "(selling)|(buying)|(lowb)|(visit)|(/p)|(/ah)|(my ah)", "hub", true, false, false, "", null); + //mining Ability + ChatRule miningAbilityRule = new ChatRule("Mining Ability Alert", false, true, false, true, "is now available!", "Crystal Hollows, Dwarven Mines", false, false, true, "&1Ability", SoundEvents.ENTITY_ARROW_HIT_PLAYER); + + chatRuleList.add(cleanHubRule); + chatRuleList.add(miningAbilityRule); + } + + 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", ChatRule.LIST_CODEC.encodeStart(JsonOps.INSTANCE, chatRuleList).result().orElseThrow()); + try (BufferedWriter writer = Files.newBufferedWriter(CHAT_RULE_FILE)) { + SkyblockerMod.GSON.toJson(chatRuleJson, writer); + LOGGER.info("[Skyblocker] Saved chat rules file"); + } catch (Exception 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); + } +} |