diff --git a/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java b/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java index 61d8fcd3..c716b02a 100644 --- a/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java +++ b/src/datagen/java/codes/cookies/mod/datagen/lang/EnglishLanguageProvider.java @@ -394,6 +394,10 @@ private void addMiningConfig(CookiesTranslationBuilder translationBuilder) { translationBuilder.addConfig(CONFIG_MINING_MOD_HELPER, "Mod Helper", "Enables the mines of divan chest helper."); + translationBuilder.addConfig( + CONFIG_MINING_MOD_CRYSTAL_HUD, + "Crystal Hud", + "Enables the crystal hud, shows information about current crystal status, parts available and tools available.\n\n§cRequires the crystal player list widget to be active!"); translationBuilder.addConfig(CONFIG_MINING_PUZZLER_SOLVER, "Puzzler solver", "Highlight the correct block for the puzzler."); @@ -588,7 +592,7 @@ private void addDungeonConfig(CookiesTranslationBuilder translationBuilder) { "Use class colors", "Uses the class colors instead of the default color."); translationBuilder.addConfig(CONFIG_DUNGEON_GLOW_CLASS_COLOR, - "Glow teammates by class colors", + "Class based glow color",//"Glow teammates by class colors", "Overrides the default hypixel glowing by rank to glow by class color."); translationBuilder.addConfig(CONFIG_DUNGEON_CLASS_COLOR, "Class colors", diff --git a/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 b/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 index 6cdf9931..646ed537 100644 --- a/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 +++ b/src/main/generated/.cache/cabcb80d088276cffde41e74584028f1c00b99b8 @@ -1,2 +1,2 @@ -// 1.21.3 2024-11-17T23:09:20.9370947 cookies-mod/Language (en_us) -9f18fc62d9f1688bfa5af6de8a9d7f91b600ea9c assets\cookies-mod\lang\en_us.json +// 1.21.3 2024-11-18T21:50:02.348035 cookies-mod/Language (en_us) +c4ccaf30006997855f4e249ad734e937b167f02f assets/cookies-mod/lang/en_us.json diff --git a/src/main/generated/assets/cookies-mod/lang/en_us.json b/src/main/generated/assets/cookies-mod/lang/en_us.json index 4ba8a1f3..c4799472 100644 --- a/src/main/generated/assets/cookies-mod/lang/en_us.json +++ b/src/main/generated/assets/cookies-mod/lang/en_us.json @@ -90,7 +90,7 @@ "cookies.config.dev.show_plot_price_breakdown.tooltip": "Shows a breakdown of how much compost you need to unlock all plots.", "cookies.config.dev.tooltip": "Development related config entries.", "cookies.config.dungeon.name": "Dungeon Config", - "cookies.config.dungeon.player_glow_by_class_color.name": "Glow teammates by class colors", + "cookies.config.dungeon.player_glow_by_class_color.name": "Class based glow color", "cookies.config.dungeon.player_glow_by_class_color.tooltip": "Overrides the default hypixel glowing by rank to glow by class color.", "cookies.config.dungeon.puzzle.creeper_beams.name": "Creeper Beams", "cookies.config.dungeon.puzzle.creeper_beams.tooltip": "Enables the creeper beams puzzle solver.", @@ -244,6 +244,8 @@ "cookies.config.item_search.show_museum.tooltip": "Shows the status of museum items.", "cookies.config.item_search.tooltip": "All item search related settings", "cookies.config.mining.categories.hotm": "HOTM", + "cookies.config.mining.crystal_hud.name": "Crystal Hud", + "cookies.config.mining.crystal_hud.tooltip": "Enables the crystal hud, shows information about current crystal status, parts available and tools available.\n\n§cRequires the crystal player list widget to be active!", "cookies.config.mining.highlight_disabled_hotm_perks.name": "Highlight disabled", "cookies.config.mining.highlight_disabled_hotm_perks.tooltip": "Change disabled perks to redstone.", "cookies.config.mining.mod_helper.name": "Mod Helper", diff --git a/src/main/java/codes/cookies/mod/CookiesMod.java b/src/main/java/codes/cookies/mod/CookiesMod.java index 14ab9ed9..48460ee4 100644 --- a/src/main/java/codes/cookies/mod/CookiesMod.java +++ b/src/main/java/codes/cookies/mod/CookiesMod.java @@ -17,13 +17,14 @@ import codes.cookies.mod.repository.Repository; import codes.cookies.mod.repository.constants.RepositoryConstants; import codes.cookies.mod.screen.search.ItemSearchScreen; +import codes.cookies.mod.services.mining.CrystalStatusService; import codes.cookies.mod.utils.UpdateChecker; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import codes.cookies.mod.utils.skyblock.MayorUtils; -import codes.cookies.mod.utils.skyblock.tab.PlayerListUtils; +import codes.cookies.mod.utils.skyblock.playerlist.PlayerListUtils; import lombok.Getter; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; @@ -79,6 +80,7 @@ public void onInitializeClient() { UpdateChecker.init(); PlayerListUtils.init(); HudManager.load(); + CrystalStatusService.register(); this.registerKeyBindings(); } diff --git a/src/main/java/codes/cookies/mod/config/categories/mining/MiningConfig.java b/src/main/java/codes/cookies/mod/config/categories/mining/MiningConfig.java index 7432d3c0..6a3c6c66 100644 --- a/src/main/java/codes/cookies/mod/config/categories/mining/MiningConfig.java +++ b/src/main/java/codes/cookies/mod/config/categories/mining/MiningConfig.java @@ -4,10 +4,12 @@ import codes.cookies.mod.config.categories.mining.powder.PowderTrackerHudFoldable; import codes.cookies.mod.config.categories.mining.shaft.ShaftConfig; import codes.cookies.mod.config.system.Category; +import codes.cookies.mod.config.system.HudSetting; import codes.cookies.mod.config.system.Parent; import codes.cookies.mod.config.system.Row; import codes.cookies.mod.config.system.options.BooleanOption; import codes.cookies.mod.config.system.options.TextDisplayOption; +import codes.cookies.mod.features.mining.hollows.CrystalRunHud; import codes.cookies.mod.features.mining.hollows.MinesOfDivanHelper; import java.util.function.Predicate; @@ -30,6 +32,8 @@ public class MiningConfig extends Category { public ShaftConfig shaftConfig = new ShaftConfig(); public PowderTrackerHudFoldable powderTrackerHud = new PowderTrackerHudFoldable(); + @HudSetting(CrystalRunHud.class) + public BooleanOption crystalHud = new BooleanOption(CONFIG_MINING_MOD_CRYSTAL_HUD, true); @Parent public TextDisplayOption hotmParentDisplay = new TextDisplayOption(CONFIG_MINING_CATEGORIES_HOTM); diff --git a/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalStatus.java b/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalStatus.java new file mode 100644 index 00000000..e0272484 --- /dev/null +++ b/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalStatus.java @@ -0,0 +1,37 @@ +package codes.cookies.mod.data.mining.crystal; + +import com.mojang.serialization.Codec; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; + +/** + * All types of crystal status, and their display name. + */ +@RequiredArgsConstructor +@Getter +public enum CrystalStatus implements StringIdentifiable { + + NOT_FOUND(Text.literal("✖ Not Placed").formatted(Formatting.RED)), + FOUND(Text.literal("✔ Found").formatted(Formatting.GREEN)), + PLACED(Text.literal("✔ Placed").formatted(Formatting.YELLOW)); + + public static final Codec CODEC = StringIdentifiable.createCodec(CrystalStatus::values); + private final Text text; + + public static CrystalStatus getCrystalStatusFromText(String text) { + return switch (text) { + case "✖ Not Placed", "✔ Found" -> FOUND; + case "✔ Placed" -> PLACED; + default -> NOT_FOUND; + }; + } + + @Override + public String asString() { + return name(); + } +} diff --git a/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalStatusData.java b/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalStatusData.java new file mode 100644 index 00000000..c21edb58 --- /dev/null +++ b/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalStatusData.java @@ -0,0 +1,46 @@ +package codes.cookies.mod.data.mining.crystal; + +import codes.cookies.mod.utils.json.CodecJsonSerializable; +import com.mojang.serialization.Codec; +import org.slf4j.Logger; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Data about the different crystal types and their respective status. + */ +public class CrystalStatusData implements CodecJsonSerializable> { + private static final Codec> CODEC = Codec.unboundedMap(CrystalType.CODEC, CrystalStatus.CODEC); + + private final Map map = new HashMap<>(); + + public CrystalStatus getStatus(CrystalType type) { + return Objects.requireNonNullElse(map.get(type), CrystalStatus.NOT_FOUND); + } + + public void setStatus(CrystalType type, CrystalStatus status) { + map.put(type, Objects.requireNonNullElse(status, CrystalStatus.NOT_FOUND)); + } + + @Override + public Codec> getCodec() { + return CODEC; + } + + @Override + public void load(Map value) { + map.putAll(value); + } + + @Override + public Map getValue() { + return map; + } + + @Override + public Logger getLogger() { + return logger; + } +} diff --git a/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalType.java b/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalType.java new file mode 100644 index 00000000..67c8a54f --- /dev/null +++ b/src/main/java/codes/cookies/mod/data/mining/crystal/CrystalType.java @@ -0,0 +1,55 @@ +package codes.cookies.mod.data.mining.crystal; + +import java.util.Optional; + +import codes.cookies.mod.utils.skyblock.playerlist.widgets.crystal.CrystalOrigin; +import com.mojang.serialization.Codec; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; + +/** + * All crystal types in the game plus their respective formatting. + */ +@Getter +@AllArgsConstructor +public enum CrystalType implements StringIdentifiable { + + JADE(CrystalOrigin.CRYSTAL_HOLLOWS, Formatting.GREEN), + AMBER(CrystalOrigin.CRYSTAL_HOLLOWS, Formatting.GOLD), + AMETHYST(CrystalOrigin.CRYSTAL_HOLLOWS, Formatting.DARK_PURPLE), + SAPPHIRE(CrystalOrigin.CRYSTAL_HOLLOWS, Formatting.AQUA), + TOPAZ(CrystalOrigin.CRYSTAL_HOLLOWS, Formatting.YELLOW), + JASPER(CrystalOrigin.MISC, Formatting.LIGHT_PURPLE), + RUBY(CrystalOrigin.MISC, Formatting.RED), // Misc crystals + OPAL(CrystalOrigin.CRIMSON_ISLE, Formatting.WHITE), // Crimson isle + AQUAMARINE(CrystalOrigin.GLACITE_TUNNELS, Formatting.BLUE), + PERIDOT(CrystalOrigin.GLACITE_TUNNELS, Formatting.DARK_GREEN), + CITRINE(CrystalOrigin.GLACITE_TUNNELS, Formatting.DARK_RED), + ONYX(CrystalOrigin.GLACITE_TUNNELS, Formatting.DARK_GRAY); // Tunnels + + public static final Codec CODEC = StringIdentifiable.createCodec(CrystalType::values); + private final CrystalOrigin crystalOrigin; + private final Formatting formatting; + + public static Optional getCrystalTypeByDisplayName(String displayName) { + if (displayName == null) { + return Optional.empty(); + } + + for (CrystalType value : values()) { + if (value.name().equalsIgnoreCase(displayName)) { + return Optional.of(value); + } + } + + return Optional.empty(); + } + + @Override + public String asString() { + return name(); + } +} diff --git a/src/main/java/codes/cookies/mod/data/profile/ProfileData.java b/src/main/java/codes/cookies/mod/data/profile/ProfileData.java index eea0688b..eed46cb5 100644 --- a/src/main/java/codes/cookies/mod/data/profile/ProfileData.java +++ b/src/main/java/codes/cookies/mod/data/profile/ProfileData.java @@ -2,6 +2,7 @@ import codes.cookies.mod.data.farming.squeakymousemat.SqueakyMousematData; import codes.cookies.mod.data.mining.PowderData; +import codes.cookies.mod.data.mining.crystal.CrystalStatusData; import codes.cookies.mod.data.player.PlayerStorage; import codes.cookies.mod.data.profile.profile.GlobalProfileStorage; import codes.cookies.mod.data.profile.profile.GlobalProfileData; @@ -58,6 +59,7 @@ public class ProfileData { private PlotData plotData = new PlotData(); private SqueakyMousematData squeakyMousematData = SqueakyMousematData.getDefault(); private PowderData powderData = new PowderData(); + private CrystalStatusData crystalStatus = new CrystalStatusData(); /** * Create a profile. diff --git a/src/main/java/codes/cookies/mod/events/PlayerListWidgetEvent.java b/src/main/java/codes/cookies/mod/events/PlayerListWidgetEvent.java index 0d666a3a..d1a9b8c3 100644 --- a/src/main/java/codes/cookies/mod/events/PlayerListWidgetEvent.java +++ b/src/main/java/codes/cookies/mod/events/PlayerListWidgetEvent.java @@ -2,9 +2,9 @@ import codes.cookies.mod.utils.cookies.CookiesEventUtils; -import codes.cookies.mod.utils.skyblock.tab.widgets.PlayerListWidget; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidget; -import codes.cookies.mod.utils.skyblock.tab.widgets.PlayerListWidgets; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidgets; import net.fabricmc.fabric.api.event.Event; diff --git a/src/main/java/codes/cookies/mod/features/dungeons/DungeonInstance.java b/src/main/java/codes/cookies/mod/features/dungeons/DungeonInstance.java index c26aaf40..8efc9280 100644 --- a/src/main/java/codes/cookies/mod/features/dungeons/DungeonInstance.java +++ b/src/main/java/codes/cookies/mod/features/dungeons/DungeonInstance.java @@ -16,7 +16,7 @@ import codes.cookies.mod.features.dungeons.solver.puzzle.PuzzleSolverInstance; import codes.cookies.mod.features.dungeons.solver.puzzle.WaterBoardPuzzleSolver; import codes.cookies.mod.utils.skyblock.PartyUtils; -import codes.cookies.mod.utils.skyblock.tab.PlayerListUtils; +import codes.cookies.mod.utils.skyblock.playerlist.PlayerListUtils; import java.util.ArrayList; import java.util.Collection; diff --git a/src/main/java/codes/cookies/mod/features/mining/MiningFeatures.java b/src/main/java/codes/cookies/mod/features/mining/MiningFeatures.java index e511d3d8..45842c6f 100644 --- a/src/main/java/codes/cookies/mod/features/mining/MiningFeatures.java +++ b/src/main/java/codes/cookies/mod/features/mining/MiningFeatures.java @@ -2,6 +2,7 @@ import codes.cookies.mod.features.Loader; import codes.cookies.mod.features.mining.commissions.CommissionCompletionHighlighter; +import codes.cookies.mod.features.mining.hollows.CrystalRunHud; import codes.cookies.mod.features.mining.hollows.MinesOfDivanHelper; import codes.cookies.mod.features.mining.shafts.CorpseWaypoints; import codes.cookies.mod.features.mining.shafts.MineshaftAnnouncements; @@ -25,6 +26,7 @@ static void load() { Loader.load("PowderHud", PowderHud::new); Loader.load("ShaftFeatures", ShaftFeatures::load); Loader.load("MineshaftCorpseMessages", MineshaftAnnouncements::register); + Loader.load("CrystalRunHud", CrystalRunHud::new); } } diff --git a/src/main/java/codes/cookies/mod/features/mining/PowderHud.java b/src/main/java/codes/cookies/mod/features/mining/PowderHud.java index 392c1da4..c504fc88 100644 --- a/src/main/java/codes/cookies/mod/features/mining/PowderHud.java +++ b/src/main/java/codes/cookies/mod/features/mining/PowderHud.java @@ -9,8 +9,8 @@ import codes.cookies.mod.render.hud.HudManager; import codes.cookies.mod.render.hud.elements.MultiLineTextHudElement; import codes.cookies.mod.render.hud.internal.HudEditAction; -import codes.cookies.mod.services.powder.PowderEntry; -import codes.cookies.mod.services.powder.PowderService; +import codes.cookies.mod.services.mining.powder.PowderEntry; +import codes.cookies.mod.services.mining.powder.PowderService; import codes.cookies.mod.utils.cookies.CookiesUtils; import codes.cookies.mod.utils.maths.InterpolatedInteger; import codes.cookies.mod.utils.maths.LinearInterpolatedInteger; diff --git a/src/main/java/codes/cookies/mod/features/mining/hollows/CrystalRunHud.java b/src/main/java/codes/cookies/mod/features/mining/hollows/CrystalRunHud.java new file mode 100644 index 00000000..add648e9 --- /dev/null +++ b/src/main/java/codes/cookies/mod/features/mining/hollows/CrystalRunHud.java @@ -0,0 +1,168 @@ +package codes.cookies.mod.features.mining.hollows; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import codes.cookies.mod.config.categories.mining.MiningConfig; +import codes.cookies.mod.data.mining.crystal.CrystalStatus; +import codes.cookies.mod.data.mining.crystal.CrystalType; +import codes.cookies.mod.data.profile.ProfileStorage; +import codes.cookies.mod.data.profile.items.Item; +import codes.cookies.mod.data.profile.items.ItemSources; +import codes.cookies.mod.generated.Regions; +import codes.cookies.mod.render.hud.HudManager; +import codes.cookies.mod.render.hud.elements.MultiLineTextHudElement; +import codes.cookies.mod.render.hud.internal.HudEditAction; +import codes.cookies.mod.repository.RepositoryItem; +import codes.cookies.mod.services.mining.CrystalStatusService; +import codes.cookies.mod.utils.items.ItemUtils; +import codes.cookies.mod.utils.skyblock.LocationUtils; +import org.apache.commons.lang3.StringUtils; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; + +/** + * Hud to display current crystal status while in the crystal hollows.
+ * Also displays information about the available robot parts and available tools in their respective area. + */ +public class CrystalRunHud extends MultiLineTextHudElement { + + private long lastUpdate; + private final List defaultTexts = new ArrayList<>(); + private final Map> regionTexts = new HashMap<>(); + + public CrystalRunHud() { + super(Identifier.of("cookies", "mining/crystal_hud")); + HudManager.register(this); + } + + @Override + protected List getText() { + if (ProfileStorage.getCurrentProfile().isEmpty()) { + return List.of(); + } + this.updateItemIndex(); + return regionTexts.getOrDefault(LocationUtils.getRegion(), defaultTexts); + } + + private void updateItemIndex() { + if (this.lastUpdate + 1000 > System.currentTimeMillis()) { + return; + } + lastUpdate = System.currentTimeMillis(); + + final Collection> relevantItemsOnPlayer = this.getRelevantItemsOnPlayer(); + + this.createLostPrecursorCityTexts(relevantItemsOnPlayer); + this.createMinesOfDivanText(relevantItemsOnPlayer); + this.createDefaultTexts(); + } + + private void createMinesOfDivanText(Collection> relevantItems) { + final List minesOfDivanText = new ArrayList<>(); + + this.addItem("DWARVEN_LAPIS_SWORD", relevantItems, minesOfDivanText); + this.addItem("DWARVEN_GOLD_HAMMER", relevantItems, minesOfDivanText); + this.addItem("DWARVEN_DIAMOND_AXE", relevantItems, minesOfDivanText); + this.addItem("DWARVEN_EMERALD_HAMMER", relevantItems, minesOfDivanText); + + this.regionTexts.put(Regions.MINES_OF_DIVAN, minesOfDivanText); + } + + private void createLostPrecursorCityTexts(Collection> relevantItems) { + final List lostPrecursorCityText = new ArrayList<>(); + + this.addItem("CONTROL_SWITCH", relevantItems, lostPrecursorCityText); + this.addItem("ELECTRON_TRANSMITTER", relevantItems, lostPrecursorCityText); + this.addItem("FTX_3070", relevantItems, lostPrecursorCityText); + this.addItem("ROBOTRON_REFLECTOR", relevantItems, lostPrecursorCityText); + this.addItem("SUPERLITE_MOTOR", relevantItems, lostPrecursorCityText); + this.addItem("SYNTHETIC_HEART", relevantItems, lostPrecursorCityText); + this.addItem("PRECURSOR_APPARATUS", relevantItems, lostPrecursorCityText); + + this.regionTexts.put(Regions.LOST_PRECURSOR_CITY, lostPrecursorCityText); + } + + private void addItem(String id, Collection> relevantItems, List texts) { + final int itemAmountAvailable = this.getAmountOfItemAvailable(relevantItems, id); + + final RepositoryItem repositoryItem = RepositoryItem.ofOrEmpty(id); + final Text itemName = repositoryItem.getFormattedName(); + final MutableText append = Text.empty().append(itemName) + .append(Text.literal(" - ").formatted(Formatting.GRAY)) + .append(Text.literal(String.valueOf(itemAmountAvailable)).formatted(Formatting.YELLOW)); + texts.add(append); + } + + private void createDefaultTexts() { + final List defaultText = new ArrayList<>(); + this.addCrystalStatusFor(CrystalType.JADE, defaultText); + this.addCrystalStatusFor(CrystalType.AMBER, defaultText); + this.addCrystalStatusFor(CrystalType.AMETHYST, defaultText); + this.addCrystalStatusFor(CrystalType.SAPPHIRE, defaultText); + this.addCrystalStatusFor(CrystalType.TOPAZ, defaultText); + this.defaultTexts.clear(); + this.defaultTexts.addAll(defaultText); + } + + private int getAmountOfItemAvailable(Collection> items, String itemId) { + return items.stream() + .filter(item -> itemId.equalsIgnoreCase(ItemUtils.getId(item))) + .mapToInt(Item::amount) + .sum(); + } + + private Collection> getRelevantItemsOnPlayer() { + return ItemSources.getItems(ItemSources.INVENTORY, ItemSources.STORAGE, ItemSources.SACKS); + } + + private void addCrystalStatusFor(CrystalType type, List texts) { + final String name = StringUtils.capitalize(type.name().toLowerCase(Locale.ROOT)); + texts.add(Text.literal(name) + .formatted(type.getFormatting()) + .append(Text.literal(" - ").formatted(Formatting.GRAY)) + .append(getStatusForOrNotFound(type).getText())); + } + + + private CrystalStatus getStatusForOrNotFound(CrystalType type) { + return CrystalStatusService.getCrystalStatus(type).orElse(CrystalStatus.NOT_FOUND); + } + + @Override + public int getMaxRows() { + return 7; + } + + @Override + public boolean shouldRender() { + if (this.hudEditAction == HudEditAction.SHOW_ALL) { + return true; + } + if (!MiningConfig.getInstance().crystalHud.getValue()) { + return false; + } + if (this.hudEditAction == HudEditAction.ALL_ENABLED) { + return true; + } + + return LocationUtils.Island.CRYSTAL_HOLLOWS.isActive(); + } + + @Override + public int getWidth() { + return 170; + } + + @Override + public Text getName() { + return Text.literal("Crystals").formatted(Formatting.RED); + } +} diff --git a/src/main/java/codes/cookies/mod/features/mining/shafts/MineshaftAnnouncements.java b/src/main/java/codes/cookies/mod/features/mining/shafts/MineshaftAnnouncements.java index 1fd60224..3bf3f9c7 100644 --- a/src/main/java/codes/cookies/mod/features/mining/shafts/MineshaftAnnouncements.java +++ b/src/main/java/codes/cookies/mod/features/mining/shafts/MineshaftAnnouncements.java @@ -6,10 +6,10 @@ import codes.cookies.mod.repository.constants.mining.ShaftCorpseLocations; import codes.cookies.mod.utils.cookies.CookiesUtils; import codes.cookies.mod.utils.skyblock.PartyUtils; -import codes.cookies.mod.utils.skyblock.tab.widgets.PlayerListWidgets; -import codes.cookies.mod.utils.skyblock.tab.widgets.corpse.CorpseEntry; -import codes.cookies.mod.utils.skyblock.tab.widgets.corpse.CorpseType; -import codes.cookies.mod.utils.skyblock.tab.widgets.corpse.FrozenCorpseWidget; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidgets; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse.CorpseEntry; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse.CorpseType; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse.FrozenCorpseWidget; import java.util.Comparator; import java.util.List; diff --git a/src/main/java/codes/cookies/mod/repository/RepositoryItem.java b/src/main/java/codes/cookies/mod/repository/RepositoryItem.java index 05825143..b4e8915f 100644 --- a/src/main/java/codes/cookies/mod/repository/RepositoryItem.java +++ b/src/main/java/codes/cookies/mod/repository/RepositoryItem.java @@ -172,6 +172,15 @@ public static RepositoryItem of(String id) { return itemMap.get(id.toLowerCase(Locale.ROOT).replace(":", "/").replace("-", "/").replace(";", "/")); } + /** + * Gets the item or creates an "empty" item. + * @param id The item id to get. + * @return The item, or a non-null empty item. + */ + public static RepositoryItem ofOrEmpty(String id) { + return Optional.ofNullable(itemMap.get(id.toLowerCase(Locale.ROOT))).orElseGet(() -> createNotFound(id)); + } + /** * Tries to fine an item by its name. * diff --git a/src/main/java/codes/cookies/mod/services/mining/CrystalStatusService.java b/src/main/java/codes/cookies/mod/services/mining/CrystalStatusService.java new file mode 100644 index 00000000..222a17ee --- /dev/null +++ b/src/main/java/codes/cookies/mod/services/mining/CrystalStatusService.java @@ -0,0 +1,40 @@ +package codes.cookies.mod.services.mining; + +import java.util.Optional; + +import codes.cookies.mod.data.mining.crystal.CrystalStatus; +import codes.cookies.mod.data.mining.crystal.CrystalType; +import codes.cookies.mod.data.profile.ProfileData; +import codes.cookies.mod.data.profile.ProfileStorage; +import codes.cookies.mod.events.PlayerListWidgetEvent; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidgets; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.crystal.CrystalWidget; + +/** + * Keeps track about current crystal status and makes accessing them easier. + */ +public class CrystalStatusService { + + public static void register() { + PlayerListWidgetEvent.register(PlayerListWidgets.CRYSTAL, CrystalStatusService::onWidgetUpdate); + } + + private static void onWidgetUpdate(CrystalWidget crystalWidget) { + for (CrystalType nucleusCrystal : CrystalType.values()) { + crystalWidget.getCrystalStatusByType(nucleusCrystal) + .ifPresent(status -> updateCrystalStatus(nucleusCrystal, status)); + } + } + + public static void updateCrystalStatus(CrystalType crystalType, CrystalStatus crystalStatus) { + ProfileStorage.getCurrentProfile() + .ifPresent(profileData -> profileData.getCrystalStatus().setStatus(crystalType, crystalStatus)); + } + + public static Optional getCrystalStatus(CrystalType crystalType) { + return ProfileStorage.getCurrentProfile() + .map(ProfileData::getCrystalStatus) + .map(status -> status.getStatus(crystalType)); + } + +} diff --git a/src/main/java/codes/cookies/mod/services/powder/PowderEntry.java b/src/main/java/codes/cookies/mod/services/mining/powder/PowderEntry.java similarity index 97% rename from src/main/java/codes/cookies/mod/services/powder/PowderEntry.java rename to src/main/java/codes/cookies/mod/services/mining/powder/PowderEntry.java index f961c18a..e1262372 100644 --- a/src/main/java/codes/cookies/mod/services/powder/PowderEntry.java +++ b/src/main/java/codes/cookies/mod/services/mining/powder/PowderEntry.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.services.powder; +package codes.cookies.mod.services.mining.powder; import codes.cookies.mod.config.categories.mining.powder.PowderTrackerHudFoldable; import codes.cookies.mod.utils.cookies.PauseableTime; diff --git a/src/main/java/codes/cookies/mod/services/powder/PowderService.java b/src/main/java/codes/cookies/mod/services/mining/powder/PowderService.java similarity index 98% rename from src/main/java/codes/cookies/mod/services/powder/PowderService.java rename to src/main/java/codes/cookies/mod/services/mining/powder/PowderService.java index 7775777a..1b295d0e 100644 --- a/src/main/java/codes/cookies/mod/services/powder/PowderService.java +++ b/src/main/java/codes/cookies/mod/services/mining/powder/PowderService.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.services.powder; +package codes.cookies.mod.services.mining.powder; import java.util.Arrays; import java.util.Comparator; diff --git a/src/main/java/codes/cookies/mod/translations/TranslationKeys.java b/src/main/java/codes/cookies/mod/translations/TranslationKeys.java index 251e4949..b7fa1a4b 100644 --- a/src/main/java/codes/cookies/mod/translations/TranslationKeys.java +++ b/src/main/java/codes/cookies/mod/translations/TranslationKeys.java @@ -282,6 +282,7 @@ public interface TranslationKeys { String CONFIG_MINING_MODIFY_COMMISSIONS = CONFIG_MINING + ".modify_commissions"; String CONFIG_MINING_PUZZLER_SOLVER = CONFIG_MINING + ".puzzler_solver"; String CONFIG_MINING_MOD_HELPER = CONFIG_MINING + ".mod_helper"; + String CONFIG_MINING_MOD_CRYSTAL_HUD = CONFIG_MINING + ".crystal_hud"; String CONFIG_MINING_CATEGORIES_HOTM = CONFIG_MINING + CATEGORIES_PART + ".hotm"; String CONFIG_MINING_SHOW_HOTM_PERK_LEVEL_AS_STACK_SIZE = CONFIG_MINING + ".show_hotm_perk_level_as_stack_size"; String CONFIG_MINING_HIGHLIGHT_DISABLED_HOTM_PERKS = CONFIG_MINING + ".highlight_disabled_hotm_perks"; diff --git a/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java b/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java index 585bc234..b291cd92 100644 --- a/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java +++ b/src/main/java/codes/cookies/mod/utils/items/ItemUtils.java @@ -1,5 +1,7 @@ package codes.cookies.mod.utils.items; +import codes.cookies.mod.data.profile.items.Item; + import net.minecraft.client.MinecraftClient; import net.minecraft.component.ComponentType; import net.minecraft.component.DataComponentTypes; @@ -72,4 +74,11 @@ public static void copy(ComponentType type, ItemStack source, ItemStack t public static T getData(ItemStack itemStack, ComponentType type) { return itemStack.getComponents().get(type); } + + public static String getId(Item item) { + if (item == null) { + return null; + } + return item.itemStack().get(CookiesDataComponentTypes.SKYBLOCK_ID); + } } diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListEntrySet.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListEntrySet.java similarity index 93% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListEntrySet.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListEntrySet.java index 9b2e2b0e..8a29dbf8 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListEntrySet.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListEntrySet.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.utils.skyblock.tab; +package codes.cookies.mod.utils.skyblock.playerlist; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListReader.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListReader.java similarity index 92% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListReader.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListReader.java index 025310b6..e13a1a53 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListReader.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListReader.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.utils.skyblock.tab; +package codes.cookies.mod.utils.skyblock.playerlist; import java.util.List; diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListUtils.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListUtils.java similarity index 92% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListUtils.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListUtils.java index 4b0f6112..51528467 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/PlayerListUtils.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/PlayerListUtils.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.utils.skyblock.tab; +package codes.cookies.mod.utils.skyblock.playerlist; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -11,8 +11,8 @@ import codes.cookies.mod.utils.SkyblockUtils; import codes.cookies.mod.utils.exceptions.ExceptionHandler; -import codes.cookies.mod.utils.skyblock.tab.widgets.PlayerListWidget; -import codes.cookies.mod.utils.skyblock.tab.widgets.PlayerListWidgets; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidget; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidgets; import net.minecraft.client.network.PlayerListEntry; diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/PlayerListWidget.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/PlayerListWidget.java similarity index 77% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/PlayerListWidget.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/PlayerListWidget.java index 46fa3ccc..fa351076 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/PlayerListWidget.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/PlayerListWidget.java @@ -1,7 +1,7 @@ -package codes.cookies.mod.utils.skyblock.tab.widgets; +package codes.cookies.mod.utils.skyblock.playerlist.widgets; import codes.cookies.mod.events.PlayerListWidgetEvent; -import codes.cookies.mod.utils.skyblock.tab.PlayerListReader; +import codes.cookies.mod.utils.skyblock.playerlist.PlayerListReader; /** * A generic player list widget. diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/PlayerListWidgets.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/PlayerListWidgets.java similarity index 77% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/PlayerListWidgets.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/PlayerListWidgets.java index e40643c0..44a574c6 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/PlayerListWidgets.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/PlayerListWidgets.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.utils.skyblock.tab.widgets; +package codes.cookies.mod.utils.skyblock.playerlist.widgets; import java.util.ArrayList; import java.util.List; @@ -6,8 +6,9 @@ import java.util.function.Predicate; import java.util.function.Supplier; -import codes.cookies.mod.utils.skyblock.tab.PlayerListReader; -import codes.cookies.mod.utils.skyblock.tab.widgets.corpse.FrozenCorpseWidget; +import codes.cookies.mod.utils.skyblock.playerlist.PlayerListReader; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse.FrozenCorpseWidget; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.crystal.CrystalWidget; public class PlayerListWidgets { @@ -17,6 +18,11 @@ public class PlayerListWidgets { FrozenCorpseWidget::doesMatch, FrozenCorpseWidget::new, FrozenCorpseWidget.class); + public static Entry CRYSTAL = register( + CrystalWidget::doesMatch, + CrystalWidget::new, + CrystalWidget.class + ); private static Entry register( Predicate predicate, diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/CorpseEntry.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/CorpseEntry.java similarity index 74% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/CorpseEntry.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/CorpseEntry.java index b53acf8b..c5d9ec6b 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/CorpseEntry.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/CorpseEntry.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.utils.skyblock.tab.widgets.corpse; +package codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse; /** * Player list corpse entry. diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/CorpseType.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/CorpseType.java similarity index 83% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/CorpseType.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/CorpseType.java index e770ec07..6ec2f896 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/CorpseType.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/CorpseType.java @@ -1,4 +1,4 @@ -package codes.cookies.mod.utils.skyblock.tab.widgets.corpse; +package codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse; /** * The different types of supported corpses. diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/FrozenCorpseWidget.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/FrozenCorpseWidget.java similarity index 85% rename from src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/FrozenCorpseWidget.java rename to src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/FrozenCorpseWidget.java index 5c28c953..525c4773 100644 --- a/src/main/java/codes/cookies/mod/utils/skyblock/tab/widgets/corpse/FrozenCorpseWidget.java +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/corpse/FrozenCorpseWidget.java @@ -1,10 +1,10 @@ -package codes.cookies.mod.utils.skyblock.tab.widgets.corpse; +package codes.cookies.mod.utils.skyblock.playerlist.widgets.corpse; import java.util.ArrayList; import java.util.List; -import codes.cookies.mod.utils.skyblock.tab.PlayerListReader; -import codes.cookies.mod.utils.skyblock.tab.widgets.PlayerListWidget; +import codes.cookies.mod.utils.skyblock.playerlist.PlayerListReader; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidget; import lombok.Getter; /** diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalEntry.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalEntry.java new file mode 100644 index 00000000..bcb7d99e --- /dev/null +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalEntry.java @@ -0,0 +1,34 @@ +package codes.cookies.mod.utils.skyblock.playerlist.widgets.crystal; + +import codes.cookies.mod.data.mining.crystal.CrystalStatus; +import codes.cookies.mod.data.mining.crystal.CrystalType; + +import java.util.Optional; + +/** + * Represents a crystal line in the player list. + * + * @param type The type of the crystal. + * @param status Whether it is missing or not. + */ +public record CrystalEntry(CrystalType type, CrystalStatus status) { + + /** + * Parses the player list line if possible. + * @param line The line to parse. + * @return The parsed entry. + */ + public static Optional createEntryFromString(String line) { + if (line == null || !line.startsWith(" ") || !line.contains(":")) { + return Optional.empty(); + } + + String[] split = line.trim().split(":"); + + final Optional type = CrystalType.getCrystalTypeByDisplayName(split[0].trim()); + CrystalStatus status = CrystalStatus.getCrystalStatusFromText(split[1].trim()); + + return type.map(crystalType -> new CrystalEntry(crystalType, status)); + } + +} diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalOrigin.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalOrigin.java new file mode 100644 index 00000000..d4609f3f --- /dev/null +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalOrigin.java @@ -0,0 +1,10 @@ +package codes.cookies.mod.utils.skyblock.playerlist.widgets.crystal; + +/** + * The location where the crystal is in, this is kinda scuffed but works for now. + */ +public enum CrystalOrigin { + + CRYSTAL_HOLLOWS, MISC, CRIMSON_ISLE, GLACITE_TUNNELS + +} diff --git a/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalWidget.java b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalWidget.java new file mode 100644 index 00000000..383a51a1 --- /dev/null +++ b/src/main/java/codes/cookies/mod/utils/skyblock/playerlist/widgets/crystal/CrystalWidget.java @@ -0,0 +1,63 @@ +package codes.cookies.mod.utils.skyblock.playerlist.widgets.crystal; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import codes.cookies.mod.data.mining.crystal.CrystalStatus; +import codes.cookies.mod.data.mining.crystal.CrystalType; +import codes.cookies.mod.utils.skyblock.playerlist.PlayerListReader; +import codes.cookies.mod.utils.skyblock.playerlist.widgets.PlayerListWidget; +import lombok.Getter; + +/** + * Contains information about different crystals and their status. Also supports the settings that are available for it. + */ +public class CrystalWidget extends PlayerListWidget { + + @Getter + private final List crystals = new ArrayList<>(); + private boolean showNucleusCrystals = false; + private boolean showJasperAndRubyCrystals = false; + private boolean showGlaciteCrystals = false; + + public static boolean doesMatch(String title) { + return "crystals:".equalsIgnoreCase(title); + } + + @Override + protected void read(PlayerListReader reader) { + while (reader.canRead() && !reader.isTitle()) { + final Optional entryFromString = CrystalEntry.createEntryFromString(reader.read()); + if (entryFromString.isEmpty()) { + return; + } + final CrystalEntry crystalEntry = entryFromString.get(); + this.crystals.add(crystalEntry); + switch (crystalEntry.type().getCrystalOrigin()) { + case CRYSTAL_HOLLOWS -> this.showNucleusCrystals = true; + case MISC -> this.showJasperAndRubyCrystals = true; + case CRIMSON_ISLE, GLACITE_TUNNELS -> this.showGlaciteCrystals = true; + } + } + } + + public Optional getCrystalStatusByType(CrystalType crystalType) { + return crystals.stream() + .filter(crystalEntry -> crystalEntry.type() == crystalType) + .map(CrystalEntry::status) + .findFirst(); + } + + public boolean doesShowNucleusCrystals() { + return this.showNucleusCrystals; + } + + public boolean doesShowJasperAndRubyCrystals() { + return this.showJasperAndRubyCrystals; + } + + public boolean doesShowGlaciteCrystals() { + return this.showGlaciteCrystals; + } +}