diff options
Diffstat (limited to 'src')
95 files changed, 1361 insertions, 895 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index b398e9b6..cbe82667 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -3,8 +3,9 @@ package de.hysky.skyblocker; import com.google.gson.Gson; 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.diana.MythologicalRitual; +import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual; import de.hysky.skyblocker.skyblock.dungeon.*; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker; @@ -17,15 +18,17 @@ import de.hysky.skyblocker.skyblock.quicknav.QuickNav; import de.hysky.skyblocker.skyblock.rift.TheRift; import de.hysky.skyblocker.skyblock.shortcut.Shortcuts; import de.hysky.skyblocker.skyblock.special.SpecialEffects; -import de.hysky.skyblocker.skyblock.spidersden.Relics; +import de.hysky.skyblocker.skyblock.waypoint.Relics; import de.hysky.skyblocker.skyblock.tabhud.TabHud; import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; +import de.hysky.skyblocker.skyblock.waypoint.FairySouls; import de.hysky.skyblocker.utils.ApiUtils; import de.hysky.skyblocker.utils.NEURepoManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.chat.ChatMessageListener; import de.hysky.skyblocker.utils.discord.DiscordRPCManager; +import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; import de.hysky.skyblocker.utils.render.gui.ContainerSolverManager; import de.hysky.skyblocker.utils.render.title.TitleContainer; @@ -113,6 +116,8 @@ public class SkyblockerMod implements ClientModInitializer { MuseumItemCache.init(); SecretsTracker.init(); ApiUtils.init(); + Debug.init(); + RenderHelper.init(); containerSolverManager.init(); statusBarTracker.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); diff --git a/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java b/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java index 145f7ec4..7820dfa4 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java @@ -1,20 +1,15 @@ package de.hysky.skyblocker.compatibility; -import java.util.List; -import java.util.Set; - +import net.fabricmc.loader.api.FabricLoader; import org.objectweb.asm.tree.ClassNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; -import net.fabricmc.loader.api.FabricLoader; +import java.util.List; +import java.util.Set; public class MixinPlugin implements IMixinConfigPlugin { - private static final Logger LOGGER = LoggerFactory.getLogger(MixinPlugin.class); private static final boolean OPTIFABRIC_LOADED = FabricLoader.getInstance().isModLoaded("optifabric"); - private static final String YACL_VERSION = FabricLoader.getInstance().getModContainer("yet_another_config_lib_v3").get().getMetadata().getVersion().getFriendlyString(); @Override public void onLoad(String mixinPackage) { @@ -29,21 +24,8 @@ public class MixinPlugin implements IMixinConfigPlugin { @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { //OptiFabric Compatibility - if (mixinClassName.endsWith("WorldRendererMixin") && OPTIFABRIC_LOADED) return false; - - //YACL#103 Patch - if (mixinClassName.endsWith("DoubleFieldControllerMixin") || mixinClassName.endsWith("FloatFieldControllerMixin") || mixinClassName.endsWith("IntegerFieldControllerMixin") || mixinClassName.endsWith("LongFieldControllerMixin") || mixinClassName.endsWith("NumberFieldControllerMixin")) { - if (YACL_VERSION.equals("3.2.1+1.20.2")) { - LOGGER.info("[Skyblocker] Applying patch for " + targetClassName + " from " + mixinClassName); - } else { - LOGGER.info("[Skyblocker] Skipping patch on " + targetClassName + " due to an Unknown YACL version being found! Version: {}", YACL_VERSION); - - return false; - } - } - - return true; - } + return !mixinClassName.endsWith("WorldRendererMixin") || !OPTIFABRIC_LOADED; + } @Override public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { diff --git a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java index b52d6ff5..218eb8d1 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java @@ -4,7 +4,6 @@ import de.hysky.skyblocker.skyblock.itemlist.SkyblockCraftingRecipe; import de.hysky.skyblocker.utils.ItemUtils; import dev.emi.emi.api.recipe.EmiCraftingRecipe; import dev.emi.emi.api.recipe.EmiRecipeCategory; -import dev.emi.emi.api.stack.Comparison; import dev.emi.emi.api.stack.EmiIngredient; import dev.emi.emi.api.stack.EmiStack; import dev.emi.emi.api.widget.WidgetHolder; @@ -16,7 +15,7 @@ public class SkyblockEmiRecipe extends EmiCraftingRecipe { private final String craftText; public SkyblockEmiRecipe(SkyblockCraftingRecipe recipe) { - super(recipe.getGrid().stream().map(EmiStack::of).map(EmiIngredient.class::cast).toList(), EmiStack.of(recipe.getResult()).comparison(Comparison.compareNbt()), Identifier.of("skyblock", ItemUtils.getItemId(recipe.getResult()).toLowerCase().replace(';', '_') + "_" + recipe.getResult().getCount())); + super(recipe.getGrid().stream().map(EmiStack::of).map(EmiIngredient.class::cast).toList(), EmiStack.of(recipe.getResult()), Identifier.of("skyblock", ItemUtils.getItemId(recipe.getResult()).toLowerCase().replace(';', '_') + "_" + recipe.getResult().getCount())); this.craftText = recipe.getCraftText(); } diff --git a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java index 6ed6a32a..8dfc5dc9 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java @@ -7,6 +7,7 @@ import dev.emi.emi.api.EmiPlugin; import dev.emi.emi.api.EmiRegistry; import dev.emi.emi.api.recipe.EmiRecipeCategory; import dev.emi.emi.api.render.EmiTexture; +import dev.emi.emi.api.stack.Comparison; import dev.emi.emi.api.stack.EmiStack; import net.minecraft.item.Items; import net.minecraft.util.Identifier; @@ -21,7 +22,10 @@ public class SkyblockerEMIPlugin implements EmiPlugin { @Override public void register(EmiRegistry registry) { - ItemRepository.getItemsStream().map(EmiStack::of).forEach(registry::addEmiStack); + ItemRepository.getItemsStream().map(EmiStack::of).forEach(emiStack -> { + registry.addEmiStack(emiStack); + registry.setDefaultComparison(emiStack, Comparison.compareNbt()); + }); registry.addCategory(SKYBLOCK); registry.addWorkstation(SKYBLOCK, EmiStack.of(Items.CRAFTING_TABLE)); ItemRepository.getRecipesStream().map(SkyblockEmiRecipe::new).forEach(registry::addRecipe); diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index 68520cab..1c6bb394 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.config; +import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.skyblock.item.CustomArmorTrims; import de.hysky.skyblocker.utils.chat.ChatFilterResult; import de.hysky.skyblocker.utils.waypoint.Waypoint; @@ -10,6 +11,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.client.resource.language.I18n; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; import java.util.ArrayList; import java.util.List; @@ -187,6 +189,9 @@ public class SkyblockerConfig { public Shortcuts shortcuts = new Shortcuts(); @SerialEntry + public Waypoints waypoints = new Waypoints(); + + @SerialEntry public QuiverWarning quiverWarning = new QuiverWarning(); @SerialEntry @@ -252,8 +257,8 @@ public class SkyblockerConfig { @Override public String toString() { return switch (this) { - case DEFAULT -> "Default"; - case ALPHABETICAL -> "Alphabetical"; + case DEFAULT -> "Default"; + case ALPHABETICAL -> "Alphabetical"; }; } } @@ -291,10 +296,10 @@ public class SkyblockerConfig { public int toInt() { return switch (this) { - case LAYER1 -> 0; - case LAYER2 -> 1; - case RIGHT -> 2; - case NONE -> -1; + case LAYER1 -> 0; + case LAYER2 -> 1; + case RIGHT -> 2; + case NONE -> -1; }; } } @@ -347,6 +352,14 @@ public class SkyblockerConfig { public boolean enableCommandArgShortcuts = true; } + public static class Waypoints { + @SerialEntry + public boolean enableWaypoints = true; + + @SerialEntry + public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; + } + public static class QuiverWarning { @SerialEntry public boolean enableQuiverWarning = true; @@ -360,7 +373,7 @@ public class SkyblockerConfig { public static class Hitbox { @SerialEntry - public boolean oldFarmlandHitbox = true; + public boolean oldFarmlandHitbox = false; @SerialEntry public boolean oldLeverHitbox = false; @@ -417,8 +430,8 @@ public class SkyblockerConfig { @Override public String toString() { return switch (this) { - case HORIZONTAL -> "Horizontal"; - case VERTICAL -> "Vertical"; + case HORIZONTAL -> "Horizontal"; + case VERTICAL -> "Vertical"; }; } } @@ -429,9 +442,9 @@ public class SkyblockerConfig { @Override public String toString() { return switch (this) { - case LEFT -> "Left"; - case RIGHT -> "Right"; - case MIDDLE -> "Middle"; + case LEFT -> "Left"; + case RIGHT -> "Right"; + case MIDDLE -> "Middle"; }; } } @@ -484,7 +497,10 @@ public class SkyblockerConfig { public boolean enableBazaarPrice = true; @SerialEntry - public boolean enableMuseumDate = true; + public boolean enableObtainedDate = true; + + @SerialEntry + public boolean enableMuseumInfo = true; @SerialEntry public boolean enableExoticTooltip = true; @@ -498,9 +514,31 @@ public class SkyblockerConfig { public boolean itemRarityBackgrounds = false; @SerialEntry + public RarityBackgroundStyle itemRarityBackgroundStyle = RarityBackgroundStyle.CIRCULAR; + + @SerialEntry public float itemRarityBackgroundsOpacity = 1f; } + public enum RarityBackgroundStyle { + CIRCULAR(new Identifier(SkyblockerMod.NAMESPACE, "item_rarity_background_circular")), + SQUARE(new Identifier(SkyblockerMod.NAMESPACE, "item_rarity_background_square")); + + public final Identifier tex; + + RarityBackgroundStyle(Identifier tex) { + this.tex = tex; + } + + @Override + public String toString() { + return switch (this) { + case CIRCULAR -> "Circular"; + case SQUARE -> "Square"; + }; + } + } + public static class WikiLookup { @SerialEntry public boolean enableWikiLookup = true; @@ -552,7 +590,7 @@ public class SkyblockerConfig { @SerialEntry public int mapY = 2; - + @SerialEntry public boolean playerSecretsTracker = false; @@ -587,10 +625,10 @@ public class SkyblockerConfig { @SerialEntry public boolean noInitSecretWaypoints = false; - + @SerialEntry public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; - + @SerialEntry public boolean showSecretText = true; @@ -620,10 +658,10 @@ public class SkyblockerConfig { @SerialEntry public boolean enableStonkWaypoints = true; - + @SerialEntry public boolean enableAotvWaypoints = true; - + @SerialEntry public boolean enablePearlWaypoints = true; @@ -659,7 +697,10 @@ public class SkyblockerConfig { public static class LividColor { @SerialEntry - public boolean enableLividColor = true; + public boolean enableLividColorGlow = true; + + @SerialEntry + public boolean enableLividColorText = true; @SerialEntry public String lividColorText = "The livid color is [color]"; @@ -713,9 +754,9 @@ public class SkyblockerConfig { @Override public String toString() { return switch (this) { - case SIMPLE -> "Simple"; - case FANCY -> "Fancy"; - case CLASSIC -> "Classic"; + case SIMPLE -> "Simple"; + case FANCY -> "Fancy"; + case CLASSIC -> "Classic"; }; } } @@ -731,10 +772,13 @@ public class SkyblockerConfig { public static class Rift { @SerialEntry public boolean mirrorverseWaypoints = true; - + + @SerialEntry + public boolean blobbercystGlow = true; + @SerialEntry public boolean enigmaSoulWaypoints = false; - + @SerialEntry public boolean highlightFoundEnigmaSouls = true; diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java index 98c83975..875090ed 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java @@ -38,11 +38,11 @@ public class SkyblockerConfigManager { .registerTypeHierarchyAdapter(Identifier.class, new Identifier.Serializer())) .build()) .build(); - + public static SkyblockerConfig get() { return HANDLER.instance(); } - + /** * This method is caller sensitive and can only be called by the mod initializer, * this is enforced. @@ -51,15 +51,15 @@ public class SkyblockerConfigManager { if (StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).getCallerClass() != SkyblockerMod.class) { throw new RuntimeException("Skyblocker: Called config init from an illegal place!"); } - + HANDLER.load(); ClientCommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal(SkyblockerMod.NAMESPACE).then(optionsLiteral("config")).then(optionsLiteral("options"))))); } - + public static void save() { HANDLER.save(); } - + public static Screen createGUI(Screen parent) { return YetAnotherConfigLib.create(HANDLER, (defaults, config, builder) -> builder .title(Text.translatable("text.autoconfig.skyblocker.title")) @@ -72,7 +72,7 @@ public class SkyblockerConfigManager { .category(MessageFilterCategory.create(defaults, config)) .category(DiscordRPCCategory.create(defaults, config))).generateScreen(parent); } - + /** * Registers an options command with the given name. Used for registering both options and config as valid commands. * diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DiscordRPCCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DiscordRPCCategory.java index fcdc3d8d..907291ca 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DiscordRPCCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DiscordRPCCategory.java @@ -13,7 +13,7 @@ public class DiscordRPCCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.category.richPresence")) - + //Uncategorized Options .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.richPresence.enableRichPresence")) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 02913a28..7bb6414c 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -23,7 +23,7 @@ public class DungeonsCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons")) - + //Dungeon Secret Waypoints .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints")) @@ -45,8 +45,8 @@ public class DungeonsCategory { .flag(OptionFlag.GAME_RESTART) .build()) .option(Option.<Type>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.waypointType")) - .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.waypointType.@Tooltip"))) + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.@Tooltip"))) .binding(defaults.locations.dungeons.secretWaypoints.waypointType, () -> config.locations.dungeons.secretWaypoints.waypointType, newValue -> config.locations.dungeons.secretWaypoints.waypointType = newValue) @@ -146,7 +146,7 @@ public class DungeonsCategory { .controller(ConfigUtils::createBooleanController) .build()) .build()) - + .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit")) .collapsed(true) @@ -212,7 +212,7 @@ public class DungeonsCategory { .controller(EnumDropdownControllerBuilder.getFactory(ConfigUtils.FORMATTING_TO_STRING)) .build()) .build()) - + //Others .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper")) @@ -242,8 +242,8 @@ public class DungeonsCategory { .controller(FloatFieldControllerBuilder::create) .build()) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretsTracker")) - .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretsTracker.@Tooltip"))) + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.playerSecretsTracker")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.playerSecretsTracker.@Tooltip"))) .binding(defaults.locations.dungeons.playerSecretsTracker, () -> config.locations.dungeons.playerSecretsTracker, newValue -> config.locations.dungeons.playerSecretsTracker = newValue) @@ -301,11 +301,19 @@ public class DungeonsCategory { .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor")) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor")) - .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip"))) - .binding(defaults.locations.dungeons.lividColor.enableLividColor, - () -> config.locations.dungeons.lividColor.enableLividColor, - newValue -> config.locations.dungeons.lividColor.enableLividColor = newValue) + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorGlow")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorGlow.@Tooltip"))) + .binding(defaults.locations.dungeons.lividColor.enableLividColorGlow, + () -> config.locations.dungeons.lividColor.enableLividColorGlow, + newValue -> config.locations.dungeons.lividColor.enableLividColorGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip"))) + .binding(defaults.locations.dungeons.lividColor.enableLividColorText, + () -> config.locations.dungeons.lividColor.enableLividColorText, + newValue -> config.locations.dungeons.lividColor.enableLividColorText = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() @@ -317,7 +325,7 @@ public class DungeonsCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Terminal Solvers .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.terminals")) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java index 719cbd79..80d6485b 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java @@ -16,7 +16,7 @@ public class DwarvenMinesCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines")) - + //Uncategorized Options .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.enableDrillFuel")) @@ -39,7 +39,7 @@ public class DwarvenMinesCategory { newValue -> config.locations.dwarvenMines.solvePuzzler = newValue) .controller(ConfigUtils::createBooleanController) .build()) - + //Dwarven HUD .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud")) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index 3cbb1b94..be5f0665 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -4,6 +4,7 @@ import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.skyblock.shortcut.ShortcutsConfigScreen; import de.hysky.skyblocker.utils.render.title.TitleContainerConfigScreen; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; @@ -261,6 +262,27 @@ public class GeneralCategory { .build()) .build()) + //Waypoints + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints")) + .collapsed(true) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.enableWaypoints")) + .binding(defaults.general.waypoints.enableWaypoints, + () -> config.general.waypoints.enableWaypoints, + newValue -> config.general.waypoints.enableWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Waypoint.Type>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.@Tooltip"), Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.generalNote"))) + .binding(defaults.general.waypoints.waypointType, + () -> config.general.waypoints.waypointType, + newValue -> config.general.waypoints.waypointType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .build()) + //Quiver Warning .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.quiverWarning")) @@ -350,10 +372,18 @@ public class GeneralCategory { .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumDate")) - .binding(defaults.general.itemTooltip.enableMuseumDate, - () -> config.general.itemTooltip.enableMuseumDate, - newValue -> config.general.itemTooltip.enableMuseumDate = newValue) + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableObtainedDate")) + .binding(defaults.general.itemTooltip.enableObtainedDate, + () -> config.general.itemTooltip.enableObtainedDate, + newValue -> config.general.itemTooltip.enableObtainedDate = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumInfo")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumInfo.@Tooltip"))) + .binding(defaults.general.itemTooltip.enableMuseumInfo, + () -> config.general.itemTooltip.enableMuseumInfo, + newValue -> config.general.itemTooltip.enableMuseumInfo = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<Boolean>createBuilder() @@ -386,6 +416,14 @@ public class GeneralCategory { newValue -> config.general.itemInfoDisplay.itemRarityBackgrounds = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.<SkyblockerConfig.RarityBackgroundStyle>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundStyle")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundStyle.@Tooltip"))) + .binding(defaults.general.itemInfoDisplay.itemRarityBackgroundStyle, + () -> config.general.itemInfoDisplay.itemRarityBackgroundStyle, + newValue -> config.general.itemInfoDisplay.itemRarityBackgroundStyle = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) .option(Option.<Float>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundsOpacity")) .binding(defaults.general.itemInfoDisplay.itemRarityBackgroundsOpacity, diff --git a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java index 5e662fcc..0b388d16 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java @@ -14,7 +14,7 @@ public class LocationsCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.category.locations")) - + //Barn .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.barn")) @@ -34,7 +34,7 @@ public class LocationsCategory { .controller(ConfigUtils::createBooleanController) .build()) .build()) - + //The Rift .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift")) @@ -47,6 +47,14 @@ public class LocationsCategory { .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.blobbercystGlow")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.blobbercystGlow.@Tooltip"))) + .binding(defaults.locations.rift.blobbercystGlow, + () -> config.locations.rift.blobbercystGlow, + newValue -> config.locations.rift.blobbercystGlow = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.enigmaSoulWaypoints")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.enigmaSoulWaypoints.@Tooltip"))) .binding(defaults.locations.rift.enigmaSoulWaypoints, @@ -70,7 +78,7 @@ public class LocationsCategory { .controller(opt -> IntegerSliderControllerBuilder.create(opt).range(0, 5).step(1)) .build()) .build()) - + //Spider's Den .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.spidersDen")) 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 ba76a903..c63b933d 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java @@ -13,7 +13,7 @@ public class MessageFilterCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.category.messages")) - + //Uncategorized Options .option(Option.<ChatFilterResult>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.messages.hideAbility")) @@ -31,6 +31,7 @@ public class MessageFilterCategory { .build()) .option(Option.<ChatFilterResult>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.messages.hideAOTE")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.messages.hideAOTE.@Tooltip"))) .binding(defaults.messages.hideAOTE, () -> config.messages.hideAOTE, newValue -> config.messages.hideAOTE = newValue) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java index 775a0ae1..e2684115 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java @@ -14,7 +14,7 @@ public class QuickNavigationCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.category.quickNav")) - + //Toggle .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.enableQuickNav")) @@ -23,7 +23,7 @@ public class QuickNavigationCategory { newValue -> config.quickNav.enableQuickNav = newValue) .controller(ConfigUtils::createBooleanController) .build()) - + //Button 1 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 1)) @@ -71,7 +71,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 2 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 2)) @@ -119,7 +119,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 3 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 3)) @@ -167,7 +167,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 4 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 4)) @@ -215,7 +215,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 5 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 5)) @@ -263,7 +263,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 6 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 6)) @@ -311,7 +311,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 7 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 7)) @@ -359,7 +359,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 8 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 8)) @@ -407,7 +407,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 9 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 9)) @@ -455,7 +455,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 10 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 10)) @@ -503,7 +503,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 11 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 11)) @@ -551,7 +551,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + //Button 12 .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 12)) @@ -599,7 +599,7 @@ public class QuickNavigationCategory { .controller(StringControllerBuilder::create) .build()) .build()) - + .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java index 2d8b1332..7df95172 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/SlayersCategory.java @@ -16,7 +16,7 @@ public class SlayersCategory { public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) { return ConfigCategory.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.category.slayer")) - + //Vampire Slayer .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.slayer.vampireSlayer")) @@ -110,7 +110,7 @@ public class SlayersCategory { .controller(opt -> IntegerSliderControllerBuilder.create(opt).range(1, 10).step(1)) .build()) .build()) - + .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/debug/Debug.java b/src/main/java/de/hysky/skyblocker/debug/Debug.java new file mode 100644 index 00000000..1fc22d2a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/debug/Debug.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.debug; + +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; + +public class Debug { + private static final boolean DEBUG_ENABLED = Boolean.parseBoolean(System.getProperty("skyblocker.debug", "false")); + + public static void init() { + if (DEBUG_ENABLED || FabricLoader.getInstance().isDevelopmentEnvironment()) { + ClientCommandRegistrationCallback.EVENT.register(DumpPlayersCommand::register); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/debug/DumpPlayersCommand.java b/src/main/java/de/hysky/skyblocker/debug/DumpPlayersCommand.java new file mode 100644 index 00000000..5f6e0362 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/debug/DumpPlayersCommand.java @@ -0,0 +1,31 @@ +package de.hysky.skyblocker.debug; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import de.hysky.skyblocker.SkyblockerMod; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.Text; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class DumpPlayersCommand { + + static void register(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(literal(SkyblockerMod.NAMESPACE) + .then(literal("debug") + .then(literal("dumpPlayers") + .executes(context -> { + FabricClientCommandSource source = context.getSource(); + + source.getWorld().getEntities().forEach(e -> { + if (e instanceof PlayerEntity player) { + source.sendFeedback(Text.of("'" + player.getName().getString() + "'")); + } + }); + + return Command.SINGLE_SUCCESS; + })))); + } +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java index f68a4e94..384986ae 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java @@ -3,7 +3,7 @@ package de.hysky.skyblocker.mixin; import com.llamalad7.mixinextras.injector.WrapWithCondition; import com.llamalad7.mixinextras.sugar.Local; import de.hysky.skyblocker.skyblock.FishingHelper; -import de.hysky.skyblocker.skyblock.diana.MythologicalRitual; +import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; import de.hysky.skyblocker.utils.Utils; import dev.cbyrne.betterinject.annotations.Inject; diff --git a/src/main/java/de/hysky/skyblocker/mixin/SocialInteractionsPlayerListWidgetMixin.java b/src/main/java/de/hysky/skyblocker/mixin/SocialInteractionsPlayerListWidgetMixin.java index 3a60bfbb..cad7cf38 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/SocialInteractionsPlayerListWidgetMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/SocialInteractionsPlayerListWidgetMixin.java @@ -18,7 +18,7 @@ public class SocialInteractionsPlayerListWidgetMixin { @WrapOperation(method = "setPlayers", at = @At(value = "INVOKE", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", remap = false)) private Object skyblocker$hideInvalidPlayers(Map<Object, Object> map, Object uuid, Object entry, Operation<Object> operation) { if (Utils.isOnSkyblock() && !((SocialInteractionsPlayerListEntry) entry).getName().matches("[A-Za-z0-9_]+")) return null; - + return operation.call(map, uuid, entry); } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java index e723c998..42601546 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/WorldRendererMixin.java @@ -9,25 +9,21 @@ import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef; -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.dungeon.StarredMobGlow; +import de.hysky.skyblocker.skyblock.entity.MobGlow; import net.minecraft.client.render.WorldRenderer; import net.minecraft.entity.Entity; @Mixin(WorldRenderer.class) public class WorldRendererMixin { - @ModifyExpressionValue(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;hasOutline(Lnet/minecraft/entity/Entity;)Z")) - private boolean skyblocker$shouldStarredMobGlow(boolean original, @Local Entity entity, @Share("isGlowingStarredMob") LocalBooleanRef isGlowingStarredMob) { - boolean isAStarredMobThatShouldGlow = SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && StarredMobGlow.shouldMobGlow(entity); - - isGlowingStarredMob.set(isAStarredMobThatShouldGlow); - - return original || isAStarredMobThatShouldGlow; + private boolean skyblocker$shouldMobGlow(boolean original, @Local Entity entity, @Share("hasCustomGlow") LocalBooleanRef hasCustomGlow) { + boolean shouldGlow = MobGlow.shouldMobGlow(entity); + hasCustomGlow.set(shouldGlow); + return original || shouldGlow; } @ModifyVariable(method = "render", at = @At("STORE"), ordinal = 0) - private int skyblocker$modifyGlowColor(int color, @Local Entity entity, @Share("isGlowingStarredMob") LocalBooleanRef isGlowingStarredMob) { - return isGlowingStarredMob.get() ? StarredMobGlow.getGlowColor(entity) : color; + private int skyblocker$modifyGlowColor(int color, @Local Entity entity, @Share("hasCustomGlow") LocalBooleanRef hasCustomGlow) { + return hasCustomGlow.get() ? MobGlow.getGlowColor(entity) : color; } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/YggdrasilServicesKeyInfoMixin.java b/src/main/java/de/hysky/skyblocker/mixin/YggdrasilServicesKeyInfoMixin.java index d38e40cc..3c2bbc9a 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/YggdrasilServicesKeyInfoMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/YggdrasilServicesKeyInfoMixin.java @@ -51,7 +51,7 @@ public class YggdrasilServicesKeyInfoMixin { throw e; } } - + @WrapOperation(method = "validateProperty", remap = false, at = @At(value = "INVOKE", target = "org/slf4j/Logger.error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) private void skyblocker$dontLogFailedSignatureValidation(Logger logger, String message, Object property, Object exception, Operation<Void> operation) { if (!Utils.isOnHypixel()) operation.call(logger, message, property, exception); diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/DoubleFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/DoubleFieldControllerMixin.java deleted file mode 100644 index ac24c09f..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/DoubleFieldControllerMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.hysky.skyblocker.mixin.yacl; - -import java.text.NumberFormat; -import java.util.function.Function; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.gui.controllers.string.number.DoubleFieldController; -import dev.isxander.yacl3.gui.controllers.string.number.NumberFieldController; -import net.minecraft.text.Text; - -@Mixin(value = DoubleFieldController.class, remap = false) -public abstract class DoubleFieldControllerMixin extends NumberFieldController<Double> { - private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(); - - - public DoubleFieldControllerMixin(Option<Double> option, Function<Double, Text> displayFormatter) { - super(option, displayFormatter); - } - - @Overwrite - public String getString() { - return NUMBER_FORMAT.format(option().pendingValue()); - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java deleted file mode 100644 index d67993c2..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.hysky.skyblocker.mixin.yacl; - -import java.text.NumberFormat; -import java.util.function.Function; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.gui.controllers.string.number.FloatFieldController; -import dev.isxander.yacl3.gui.controllers.string.number.NumberFieldController; -import net.minecraft.text.Text; - -@Mixin(value = FloatFieldController.class, remap = false) -public abstract class FloatFieldControllerMixin extends NumberFieldController<Float> { - private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(); - - - public FloatFieldControllerMixin(Option<Float> option, Function<Float, Text> displayFormatter) { - super(option, displayFormatter); - } - - @Overwrite - public String getString() { - return NUMBER_FORMAT.format(option().pendingValue()); - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java deleted file mode 100644 index b95cbef7..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.hysky.skyblocker.mixin.yacl; - -import java.text.NumberFormat; -import java.util.function.Function; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.gui.controllers.string.number.IntegerFieldController; -import dev.isxander.yacl3.gui.controllers.string.number.NumberFieldController; -import net.minecraft.text.Text; - -@Mixin(value = IntegerFieldController.class, remap = false) -public abstract class IntegerFieldControllerMixin extends NumberFieldController<Integer> { - private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(); - - public IntegerFieldControllerMixin(Option<Integer> option, Function<Integer, Text> displayFormatter) { - super(option, displayFormatter); - } - - @Overwrite - public String getString() { - return NUMBER_FORMAT.format(option().pendingValue()); - } - - @Overwrite - public boolean isInputValid(String input) { - return super.isInputValid(input); - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/LongFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/LongFieldControllerMixin.java deleted file mode 100644 index 99871e2e..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/LongFieldControllerMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.hysky.skyblocker.mixin.yacl; - -import java.text.NumberFormat; -import java.util.function.Function; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.gui.controllers.string.number.LongFieldController; -import dev.isxander.yacl3.gui.controllers.string.number.NumberFieldController; -import net.minecraft.text.Text; - -@Mixin(value = LongFieldController.class, remap = false) -public abstract class LongFieldControllerMixin extends NumberFieldController<Long> { - private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(); - - public LongFieldControllerMixin(Option<Long> option, Function<Long, Text> displayFormatter) { - super(option, displayFormatter); - } - - @Overwrite - public String getString() { - return NUMBER_FORMAT.format(option().pendingValue()); - } - - @Overwrite - public boolean isInputValid(String input) { - return super.isInputValid(input); - } -} diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/NumberFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/NumberFieldControllerMixin.java deleted file mode 100644 index 17a99cfd..00000000 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/NumberFieldControllerMixin.java +++ /dev/null @@ -1,43 +0,0 @@ -package de.hysky.skyblocker.mixin.yacl; - -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.ParsePosition; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import dev.isxander.yacl3.gui.controllers.slider.ISliderController; -import dev.isxander.yacl3.gui.controllers.string.number.NumberFieldController; -import dev.isxander.yacl3.impl.utils.YACLConstants; -import net.minecraft.util.math.MathHelper; - -@Mixin(value = NumberFieldController.class, remap = false) -public abstract class NumberFieldControllerMixin<T extends Number> implements ISliderController<T> { - private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(); - private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = DecimalFormatSymbols.getInstance(); - - @Overwrite - public void setFromString(String value) { - try { - setPendingValue(MathHelper.clamp(NUMBER_FORMAT.parse(value).doubleValue(), min(), max())); - } catch (ParseException ignore) { - YACLConstants.LOGGER.warn("Failed to parse number: {}", value); - } - } - - @Overwrite - public boolean isInputValid(String input) { - input = input.replace(DECIMAL_FORMAT_SYMBOLS.getGroupingSeparator() + "", ""); - ParsePosition parsePosition = new ParsePosition(0); - NUMBER_FORMAT.parse(input, parsePosition); - - return parsePosition.getIndex() == input.length(); - } - - @Overwrite - protected String cleanupNumberString(String number) { - throw new UnsupportedOperationException("This method should no longer be called."); - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/FancyStatusBars.java b/src/main/java/de/hysky/skyblocker/skyblock/FancyStatusBars.java index 4cd356a8..3456d1ad 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/FancyStatusBars.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/FancyStatusBars.java @@ -85,12 +85,11 @@ public class FancyStatusBars { bars[bar].anchorNum = location; // Count how many bars are in each location - int layer1Count = 0, layer2Count = 0, rightCount = 0; + int layer1Count = 0, layer2Count = 0; for (int i = 0; i < 4; i++) { switch (bars[i].anchorNum) { case 0 -> layer1Count++; case 1 -> layer2Count++; - case 2 -> rightCount++; } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java index c290e5b8..e572d9dc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java @@ -102,7 +102,7 @@ public class TeleportOverlay { @SuppressWarnings("DataFlowIssue") BlockState state = client.world.getBlockState(pos); if (!state.isAir() && client.world.getBlockState(pos.up()).isAir() && client.world.getBlockState(pos.up(2)).isAir()) { - RenderHelper.renderFilledIfVisible(wrc, pos, COLOR_COMPONENTS, 0.5f); + RenderHelper.renderFilled(wrc, pos, COLOR_COMPONENTS, 0.5f, false); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java index 08c22b27..5c7a01f9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java @@ -31,14 +31,13 @@ public class CreeperBeams { private static final Logger LOGGER = LoggerFactory.getLogger(CreeperBeams.class.getName()); - // "missing, this palette looks like you stole it from a 2018 bootstrap webapp!" private static final float[][] COLORS = { DyeColor.LIGHT_BLUE.getColorComponents(), - DyeColor.PINK.getColorComponents(), - DyeColor.ORANGE.getColorComponents(), + DyeColor.LIME.getColorComponents(), + DyeColor.YELLOW.getColorComponents(), DyeColor.MAGENTA.getColorComponents(), }; - private static final float[] LIME_COLOR_COMPONENTS = DyeColor.LIME.getColorComponents(); + private static final float[] GREEN_COLOR_COMPONENTS = DyeColor.GREEN.getColorComponents(); private static final int FLOOR_Y = 68; private static final int BASE_Y = 74; @@ -81,7 +80,7 @@ public class CreeperBeams { if (base == null) { return; } - Vec3d creeperPos = new Vec3d(base.getX() + 0.5, BASE_Y + 3.5, base.getZ() + 0.5); + Vec3d creeperPos = new Vec3d(base.getX() + 0.5, BASE_Y + 1.75, base.getZ() + 0.5); ArrayList<BlockPos> targets = findTargets(world, base); beams = findLines(creeperPos, targets); } @@ -242,9 +241,9 @@ public class CreeperBeams { RenderHelper.renderOutline(wrc, outlineTwo, color, 3, false); RenderHelper.renderLinesFromPoints(wrc, line, color, 1, 2); } else { - RenderHelper.renderOutline(wrc, outlineOne, LIME_COLOR_COMPONENTS, 1, false); - RenderHelper.renderOutline(wrc, outlineTwo, LIME_COLOR_COMPONENTS, 1, false); - RenderHelper.renderLinesFromPoints(wrc, line, LIME_COLOR_COMPONENTS, 0.75f, 1); + RenderHelper.renderOutline(wrc, outlineOne, GREEN_COLOR_COMPONENTS, 1, false); + RenderHelper.renderOutline(wrc, outlineTwo, GREEN_COLOR_COMPONENTS, 1, false); + RenderHelper.renderLinesFromPoints(wrc, line, GREEN_COLOR_COMPONENTS, 0.75f, 1); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java index df5f36ce..02b08254 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java @@ -13,7 +13,7 @@ public class DungeonMapConfigScreen extends Screen { private int hudX = SkyblockerConfigManager.get().locations.dungeons.mapX; private int hudY = SkyblockerConfigManager.get().locations.dungeons.mapY; private final Screen parent; - + protected DungeonMapConfigScreen() { this(null); } @@ -57,7 +57,7 @@ public class DungeonMapConfigScreen extends Screen { SkyblockerConfigManager.get().locations.dungeons.mapX = hudX; SkyblockerConfigManager.get().locations.dungeons.mapY = hudY; SkyblockerConfigManager.save(); - + this.client.setScreen(parent); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java index 762a6e17..f40b7859 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LividColor.java @@ -1,18 +1,49 @@ package de.hysky.skyblocker.skyblock.dungeon; +import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; +import net.minecraft.registry.Registries; +import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; +import java.util.Map; + public class LividColor { + private static final Map<Block, Formatting> WOOL_TO_FORMATTING = Map.of( + Blocks.RED_WOOL, Formatting.RED, + Blocks.YELLOW_WOOL, Formatting.YELLOW, + Blocks.LIME_WOOL, Formatting.GREEN, + Blocks.GREEN_WOOL, Formatting.DARK_GREEN, + Blocks.BLUE_WOOL, Formatting.BLUE, + Blocks.MAGENTA_WOOL, Formatting.LIGHT_PURPLE, + Blocks.PURPLE_WOOL, Formatting.DARK_PURPLE, + Blocks.GRAY_WOOL, Formatting.GRAY, + Blocks.WHITE_WOOL, Formatting.WHITE + ); + private static final Map<String, Formatting> LIVID_TO_FORMATTING = Map.of( + "Hockey Livid", Formatting.RED, + "Arcade Livid", Formatting.YELLOW, + "Smile Livid", Formatting.GREEN, + "Frog Livid", Formatting.DARK_GREEN, + "Scream Livid", Formatting.BLUE, + "Crossed Livid", Formatting.LIGHT_PURPLE, + "Purple Livid", Formatting.DARK_PURPLE, + "Doctor Livid", Formatting.GRAY, + "Vendetta Livid", Formatting.WHITE + ); private static int tenTicks = 0; + private static Formatting color; public static void init() { ClientReceiveMessageEvents.GAME.register((message, overlay) -> { - if (SkyblockerConfigManager.get().locations.dungeons.lividColor.enableLividColor && message.getString().equals("[BOSS] Livid: I respect you for making it to here, but I'll be your undoing.")) { + SkyblockerConfig.LividColor config = SkyblockerConfigManager.get().locations.dungeons.lividColor; + if ((config.enableLividColorText || config.enableLividColorGlow) && message.getString().equals("[BOSS] Livid: I respect you for making it to here, but I'll be your undoing.")) { tenTicks = 8; } }); @@ -21,16 +52,15 @@ public class LividColor { public static void update() { MinecraftClient client = MinecraftClient.getInstance(); if (tenTicks != 0) { - if (SkyblockerConfigManager.get().locations.dungeons.lividColor.enableLividColor && Utils.isInDungeons() && client.world != null) { + SkyblockerConfig.LividColor config = SkyblockerConfigManager.get().locations.dungeons.lividColor; + if ((config.enableLividColorText || config.enableLividColorGlow) && Utils.isInDungeons() && client.world != null) { if (tenTicks == 1) { - MessageScheduler.INSTANCE.sendMessageAfterCooldown(SkyblockerConfigManager.get().locations.dungeons.lividColor.lividColorText.replace("[color]", "red")); - tenTicks = 0; + onLividColorFound(Blocks.RED_WOOL); return; } - String key = client.world.getBlockState(new BlockPos(5, 110, 42)).getBlock().getTranslationKey(); - if (key.startsWith("block.minecraft.") && key.endsWith("wool") && !key.endsWith("red_wool")) { - MessageScheduler.INSTANCE.sendMessageAfterCooldown(SkyblockerConfigManager.get().locations.dungeons.lividColor.lividColorText.replace("[color]", key.substring(16, key.length() - 5))); - tenTicks = 0; + Block color = client.world.getBlockState(new BlockPos(5, 110, 42)).getBlock(); + if (WOOL_TO_FORMATTING.containsKey(color) && !color.equals(Blocks.RED_WOOL)) { + onLividColorFound(color); return; } tenTicks--; @@ -39,4 +69,22 @@ public class LividColor { } } } + + private static void onLividColorFound(Block color) { + LividColor.color = WOOL_TO_FORMATTING.get(color); + if (SkyblockerConfigManager.get().locations.dungeons.lividColor.enableLividColorText) { + String colorString = Registries.BLOCK.getId(color).getPath(); + MessageScheduler.INSTANCE.sendMessageAfterCooldown(SkyblockerConfigManager.get().locations.dungeons.lividColor.lividColorText.replaceAll("\\[color]", colorString.substring(0, colorString.length() - 5))); + } + tenTicks = 0; + } + + public static boolean shouldGlow(String name) { + return SkyblockerConfigManager.get().locations.dungeons.lividColor.enableLividColorGlow && color == LIVID_TO_FORMATTING.get(name); + } + + @SuppressWarnings("DataFlowIssue") + public static int getGlowColor(String name) { + return LIVID_TO_FORMATTING.containsKey(name) ? LIVID_TO_FORMATTING.get(name).getColorValue() : Formatting.WHITE.getColorValue(); + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/StarredMobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/StarredMobGlow.java deleted file mode 100644 index 2072017d..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/StarredMobGlow.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.hysky.skyblocker.skyblock.dungeon; - -import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; -import net.minecraft.entity.Entity; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.entity.passive.BatEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.predicate.entity.EntityPredicates; -import net.minecraft.util.math.Box; - -import java.util.List; - -public class StarredMobGlow { - - public static boolean shouldMobGlow(Entity entity) { - Box box = entity.getBoundingBox(); - - if (Utils.isInDungeons() && !entity.isInvisible() && OcclusionCulling.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { - // Minibosses - if (entity instanceof PlayerEntity) { - switch (entity.getName().getString()) { - case "Lost Adventurer", "Shadow Assassin", "Diamond Guy" -> { - return true; - } - } - } - - // Regular Mobs - if (!(entity instanceof ArmorStandEntity)) { - Box searchBox = box.expand(0, 2, 0); - List<ArmorStandEntity> armorStands = entity.getWorld().getEntitiesByClass(ArmorStandEntity.class, searchBox, EntityPredicates.NOT_MOUNTED); - - if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) return true; - } - - // Bats - return entity instanceof BatEntity; - } - - return false; - } - - public static int getGlowColor(Entity entity) { - if (entity instanceof PlayerEntity) { - return switch (entity.getName().getString()) { - case "Lost Adventurer" -> 0xfee15c; - case "Shadow Assassin" -> 0x5b2cb2; - case "Diamond Guy" -> 0x57c2f7; - default -> 0xf57738; - }; - } - - return 0xf57738; - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Trivia.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Trivia.java index 262d4a4e..53368c14 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Trivia.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Trivia.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.FairySouls; +import de.hysky.skyblocker.skyblock.waypoint.FairySouls; import de.hysky.skyblocker.utils.chat.ChatFilterResult; import de.hysky.skyblocker.utils.chat.ChatPatternListener; import net.minecraft.client.MinecraftClient; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index eda08cf6..ee517eb8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -255,7 +255,7 @@ public class DungeonSecrets { dungeonFutures.add(CompletableFuture.runAsync(() -> { try (BufferedReader customWaypointsReader = Files.newBufferedReader(CUSTOM_WAYPOINTS_DIR)) { SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach((room, waypointsJson) -> - addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseThrow()) + addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseGet(ArrayList::new)) ); LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); } catch (Exception e) { @@ -273,7 +273,7 @@ public class DungeonSecrets { try (BufferedWriter writer = Files.newBufferedWriter(CUSTOM_WAYPOINTS_DIR)) { JsonObject customWaypointsJson = new JsonObject(); customWaypoints.rowMap().forEach((room, waypoints) -> - customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow()) + customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseGet(JsonArray::new)) ); SkyblockerMod.GSON.toJson(customWaypointsJson, writer); LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index ecfcf496..9b95f146 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -41,6 +41,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Room { + private static final Pattern SECRET_INDEX = Pattern.compile("^(\\d+)"); private static final Pattern SECRETS = Pattern.compile("§7(\\d{1,2})/(\\d{1,2}) Secrets"); @NotNull private final Type type; @@ -70,11 +71,12 @@ public class Room { private int doubleCheckBlocks; /** * Represents the matching state of the room with the following possible values: - * <li>{@link TriState#DEFAULT} means that the room has not been checked, is being processed, or does not {@link Type#needsScanning() need to be processed}. - * <li>{@link TriState#FALSE} means that the room has been checked and there is no match. - * <li>{@link TriState#TRUE} means that the room has been checked and there is a match. + * <li>{@link MatchState#MATCHING} means that the room has not been checked, is being processed, or does not {@link Type#needsScanning() need to be processed}.</li> + * <li>{@link MatchState#DOUBLE_CHECKING} means that the room has a unique match and is being double checked.</li> + * <li>{@link MatchState#MATCHED} means that the room has a unique match ans has been double checked.</li> + * <li>{@link MatchState#FAILED} means that the room has been checked and there is no match.</li> */ - private TriState matched = TriState.DEFAULT; + private MatchState matchState = MatchState.MATCHING; private Table<Integer, BlockPos, SecretWaypoint> secretWaypoints; private String name; private Direction direction; @@ -96,7 +98,7 @@ public class Room { } public boolean isMatched() { - return matched == TriState.TRUE; + return matchState == MatchState.DOUBLE_CHECKING || matchState == MatchState.MATCHED; } /** @@ -108,7 +110,7 @@ public class Room { @Override public String toString() { - return "Room{type=" + type + ", shape=" + shape + ", matched=" + matched + ", segments=" + Arrays.toString(segments.toArray()) + "}"; + return "Room{type=%s, segments=%s, shape=%s, matchState=%s, name=%s, direction=%s, physicalCornerPos=%s}".formatted(type, Arrays.toString(segments.toArray()), shape, matchState, name, direction, physicalCornerPos); } @NotNull @@ -208,6 +210,7 @@ public class Room { /** * Removes a custom waypoint relative to this room from {@link DungeonSecrets#customWaypoints} and all existing instances of this room. + * * @param pos the position of the secret waypoint relative to this room * @return the removed secret waypoint or {@code null} if there was no secret waypoint at the given position */ @@ -223,6 +226,7 @@ public class Room { /** * Removes a custom waypoint relative to this room from this instance of the room. + * * @param secretIndex the index of the secret waypoint * @param relativePos the position of the secret waypoint relative to this room */ @@ -237,7 +241,7 @@ public class Room { * This method returns immediately if any of the following conditions are met: * <ul> * <li> The room does not need to be scanned and matched. (When the room is not of type {@link Type.ROOM}, {@link Type.PUZZLE}, or {@link Type.TRAP}. See {@link Type#needsScanning()}) </li> - * <li> The room has been matched or failed to match and is on cooldown. See {@link #matched}. </li> + * <li> The room has been matched or failed to match and is on cooldown. See {@link #matchState}. </li> * <li> {@link #findRoom The previous update} has not completed. </li> * </ul> * Then this method tries to match this room through: @@ -251,7 +255,7 @@ public class Room { @SuppressWarnings("JavadocReference") protected void update() { // Logical AND has higher precedence than logical OR - if (!type.needsScanning() || matched != TriState.DEFAULT || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) { + if (!type.needsScanning() || matchState != MatchState.MATCHING && matchState != MatchState.DOUBLE_CHECKING || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) { return; } MinecraftClient client = MinecraftClient.getInstance(); @@ -266,6 +270,9 @@ public class Room { break; } } + }).exceptionally(e -> { + DungeonSecrets.LOGGER.error("[Skyblocker Dungeon Secrets] Encountered an unknown exception while matching room {}", this, e); + return null; }); } @@ -297,16 +304,24 @@ public class Room { * </ul> * <li> If there are no matching rooms left: </li> * <ul> - * <li> Terminate matching by setting {@link #matched} to {@link TriState#FALSE}. </li> + * <li> Terminate matching by setting {@link #matchState} to {@link TriState#FALSE}. </li> * <li> Schedule another matching attempt in 50 ticks (2.5 seconds). </li> * <li> Reset {@link #possibleRooms} and {@link #checkedBlocks} with {@link #reset()}. </li> * <li> Return {@code true} </li> * </ul> * <li> If there are exactly one room matching: </li> * <ul> - * <li> Call {@link #roomMatched()}. </li> - * <li> Discard the no longer needed fields to save memory. </li> - * <li> Return {@code true} </li> + * <li> If {@link #matchState} is {@link MatchState#MATCHING}: </li> + * <ul> + * <li> Call {@link #roomMatched()}. </li> + * <li> Return {@code false}. </li> + * </ul> + * <li> If {@link #matchState} is {@link MatchState#DOUBLE_CHECKING}: </li> + * <ul> + * <li> Set the match state to {@link MatchState#MATCHED}. </li> + * <li> Discard the no longer needed fields to save memory. </li> + * <li> Return {@code true}. </li> + * </ul> * </ul> * <li> Return {@code false} </li> * </ul> @@ -334,26 +349,29 @@ public class Room { int matchingRoomsSize = possibleRooms.stream().map(Triple::getRight).mapToInt(Collection::size).sum(); if (matchingRoomsSize == 0) { // If no rooms match, reset the fields and scan again after 50 ticks. - matched = TriState.FALSE; - DungeonSecrets.LOGGER.warn("[Skyblocker] No dungeon room matches after checking {} block(s)", checkedBlocks.size()); - Scheduler.INSTANCE.schedule(() -> matched = TriState.DEFAULT, 50); + DungeonSecrets.LOGGER.warn("[Skyblocker Dungeon Secrets] No dungeon room matched after checking {} block(s) including double checking {} block(s)", checkedBlocks.size(), doubleCheckBlocks); + Scheduler.INSTANCE.schedule(() -> matchState = MatchState.MATCHING, 50); reset(); return true; - } else if (matchingRoomsSize == 1 && ++doubleCheckBlocks >= 10) { - // If one room matches, load the secrets for that room and discard the no longer needed fields. - for (Triple<Direction, Vector2ic, List<String>> directionRooms : possibleRooms) { - if (directionRooms.getRight().size() == 1) { - name = directionRooms.getRight().get(0); - direction = directionRooms.getLeft(); - physicalCornerPos = directionRooms.getMiddle(); - roomMatched(); - discard(); - return true; - } + } else if (matchingRoomsSize == 1) { + if (matchState == MatchState.MATCHING) { + // If one room matches, load the secrets for that room and set state to double-checking. + Triple<Direction, Vector2ic, List<String>> directionRoom = possibleRooms.stream().filter(directionRooms -> directionRooms.getRight().size() == 1).findAny().orElseThrow(); + name = directionRoom.getRight().get(0); + direction = directionRoom.getLeft(); + physicalCornerPos = directionRoom.getMiddle(); + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s), starting double checking", name, checkedBlocks.size()); + roomMatched(); + return false; + } else if (matchState == MatchState.DOUBLE_CHECKING && ++doubleCheckBlocks >= 10) { + // If double-checked, set state to matched and discard the no longer needed fields. + DungeonSecrets.LOGGER.info("[Skyblocker Dungeon Secrets] Room {} matched after checking {} block(s) including double checking {} block(s)", name, checkedBlocks.size(), doubleCheckBlocks); + discard(); + return true; } - return false; // This should never happen, we just checked that there is one possible room, and the return true in the loop should activate + return false; } else { - DungeonSecrets.LOGGER.debug("[Skyblocker] {} room(s) remaining after checking {} block(s)", matchingRoomsSize, checkedBlocks.size()); + DungeonSecrets.LOGGER.debug("[Skyblocker Dungeon Secrets] {} room(s) remaining after checking {} block(s)", matchingRoomsSize, checkedBlocks.size()); return false; } } @@ -371,7 +389,7 @@ public class Room { /** * Loads the secret waypoints for the room from {@link DungeonSecrets#waypointsJson} once it has been matched - * and sets {@link #matched} to {@link TriState#TRUE}. + * and sets {@link #matchState} to {@link MatchState#DOUBLE_CHECKING}. * * @param directionRooms the direction, position, and name of the room */ @@ -381,25 +399,29 @@ public class Room { for (JsonElement waypointElement : DungeonSecrets.getRoomWaypoints(name)) { JsonObject waypoint = waypointElement.getAsJsonObject(); String secretName = waypoint.get("secretName").getAsString(); - int secretIndex = Integer.parseInt(secretName.substring(0, Character.isDigit(secretName.charAt(1)) ? 2 : 1)); + Matcher secretIndexMatcher = SECRET_INDEX.matcher(secretName); + int secretIndex = secretIndexMatcher.find() ? Integer.parseInt(secretIndexMatcher.group(1)) : 0; BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } DungeonSecrets.getCustomWaypoints(name).values().forEach(this::addCustomWaypoint); - matched = TriState.TRUE; - - DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); + matchState = MatchState.DOUBLE_CHECKING; } /** * Resets fields for another round of matching after room matching fails. */ private void reset() { + matchState = MatchState.FAILED; IntSortedSet segmentsX = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::x).toArray())); IntSortedSet segmentsY = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::y).toArray())); possibleRooms = getPossibleRooms(segmentsX, segmentsY); checkedBlocks = new HashSet<>(); doubleCheckBlocks = 0; + secretWaypoints = null; + name = null; + direction = null; + physicalCornerPos = null; } /** @@ -407,6 +429,7 @@ public class Room { * These fields are no longer needed and are discarded to save memory. */ private void discard() { + matchState = MatchState.MATCHED; roomsData = null; possibleRooms = null; checkedBlocks = null; @@ -473,7 +496,7 @@ public class Room { BlockState state = world.getBlockState(hitResult.getBlockPos()); if (state.isOf(Blocks.CHEST) || state.isOf(Blocks.PLAYER_HEAD) || state.isOf(Blocks.PLAYER_WALL_HEAD)) { secretWaypoints.column(hitResult.getBlockPos()).values().stream().filter(SecretWaypoint::needsInteraction).findAny() - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} interaction, setting secret #{} as found", secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} interaction, setting secret #{} as found", secretWaypoint.category, secretWaypoint.secretIndex)); } else if (state.isOf(Blocks.LEVER)) { secretWaypoints.column(hitResult.getBlockPos()).values().stream().filter(SecretWaypoint::isLever).forEach(SecretWaypoint::setFound); } @@ -491,7 +514,7 @@ public class Room { return; } secretWaypoints.values().stream().filter(SecretWaypoint::needsItemPickup).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(collector))).filter(SecretWaypoint.getRangePredicate(collector)) - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} picked up a {} from a {} secret, setting secret #{} as found", collector.getName().getString(), itemEntity.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} picked up a {} from a {} secret, setting secret #{} as found", collector.getName().getString(), itemEntity.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); } /** @@ -502,7 +525,7 @@ public class Room { */ protected void onBatRemoved(AmbientEntity bat) { secretWaypoints.values().stream().filter(SecretWaypoint::isBat).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(bat))) - .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker Dungeon Secrets] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); } /** @@ -575,4 +598,8 @@ public class Room { public enum Direction { NW, NE, SW, SE } + + public enum MatchState { + MATCHING, DOUBLE_CHECKING, MATCHED, FAILED + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 0c2d1b34..43f624f6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -20,6 +20,8 @@ import net.minecraft.util.dynamic.Codecs; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; import java.util.function.Predicate; @@ -27,6 +29,7 @@ import java.util.function.Supplier; import java.util.function.ToDoubleFunction; public class SecretWaypoint extends Waypoint { + protected static final Logger LOGGER = LoggerFactory.getLogger(SecretWaypoint.class); public static final Codec<SecretWaypoint> CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.INT.fieldOf("secretIndex").forGetter(secretWaypoint -> secretWaypoint.secretIndex), Category.CODEC.fieldOf("category").forGetter(secretWaypoint -> secretWaypoint.category), @@ -35,8 +38,8 @@ public class SecretWaypoint extends Waypoint { ).apply(instance, SecretWaypoint::new)); public static final Codec<List<SecretWaypoint>> LIST_CODEC = CODEC.listOf(); static final List<String> SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); - private static final SkyblockerConfig.SecretWaypoints CONFIG = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; - private static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.waypointType; + private static final Supplier<SkyblockerConfig.SecretWaypoints> CONFIG = () -> SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; + private static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.get().waypointType; final int secretIndex; final Category category; final Text name; @@ -95,7 +98,7 @@ public class SecretWaypoint extends Waypoint { //TODO In the future, shrink the box for wither essence and items so its more realistic super.render(context); - if (CONFIG.showSecretText) { + if (CONFIG.get().showSecretText) { Vec3d posUp = centerPos.add(0, 1, 0); RenderHelper.renderText(context, name, posUp, true); double distance = context.camera().getPos().distanceTo(centerPos); @@ -135,8 +138,8 @@ public class SecretWaypoint extends Waypoint { } } - private static Category get(JsonObject waypointJson) { - return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElseThrow(); + static Category get(JsonObject waypointJson) { + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(LOGGER::error).orElse(Category.DEFAULT); } boolean needsInteraction() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHudConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHudConfigScreen.java index 9bd6bef1..6f281ba9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHudConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHudConfigScreen.java @@ -23,7 +23,7 @@ public class DwarvenHudConfigScreen extends Screen { protected DwarvenHudConfigScreen() { this(null); } - + public DwarvenHudConfigScreen(Screen parent) { super(Text.of("Dwarven HUD Config")); this.parent = parent; @@ -62,7 +62,7 @@ public class DwarvenHudConfigScreen extends Screen { SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.x = hudX; SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.y = hudY; SkyblockerConfigManager.save(); - + client.setScreen(parent); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java new file mode 100644 index 00000000..5e0995e6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -0,0 +1,83 @@ +package de.hysky.skyblocker.skyblock.entity; + +import java.util.List; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.dungeon.LividColor; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.passive.BatEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.Box; +import net.minecraft.world.World; + +public class MobGlow { + public static boolean shouldMobGlow(Entity entity) { + Box box = entity.getBoundingBox(); + + if (!entity.isInvisible() && OcclusionCulling.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { + String name = entity.getName().getString(); + + // Dungeons + if (Utils.isInDungeons()) { + + // Minibosses + if (entity instanceof PlayerEntity) { + switch (name) { + case "Lost Adventurer", "Shadow Assassin", "Diamond Guy": return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; + case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", + "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid": return LividColor.shouldGlow(name); + } + } + + // Regular Mobs + if (!(entity instanceof ArmorStandEntity)) { + List<ArmorStandEntity> armorStands = getArmorStands(entity.getWorld(), box); + + if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow; + } + + // Bats + return SkyblockerConfigManager.get().locations.dungeons.starredMobGlow && entity instanceof BatEntity; + } + + // Rift + if (Utils.isInTheRift()) { + if (entity instanceof PlayerEntity) { + switch (name) { + // They have a space in their name for some reason... + case "Blobbercyst ": return SkyblockerConfigManager.get().locations.rift.blobbercystGlow; + } + } + } + } + + return false; + } + + private static List<ArmorStandEntity> getArmorStands(World world, Box box) { + return world.getEntitiesByClass(ArmorStandEntity.class, box.expand(0, 2, 0), EntityPredicates.NOT_MOUNTED); + } + + public static int getGlowColor(Entity entity) { + String name = entity.getName().getString(); + + if (entity instanceof PlayerEntity) { + return switch (name) { + case "Lost Adventurer" -> 0xfee15c; + case "Shadow Assassin" -> 0x5b2cb2; + case "Diamond Guy" -> 0x57c2f7; + case "Arcade Livid", "Crossed Livid", "Doctor Livid", "Frog Livid", "Hockey Livid", + "Purple Livid", "Scream Livid", "Smile Livid", "Vendetta Livid" -> LividColor.getGlowColor(name); + case "Blobbercyst " -> Formatting.GREEN.getColorValue(); + default -> 0xf57738; + }; + } + + return 0xf57738; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/filters/ComboFilter.java b/src/main/java/de/hysky/skyblocker/skyblock/filters/ComboFilter.java index 5fd6f741..d6a40d2d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/filters/ComboFilter.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/filters/ComboFilter.java @@ -5,8 +5,8 @@ import de.hysky.skyblocker.utils.chat.ChatFilterResult; public class ComboFilter extends SimpleChatFilter { public ComboFilter() { - super("^(\\+\\d+ Kill Combo \\+\\d+(% ✯ Magic Find| coins per kill|% Combat Exp)" + - "|Your Kill Combo has expired! You reached a \\d+ Kill Combo!)$"); + // ^(\+\d+ Kill Combo( \+\d+(✯ Magic Find| coins per kill|☯ Combat Wisdom))?|Your Kill Combo has expired! You reached a \d+ Kill Combo!)$ + super("^(\\+\\d+ Kill Combo( \\+\\d+(✯ Magic Find| coins per kill|☯ Combat Wisdom))?|Your Kill Combo has expired! You reached a \\d+ Kill Combo!)$"); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java index cec84b38..3434f026 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java @@ -145,7 +145,7 @@ public class CustomArmorTrims { Identifier.CODEC.fieldOf("material").forGetter(ArmorTrimId::material), Identifier.CODEC.fieldOf("pattern").forGetter(ArmorTrimId::pattern)) .apply(instance, ArmorTrimId::new)); - + @Override public Identifier left() { return material(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java index 9e1df2bb..8867af91 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java @@ -1,8 +1,14 @@ package de.hysky.skyblocker.skyblock.item; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + import com.google.common.collect.ImmutableMap; import com.mojang.blaze3d.systems.RenderSystem; -import de.hysky.skyblocker.SkyblockerMod; + +import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; @@ -16,16 +22,10 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.texture.Sprite; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; -import net.minecraft.util.Identifier; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; public class ItemRarityBackgrounds { - private static final Identifier RARITY_BG_TEX = new Identifier(SkyblockerMod.NAMESPACE, "item_rarity_background"); - private static final Supplier<Sprite> SPRITE = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(RARITY_BG_TEX); + private static final SkyblockerConfig.ItemInfoDisplay CONFIG = SkyblockerConfigManager.get().general.itemInfoDisplay; + private static final Supplier<Sprite> SPRITE = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(CONFIG.itemRarityBackgroundStyle.tex); private static final ImmutableMap<String, SkyblockItemRarity> LORE_RARITIES = ImmutableMap.ofEntries( Map.entry("ADMIN", SkyblockItemRarity.ADMIN), Map.entry("SPECIAL", SkyblockItemRarity.SPECIAL), //Very special is the same color so this will cover it @@ -39,27 +39,27 @@ public class ItemRarityBackgrounds { Map.entry("COMMON", SkyblockItemRarity.COMMON) ); private static final Int2ReferenceOpenHashMap<SkyblockItemRarity> CACHE = new Int2ReferenceOpenHashMap<>(); - + public static void init() { //Clear the cache every 5 minutes, ints are very compact! Scheduler.INSTANCE.scheduleCyclic(CACHE::clear, 4800); - + //Clear cache after a screen where items can be upgraded in rarity closes ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> { String title = screen.getTitle().getString(); - + if (Utils.isOnSkyblock() && (title.equals("The Hex") || title.equals("Craft Item") || title.equals("Anvil") || title.equals("Reforge Anvil"))) { ScreenEvents.remove(screen).register(screen1 -> CACHE.clear()); } }); } - + public static void tryDraw(ItemStack stack, DrawContext context, int x, int y) { MinecraftClient client = MinecraftClient.getInstance(); - + if (client.player != null) { SkyblockItemRarity itemRarity = getItemRarity(stack, client.player); - + if (itemRarity != null) draw(context, x, y, itemRarity); } } @@ -73,30 +73,30 @@ public class ItemRarityBackgrounds { int hashCode = itemUuid.isEmpty() ? System.identityHashCode(stack) : itemUuid.hashCode(); if (CACHE.containsKey(hashCode)) return CACHE.get(hashCode); - + List<Text> tooltip = stack.getTooltip(player, TooltipContext.BASIC); String[] stringifiedTooltip = tooltip.stream().map(Text::getString).toArray(String[]::new); - + for (String rarityString : LORE_RARITIES.keySet()) { if (Arrays.stream(stringifiedTooltip).anyMatch(line -> line.contains(rarityString))) { SkyblockItemRarity rarity = LORE_RARITIES.get(rarityString); - + CACHE.put(hashCode, rarity); return rarity; } } - + CACHE.put(hashCode, null); return null; } - + private static void draw(DrawContext context, int x, int y, SkyblockItemRarity rarity) { //Enable blending to handle HUD translucency RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); context.drawSprite(x, y, 0, 16, 16, SPRITE.get(), rarity.r, rarity.g, rarity.b, SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgroundsOpacity); - + RenderSystem.disableBlend(); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java index ac9b1bf0..823c4c99 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java @@ -40,18 +40,19 @@ public class MuseumItemCache { private static final Path CACHE_FILE = SkyblockerMod.CONFIG_DIR.resolve("museum_item_cache.json"); private static final Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> MUSEUM_ITEM_CACHE = new Object2ObjectOpenHashMap<>(); private static final Type MAP_TYPE = new TypeToken<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>>>() {}.getType(); - + private static final String ERROR_LOG_TEMPLATE = "[Skyblocker] Failed to refresh museum item data for profile {}"; + private static CompletableFuture<Void> loaded; public static void init() { ClientLifecycleEvents.CLIENT_STARTED.register(MuseumItemCache::load); } - + private static void load(MinecraftClient client) { loaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = Files.newBufferedReader(CACHE_FILE)) { Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> cachedData = SkyblockerMod.GSON.fromJson(reader, MAP_TYPE); - + MUSEUM_ITEM_CACHE.putAll(cachedData); LOGGER.info("[Skyblocker] Loaded museum items cache"); } catch (NoSuchFileException ignored) { @@ -60,7 +61,7 @@ public class MuseumItemCache { } }); } - + private static void save() { CompletableFuture.runAsync(() -> { try (BufferedWriter writer = Files.newBufferedWriter(CACHE_FILE)) { @@ -70,48 +71,70 @@ public class MuseumItemCache { } }); } - + private static void updateData4ProfileMember(String uuid, String profileId) { CompletableFuture.runAsync(() -> { try (ApiResponse response = Http.sendHypixelRequest("skyblock/museum", "?profile=" + profileId)) { //The request was successful if (response.ok()) { JsonObject profileData = JsonParser.parseString(response.content()).getAsJsonObject(); - JsonObject memberData = profileData.get("members").getAsJsonObject().get(uuid).getAsJsonObject(); - - //We call them sets because it could either be a singular item or an entire armour set - Map<String, JsonElement> donatedSets = memberData.get("items").getAsJsonObject().asMap(); - - //Set of all found item ids on profile - ObjectOpenHashSet<String> itemIds = new ObjectOpenHashSet<>(); - - for (Map.Entry<String, JsonElement> donatedSet : donatedSets.entrySet()) { - //Item is plural here because the nbt is a list - String itemsData = donatedSet.getValue().getAsJsonObject().get("items").getAsJsonObject().get("data").getAsString(); - NbtList items = NbtIo.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(itemsData))).getList("i", NbtElement.COMPOUND_TYPE); - - for (int i = 0; i < items.size(); i++) { - NbtCompound tag = items.getCompound(i).getCompound("tag"); - - if (tag.contains("ExtraAttributes")) { - NbtCompound extraAttributes = tag.getCompound("ExtraAttributes"); - - if (extraAttributes.contains("id")) itemIds.add(extraAttributes.getString("id")); + JsonObject members = profileData.getAsJsonObject("members"); + + if (members.has(uuid)) { + JsonObject memberData = members.get(uuid).getAsJsonObject(); + + //We call them sets because it could either be a singular item or an entire armour set + Map<String, JsonElement> donatedSets = memberData.get("items").getAsJsonObject().asMap(); + + //Set of all found item ids on profile + ObjectOpenHashSet<String> itemIds = new ObjectOpenHashSet<>(); + + for (Map.Entry<String, JsonElement> donatedSet : donatedSets.entrySet()) { + //Item is plural here because the nbt is a list + String itemsData = donatedSet.getValue().getAsJsonObject().get("items").getAsJsonObject().get("data").getAsString(); + NbtList items = NbtIo.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(itemsData))).getList("i", NbtElement.COMPOUND_TYPE); + + for (int i = 0; i < items.size(); i++) { + NbtCompound tag = items.getCompound(i).getCompound("tag"); + + if (tag.contains("ExtraAttributes")) { + NbtCompound extraAttributes = tag.getCompound("ExtraAttributes"); + + if (extraAttributes.contains("id")) itemIds.add(extraAttributes.getString("id")); + } } } + + MUSEUM_ITEM_CACHE.get(uuid).put(profileId, new ProfileMuseumData(System.currentTimeMillis(), itemIds)); + save(); + + LOGGER.info("[Skyblocker] Successfully updated museum item cache for profile {}", profileId); + } else { + //If the player's Museum API is disabled + putEmpty(uuid, profileId); + + LOGGER.warn(ERROR_LOG_TEMPLATE + " because the Museum API is disabled!", profileId); } - - MUSEUM_ITEM_CACHE.get(uuid).put(profileId, new ProfileMuseumData(System.currentTimeMillis(), itemIds)); - save(); - - LOGGER.info("[Skyblocker] Successfully updated museum item cache for profile {}", profileId); + } else { + //If the request returns a non 200 status code + putEmpty(uuid, profileId); + + LOGGER.error(ERROR_LOG_TEMPLATE + " because a non 200 status code was encountered! Status Code: {}", profileId, response.statusCode()); } } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to refresh museum item data for profile {}", profileId, e); + //If an exception was somehow thrown + putEmpty(uuid, profileId); + + LOGGER.error(ERROR_LOG_TEMPLATE, profileId, e); } }); } - + + private static void putEmpty(String uuid, String profileId) { + MUSEUM_ITEM_CACHE.get(uuid).put(profileId, new ProfileMuseumData(System.currentTimeMillis(), ObjectOpenHashSet.of())); + save(); + } + /** * The cache is ticked upon switching skyblock servers */ @@ -121,22 +144,22 @@ public class MuseumItemCache { Object2ObjectOpenHashMap<String, ProfileMuseumData> playerData = MUSEUM_ITEM_CACHE.computeIfAbsent(uuid, uuid1 -> Util.make(new Object2ObjectOpenHashMap<>(), map -> { map.put(profileId, ProfileMuseumData.EMPTY); })); - + if (playerData.get(profileId).stale()) updateData4ProfileMember(uuid, profileId); } } - + public static boolean hasItemInMuseum(String id) { String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); - ObjectOpenHashSet<String> collectedItemIds = MUSEUM_ITEM_CACHE.get(uuid).get(Utils.getProfileId()).collectedItemIds(); - + ObjectOpenHashSet<String> collectedItemIds = (!MUSEUM_ITEM_CACHE.containsKey(uuid) || Utils.getProfileId().isBlank() || !MUSEUM_ITEM_CACHE.get(uuid).containsKey(Utils.getProfileId())) ? null : MUSEUM_ITEM_CACHE.get(uuid).get(Utils.getProfileId()).collectedItemIds(); + return collectedItemIds != null && collectedItemIds.contains(id); } - + private record ProfileMuseumData(long lastUpdated, ObjectOpenHashSet<String> collectedItemIds) { private static final ProfileMuseumData EMPTY = new ProfileMuseumData(0L, null); private static final long MAX_AGE = 86_400_000; - + private boolean stale() { return System.currentTimeMillis() > lastUpdated + MAX_AGE; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java index 08cc5377..07a566af 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java @@ -13,7 +13,7 @@ public enum SkyblockItemRarity { RARE(Formatting.BLUE), UNCOMMON(Formatting.GREEN), COMMON(Formatting.WHITE); - + public final float r; public final float g; public final float b; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index e050aff5..adc23bbb 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.MuseumItemCache; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; @@ -146,26 +147,41 @@ public class ItemTooltip { .append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), count))); } - if (TooltipInfoType.MUSEUM.isTooltipEnabled() && !bazaarOpened) { + if (TooltipInfoType.OBTAINED.isTooltipEnabled()) { String timestamp = getTimestamp(stack); - if (TooltipInfoType.MUSEUM.hasOrNullWarning(internalID)) { - String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID).getAsString(); - String format = switch (itemCategory) { - case "Weapons" -> "%-18s"; - case "Armor" -> "%-19s"; - default -> "%-20s"; - }; - lines.add(Text.literal(String.format(format, "Museum: (" + itemCategory + ")")) - .formatted(Formatting.LIGHT_PURPLE) - .append(Text.literal(timestamp).formatted(Formatting.RED))); - } else if (!timestamp.isEmpty()) { + if (!timestamp.isEmpty()) { lines.add(Text.literal(String.format("%-21s", "Obtained: ")) .formatted(Formatting.LIGHT_PURPLE) .append(Text.literal(timestamp).formatted(Formatting.RED))); } } + if (TooltipInfoType.MUSEUM.isTooltipEnabledAndHasOrNullWarning(internalID) && !bazaarOpened) { + String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID).getAsString(); + String format = switch (itemCategory) { + case "Weapons" -> "%-18s"; + case "Armor" -> "%-19s"; + default -> "%-20s"; + }; + + //Special case the special category so that it doesn't always display not donated + if (itemCategory.equals("Special")) { + lines.add(Text.literal(String.format(format, "Museum: (" + itemCategory + ")")) + .formatted(Formatting.LIGHT_PURPLE)); + } else { + NbtCompound extraAttributes = ItemUtils.getExtraAttributes(stack); + boolean isInMuseum = (extraAttributes.contains("donated_museum") && extraAttributes.getBoolean("donated_museum")) || MuseumItemCache.hasItemInMuseum(internalID); + + Formatting donatedIndicatorFormatting = isInMuseum ? Formatting.GREEN : Formatting.RED; + + lines.add(Text.literal(String.format(format, "Museum (" + itemCategory + "):")) + .formatted(Formatting.LIGHT_PURPLE) + .append(Text.literal(isInMuseum ? "✔" : "✖").formatted(donatedIndicatorFormatting, Formatting.BOLD)) + .append(Text.literal(isInMuseum ? " Donated" : " Not Donated").formatted(donatedIndicatorFormatting))); + } + } + if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.getNbt() != null) { final NbtElement color = stack.getNbt().getCompound("display").get("color"); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java index 086fcb00..38dcb762 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java @@ -20,7 +20,8 @@ public enum TooltipInfoType implements Runnable { ONE_DAY_AVERAGE("https://moulberry.codes/auction_averages_lbin/1day.json", itemTooltip -> itemTooltip.enableAvgBIN, false), THREE_DAY_AVERAGE("https://moulberry.codes/auction_averages_lbin/3day.json", itemTooltip -> itemTooltip.enableAvgBIN, false), MOTES("https://hysky.de/api/motesprice", itemTooltip -> itemTooltip.enableMotesPrice, itemTooltip -> itemTooltip.enableMotesPrice && Utils.isInTheRift(), true), - MUSEUM("https://hysky.de/api/museum", itemTooltip -> itemTooltip.enableMuseumDate, true), + OBTAINED(itemTooltip -> itemTooltip.enableObtainedDate), + MUSEUM("https://hysky.de/api/museum", itemTooltip -> itemTooltip.enableMuseumInfo, true), COLOR("https://hysky.de/api/color", itemTooltip -> itemTooltip.enableExoticTooltip, true); private final String address; @@ -31,6 +32,13 @@ public enum TooltipInfoType implements Runnable { private long hash; /** + * Use this for when you're adding tooltip info that has no data associated with it + */ + TooltipInfoType(Predicate<SkyblockerConfig.ItemTooltip> enabled) { + this(null, itemTooltip -> false, enabled, null, false); + } + + /** * @param address the address to download the data from * @param enabled the predicate to check if the data should be downloaded and the tooltip should be shown * @param cacheable whether the data should be cached diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EffigyWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EffigyWaypoints.java index a0e1a0f2..95e08c80 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EffigyWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EffigyWaypoints.java @@ -30,15 +30,15 @@ public class EffigyWaypoints { if (!SkyblockerConfigManager.get().slayer.vampireSlayer.enableEffigyWaypoints || !Utils.isOnSkyblock() || !Utils.isInTheRift() || !Utils.getIslandArea().contains("Stillgore Château")) return; UNBROKEN_EFFIGIES.clear(); - + try { for (int i = 0; i < Utils.STRING_SCOREBOARD.size(); i++) { String line = Utils.STRING_SCOREBOARD.get(i); - + if (line.contains("Effigies")) { List<Text> effigiesText = new ArrayList<>(); List<Text> prefixAndSuffix = Utils.TEXT_SCOREBOARD.get(i).getSiblings(); - + //Add contents of prefix and suffix to list effigiesText.addAll(prefixAndSuffix.get(0).getSiblings()); effigiesText.addAll(prefixAndSuffix.get(1).getSiblings()); @@ -58,11 +58,11 @@ public class EffigyWaypoints { for (BlockPos effigy : UNBROKEN_EFFIGIES) { float[] colorComponents = DyeColor.RED.getColorComponents(); if (SkyblockerConfigManager.get().slayer.vampireSlayer.compactEffigyWaypoints) { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, effigy.down(6), colorComponents, 0.5F); + RenderHelper.renderFilledWithBeaconBeam(context, effigy.down(6), colorComponents, 0.5F, true); } else { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, effigy, colorComponents, 0.5F); + RenderHelper.renderFilledWithBeaconBeam(context, effigy, colorComponents, 0.5F, true); for (int i = 1; i < 6; i++) { - RenderHelper.renderFilledThroughWalls(context, effigy.down(i), colorComponents, 0.5F - (0.075F * i)); + RenderHelper.renderFilled(context, effigy.down(i), colorComponents, 0.5F - (0.075F * i), true); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java index 744edd4c..aa55a4e3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -1,38 +1,19 @@ package de.hysky.skyblocker.skyblock.rift; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; - -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.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; - import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.PosUtils; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import de.hysky.skyblocker.utils.waypoint.ProfileAwareWaypoint; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; @@ -43,13 +24,27 @@ import net.minecraft.util.DyeColor; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +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; +import java.util.function.Supplier; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; public class EnigmaSouls { private static final Logger LOGGER = LoggerFactory.getLogger(EnigmaSouls.class); + private static final Supplier<Waypoint.Type> TYPE_SUPPLIER = () -> SkyblockerConfigManager.get().general.waypoints.waypointType; private static final Identifier WAYPOINTS_JSON = new Identifier(SkyblockerMod.NAMESPACE, "rift/enigma_soul_waypoints.json"); - private static final BlockPos[] SOUL_WAYPOINTS = new BlockPos[42]; + private static final Map<BlockPos, ProfileAwareWaypoint> SOUL_WAYPOINTS = new HashMap<>(42); private static final Path FOUND_SOULS_FILE = SkyblockerMod.CONFIG_DIR.resolve("found_enigma_souls.json"); - private static final Object2ObjectOpenHashMap<String, ObjectOpenHashSet<BlockPos>> FOUND_SOULS = new Object2ObjectOpenHashMap<>(); private static final float[] GREEN = DyeColor.GREEN.getColorComponents(); private static final float[] RED = DyeColor.RED.getColorComponents(); @@ -64,7 +59,8 @@ public class EnigmaSouls { for (int i = 0; i < waypoints.size(); i++) { JsonObject waypoint = waypoints.get(i).getAsJsonObject(); - SOUL_WAYPOINTS[i] = new BlockPos(waypoint.get("x").getAsInt(), waypoint.get("y").getAsInt(), waypoint.get("z").getAsInt()); + BlockPos pos = new BlockPos(waypoint.get("x").getAsInt(), waypoint.get("y").getAsInt(), waypoint.get("z").getAsInt()); + SOUL_WAYPOINTS.put(pos, new ProfileAwareWaypoint(pos, TYPE_SUPPLIER, GREEN, RED)); } } catch (IOException e) { @@ -74,13 +70,9 @@ public class EnigmaSouls { //Load found souls try (BufferedReader reader = Files.newBufferedReader(FOUND_SOULS_FILE)) { for (Map.Entry<String, JsonElement> profile : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { - ObjectOpenHashSet<BlockPos> foundSoulsOnProfile = new ObjectOpenHashSet<>(); - for (JsonElement foundSoul : profile.getValue().getAsJsonArray().asList()) { - foundSoulsOnProfile.add(PosUtils.parsePosString(foundSoul.getAsString())); + SOUL_WAYPOINTS.get(PosUtils.parsePosString(foundSoul.getAsString())).setFound(); } - - FOUND_SOULS.put(profile.getKey(), foundSoulsOnProfile); } } catch (NoSuchFileException ignored) { } catch (IOException e) { @@ -90,9 +82,16 @@ public class EnigmaSouls { } static void save(MinecraftClient client) { - JsonObject json = new JsonObject(); + Map<String, Set<BlockPos>> foundSouls = new HashMap<>(); + for (ProfileAwareWaypoint soul : SOUL_WAYPOINTS.values()) { + for (String profile : soul.foundProfiles) { + foundSouls.computeIfAbsent(profile, profile_ -> new HashSet<>()); + foundSouls.get(profile).add(soul.pos); + } + } - for (Map.Entry<String, ObjectOpenHashSet<BlockPos>> foundSoulsForProfile : FOUND_SOULS.entrySet()) { + JsonObject json = new JsonObject(); + for (Map.Entry<String, Set<BlockPos>> foundSoulsForProfile : foundSouls.entrySet()) { JsonArray foundSoulsJson = new JsonArray(); for (BlockPos foundSoul : foundSoulsForProfile.getValue()) { @@ -109,15 +108,15 @@ public class EnigmaSouls { } } - static void render(WorldRenderContext wrc) { + static void render(WorldRenderContext context) { SkyblockerConfig.Rift config = SkyblockerConfigManager.get().locations.rift; if (Utils.isInTheRift() && config.enigmaSoulWaypoints && soulsLoaded.isDone()) { - for (BlockPos pos : SOUL_WAYPOINTS) { - if (isSoulMissing(pos)) { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(wrc, pos, GREEN, 0.5f); + for (Waypoint soul : SOUL_WAYPOINTS.values()) { + if (soul.shouldRender()) { + soul.render(context); } else if (config.highlightFoundEnigmaSouls) { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(wrc, pos, RED, 0.5f); + soul.render(context); } } } @@ -127,7 +126,8 @@ public class EnigmaSouls { if (Utils.isInTheRift() && !overlay) { String message = text.getString(); - if (message.equals("You have already found that Enigma Soul!") || Formatting.strip(message).equals("SOUL! You unlocked an Enigma Soul!")) markClosestSoulAsFound(); + if (message.equals("You have already found that Enigma Soul!") || Formatting.strip(message).equals("SOUL! You unlocked an Enigma Soul!")) + markClosestSoulAsFound(); } } @@ -136,13 +136,13 @@ public class EnigmaSouls { .then(literal("rift") .then(literal("enigmaSouls") .then(literal("markAllFound").executes(context -> { - markAllFound(); + SOUL_WAYPOINTS.values().forEach(Waypoint::setFound); context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.rift.enigmaSouls.markAllFound"))); return Command.SINGLE_SUCCESS; })) .then(literal("markAllMissing").executes(context -> { - markAllMissing(); + SOUL_WAYPOINTS.values().forEach(Waypoint::setMissing); context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.rift.enigmaSouls.markAllMissing"))); return Command.SINGLE_SUCCESS; @@ -154,30 +154,10 @@ public class EnigmaSouls { if (!soulsLoaded.isDone() || player == null) return; - Arrays.stream(SOUL_WAYPOINTS) - .filter(EnigmaSouls::isSoulMissing) - .min(Comparator.comparingDouble(soulPos -> soulPos.getSquaredDistance(player.getPos()))) - .filter(soulPos -> soulPos.getSquaredDistance(player.getPos()) <= 16) - .ifPresent(soulPos -> { - FOUND_SOULS.computeIfAbsent(Utils.getProfile(), profile -> new ObjectOpenHashSet<>()); - FOUND_SOULS.get(Utils.getProfile()).add(soulPos); - }); - } - - private static boolean isSoulMissing(BlockPos soulPos) { - ObjectOpenHashSet<BlockPos> foundSoulsOnProfile = FOUND_SOULS.get(Utils.getProfile()); - - return foundSoulsOnProfile == null || !foundSoulsOnProfile.contains(soulPos); - } - - private static void markAllFound() { - FOUND_SOULS.computeIfAbsent(Utils.getProfile(), profile -> new ObjectOpenHashSet<>()); - FOUND_SOULS.get(Utils.getProfile()).addAll(List.of(SOUL_WAYPOINTS)); - } - - private static void markAllMissing() { - ObjectOpenHashSet<BlockPos> foundSoulsOnProfile = FOUND_SOULS.get(Utils.getProfile()); - - if (foundSoulsOnProfile != null) foundSoulsOnProfile.clear(); + SOUL_WAYPOINTS.values().stream() + .filter(Waypoint::shouldRender) + .min(Comparator.comparingDouble(soul -> soul.pos.getSquaredDistance(player.getPos()))) + .filter(soul -> soul.pos.getSquaredDistance(player.getPos()) <= 16) + .ifPresent(Waypoint::setFound); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/MirrorverseWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/MirrorverseWaypoints.java index 7dda741f..83199e99 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/MirrorverseWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/MirrorverseWaypoints.java @@ -6,7 +6,7 @@ import com.google.gson.JsonParser; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; import net.minecraft.util.DyeColor; @@ -18,13 +18,15 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; public class MirrorverseWaypoints { private static final Logger LOGGER = LoggerFactory.getLogger("skyblocker"); + private static final Supplier<Waypoint.Type> WAYPOINT_TYPE = () -> Waypoint.Type.HIGHLIGHT; private static final Identifier WAYPOINTS_JSON = new Identifier(SkyblockerMod.NAMESPACE, "rift/mirrorverse_waypoints.json"); - private static final BlockPos[] LAVA_PATH_WAYPOINTS = new BlockPos[107]; - private static final BlockPos[] UPSIDE_DOWN_WAYPOINTS = new BlockPos[66]; - private static final BlockPos[] TURBULATOR_WAYPOINTS = new BlockPos[27]; + private static Waypoint[] LAVA_PATH_WAYPOINTS; + private static Waypoint[] UPSIDE_DOWN_WAYPOINTS; + private static Waypoint[] TURBULATOR_WAYPOINTS; private static final float[] COLOR_COMPONENTS = DyeColor.RED.getColorComponents(); private static CompletableFuture<Void> waypointsLoaded; @@ -35,51 +37,44 @@ public class MirrorverseWaypoints { static void load(MinecraftClient client) { waypointsLoaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = client.getResourceManager().openAsReader(WAYPOINTS_JSON)) { - JsonObject file = JsonParser.parseReader(reader).getAsJsonObject(); - JsonArray sections = file.get("sections").getAsJsonArray(); + JsonArray sections = JsonParser.parseReader(reader).getAsJsonObject().get("sections").getAsJsonArray(); /// Lava Path - JsonArray lavaPathWaypoints = sections.get(0).getAsJsonObject().get("waypoints").getAsJsonArray(); - - for (int i = 0; i < lavaPathWaypoints.size(); i++) { - JsonObject point = lavaPathWaypoints.get(i).getAsJsonObject(); - LAVA_PATH_WAYPOINTS[i] = new BlockPos(point.get("x").getAsInt(), point.get("y").getAsInt(), point.get("z").getAsInt()); - } + LAVA_PATH_WAYPOINTS = loadWaypoints(sections.get(0).getAsJsonObject().get("waypoints").getAsJsonArray()); /// Upside Down Parkour - JsonArray upsideDownParkourWaypoints = sections.get(1).getAsJsonObject().get("waypoints").getAsJsonArray(); - - for (int i = 0; i < upsideDownParkourWaypoints.size(); i++) { - JsonObject point = upsideDownParkourWaypoints.get(i).getAsJsonObject(); - UPSIDE_DOWN_WAYPOINTS[i] = new BlockPos(point.get("x").getAsInt(), point.get("y").getAsInt(), point.get("z").getAsInt()); - } + UPSIDE_DOWN_WAYPOINTS = loadWaypoints(sections.get(1).getAsJsonObject().get("waypoints").getAsJsonArray()); /// Turbulator Parkour - JsonArray turbulatorParkourWaypoints = sections.get(2).getAsJsonObject().get("waypoints").getAsJsonArray(); - - for (int i = 0; i < turbulatorParkourWaypoints.size(); i++) { - JsonObject point = turbulatorParkourWaypoints.get(i).getAsJsonObject(); - TURBULATOR_WAYPOINTS[i] = new BlockPos(point.get("x").getAsInt(), point.get("y").getAsInt(), point.get("z").getAsInt()); - } + TURBULATOR_WAYPOINTS = loadWaypoints(sections.get(2).getAsJsonObject().get("waypoints").getAsJsonArray()); } catch (IOException e) { LOGGER.error("[Skyblocker] Mirrorverse Waypoints failed to load ;(", e); } }); } + private static Waypoint[] loadWaypoints(JsonArray waypointsJson) { + Waypoint[] waypoints = new Waypoint[waypointsJson.size()]; + for (int i = 0; i < waypointsJson.size(); i++) { + JsonObject point = waypointsJson.get(i).getAsJsonObject(); + waypoints[i] = new Waypoint(new BlockPos(point.get("x").getAsInt(), point.get("y").getAsInt(), point.get("z").getAsInt()), WAYPOINT_TYPE, COLOR_COMPONENTS, false); + } + return waypoints; + } + protected static void render(WorldRenderContext wrc) { //I would also check for the mirrorverse location but the scoreboard stuff is not performant at all... if (Utils.isInTheRift() && SkyblockerConfigManager.get().locations.rift.mirrorverseWaypoints && waypointsLoaded.isDone()) { - for (BlockPos pos : LAVA_PATH_WAYPOINTS) { - RenderHelper.renderFilledIfVisible(wrc, pos, COLOR_COMPONENTS, 0.5f); + for (Waypoint waypoint : LAVA_PATH_WAYPOINTS) { + waypoint.render(wrc); } - for (BlockPos pos : UPSIDE_DOWN_WAYPOINTS) { - RenderHelper.renderFilledIfVisible(wrc, pos, COLOR_COMPONENTS, 0.5f); + for (Waypoint waypoint : UPSIDE_DOWN_WAYPOINTS) { + waypoint.render(wrc); } - for (BlockPos pos : TURBULATOR_WAYPOINTS) { - RenderHelper.renderFilledIfVisible(wrc, pos, COLOR_COMPONENTS, 0.5f); + for (Waypoint waypoint : TURBULATOR_WAYPOINTS) { + waypoint.render(wrc); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/Shortcuts.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/Shortcuts.java index 9c058a4f..c2c952cf 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/Shortcuts.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/Shortcuts.java @@ -21,6 +21,9 @@ import org.slf4j.LoggerFactory; import java.io.*; import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -30,7 +33,7 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit public class Shortcuts { private static final Logger LOGGER = LoggerFactory.getLogger(Shortcuts.class); - private static final File SHORTCUTS_FILE = SkyblockerMod.CONFIG_DIR.resolve("shortcuts.json").toFile(); + private static final Path SHORTCUTS_FILE = SkyblockerMod.CONFIG_DIR.resolve("shortcuts.json"); @Nullable private static CompletableFuture<Void> shortcutsLoaded; public static final Map<String, String> commands = new HashMap<>(); @@ -52,7 +55,7 @@ public class Shortcuts { return; } shortcutsLoaded = CompletableFuture.runAsync(() -> { - try (BufferedReader reader = new BufferedReader(new FileReader(SHORTCUTS_FILE))) { + try (BufferedReader reader = Files.newBufferedReader(SHORTCUTS_FILE)) { Type shortcutsType = new TypeToken<Map<String, Map<String, String>>>() { }.getType(); Map<String, Map<String, String>> shortcuts = SkyblockerMod.GSON.fromJson(reader, shortcutsType); @@ -61,7 +64,7 @@ public class Shortcuts { commands.putAll(shortcuts.get("commands")); commandArgs.putAll(shortcuts.get("commandArgs")); LOGGER.info("[Skyblocker] Loaded {} command shortcuts and {} command argument shortcuts", commands.size(), commandArgs.size()); - } catch (FileNotFoundException e) { + } catch (NoSuchFileException e) { registerDefaultShortcuts(); LOGGER.warn("[Skyblocker] Shortcuts file not found, using default shortcuts. This is normal when using for the first time."); } catch (IOException e) { @@ -140,7 +143,7 @@ public class Shortcuts { JsonObject shortcutsJson = new JsonObject(); shortcutsJson.add("commands", SkyblockerMod.GSON.toJsonTree(commands)); shortcutsJson.add("commandArgs", SkyblockerMod.GSON.toJsonTree(commandArgs)); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(SHORTCUTS_FILE))) { + try (BufferedWriter writer = Files.newBufferedWriter(SHORTCUTS_FILE)) { SkyblockerMod.GSON.toJson(shortcutsJson, writer); LOGGER.info("[Skyblocker] Saved {} command shortcuts and {} command argument shortcuts", commands.size(), commandArgs.size()); } catch (IOException e) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java index 196ad0d6..a5f8ae2d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java @@ -19,7 +19,7 @@ public class ShortcutsConfigScreen extends Screen { private boolean initialized; private double scrollAmount; private final Screen parent; - + public ShortcutsConfigScreen() { this(null); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java b/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java index fba447ea..bc4f98c2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/special/SpecialEffects.java @@ -1,8 +1,8 @@ package de.hysky.skyblocker.skyblock.special; -import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.RenderHelper; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.enchantment.Enchantments; @@ -58,15 +58,10 @@ public class SpecialEffects { ItemStack stack = getStackFromName(matcher.group("item")); if (!stack.isEmpty()) { - if (RenderSystem.isOnRenderThread()) { + RenderHelper.runOnRenderThread(() -> { client.particleManager.addEmitter(client.player, ParticleTypes.PORTAL, 30); client.gameRenderer.showFloatingItem(stack); - } else { - RenderSystem.recordRenderCall(() -> { - client.particleManager.addEmitter(client.player, ParticleTypes.PORTAL, 30); - client.gameRenderer.showFloatingItem(stack); - }); - } + }); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Colors.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Colors.java new file mode 100644 index 00000000..0de3e45f --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Colors.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.skyblock.tabhud.util; + +import net.minecraft.util.math.MathHelper; + +public class Colors { + + /** + * @param pcnt Percentage between 0% and 100%, NOT 0-1! + * @return an int representing a color, where 100% = green and 0% = red + */ + public static int pcntToCol(float pcnt) { + return MathHelper.hsvToRgb(pcnt / 300f, 0.9f, 0.9f); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java index 24883d77..82394a78 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java @@ -10,6 +10,7 @@ public class Ico { public static final ItemStack MAP = new ItemStack(Items.FILLED_MAP); public static final ItemStack NTAG = new ItemStack(Items.NAME_TAG); public static final ItemStack EMERALD = new ItemStack(Items.EMERALD); + public static final ItemStack AMETHYST_SHARD = new ItemStack(Items.AMETHYST_SHARD); public static final ItemStack CLOCK = new ItemStack(Items.CLOCK); public static final ItemStack DIASWORD = new ItemStack(Items.DIAMOND_SWORD); public static final ItemStack DBUSH = new ItemStack(Items.DEAD_BUSH); @@ -48,8 +49,10 @@ public class Ico { public static final ItemStack B_ROD = new ItemStack(Items.BLAZE_ROD); public static final ItemStack BOW = new ItemStack(Items.BOW); public static final ItemStack COPPER = new ItemStack(Items.COPPER_INGOT); + public static final ItemStack NETHERITE_UPGRADE_ST = new ItemStack(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE); public static final ItemStack COMPOSTER = new ItemStack(Items.COMPOSTER); public static final ItemStack SAPLING = new ItemStack(Items.OAK_SAPLING); + public static final ItemStack SEEDS = new ItemStack(Items.WHEAT_SEEDS); public static final ItemStack MILESTONE = new ItemStack(Items.LODESTONE); public static final ItemStack PICKAXE = new ItemStack(Items.IRON_PICKAXE); public static final ItemStack NETHER_STAR = new ItemStack(Items.NETHER_STAR); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java index f577f2d3..3ef968a3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java @@ -35,7 +35,7 @@ public class PlayerListMgr { ClientPlayNetworkHandler cpnwh = MinecraftClient.getInstance().getNetworkHandler(); - // check is needed, else game crash on server leave + // check is needed, else game crashes on server leave if (cpnwh != null) { playerList = cpnwh.getPlayerList().stream().sorted(PlayerListHudAccessor.getOrdering()).toList(); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/CommsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/CommsWidget.java index e8bf91ab..a5fb4d32 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/CommsWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/CommsWidget.java @@ -3,14 +3,14 @@ package de.hysky.skyblocker.skyblock.tabhud.widget; import java.util.regex.Matcher; import java.util.regex.Pattern; -import de.hysky.skyblocker.skyblock.tabhud.widget.component.IcoTextComponent; -import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; +import de.hysky.skyblocker.skyblock.tabhud.util.Colors; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; +import de.hysky.skyblocker.skyblock.tabhud.widget.component.IcoTextComponent; +import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.math.MathHelper; // this widget shows the status of the king's commissions. // (dwarven mines and crystal hollows) @@ -47,17 +47,13 @@ public class CommsWidget extends Widget { String progress = m.group("progress"); if (progress.equals("DONE")) { - pc = new ProgressComponent(Ico.BOOK, Text.of(name), Text.of(progress), 100f, pcntToCol(100)); + pc = new ProgressComponent(Ico.BOOK, Text.of(name), Text.of(progress), 100f, Colors.pcntToCol(100)); } else { float pcnt = Float.parseFloat(progress.substring(0, progress.length() - 1)); - pc = new ProgressComponent(Ico.BOOK, Text.of(name), pcnt, pcntToCol(pcnt)); + pc = new ProgressComponent(Ico.BOOK, Text.of(name), pcnt, Colors.pcntToCol(pcnt)); } this.addComponent(pc); } } - private int pcntToCol(float pcnt) { - return MathHelper.hsvToRgb(pcnt / 300f, 0.9f, 0.9f); - } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ComposterWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ComposterWidget.java index fbeb5ae5..f50b617b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ComposterWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ComposterWidget.java @@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.tabhud.widget; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; - +import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; @@ -20,11 +20,11 @@ public class ComposterWidget extends Widget { @Override public void updateContent() { - this.addSimpleIcoText(Ico.SAPLING, "Organic Matter:", Formatting.YELLOW, 48); - this.addSimpleIcoText(Ico.FURNACE, "Fuel:", Formatting.BLUE, 49); - this.addSimpleIcoText(Ico.CLOCK, "Time Left:", Formatting.RED, 50); - this.addSimpleIcoText(Ico.COMPOSTER, "Stored Compost:", Formatting.DARK_GREEN, 51); + int offset = (PlayerListMgr.strAt(46) != null) ? 1 : 0; + this.addSimpleIcoText(Ico.SAPLING, "Organic Matter:", Formatting.YELLOW, 48 + offset); + this.addSimpleIcoText(Ico.FURNACE, "Fuel:", Formatting.BLUE, 49 + offset); + this.addSimpleIcoText(Ico.CLOCK, "Time Left:", Formatting.RED, 50 + offset); + this.addSimpleIcoText(Ico.COMPOSTER, "Stored Compost:", Formatting.DARK_GREEN, 51 + offset); } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPuzzleWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPuzzleWidget.java index 1b3b8644..53f84f71 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPuzzleWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPuzzleWidget.java @@ -37,16 +37,21 @@ public class DungeonPuzzleWidget extends Widget { if (m == null) { break; } + + Formatting statcol = switch (m.group("status")) { + case "✦" -> Formatting.GOLD; // Unsolved + case "✔" -> Formatting.GREEN; // Solved + case "✖" -> Formatting.RED; // Failed + default -> Formatting.WHITE; // Who knows if they'll add another puzzle state or not? + }; + Text t = Text.literal(m.group("name") + ": ") .append(Text.literal("[").formatted(Formatting.GRAY)) - .append(m.group("status")) + .append(Text.literal(m.group("status")).formatted(statcol, Formatting.BOLD)) .append(Text.literal("]").formatted(Formatting.GRAY)); IcoTextComponent itc = new IcoTextComponent(Ico.SIGN, t); this.addComponent(itc); pos++; - // code points for puzzle status chars unsolved and solved: 10022, 10004 - // not sure which one is which - // still need to find out codepoint for the puzzle failed char } if (pos == 48) { this.addComponent( diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/FireSaleWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/FireSaleWidget.java index 0211cbd6..e08b4acf 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/FireSaleWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/FireSaleWidget.java @@ -3,14 +3,13 @@ package de.hysky.skyblocker.skyblock.tabhud.widget; import java.util.regex.Matcher; import java.util.regex.Pattern; +import de.hysky.skyblocker.skyblock.tabhud.util.Colors; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; import de.hysky.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; - import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.Formatting; // this widget shows info about fire sales when in the hub. @@ -55,14 +54,10 @@ public class FireSaleWidget extends Widget { float total = Float.parseFloat(m.group("total")) * 1000; Text prgressTxt = Text.literal(String.format("%s/%.0f", avail, total)); float pcnt = (Float.parseFloat(avail) / (total)) * 100f; - ProgressComponent pc = new ProgressComponent(Ico.GOLD, itemTxt, prgressTxt, pcnt, pcntToCol(pcnt)); + ProgressComponent pc = new ProgressComponent(Ico.GOLD, itemTxt, prgressTxt, pcnt, Colors.pcntToCol(pcnt)); this.addComponent(pc); } } - private int pcntToCol(float pcnt) { - return MathHelper.hsvToRgb( pcnt / 300f, 0.9f, 0.9f); - } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ForgeWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ForgeWidget.java index 1a4683f5..adae7daf 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ForgeWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/ForgeWidget.java @@ -69,7 +69,11 @@ public class ForgeWidget extends Widget { c = new IcoFatTextComponent(); } else { l1 = Text.literal(parts[0].substring(3)).formatted(Formatting.YELLOW); - l2 = Text.literal("Done in: ").formatted(Formatting.GRAY).append(Text.literal(parts[1]).formatted(Formatting.WHITE)); + if (parts[1].equals("Ready!")) { + l2 = Text.literal("Done!").formatted(Formatting.GREEN); + } else { + l2 = Text.literal("Done in: ").formatted(Formatting.GRAY).append(Text.literal(parts[1]).formatted(Formatting.WHITE)); + } c = new IcoFatTextComponent(Ico.FIRE, l1, l2); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenServerWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenServerWidget.java index 221f8b08..b6b65896 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenServerWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenServerWidget.java @@ -6,7 +6,7 @@ import java.util.regex.Pattern; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; import de.hysky.skyblocker.skyblock.tabhud.widget.component.IcoTextComponent; - +import de.hysky.skyblocker.utils.Constants; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; @@ -14,13 +14,14 @@ import net.minecraft.util.Formatting; // this widget shows info about the garden server public class GardenServerWidget extends Widget { - private static final MutableText TITLE = Text.literal("Server Info").formatted(Formatting.DARK_AQUA, Formatting.BOLD); + //From the armor trim tooltip + private static final int COPPER_COLOR = 11823181; // match the next visitor in the garden // group 1: visitor name - private static final Pattern VISITOR_PATTERN = Pattern.compile("Next Visitor: (?<vis>.*)"); + private static final Pattern VISITOR_PATTERN = Pattern.compile("Visitors: (?<vis>.*)"); public GardenServerWidget() { super(TITLE, Formatting.DARK_AQUA.getColorValue()); @@ -31,17 +32,29 @@ public class GardenServerWidget extends Widget { this.addSimpleIcoText(Ico.MAP, "Area:", Formatting.DARK_AQUA, 41); this.addSimpleIcoText(Ico.NTAG, "Server ID:", Formatting.GRAY, 42); this.addSimpleIcoText(Ico.EMERALD, "Gems:", Formatting.GREEN, 43); - this.addSimpleIcoText(Ico.COPPER, "Copper:", Formatting.GOLD, 44); - Matcher m = PlayerListMgr.regexAt(45, VISITOR_PATTERN); + Text copperText = Widget.simpleEntryText(44, "Copper:", Formatting.WHITE); + ((MutableText) copperText.getSiblings().get(0)).styled(Constants.WITH_COLOR.apply(COPPER_COLOR)); + + this.addComponent(new IcoTextComponent(Ico.COPPER, copperText)); + + boolean hasPesthunterBonus = PlayerListMgr.strAt(46) != null; + + if (hasPesthunterBonus) { + this.addComponent(new IcoTextComponent(Ico.NETHERITE_UPGRADE_ST, PlayerListMgr.textAt(46))); + } + + int offset = hasPesthunterBonus ? 1 : 0; + + Matcher m = PlayerListMgr.regexAt(53 + offset, VISITOR_PATTERN); if (m == null ) { this.addComponent(new IcoTextComponent()); return; } - String vis = m.group("vis"); + String vis = m.group("vis").replaceAll("[()]*", ""); Formatting col; - if (vis.equals("Not Unlocked!")) { + if (vis.equals("Not Unlocked!") || vis.equals("Queue Full!")) { col = Formatting.RED; } else { col = Formatting.GREEN; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenSkillsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenSkillsWidget.java index 41eee8d6..75652b33 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenSkillsWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenSkillsWidget.java @@ -26,6 +26,8 @@ public class GardenSkillsWidget extends Widget { private static final Pattern SKILL_PATTERN = Pattern .compile("Skills: (?<skill>[A-Za-z]* [0-9]*): (?<progress>[0-9.MAX]*)%?"); + private static final Pattern GARDEN_LEVEL_PATTERN = Pattern.compile("Garden Level: (?<level>[IVX0-9]+)(?: \\((?<progress>[0-9.]+)% to [IVX0-9]+\\))?"); + // same, more or less private static final Pattern MS_PATTERN = Pattern .compile("Milestone: (?<milestone>[A-Za-z ]* [0-9]*): (?<progress>[0-9.]*)%"); @@ -36,26 +38,46 @@ public class GardenSkillsWidget extends Widget { @Override public void updateContent() { - ProgressComponent pc; - Matcher m = PlayerListMgr.regexAt(66, SKILL_PATTERN); - if (m == null) { - pc = new ProgressComponent(); + ProgressComponent spc; + Matcher skillMatcher = PlayerListMgr.regexAt(66, SKILL_PATTERN); + if (skillMatcher == null) { + spc = new ProgressComponent(); } else { - String strpcnt = m.group("progress"); - String skill = m.group("skill"); + String strpcnt = skillMatcher.group("progress"); + String skill = skillMatcher.group("skill"); if (strpcnt.equals("MAX")) { - pc = new ProgressComponent(Ico.LANTERN, Text.of(skill), Text.of("MAX"), 100f, + spc = new ProgressComponent(Ico.LANTERN, Text.of(skill), Text.of("MAX"), 100f, Formatting.RED.getColorValue()); } else { float pcnt = Float.parseFloat(strpcnt); - pc = new ProgressComponent(Ico.LANTERN, Text.of(skill), pcnt, + spc = new ProgressComponent(Ico.LANTERN, Text.of(skill), pcnt, Formatting.GOLD.getColorValue()); } } - this.addComponent(pc); + this.addComponent(spc); + + ProgressComponent glpc; + Matcher glMatcher = PlayerListMgr.regexAt(45, GARDEN_LEVEL_PATTERN); + + if (glMatcher == null) { + glpc = new ProgressComponent(); + } else { + String level = glMatcher.group("level"); + + if (level.equals("15") || level.equals("XV")) { + glpc = new ProgressComponent(Ico.SEEDS, Text.literal("Garden Level " + level), 100f, Formatting.RED.getColorValue()); + } else { + String strpcnt = glMatcher.group("progress"); + float pcnt = Float.parseFloat(strpcnt); + + glpc = new ProgressComponent(Ico.SEEDS, Text.literal("Garden Level " + level), pcnt, Formatting.DARK_GREEN.getColorValue()); + } + } + + this.addComponent(glpc); Text speed = Widget.simpleEntryText(67, "SPD", Formatting.WHITE); IcoTextComponent spd = new IcoTextComponent(Ico.SUGAR, speed); @@ -66,22 +88,21 @@ public class GardenSkillsWidget extends Widget { tc.addToCell(0, 0, spd); tc.addToCell(1, 0, ffo); this.addComponent(tc); + + this.addComponent(new IcoTextComponent(Ico.HOE, PlayerListMgr.textAt(70))); ProgressComponent pc2; - m = PlayerListMgr.regexAt(69, MS_PATTERN); - if (m == null) { + Matcher milestoneMatcher = PlayerListMgr.regexAt(69, MS_PATTERN); + if (milestoneMatcher == null) { pc2 = new ProgressComponent(); } else { - String strpcnt = m.group("progress"); - String milestone = m.group("milestone"); + String strpcnt = milestoneMatcher.group("progress"); + String milestone = milestoneMatcher.group("milestone"); float pcnt = Float.parseFloat(strpcnt); pc2 = new ProgressComponent(Ico.MILESTONE, Text.of(milestone), pcnt, Formatting.GREEN.getColorValue()); - } this.addComponent(pc2); - } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenVisitorsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenVisitorsWidget.java index cfbd6cd0..2b0036ad 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenVisitorsWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenVisitorsWidget.java @@ -15,16 +15,17 @@ public class GardenVisitorsWidget extends Widget { @Override public void updateContent() { - if (PlayerListMgr.textAt(54) == null) { + int offset = (PlayerListMgr.strAt(46) != null) ? 1 : 0; + + if (PlayerListMgr.textAt(54 + offset) == null) { this.addComponent(new PlainTextComponent(Text.literal("No visitors!").formatted(Formatting.GRAY))); return; } - for (int i = 54; i < 59; i++) { + for (int i = 54 + offset; i < 59 + offset; i++) { String text = PlayerListMgr.strAt(i); if (text != null) this.addComponent(new PlainTextComponent(Text.literal(text))); } - } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/JacobsContestWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/JacobsContestWidget.java index 5ae0bd3d..472e6d61 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/JacobsContestWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/JacobsContestWidget.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.skyblock.tabhud.widget; import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; @@ -19,6 +21,9 @@ public class JacobsContestWidget extends Widget { private static final MutableText TITLE = Text.literal("Jacob's Contest").formatted(Formatting.YELLOW, Formatting.BOLD); + //TODO Properly match the contest placement and display it + private static final Pattern CROP_PATTERN = Pattern.compile("(?:☘|○) (?<crop>[A-Za-z ]+)(?:.+)?"); + private static final HashMap<String, ItemStack> FARM_DATA = new HashMap<>(); // again, there HAS to be a better way to do this @@ -41,22 +46,27 @@ public class JacobsContestWidget extends Widget { @Override public void updateContent() { - this.addSimpleIcoText(Ico.CLOCK, "Starts in:", Formatting.GOLD, 76); + Text jacobStatus = PlayerListMgr.textAt(76); + + if (jacobStatus.getString().equals("ACTIVE")) { + this.addComponent(new IcoTextComponent(Ico.CLOCK, jacobStatus)); + } else { + this.addSimpleIcoText(Ico.CLOCK, "Starts in:", Formatting.GOLD, 76); + } TableComponent tc = new TableComponent(1, 3, Formatting.YELLOW .getColorValue()); for (int i = 77; i < 80; i++) { - String item = PlayerListMgr.strAt(i); + Matcher item = PlayerListMgr.regexAt(i, CROP_PATTERN); IcoTextComponent itc; if (item == null) { itc = new IcoTextComponent(); } else { - itc = new IcoTextComponent(FARM_DATA.get(item), Text.of(item)); + String cropName = item.group("crop").trim(); //Trimming is needed because during a contest the space separator will be caught + itc = new IcoTextComponent(FARM_DATA.get(cropName), Text.of(cropName)); } tc.addToCell(0, i - 77, itc); } this.addComponent(tc); - } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/PowderWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/PowderWidget.java index 44635fbe..ec176a98 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/PowderWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/PowderWidget.java @@ -22,7 +22,7 @@ public class PowderWidget extends Widget { @Override public void updateContent() { this.addSimpleIcoText(Ico.MITHRIL, "Mithril:", Formatting.AQUA, 46); - this.addSimpleIcoText(Ico.EMERALD, "Gemstone:", Formatting.DARK_PURPLE, 47); + this.addSimpleIcoText(Ico.AMETHYST_SHARD, "Gemstone:", Formatting.DARK_PURPLE, 47); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudCommsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudCommsWidget.java index 6aa363c9..442f12ca 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudCommsWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudCommsWidget.java @@ -2,16 +2,16 @@ package de.hysky.skyblocker.skyblock.tabhud.widget.hud; import java.util.List; -import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud.Commission; +import de.hysky.skyblocker.skyblock.tabhud.util.Colors; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; import de.hysky.skyblocker.skyblock.tabhud.widget.component.Component; import de.hysky.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.math.MathHelper; // this widget shows the status of the king's commissions. // (dwarven mines and crystal hollows) @@ -56,7 +56,7 @@ public class HudCommsWidget extends Widget { Component comp; if (isFancy) { - comp = new ProgressComponent(Ico.BOOK, c, p, pcntToCol(p)); + comp = new ProgressComponent(Ico.BOOK, c, p, Colors.pcntToCol(p)); } else { comp = new PlainTextComponent( Text.literal(comm.commission() + ": ") @@ -66,8 +66,4 @@ public class HudCommsWidget extends Widget { } } - private int pcntToCol(float pcnt) { - return MathHelper.hsvToRgb(pcnt / 300f, 0.9f, 0.9f); - } - } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java index 93ade5cb..6cd7736b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java @@ -3,15 +3,15 @@ package de.hysky.skyblocker.skyblock.tabhud.widget.rift; import java.util.regex.Matcher; import java.util.regex.Pattern; -import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.util.Colors; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; import de.hysky.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.math.MathHelper; public class RiftProgressWidget extends Widget { @@ -75,10 +75,6 @@ public class RiftProgressWidget extends Widget { } - private static int pcntToCol(float pcnt) { - return MathHelper.hsvToRgb(pcnt / 300f, 0.9f, 0.9f); - } - private void addTimecharmsComponent(int pos) { Matcher m = PlayerListMgr.regexAt(pos, TIMECHARMS_PATTERN); @@ -88,7 +84,7 @@ public class RiftProgressWidget extends Widget { Text progressText = Text.literal(current + "/" + total); ProgressComponent pc = new ProgressComponent(Ico.NETHER_STAR, Text.literal("Timecharms"), progressText, - pcnt, pcntToCol(pcnt)); + pcnt, Colors.pcntToCol(pcnt)); this.addComponent(pc); } @@ -102,7 +98,7 @@ public class RiftProgressWidget extends Widget { Text progressText = Text.literal(current + "/" + total); ProgressComponent pc = new ProgressComponent(Ico.HEART_OF_THE_SEA, Text.literal("Enigma Souls"), - progressText, pcnt, pcntToCol(pcnt)); + progressText, pcnt, Colors.pcntToCol(pcnt)); this.addComponent(pc); } @@ -116,7 +112,7 @@ public class RiftProgressWidget extends Widget { Text progressText = Text.literal(current + "/" + total); ProgressComponent pc = new ProgressComponent(Ico.BONE, Text.literal("Montezuma"), progressText, pcnt, - pcntToCol(pcnt)); + Colors.pcntToCol(pcnt)); this.addComponent(pc); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/FairySouls.java index cef17d8e..f0e94770 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/FairySouls.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock; +package de.hysky.skyblocker.skyblock.waypoint; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -12,7 +12,8 @@ import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.NEURepoManager; import de.hysky.skyblocker.utils.PosUtils; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.ProfileAwareWaypoint; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; @@ -29,19 +30,24 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import java.util.stream.Collectors; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; public class FairySouls { private static final Logger LOGGER = LoggerFactory.getLogger(FairySouls.class); + private static final Supplier<Waypoint.Type> TYPE_SUPPLIER = () -> SkyblockerConfigManager.get().general.waypoints.waypointType; private static CompletableFuture<Void> fairySoulsLoaded; private static int maxSouls = 0; - private static final Map<String, Set<BlockPos>> fairySouls = new HashMap<>(); - private static final Map<String, Map<String, Set<BlockPos>>> foundFairies = new HashMap<>(); + private static final Map<String, Map<BlockPos, ProfileAwareWaypoint>> fairySouls = new HashMap<>(); @SuppressWarnings("UnusedReturnValue") public static CompletableFuture<Void> runAsyncAfterFairySoulsLoad(Runnable runnable) { @@ -67,32 +73,41 @@ public class FairySouls { private static void loadFairySouls() { fairySoulsLoaded = NEURepoManager.runAsyncAfterLoad(() -> { maxSouls = NEURepoManager.NEU_REPO.getConstants().getFairySouls().getMaxSouls(); - NEURepoManager.NEU_REPO.getConstants().getFairySouls().getSoulLocations().forEach((location, fairySoulsForLocation) -> fairySouls.put(location, fairySoulsForLocation.stream().map(coordinate -> new BlockPos(coordinate.getX(), coordinate.getY(), coordinate.getZ())).collect(Collectors.toUnmodifiableSet()))); - LOGGER.debug("[Skyblocker] Loaded {} fairy souls across {} locations", fairySouls.values().stream().mapToInt(Set::size).sum(), fairySouls.size()); + NEURepoManager.NEU_REPO.getConstants().getFairySouls().getSoulLocations().forEach((location, fairiesForLocation) -> fairySouls.put(location, fairiesForLocation.stream().map(coordinate -> new BlockPos(coordinate.getX(), coordinate.getY(), coordinate.getZ())).collect(Collectors.toUnmodifiableMap(pos -> pos, pos -> new ProfileAwareWaypoint(pos, TYPE_SUPPLIER, DyeColor.GREEN.getColorComponents(), DyeColor.RED.getColorComponents()))))); + LOGGER.debug("[Skyblocker] Loaded {} fairy souls across {} locations", fairySouls.values().stream().mapToInt(Map::size).sum(), fairySouls.size()); - try (BufferedReader reader = new BufferedReader(new FileReader(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()))) { + try (BufferedReader reader = Files.newBufferedReader(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json"))) { for (Map.Entry<String, JsonElement> foundFairiesForProfileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { - Map<String, Set<BlockPos>> foundFairiesForProfile = new HashMap<>(); for (Map.Entry<String, JsonElement> foundFairiesForLocationJson : foundFairiesForProfileJson.getValue().getAsJsonObject().asMap().entrySet()) { - Set<BlockPos> foundFairiesForLocation = new HashSet<>(); + String profile = foundFairiesForLocationJson.getKey(); + Map<BlockPos, ProfileAwareWaypoint> fairiesForLocation = fairySouls.get(profile); for (JsonElement foundFairy : foundFairiesForLocationJson.getValue().getAsJsonArray().asList()) { - foundFairiesForLocation.add(PosUtils.parsePosString(foundFairy.getAsString())); + fairiesForLocation.get(PosUtils.parsePosString(foundFairy.getAsString())).setFound(profile); } - foundFairiesForProfile.put(foundFairiesForLocationJson.getKey(), foundFairiesForLocation); } - foundFairies.put(foundFairiesForProfileJson.getKey(), foundFairiesForProfile); } LOGGER.debug("[Skyblocker] Loaded found fairy souls"); - } catch (FileNotFoundException ignored) { + } catch (NoSuchFileException ignored) { } catch (IOException e) { LOGGER.error("[Skyblocker] Failed to load found fairy souls", e); } - LOGGER.info("[Skyblocker] Loaded {} fairy souls across {} locations and {} found fairy souls across {} locations in {} profiles", fairySouls.values().stream().mapToInt(Set::size).sum(), fairySouls.size(), foundFairies.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Set::size).sum(), foundFairies.values().stream().mapToInt(Map::size).sum(), foundFairies.size()); + LOGGER.info("[Skyblocker] Loaded {} fairy souls across {} locations", fairySouls.values().stream().mapToInt(Map::size).sum(), fairySouls.size()); }); } private static void saveFoundFairySouls(MinecraftClient client) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()))) { + Map<String, Map<String, Set<BlockPos>>> foundFairies = new HashMap<>(); + for (Map.Entry<String, Map<BlockPos, ProfileAwareWaypoint>> fairiesForLocation : fairySouls.entrySet()) { + for (ProfileAwareWaypoint fairySoul : fairiesForLocation.getValue().values()) { + for (String profile : fairySoul.foundProfiles) { + foundFairies.computeIfAbsent(profile, profile_ -> new HashMap<>()); + foundFairies.get(profile).computeIfAbsent(fairiesForLocation.getKey(), location_ -> new HashSet<>()); + foundFairies.get(profile).get(fairiesForLocation.getKey()).add(fairySoul.pos); + } + } + } + + try (BufferedWriter writer = Files.newBufferedWriter(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json"))) { JsonObject foundFairiesJson = new JsonObject(); for (Map.Entry<String, Map<String, Set<BlockPos>>> foundFairiesForProfile : foundFairies.entrySet()) { JsonObject foundFairiesForProfileJson = new JsonObject(); @@ -106,7 +121,6 @@ public class FairySouls { foundFairiesJson.add(foundFairiesForProfile.getKey(), foundFairiesForProfileJson); } SkyblockerMod.GSON.toJson(foundFairiesJson, writer); - writer.close(); LOGGER.info("[Skyblocker] Saved found fairy souls"); } catch (IOException e) { LOGGER.error("[Skyblocker] Failed to write found fairy souls to file", e); @@ -132,13 +146,12 @@ public class FairySouls { SkyblockerConfig.FairySouls fairySoulsConfig = SkyblockerConfigManager.get().general.fairySouls; if (fairySoulsConfig.enableFairySoulsHelper && fairySoulsLoaded.isDone() && fairySouls.containsKey(Utils.getLocationRaw())) { - for (BlockPos fairySoulPos : fairySouls.get(Utils.getLocationRaw())) { - boolean fairySoulNotFound = isFairySoulMissing(fairySoulPos); - if (!fairySoulsConfig.highlightFoundSouls && !fairySoulNotFound || fairySoulsConfig.highlightOnlyNearbySouls && fairySoulPos.getSquaredDistance(context.camera().getPos()) > 2500) { + for (Waypoint fairySoul : fairySouls.get(Utils.getLocationRaw()).values()) { + boolean fairySoulNotFound = fairySoul.shouldRender(); + if (!fairySoulsConfig.highlightFoundSouls && !fairySoulNotFound || fairySoulsConfig.highlightOnlyNearbySouls && fairySoul.pos.getSquaredDistance(context.camera().getPos()) > 2500) { continue; } - float[] colorComponents = fairySoulNotFound ? DyeColor.GREEN.getColorComponents() : DyeColor.RED.getColorComponents(); - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, fairySoulPos, colorComponents, 0.5F); + fairySoul.render(context); } } } @@ -152,51 +165,37 @@ public class FairySouls { private static void markClosestFairyFound() { if (!fairySoulsLoaded.isDone()) return; + PlayerEntity player = MinecraftClient.getInstance().player; if (player == null) { LOGGER.warn("[Skyblocker] Failed to mark closest fairy soul as found because player is null"); return; } - fairySouls.get(Utils.getLocationRaw()).stream() - .filter(FairySouls::isFairySoulMissing) - .min(Comparator.comparingDouble(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos()))) - .filter(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos()) <= 16) - .ifPresent(fairySoulPos -> { - initializeFoundFairiesForCurrentProfileAndLocation(); - foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).add(fairySoulPos); - }); - } - private static boolean isFairySoulMissing(BlockPos fairySoulPos) { - Map<String, Set<BlockPos>> foundFairiesForProfile = foundFairies.get(Utils.getProfile()); - if (foundFairiesForProfile == null) { - return true; - } - Set<BlockPos> foundFairiesForProfileAndLocation = foundFairiesForProfile.get(Utils.getLocationRaw()); - if (foundFairiesForProfileAndLocation == null) { - return true; + Map<BlockPos, ProfileAwareWaypoint> fairiesOnCurrentIsland = fairySouls.get(Utils.getLocationRaw()); + if (fairiesOnCurrentIsland == null) { + LOGGER.warn("[Skyblocker] Failed to mark closest fairy soul as found because there are no fairy souls loaded on the current island. NEU repo probably failed to load."); + return; } - return !foundFairiesForProfileAndLocation.contains(fairySoulPos); + + fairiesOnCurrentIsland.values().stream() + .filter(Waypoint::shouldRender) + .min(Comparator.comparingDouble(fairySoul -> fairySoul.pos.getSquaredDistance(player.getPos()))) + .filter(fairySoul -> fairySoul.pos.getSquaredDistance(player.getPos()) <= 16) + .ifPresent(Waypoint::setFound); } public static void markAllFairiesOnCurrentIslandFound() { - initializeFoundFairiesForCurrentProfileAndLocation(); - foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).addAll(fairySouls.get(Utils.getLocationRaw())); + Map<BlockPos, ProfileAwareWaypoint> fairiesForLocation = fairySouls.get(Utils.getLocationRaw()); + if (fairiesForLocation != null) { + fairiesForLocation.values().forEach(ProfileAwareWaypoint::setFound); + } } public static void markAllFairiesOnCurrentIslandMissing() { - Map<String, Set<BlockPos>> foundFairiesForProfile = foundFairies.get(Utils.getProfile()); - if (foundFairiesForProfile != null) { - foundFairiesForProfile.remove(Utils.getLocationRaw()); + Map<BlockPos, ProfileAwareWaypoint> fairiesForLocation = fairySouls.get(Utils.getLocationRaw()); + if (fairiesForLocation != null) { + fairiesForLocation.values().forEach(ProfileAwareWaypoint::setMissing); } } - - private static void initializeFoundFairiesForCurrentProfileAndLocation() { - initializeFoundFairiesForProfileAndLocation(Utils.getProfile(), Utils.getLocationRaw()); - } - - private static void initializeFoundFairiesForProfileAndLocation(String profile, String location) { - foundFairies.computeIfAbsent(profile, profileKey -> new HashMap<>()); - foundFairies.get(profile).computeIfAbsent(location, locationKey -> new HashSet<>()); - } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/MythologicalRitual.java index e2962702..5b5f4715 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/MythologicalRitual.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.diana; +package de.hysky.skyblocker.skyblock.waypoint; import com.mojang.brigadier.Command; import de.hysky.skyblocker.SkyblockerMod; @@ -108,7 +108,7 @@ public class MythologicalRitual { burrow.nextBurrowPlane[1] = Vec3d.of(pos).subtract(nextBurrowDirection).subtract(0, 50, 0); burrow.nextBurrowPlane[2] = burrow.nextBurrowPlane[1].add(0, 100, 0); burrow.nextBurrowPlane[3] = burrow.nextBurrowPlane[0].add(0, 100, 0); - } else if (ParticleTypes.DRIPPING_LAVA.equals(packet.getParameters().getType())) { + } else if (ParticleTypes.DRIPPING_LAVA.equals(packet.getParameters().getType()) && packet.getCount() == 2) { if (System.currentTimeMillis() > lastEchoTime + 10_000) { return; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Relics.java index aaf4d77c..952f2f59 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Relics.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.spidersden; +package de.hysky.skyblocker.skyblock.waypoint; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -11,7 +11,8 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.PosUtils; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.ProfileAwareWaypoint; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; @@ -28,19 +29,24 @@ import net.minecraft.util.math.BlockPos; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; public class Relics { private static final Logger LOGGER = LoggerFactory.getLogger(Relics.class); + private static final Supplier<Waypoint.Type> TYPE_SUPPLIER = () -> SkyblockerConfigManager.get().general.waypoints.waypointType; private static CompletableFuture<Void> relicsLoaded; @SuppressWarnings({"unused", "FieldCanBeLocal"}) private static int totalRelics = 0; - private static final List<BlockPos> relics = new ArrayList<>(); - private static final Map<String, Set<BlockPos>> foundRelics = new HashMap<>(); + private static final Map<BlockPos, ProfileAwareWaypoint> relics = new HashMap<>(); public static void init() { ClientLifecycleEvents.CLIENT_STARTED.register(Relics::loadRelics); @@ -59,7 +65,8 @@ public class Relics { } else if (json.getKey().equals("locations")) { for (JsonElement locationJson : json.getValue().getAsJsonArray().asList()) { JsonObject posData = locationJson.getAsJsonObject(); - relics.add(new BlockPos(posData.get("x").getAsInt(), posData.get("y").getAsInt(), posData.get("z").getAsInt())); + BlockPos pos = new BlockPos(posData.get("x").getAsInt(), posData.get("y").getAsInt(), posData.get("z").getAsInt()); + relics.put(pos, new ProfileAwareWaypoint(pos, TYPE_SUPPLIER, DyeColor.YELLOW.getColorComponents(), DyeColor.BROWN.getColorComponents())); } } } @@ -68,16 +75,14 @@ public class Relics { LOGGER.error("[Skyblocker] Failed to load relics locations", e); } - try (BufferedReader reader = new BufferedReader(new FileReader(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json").toFile()))) { + try (BufferedReader reader = Files.newBufferedReader(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json"))) { for (Map.Entry<String, JsonElement> profileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { - Set<BlockPos> foundRelicsForProfile = new HashSet<>(); for (JsonElement foundRelicsJson : profileJson.getValue().getAsJsonArray().asList()) { - foundRelicsForProfile.add(PosUtils.parsePosString(foundRelicsJson.getAsString())); + relics.get(PosUtils.parsePosString(foundRelicsJson.getAsString())).setFound(profileJson.getKey()); } - foundRelics.put(profileJson.getKey(), foundRelicsForProfile); } LOGGER.debug("[Skyblocker] Loaded found relics"); - } catch (FileNotFoundException ignored) { + } catch (NoSuchFileException ignored) { } catch (IOException e) { LOGGER.error("[Skyblocker] Failed to load found relics", e); } @@ -85,7 +90,15 @@ public class Relics { } private static void saveFoundRelics(MinecraftClient client) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json").toFile()))) { + Map<String, Set<BlockPos>> foundRelics = new HashMap<>(); + for (ProfileAwareWaypoint relic : relics.values()) { + for (String profile : relic.foundProfiles) { + foundRelics.computeIfAbsent(profile, profile_ -> new HashSet<>()); + foundRelics.get(profile).add(relic.pos); + } + } + + try (BufferedWriter writer = Files.newBufferedWriter(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json"))) { JsonObject json = new JsonObject(); for (Map.Entry<String, Set<BlockPos>> foundRelicsForProfile : foundRelics.entrySet()) { JsonArray foundRelicsJson = new JsonArray(); @@ -105,12 +118,12 @@ public class Relics { dispatcher.register(literal(SkyblockerMod.NAMESPACE) .then(literal("relics") .then(literal("markAllFound").executes(context -> { - Relics.markAllFound(); + relics.values().forEach(ProfileAwareWaypoint::setFound); context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.relics.markAllFound"))); return 1; })) .then(literal("markAllMissing").executes(context -> { - Relics.markAllMissing(); + relics.values().forEach(ProfileAwareWaypoint::setMissing); context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.relics.markAllMissing"))); return 1; })))); @@ -120,11 +133,10 @@ public class Relics { SkyblockerConfig.Relics config = SkyblockerConfigManager.get().locations.spidersDen.relics; if (config.enableRelicsHelper && relicsLoaded.isDone() && Utils.getLocationRaw().equals("combat_1")) { - for (BlockPos fairySoulPos : relics) { - boolean isRelicMissing = isRelicMissing(fairySoulPos); + for (ProfileAwareWaypoint relic : relics.values()) { + boolean isRelicMissing = relic.shouldRender(); if (!isRelicMissing && !config.highlightFoundRelics) continue; - float[] colorComponents = isRelicMissing ? DyeColor.YELLOW.getColorComponents() : DyeColor.BROWN.getColorComponents(); - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, fairySoulPos, colorComponents, 0.5F); + relic.render(context); } } } @@ -143,30 +155,10 @@ public class Relics { LOGGER.warn("[Skyblocker] Failed to mark closest relic as found because player is null"); return; } - relics.stream() - .filter(Relics::isRelicMissing) - .min(Comparator.comparingDouble(relicPos -> relicPos.getSquaredDistance(player.getPos()))) - .filter(relicPos -> relicPos.getSquaredDistance(player.getPos()) <= 16) - .ifPresent(relicPos -> { - foundRelics.computeIfAbsent(Utils.getProfile(), profileKey -> new HashSet<>()); - foundRelics.get(Utils.getProfile()).add(relicPos); - }); - } - - private static boolean isRelicMissing(BlockPos relicPos) { - Set<BlockPos> foundRelicsForProfile = foundRelics.get(Utils.getProfile()); - return foundRelicsForProfile == null || !foundRelicsForProfile.contains(relicPos); - } - - private static void markAllFound() { - foundRelics.computeIfAbsent(Utils.getProfile(), profileKey -> new HashSet<>()); - foundRelics.get(Utils.getProfile()).addAll(relics); - } - - private static void markAllMissing() { - Set<BlockPos> foundRelicsForProfile = foundRelics.get(Utils.getProfile()); - if (foundRelicsForProfile != null) { - foundRelicsForProfile.clear(); - } + relics.values().stream() + .filter(Waypoint::shouldRender) + .min(Comparator.comparingDouble(relic -> relic.pos.getSquaredDistance(player.getPos()))) + .filter(relic -> relic.pos.getSquaredDistance(player.getPos()) <= 16) + .ifPresent(Waypoint::setFound); } } diff --git a/src/main/java/de/hysky/skyblocker/utils/ApiUtils.java b/src/main/java/de/hysky/skyblocker/utils/ApiUtils.java index c0648eba..0121f8ad 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ApiUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ApiUtils.java @@ -21,33 +21,33 @@ public class ApiUtils { * Do not iterate over this map, it will be accessed and modified by multiple threads. */ private static final Object2ObjectOpenHashMap<String, String> NAME_2_UUID_CACHE = new Object2ObjectOpenHashMap<>(); - + public static void init() { //Clear cache every 20 minutes Scheduler.INSTANCE.scheduleCyclic(NAME_2_UUID_CACHE::clear, 24_000, true); } - + /** * Multithreading is to be handled by the method caller */ public static String name2Uuid(String name) { Session session = MinecraftClient.getInstance().getSession(); - + if (session.getUsername().equals(name)) return UndashedUuid.toString(session.getUuidOrNull()); if (NAME_2_UUID_CACHE.containsKey(name)) return NAME_2_UUID_CACHE.get(name); - + try (ApiResponse response = Http.sendName2UuidRequest(name)) { if (response.ok()) { String uuid = JsonParser.parseString(response.content()).getAsJsonObject().get("id").getAsString(); - + NAME_2_UUID_CACHE.put(name, uuid); - + return uuid; } } catch (Exception e) { LOGGER.error("[Skyblocker] Name to uuid lookup failed! Name: {}", name, e); } - + return ""; } } diff --git a/src/main/java/de/hysky/skyblocker/utils/Constants.java b/src/main/java/de/hysky/skyblocker/utils/Constants.java index 94eacf49..134b7888 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Constants.java +++ b/src/main/java/de/hysky/skyblocker/utils/Constants.java @@ -14,7 +14,7 @@ import net.minecraft.util.Formatting; * Holds generic static constants */ public interface Constants { - String LEVEL_EMBLEMS = "\u2E15\u273F\u2741\u2E19\u03B1\u270E\u2615\u2616\u2663\u213B\u2694\u27B6\u26A1\u2604\u269A\u2693\u2620\u269B\u2666\u2660\u2764\u2727\u238A\u1360\u262C\u269D\u29C9\uA214\u32D6\u2E0E\u26A0\uA541\u3020\u30C4\u2948\u2622\u2623\u273E\u269C\u0BD0\u0A6D\u2742\u16C3\u3023\u10F6\u0444\u266A\u266B\u04C3\u26C1\u26C3\u16DD\uA03E\u1C6A\u03A3\u09EB\u2603\u2654\u26C2\u12DE"; + String LEVEL_EMBLEMS = "\u2E15\u273F\u2741\u2E19\u03B1\u270E\u2615\u2616\u2663\u213B\u2694\u27B6\u26A1\u2604\u269A\u2693\u2620\u269B\u2666\u2660\u2764\u2727\u238A\u1360\u262C\u269D\u29C9\uA214\u32D6\u2E0E\u26A0\uA541\u3020\u30C4\u2948\u2622\u2623\u273E\u269C\u0BD0\u0A6D\u2742\u16C3\u3023\u10F6\u0444\u266A\u266B\u04C3\u26C1\u26C3\u16DD\uA03E\u1C6A\u03A3\u09EB\u2603\u2654\u26C2\u0FC7\uA56A\u12DE"; IntFunction<UnaryOperator<Style>> WITH_COLOR = color -> style -> style.withColor(color); Supplier<MutableText> PREFIX = () -> Text.empty() .append(Text.literal("[").formatted(Formatting.GRAY)) diff --git a/src/main/java/de/hysky/skyblocker/utils/Http.java b/src/main/java/de/hysky/skyblocker/utils/Http.java index 573c3458..eced3c08 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Http.java +++ b/src/main/java/de/hysky/skyblocker/utils/Http.java @@ -26,17 +26,17 @@ import net.minecraft.SharedConstants; */ public class Http { private static final String NAME_2_UUID = "https://api.minecraftservices.com/minecraft/profile/lookup/name/"; - private static final String HYPIXEL_PROXY = "https://hysky.de/api/hypixel/"; + private static final String HYPIXEL_PROXY = "https://hysky.de/api/hypixel/v2/"; private static final String USER_AGENT = "Skyblocker/" + SkyblockerMod.VERSION + " (" + SharedConstants.getGameVersion().getName() + ")"; private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(10)) .followRedirects(Redirect.NORMAL) .build(); - + public static String sendGetRequest(String url) throws IOException, InterruptedException { return sendCacheableGetRequest(url).content(); } - + private static ApiResponse sendCacheableGetRequest(String url) throws IOException, InterruptedException { HttpRequest request = HttpRequest.newBuilder() .GET() @@ -46,16 +46,16 @@ public class Http { .version(Version.HTTP_2) .uri(URI.create(url)) .build(); - + HttpResponse<InputStream> response = HTTP_CLIENT.send(request, BodyHandlers.ofInputStream()); InputStream decodedInputStream = getDecodedInputStream(response); - + String body = new String(decodedInputStream.readAllBytes()); HttpHeaders headers = response.headers(); - + return new ApiResponse(body, response.statusCode(), getCacheStatus(headers), getAge(headers)); } - + public static HttpHeaders sendHeadRequest(String url) throws IOException, InterruptedException { HttpRequest request = HttpRequest.newBuilder() .method("HEAD", BodyPublishers.noBody()) @@ -63,27 +63,29 @@ public class Http { .version(Version.HTTP_2) .uri(URI.create(url)) .build(); - - HttpResponse<Void> response = HTTP_CLIENT.send(request, BodyHandlers.discarding()); + + HttpResponse<Void> response = HTTP_CLIENT.send(request, BodyHandlers.discarding()); return response.headers(); } - + public static ApiResponse sendName2UuidRequest(String name) throws IOException, InterruptedException { return sendCacheableGetRequest(NAME_2_UUID + name); } - + /** * @param endpoint the endpoint - do not include any leading or trailing slashes * @param query the query string - use empty string if n/a * @return the requested data with zero pre-processing applied + * + * @implNote the {@code v2} prefix is automatically added */ public static ApiResponse sendHypixelRequest(String endpoint, @NotNull String query) throws IOException, InterruptedException { return sendCacheableGetRequest(HYPIXEL_PROXY + endpoint + query); } - + private static InputStream getDecodedInputStream(HttpResponse<InputStream> response) { String encoding = getContentEncoding(response.headers()); - + try { switch (encoding) { case "": @@ -99,19 +101,19 @@ public class Http { throw new UncheckedIOException(e); } } - + private static String getContentEncoding(HttpHeaders headers) { return headers.firstValue("Content-Encoding").orElse(""); } - + public static String getEtag(HttpHeaders headers) { return headers.firstValue("Etag").orElse(""); } - + public static String getLastModified(HttpHeaders headers) { return headers.firstValue("Last-Modified").orElse(""); } - + /** * Returns the cache status of the resource * @@ -120,18 +122,18 @@ public class Http { private static String getCacheStatus(HttpHeaders headers) { return headers.firstValue("CF-Cache-Status").orElse("UNKNOWN"); } - + private static int getAge(HttpHeaders headers) { return Integer.parseInt(headers.firstValue("Age").orElse("-1")); } - + //TODO If ever needed, we could just replace cache status with the response headers and go from there public record ApiResponse(String content, int statusCode, String cacheStatus, int age) implements AutoCloseable { - + public boolean ok() { return statusCode == 200; } - + public boolean cached() { return cacheStatus.equals("HIT"); } diff --git a/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java b/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java index 6d78b3f3..870e94da 100644 --- a/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java @@ -14,10 +14,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; /** * Initializes the NEU repo, which contains item metadata and fairy souls location data. Clones the repo if it does not exist and checks for updates. Use {@link #runAsyncAfterLoad(Runnable)} to run code after the repo is initialized. @@ -74,8 +76,7 @@ public class NEURepoManager { CompletableFuture.runAsync(() -> { try { ItemRepository.setFilesImported(false); - File dir = NEURepoManager.LOCAL_REPO_DIR.toFile(); - recursiveDelete(dir); + recursiveDelete(NEURepoManager.LOCAL_REPO_DIR); } catch (Exception ex) { if (MinecraftClient.getInstance().player != null) MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.updaterepository.failed")), false); @@ -86,14 +87,18 @@ public class NEURepoManager { } @SuppressWarnings("ResultOfMethodCallIgnored") - private static void recursiveDelete(File dir) { - File[] children; - if (dir.isDirectory() && !Files.isSymbolicLink(dir.toPath()) && (children = dir.listFiles()) != null) { - for (File child : children) { - recursiveDelete(child); - } + private static void recursiveDelete(Path dir) throws IOException { + if (Files.isDirectory(dir) && !Files.isSymbolicLink(dir)) { + Files.list(dir).forEach(child -> { + try { + recursiveDelete(child); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Encountered an exception while deleting a file! Path: {}", child.toAbsolutePath(), e); + } + }); } - dir.delete(); + + Files.delete(dir); } /** diff --git a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java index 0a42c6ae..2edd61f1 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java @@ -42,13 +42,13 @@ public class SlayerUtils { try { for (int i = 0; i < Utils.STRING_SCOREBOARD.size(); i++) { String line = Utils.STRING_SCOREBOARD.get(i); - + if (line.contains("Slay the boss!")) return true; } } catch (NullPointerException e) { LOGGER.error("[Skyblocker] Error while checking if player is in slayer", e); } - + return false; } }
\ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index 71e08865..02b1637b 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -363,7 +363,7 @@ public class Utils { if (isOnSkyblock && message.startsWith("Profile ID: ")) { profileId = message.replace("Profile ID: ", ""); - + MuseumItemCache.tick(profileId); } diff --git a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java index 7892445e..2c75ef0a 100644 --- a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java +++ b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java @@ -9,7 +9,6 @@ import de.hysky.skyblocker.skyblock.dungeon.ThreeWeirdos; import de.hysky.skyblocker.skyblock.dungeon.Trivia; import de.hysky.skyblocker.skyblock.dwarven.Fetchur; import de.hysky.skyblocker.skyblock.dwarven.Puzzler; -import de.hysky.skyblocker.skyblock.filters.*; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; diff --git a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java index 064b564c..43d595a5 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -1,11 +1,16 @@ package de.hysky.skyblocker.utils.render; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.logging.LogUtils; + +import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.mixin.accessor.BeaconBlockEntityRendererInvoker; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.fabric.api.event.Event; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.render.*; @@ -14,65 +19,63 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.sound.SoundEvents; import net.minecraft.text.OrderedText; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + import org.joml.Matrix3f; import org.joml.Matrix4f; import org.lwjgl.opengl.GL11; +import org.slf4j.Logger; public class RenderHelper { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final Identifier TRANSLUCENT_DRAW = new Identifier(SkyblockerMod.NAMESPACE, "translucent_draw"); + private static final MethodHandle SCHEDULE_DEFERRED_RENDER_TASK = getDeferredRenderTaskHandle(); private static final Vec3d ONE = new Vec3d(1, 1, 1); private static final int MAX_OVERWORLD_BUILD_HEIGHT = 319; private static final MinecraftClient client = MinecraftClient.getInstance(); - public static void renderFilledThroughWallsWithBeaconBeam(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) { - renderFilledThroughWalls(context, pos, colorComponents, alpha); - renderBeaconBeam(context, pos, colorComponents); + public static void init() { + WorldRenderEvents.AFTER_TRANSLUCENT.addPhaseOrdering(Event.DEFAULT_PHASE, TRANSLUCENT_DRAW); + WorldRenderEvents.AFTER_TRANSLUCENT.register(TRANSLUCENT_DRAW, RenderHelper::drawTranslucents); } - public static void renderFilledThroughWalls(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) { - if (FrustumUtils.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) { - renderFilled(context, Vec3d.of(pos), ONE, colorComponents, alpha, true); - } + public static void renderFilledWithBeaconBeam(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha, boolean throughWalls) { + renderFilled(context, pos, colorComponents, alpha, throughWalls); + renderBeaconBeam(context, pos, colorComponents); } - public static void renderFilledIfVisible(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) { - if (OcclusionCulling.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) { - renderFilled(context, Vec3d.of(pos), ONE, colorComponents, alpha, false); + public static void renderFilled(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha, boolean throughWalls) { + if (throughWalls) { + if (FrustumUtils.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) { + renderFilled(context, Vec3d.of(pos), ONE, colorComponents, alpha, true); + } + } else { + if (OcclusionCulling.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) { + renderFilled(context, Vec3d.of(pos), ONE, colorComponents, alpha, false); + } } } - + private static void renderFilled(WorldRenderContext context, Vec3d pos, Vec3d dimensions, float[] colorComponents, float alpha, boolean throughWalls) { MatrixStack matrices = context.matrixStack(); Vec3d camera = context.camera().getPos(); - Tessellator tessellator = RenderSystem.renderThreadTesselator(); - BufferBuilder buffer = tessellator.getBuffer(); - + matrices.push(); matrices.translate(-camera.x, -camera.y, -camera.z); - - RenderSystem.setShader(GameRenderer::getPositionColorProgram); - RenderSystem.setShaderColor(1f, 1f, 1f, 1f); - RenderSystem.polygonOffset(-1f, -10f); - RenderSystem.enablePolygonOffset(); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.enableDepthTest(); - RenderSystem.depthFunc(throughWalls ? GL11.GL_ALWAYS : GL11.GL_LEQUAL); - RenderSystem.disableCull(); - - buffer.begin(DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR); + + VertexConsumerProvider consumers = context.consumers(); + VertexConsumer buffer = consumers.getBuffer(throughWalls ? SkyblockerRenderLayers.FILLED_THROUGH_WALLS : SkyblockerRenderLayers.FILLED); + WorldRenderer.renderFilledBox(matrices, buffer, pos.x, pos.y, pos.z, pos.x + dimensions.x, pos.y + dimensions.y, pos.z + dimensions.z, colorComponents[0], colorComponents[1], colorComponents[2], alpha); - tessellator.draw(); - + matrices.pop(); - RenderSystem.polygonOffset(0f, 0f); - RenderSystem.disablePolygonOffset(); - RenderSystem.disableBlend(); - RenderSystem.disableDepthTest(); - RenderSystem.depthFunc(GL11.GL_LEQUAL); - RenderSystem.enableCull(); } private static void renderBeaconBeam(WorldRenderContext context, BlockPos pos, float[] colorComponents) { @@ -83,13 +86,8 @@ public class RenderHelper { matrices.push(); matrices.translate(pos.getX() - camera.getX(), pos.getY() - camera.getY(), pos.getZ() - camera.getZ()); - Tessellator tessellator = RenderSystem.renderThreadTesselator(); - BufferBuilder buffer = tessellator.getBuffer(); - VertexConsumerProvider.Immediate consumer = VertexConsumerProvider.immediate(buffer); - - BeaconBlockEntityRendererInvoker.renderBeam(matrices, consumer, context.tickDelta(), context.world().getTime(), 0, MAX_OVERWORLD_BUILD_HEIGHT, colorComponents); + BeaconBlockEntityRendererInvoker.renderBeam(matrices, context.consumers(), context.tickDelta(), context.world().getTime(), 0, MAX_OVERWORLD_BUILD_HEIGHT, colorComponents); - consumer.draw(); matrices.pop(); } } @@ -259,6 +257,28 @@ public class RenderHelper { } /** + * This is called after all {@link WorldRenderEvents#AFTER_TRANSLUCENT} listeners have been called so that we can draw all remaining render layers. + */ + private static void drawTranslucents(WorldRenderContext context) { + //Draw all render layers that haven't been drawn yet - drawing a specific layer does nothing and idk why + ((VertexConsumerProvider.Immediate) context.consumers()).draw(); + } + + public static void runOnRenderThread(Runnable runnable) { + if (RenderSystem.isOnRenderThread()) { + runnable.run(); + } else if (SCHEDULE_DEFERRED_RENDER_TASK != null) { //Sodium + try { + SCHEDULE_DEFERRED_RENDER_TASK.invokeExact(runnable); + } catch (Throwable t) { + LOGGER.error("[Skyblocker] Failed to schedule a render task!", t); + } + } else { //Vanilla + RenderSystem.recordRenderCall(runnable::run); + } + } + + /** * Adds the title to {@link TitleContainer} and {@link #playNotificationSound() plays the notification sound} if the title is not in the {@link TitleContainer} already. * No checking needs to be done on whether the title is in the {@link TitleContainer} already by the caller. * @@ -284,12 +304,26 @@ public class RenderHelper { } private static void playNotificationSound() { - if (MinecraftClient.getInstance().player != null) { - MinecraftClient.getInstance().player.playSound(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 100f, 0.1f); + if (client.player != null) { + client.player.playSound(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 100f, 0.1f); } } public static boolean pointIsInArea(double x, double y, double x1, double y1, double x2, double y2) { return x >= x1 && x <= x2 && y >= y1 && y <= y2; } + + // TODO Get rid of reflection once the new Sodium is released + private static MethodHandle getDeferredRenderTaskHandle() { + try { + Class<?> deferredTaskClass = Class.forName("me.jellysquid.mods.sodium.client.render.util.DeferredRenderTask"); + + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + MethodType mt = MethodType.methodType(void.class, Runnable.class); + + return lookup.findStatic(deferredTaskClass, "schedule", mt); + } catch (Throwable ignored) {} + + return null; + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/render/SkyblockerRenderLayers.java b/src/main/java/de/hysky/skyblocker/utils/render/SkyblockerRenderLayers.java new file mode 100644 index 00000000..ee113cc4 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/render/SkyblockerRenderLayers.java @@ -0,0 +1,36 @@ +package de.hysky.skyblocker.utils.render; + +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.RenderLayer.MultiPhase; +import net.minecraft.client.render.RenderLayer.MultiPhaseParameters; +import net.minecraft.client.render.RenderPhase; +import net.minecraft.client.render.RenderPhase.Cull; +import net.minecraft.client.render.RenderPhase.DepthTest; +import net.minecraft.client.render.RenderPhase.Transparency; +import net.minecraft.client.render.VertexFormat.DrawMode; +import net.minecraft.client.render.VertexFormats; + +public class SkyblockerRenderLayers { + private static final Transparency DEFAULT_TRANSPARENCY = new Transparency("default_transparency", () -> { + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + }, RenderSystem::disableBlend); + + public static final MultiPhase FILLED = RenderLayer.of("filled", VertexFormats.POSITION_COLOR, DrawMode.TRIANGLE_STRIP, RenderLayer.CUTOUT_BUFFER_SIZE, false, true, MultiPhaseParameters.builder() + .program(RenderPhase.COLOR_PROGRAM) + .cull(Cull.DISABLE_CULLING) + .layering(RenderPhase.POLYGON_OFFSET_LAYERING) + .transparency(DEFAULT_TRANSPARENCY) + .depthTest(DepthTest.LEQUAL_DEPTH_TEST) + .build(false)); + + public static final MultiPhase FILLED_THROUGH_WALLS = RenderLayer.of("filled_through_walls", VertexFormats.POSITION_COLOR, DrawMode.TRIANGLE_STRIP, RenderLayer.CUTOUT_BUFFER_SIZE, false, true, MultiPhaseParameters.builder() + .program(RenderPhase.COLOR_PROGRAM) + .cull(Cull.DISABLE_CULLING) + .layering(RenderPhase.POLYGON_OFFSET_LAYERING) + .transparency(DEFAULT_TRANSPARENCY) + .depthTest(DepthTest.ALWAYS_DEPTH_TEST) + .build(false)); +} diff --git a/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainerConfigScreen.java b/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainerConfigScreen.java index 19d41c91..cc80f74c 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainerConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainerConfigScreen.java @@ -27,7 +27,7 @@ public class TitleContainerConfigScreen extends Screen { private float hudY = SkyblockerConfigManager.get().general.titleContainer.y; private final Screen parent; private boolean changedScale; - + protected TitleContainerConfigScreen() { this(null); } @@ -173,18 +173,18 @@ public class TitleContainerConfigScreen extends Screen { public void close() { SkyblockerConfigManager.get().general.titleContainer.x = (int) hudX; SkyblockerConfigManager.get().general.titleContainer.y = (int) hudY; - + //TODO Come up with a better, less hacky solution for this in the future (: if (parent instanceof YACLScreen yaclScreen) { ConfigCategory category = yaclScreen.config.categories().stream().filter(cat -> cat.name().getString().equals(I18n.translate("text.autoconfig.skyblocker.category.general"))).findFirst().orElseThrow(); OptionGroup group = category.groups().stream().filter(grp -> grp.name().getString().equals(I18n.translate("text.autoconfig.skyblocker.option.general.titleContainer"))).findFirst().orElseThrow(); - + Option<?> scaleOpt = group.options().get(0); - + // Refresh the value in the config with the bound value if (changedScale) scaleOpt.forgetPendingValue(); } - + SkyblockerConfigManager.save(); this.client.setScreen(parent); } diff --git a/src/main/java/de/hysky/skyblocker/utils/scheduler/Scheduler.java b/src/main/java/de/hysky/skyblocker/utils/scheduler/Scheduler.java index b254f524..139ac05e 100644 --- a/src/main/java/de/hysky/skyblocker/utils/scheduler/Scheduler.java +++ b/src/main/java/de/hysky/skyblocker/utils/scheduler/Scheduler.java @@ -28,14 +28,14 @@ public class Scheduler { protected Scheduler() { } - + /** * @see #schedule(Runnable, int, boolean) */ public void schedule(Runnable task, int delay) { schedule(task, delay, false); } - + /** * @see #scheduleCyclic(Runnable, int, boolean) */ diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java new file mode 100644 index 00000000..7aa99d14 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java @@ -0,0 +1,44 @@ +package de.hysky.skyblocker.utils.waypoint; + +import de.hysky.skyblocker.utils.Utils; +import net.minecraft.util.math.BlockPos; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Supplier; + +public class ProfileAwareWaypoint extends Waypoint { + public final Set<String> foundProfiles = new HashSet<>(); + private final float[] missingColor; + private final float[] foundColor; + + public ProfileAwareWaypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] missingColor, float[] foundColor) { + super(pos, typeSupplier, null); + this.missingColor = missingColor; + this.foundColor = foundColor; + } + + @Override + public boolean shouldRender() { + return !foundProfiles.contains(Utils.getProfile()); + } + + @Override + public void setFound() { + foundProfiles.add(Utils.getProfile()); + } + + public void setFound(String profile) { + foundProfiles.add(profile); + } + + @Override + public void setMissing() { + foundProfiles.remove(Utils.getProfile()); + } + + @Override + protected float[] getColorComponents() { + return foundProfiles.contains(Utils.getProfile()) ? foundColor : missingColor; + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java index e7858f05..eb30cf8d 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -11,30 +11,30 @@ public class Waypoint { protected static final float DEFAULT_HIGHLIGHT_ALPHA = 0.5f; protected static final float DEFAULT_LINE_WIDTH = 5f; public final BlockPos pos; - private final Box box; - private final Supplier<Type> typeSupplier; - private final float[] colorComponents; - private final float alpha; - private final float lineWidth; - private final boolean throughWalls; + final Box box; + final Supplier<Type> typeSupplier; + final float[] colorComponents; + final float alpha; + final float lineWidth; + final boolean throughWalls; private boolean shouldRender; protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents) { - this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA); + this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, DEFAULT_LINE_WIDTH); } protected Waypoint(BlockPos pos, Type type, float[] colorComponents, float alpha) { - this(pos, () -> type, colorComponents, alpha); - } - - protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha) { - this(pos, typeSupplier, colorComponents, alpha, DEFAULT_LINE_WIDTH); + this(pos, () -> type, colorComponents, alpha, DEFAULT_LINE_WIDTH); } protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha, float lineWidth) { this(pos, typeSupplier, colorComponents, alpha, lineWidth, true); } + public Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, boolean throughWalls) { + this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, DEFAULT_LINE_WIDTH, throughWalls); + } + protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha, float lineWidth, boolean throughWalls) { this(pos, typeSupplier, colorComponents, alpha, lineWidth, throughWalls, true); } @@ -62,19 +62,25 @@ public class Waypoint { this.shouldRender = true; } + protected float[] getColorComponents() { + return colorComponents; + } + public void render(WorldRenderContext context) { switch (typeSupplier.get()) { - case WAYPOINT -> RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); + case WAYPOINT -> RenderHelper.renderFilledWithBeaconBeam(context, pos, getColorComponents(), alpha, throughWalls); case OUTLINED_WAYPOINT -> { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); + float[] colorComponents = getColorComponents(); + RenderHelper.renderFilledWithBeaconBeam(context, pos, colorComponents, alpha, throughWalls); RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); } - case HIGHLIGHT -> RenderHelper.renderFilledThroughWalls(context, pos, colorComponents, alpha); + case HIGHLIGHT -> RenderHelper.renderFilled(context, pos, getColorComponents(), alpha, throughWalls); case OUTLINED_HIGHLIGHT -> { - RenderHelper.renderFilledThroughWalls(context, pos, colorComponents, alpha); + float[] colorComponents = getColorComponents(); + RenderHelper.renderFilled(context, pos, colorComponents, alpha, throughWalls); RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); } - case OUTLINE -> RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + case OUTLINE -> RenderHelper.renderOutline(context, box, getColorComponents(), lineWidth, throughWalls); } } diff --git a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json index a0a97c67..0f22f597 100644 --- a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json +++ b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json @@ -2173,7 +2173,7 @@ }, { "secretName":"3 - Lever 2", - "category":"Lever", + "category":"lever", "x":31, "y":53, "z":24 @@ -2375,7 +2375,7 @@ }, { "secretName":"2 - Item", - "category":"Item", + "category":"item", "x":27, "y":56, "z":19 @@ -3936,7 +3936,7 @@ }, { "secretName":"4/5/6 - Entrance 3", - "category":"", + "category":"entrance", "x":31, "y":142, "z":39 diff --git a/src/main/resources/assets/skyblocker/lang/en_ca.json b/src/main/resources/assets/skyblocker/lang/en_ca.json index 5ecbd676..883de5dc 100644 --- a/src/main/resources/assets/skyblocker/lang/en_ca.json +++ b/src/main/resources/assets/skyblocker/lang/en_ca.json @@ -2,8 +2,8 @@ "text.autoconfig.skyblocker.option.general.bars": "Health, Mana, Defence & XP Bars", "text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper.@Tooltip": "Grey out chests that have already been opened.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor": "Livid Colour", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "Enable Livid Colour", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip": "Send the livid colour in the chat during the Livid boss fight.", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText": "Enable Livid Colour", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip": "Send the livid colour in the chat during the Livid boss fight.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText": "Livid Colour Text", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Text which will be sent in the chat during the Livid boss fight. The string \"[color]\" will be replaced with the livid colour.", "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveColor": "Solve Select Coloured", diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 31e7bb9c..b0d70a2d 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -50,6 +50,11 @@ "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts": "Enable Command Argument Shortcuts", "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts.@Tooltip": "Shortcuts that replace one or more word(s)/argument(s) of a command which has multiple words/arguments. Edit shortcuts with \"/skyblocker shortcuts\". Shortcuts must be enabled for this to take effect.", "text.autoconfig.skyblocker.option.general.shortcuts.config": "Shortcuts Config...", + "text.autoconfig.skyblocker.option.general.waypoints": "Waypoints", + "text.autoconfig.skyblocker.option.general.waypoints.enableWaypoints": "Enable Waypoints", + "text.autoconfig.skyblocker.option.general.waypoints.waypointType": "Waypoint Type", + "text.autoconfig.skyblocker.option.general.waypoints.waypointType.@Tooltip": "Waypoint: Displays a highlight and a beacon beam.\n\nOutlined Waypoint: Displays both a waypoint and an outline.\n\nHighlight: Only displays a highlight.\n\nOutlined Highlight: Displays both a highlight and an outline.\n\nOutline: Only displays an outline.", + "text.autoconfig.skyblocker.option.general.waypoints.waypointType.generalNote": "\n\n\nThis option does not apply to all waypoints. Some waypoints such as secret waypoints have their own waypoint type option.", "text.autoconfig.skyblocker.option.general.quiverWarning": "Quiver Warning", "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarning": "Enable Quiver Warning", "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningInDungeons": "Enable Quiver Warning In Dungeons", @@ -76,7 +81,9 @@ "text.autoconfig.skyblocker.option.general.itemTooltip.avg.BOTH": "Both", "text.autoconfig.skyblocker.option.general.itemTooltip.enableLowestBIN": "Enable Lowest BIN Price", "text.autoconfig.skyblocker.option.general.itemTooltip.enableBazaarPrice": "Enable Bazaar buy/sell Price", - "text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumDate": "Enable Museum & Date", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableObtainedDate": "Enable Obtained Date", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumInfo": "Enable Museum Info", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumInfo.@Tooltip": "If this item is donatable to the museum, then the item's category in the musuem is displayed. It also displays a marker indicating whether you've donated that item to your musuem or not (freebies not yet supported).\n\nMake sure to enable your Museum API for accurate information!", "text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip": "Enable Exotic Tooltip", "text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip.@Tooltip": "Displays the type of exotic below the item's name if an armor piece is exotic.", "text.autoconfig.skyblocker.option.general.itemInfoDisplay": "Item Info Display", @@ -84,6 +91,8 @@ "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo.@Tooltip": "Displays the attribute's level as the stack count and the initials of the attribute's name.", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds": "Item Rarity Backgrounds", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds.@Tooltip": "Displays a colored background behind an item, the color represents the item's rarity.", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundStyle": "Item Rarity Background Style", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundStyle.@Tooltip": "Choose between a circular or a square background style!", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundsOpacity": "Item Rarity Backgrounds Opacity", "text.autoconfig.skyblocker.option.general.wikiLookup": "Wiki Lookup", "text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup": "Enable Wiki Lookup", @@ -152,8 +161,6 @@ "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableSecretWaypoints": "Enable Dungeon Secret Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.noInitSecretWaypoints": "Do Not Initialize Secret Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.noInitSecretWaypoints.@Tooltip": "This option can save around 20 MB of ram if enabled, but Secret Waypoint will require a restart after turning off this option to work.", - "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.waypointType": "Waypoint Type", - "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.waypointType.@Tooltip": "Waypoint: Displays a highlight and beam.\n\nOutlined Waypoint: Displays both a waypoint and an outline.\n\nHighlight: Only displays a highlight.\n\nOutlined Highlight: Displays both a highlight and an outline.\n\nOutline: Outlines the secret in a box.", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.showSecretText": "Show Secret Text", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableEntranceWaypoints" : "Enable Entrance Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableSuperboomWaypoints" : "Enable Superboom Waypoints", @@ -188,6 +195,8 @@ "text.autoconfig.skyblocker.option.locations.dungeons.enableMap": "Enable Map", "text.autoconfig.skyblocker.option.locations.dungeons.mapScreen": "Dungeon Map Placement Config...", "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "Map Scaling", + "text.autoconfig.skyblocker.option.locations.dungeons.playerSecretsTracker": "Player Secrets Tracker", + "text.autoconfig.skyblocker.option.locations.dungeons.playerSecretsTracker.@Tooltip": "Tracks the amount of secrets people in your dungeon run are doing.", "text.autoconfig.skyblocker.option.locations.dungeons.starredMobGlow": "Starred Mob Glow", "text.autoconfig.skyblocker.option.locations.dungeons.starredMobGlow.@Tooltip": "Applies the glowing effect to starred mobs that are visible.", "text.autoconfig.skyblocker.option.locations.dungeons.solveThreeWeirdos": "Solve Three Weirdos Puzzle", @@ -199,8 +208,10 @@ "text.autoconfig.skyblocker.option.locations.dungeons.solveTicTacToe": "Solve Tic Tac Toe Puzzle", "text.autoconfig.skyblocker.option.locations.dungeons.solveTicTacToe.@Tooltip": "Puts a red box around the next best move for you to make!", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor": "Livid Color", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "Enable Livid Color", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip": "Send the livid color in the chat during the Livid boss fight.", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorGlow": "Enable Livid Color Glow", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorGlow.@Tooltip": "Applies the glowing effect to the correct Livid in F5/M5.", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText": "Enable Livid Color Text", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip": "Send the livid color in the chat during the Livid boss fight.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText": "Livid Color Text", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Text which will be sent in the chat during the Livid boss fight. The string \"[color]\" will be replaced with the livid color.", "text.autoconfig.skyblocker.option.locations.dungeons.terminals": "Terminal Solvers", @@ -222,6 +233,8 @@ "text.autoconfig.skyblocker.option.locations.rift": "The Rift", "text.autoconfig.skyblocker.option.locations.rift.mirrorverseWaypoints": "Enable Mirrorverse Waypoints", + "text.autoconfig.skyblocker.option.locations.rift.blobbercystGlow": "Blobbercyst Glow", + "text.autoconfig.skyblocker.option.locations.rift.blobbercystGlow.@Tooltip": "Applies the glowing effect to the Blobbercysts from the BACTE fight.", "text.autoconfig.skyblocker.option.locations.rift.enigmaSoulWaypoints": "Enable Enigma Soul Waypoints", "text.autoconfig.skyblocker.option.locations.rift.enigmaSoulWaypoints.@Tooltip": "Note: Many enigma souls have a small task you must complete in order to get it, so its recommended to also watch a YouTube video when finding them.", "text.autoconfig.skyblocker.option.locations.rift.highlightFoundEnigmaSouls": "Highlight Found Enigma Souls", @@ -234,7 +247,8 @@ "text.autoconfig.skyblocker.option.messages.chatFilterResult.ACTION_BAR": "Move to action bar", "text.autoconfig.skyblocker.option.messages.hideAbility": "Hide Ability Cooldown", "text.autoconfig.skyblocker.option.messages.hideHeal": "Hide Heal Messages", - "text.autoconfig.skyblocker.option.messages.hideAOTE": "Hide AOTE Messages", + "text.autoconfig.skyblocker.option.messages.hideAOTE": "Hide Teleport Ability Messages", + "text.autoconfig.skyblocker.option.messages.hideAOTE.@Tooltip": "Hides those pesky \"There are blocks in the way!\" messages.", "text.autoconfig.skyblocker.option.messages.hideImplosion": "Hide Implosion Message", "text.autoconfig.skyblocker.option.messages.hideMoltenWave": "Hide Molten Wave Message", "text.autoconfig.skyblocker.option.messages.hideAds": "Hide Ads From Public Chat", @@ -315,7 +329,7 @@ "skyblocker.shortcuts.deleteQuestion": "Are you sure you want to remove this shortcut?", "skyblocker.shortcuts.deleteWarning": "Shortcut '%s' will be lost forever! (A long time!)", "skyblocker.shortcuts.new": "New Shortcut", - "skyblocker.shortcuts.commandSuggestionTooltip": "Due to limitations of Minecraft, command suggestions will only work after a restart of the game.", + "skyblocker.shortcuts.commandSuggestionTooltip": "Due to limitations of Minecraft, command suggestions will only work after joining a new world.", "skyblocker.customItemNames.removed": "§fRemoved this item's custom name.", "skyblocker.customItemNames.neverHad": "§fThis item doesn't have a custom name set, but why not add one? ;)", diff --git a/src/main/resources/assets/skyblocker/lang/fr_fr.json b/src/main/resources/assets/skyblocker/lang/fr_fr.json index 207852ac..a08371b3 100644 --- a/src/main/resources/assets/skyblocker/lang/fr_fr.json +++ b/src/main/resources/assets/skyblocker/lang/fr_fr.json @@ -67,8 +67,8 @@ "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "Taille de la Carte", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Texte qui sera envoyé dans le chat lors du boss Livid. Le string \"[color]\" sera remplacé par la couleur Livid.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor": "Couleur Livid", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "Activer la Couleur Livid", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip": "Envoyer la Couler Livid dans le chat durant le boss Livid.", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText": "Activer la Couleur Livid", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip": "Envoyer la Couler Livid dans le chat durant le boss Livid.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText": "Texte de la Couleur Livid", "text.autoconfig.skyblocker.option.general.bars.barpositions.LAYER1": "Couche 1", "text.autoconfig.skyblocker.option.general.bars.barpositions.NONE": "Désactivé", diff --git a/src/main/resources/assets/skyblocker/lang/pt_br.json b/src/main/resources/assets/skyblocker/lang/pt_br.json index d0371642..f6362986 100644 --- a/src/main/resources/assets/skyblocker/lang/pt_br.json +++ b/src/main/resources/assets/skyblocker/lang/pt_br.json @@ -184,7 +184,7 @@ "text.autoconfig.skyblocker.option.locations.dungeons.enableMap": "Ativar mapa", "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "Tamanho do mapa", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor": "Cor do Livid", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "Ativar cor para Livid", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText": "Ativar cor para Livid", "text.autoconfig.skyblocker.option.locations.dungeons.terminals": "Guia dos terminais", "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveColor": "Guia de seleção colorido", "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveOrder": "Guia de clique em ordem", @@ -238,5 +238,5 @@ "text.autoconfig.skyblocker.option.locations.dungeons.starredMobGlow": "Brilho em Mobs com estrela", "text.autoconfig.skyblocker.option.locations.dungeons.starredMobGlow.@Tooltip": "Aplicar o efeito de brilho para Mobs estrelados que estão visíveis.", "text.autoconfig.skyblocker.option.locations.dungeons.solveTicTacToe": "Guia para o Puzzle do jogo da velha", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip": "Mandar a cor do Livid no chat durante a luta contra Livid." + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip": "Mandar a cor do Livid no chat durante a luta contra Livid." } diff --git a/src/main/resources/assets/skyblocker/lang/ru_ru.json b/src/main/resources/assets/skyblocker/lang/ru_ru.json index 980c130a..d22f6274 100644 --- a/src/main/resources/assets/skyblocker/lang/ru_ru.json +++ b/src/main/resources/assets/skyblocker/lang/ru_ru.json @@ -82,9 +82,9 @@ "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Текст, который будет отправлен в чат во время боя с Livid. Вместо \"[color]\" отправится цвет босса.", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[1]": "\nКрасивый: Показывает название, процент и шкалу выполнения, а также иконку.", "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "Размер Карты", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "Включить Цвет Босса Livid", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText": "Включить Цвет Босса Livid", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor": "Цвет Босса Livid", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip": "Отправляет в чат информацию о том, какого цвета босс Livid.", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip": "Отправляет в чат информацию о том, какого цвета босс Livid.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText": "Текст О Цвете Livid", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style": "Стиль HUD", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[0]": "Упрощенный: Показывает название и процент выполнения.", diff --git a/src/main/resources/assets/skyblocker/lang/zh_cn.json b/src/main/resources/assets/skyblocker/lang/zh_cn.json index 4a3abde3..9f8bb08c 100644 --- a/src/main/resources/assets/skyblocker/lang/zh_cn.json +++ b/src/main/resources/assets/skyblocker/lang/zh_cn.json @@ -88,9 +88,9 @@ "text.autoconfig.skyblocker.option.general.fishing": "钓鱼助手", "text.autoconfig.skyblocker.option.general.fishing.enableFishingHelper": "启用钓鱼助手", "skyblocker.fishing.reelNow": "收竿!", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "启用真 Livid 的颜色提示", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText": "启用真 Livid 的颜色提示", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor": "提示真 Livid 的颜色", - "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor.@Tooltip": "将真 Livid 的颜色发送到聊天栏。", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColorText.@Tooltip": "将真 Livid 的颜色发送到聊天栏。", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText": "真 Livid 颜色提示信息", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Livid Boss战时发送到聊天栏的信息, 字段 “[color]” 将被替换为真 Livid 的颜色", "key.skyblocker.defaultTgl": "将tab键所显示的列表改为默认空岛生存列表", diff --git a/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background.png b/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background_circular.png Binary files differindex fd8e8604..fd8e8604 100644 --- a/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background.png +++ b/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background_circular.png diff --git a/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background_square.png b/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background_square.png Binary files differnew file mode 100644 index 00000000..0392b56c --- /dev/null +++ b/src/main/resources/assets/skyblocker/textures/gui/sprites/item_rarity_background_square.png diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index 5bafb324..4e7bfe16 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -36,12 +36,7 @@ "accessor.PlayerListHudAccessor", "accessor.RecipeBookWidgetAccessor", "accessor.ScreenAccessor", - "accessor.WorldRendererAccessor", - "yacl.DoubleFieldControllerMixin", - "yacl.FloatFieldControllerMixin", - "yacl.IntegerFieldControllerMixin", - "yacl.LongFieldControllerMixin", - "yacl.NumberFieldControllerMixin" + "accessor.WorldRendererAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java new file mode 100644 index 00000000..0870e744 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypointTest.java @@ -0,0 +1,79 @@ +package de.hysky.skyblocker.skyblock.dungeon.secrets; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; +import net.minecraft.util.math.BlockPos; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class SecretWaypointTest { + private final Gson gson = new Gson(); + + @Test + void testCodecSerialize() { + SecretWaypoint waypoint = new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN); + JsonElement json = SecretWaypoint.CODEC.encodeStart(JsonOps.INSTANCE, waypoint).result().orElseThrow(); + String expectedJson = "{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]}"; + + Assertions.assertEquals(expectedJson, json.toString()); + } + + @Test + void testCodecDeserialize() { + String json = "{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]}"; + SecretWaypoint waypoint = SecretWaypoint.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + SecretWaypoint expectedWaypoint = new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN); + + equal(expectedWaypoint, waypoint); + } + + @Test + void testListCodecSerialize() { + List<SecretWaypoint> waypoints = List.of(new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN), new SecretWaypoint(1, SecretWaypoint.Category.CHEST, "name", new BlockPos(-1, 0, 1))); + JsonElement json = SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, waypoints).result().orElseThrow(); + String expectedJson = "[{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]},{\"secretIndex\":1,\"category\":\"chest\",\"name\":{\"text\":\"name\"},\"pos\":[-1,0,1]}]"; + + Assertions.assertEquals(expectedJson, json.toString()); + } + + @Test + void testListCodecDeserialize() { + String json = "[{\"secretIndex\":0,\"category\":\"default\",\"name\":{\"text\":\"name\"},\"pos\":[0,0,0]},{\"secretIndex\":1,\"category\":\"chest\",\"name\":{\"text\":\"name\"},\"pos\":[-1,0,1]}]"; + List<SecretWaypoint> waypoints = SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + List<SecretWaypoint> expectedWaypoints = List.of(new SecretWaypoint(0, SecretWaypoint.Category.DEFAULT, "name", BlockPos.ORIGIN), new SecretWaypoint(1, SecretWaypoint.Category.CHEST, "name", new BlockPos(-1, 0, 1))); + + Assertions.assertEquals(expectedWaypoints.size(), waypoints.size()); + for (int i = 0; i < expectedWaypoints.size(); i++) { + SecretWaypoint expectedWaypoint = expectedWaypoints.get(i); + SecretWaypoint waypoint = waypoints.get(i); + equal(expectedWaypoint, waypoint); + } + } + + @Test + void testGetCategory() { + JsonObject waypointJson = new JsonObject(); + waypointJson.addProperty("category", "chest"); + SecretWaypoint.Category category = SecretWaypoint.Category.get(waypointJson); + Assertions.assertEquals(SecretWaypoint.Category.CHEST, category); + } + + @Test + void testGetCategoryDefault() { + JsonObject waypointJson = new JsonObject(); + waypointJson.addProperty("category", ""); + SecretWaypoint.Category category = SecretWaypoint.Category.get(waypointJson); + Assertions.assertEquals(SecretWaypoint.Category.DEFAULT, category); + } + + private static void equal(SecretWaypoint expectedWaypoint, SecretWaypoint waypoint) { + Assertions.assertEquals(expectedWaypoint.secretIndex, waypoint.secretIndex); + Assertions.assertEquals(expectedWaypoint.category, waypoint.category); + Assertions.assertEquals(expectedWaypoint.name, waypoint.name); + Assertions.assertEquals(expectedWaypoint.pos, waypoint.pos); + } +} diff --git a/src/test/java/de/hysky/skyblocker/skyblock/filters/ComboFilterTest.java b/src/test/java/de/hysky/skyblocker/skyblock/filters/ComboFilterTest.java index 85b01b4b..93d33070 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/filters/ComboFilterTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/filters/ComboFilterTest.java @@ -9,7 +9,7 @@ public class ComboFilterTest extends ChatFilterTest<ComboFilter> { @Test void testComboMF() { - assertMatches("+5 Kill Combo +3% ✯ Magic Find"); + assertMatches("+5 Kill Combo +3✯ Magic Find"); } @Test @@ -18,8 +18,13 @@ public class ComboFilterTest extends ChatFilterTest<ComboFilter> { } @Test - void testComboEXP() { - assertMatches("+20 Kill Combo +15% Combat Exp"); + void testComboWisdom() { + assertMatches("+20 Kill Combo +15☯ Combat Wisdom"); + } + + @Test + void testComboNoBonus() { + assertMatches("+50 Kill Combo"); } @Test diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypointTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypointTest.java new file mode 100644 index 00000000..9dc5b2b9 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypointTest.java @@ -0,0 +1,38 @@ +package de.hysky.skyblocker.utils.waypoint; + +import net.minecraft.util.math.BlockPos; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ProfileAwareWaypointTest { + @Test + void testShouldRender() { + ProfileAwareWaypoint waypoint = new ProfileAwareWaypoint(BlockPos.ORIGIN, null, null, null); + waypoint.setFound("profile"); + Assertions.assertTrue(waypoint.shouldRender()); + waypoint.setFound(""); + Assertions.assertFalse(waypoint.shouldRender()); + waypoint.setMissing(); + Assertions.assertTrue(waypoint.shouldRender()); + } + + @Test + void testGetColorComponents() { + ProfileAwareWaypoint waypoint = new ProfileAwareWaypoint(BlockPos.ORIGIN, null, new float[]{0f, 0.5f, 1f}, new float[]{1f, 0.5f, 0f}); + waypoint.setFound("profile"); + float[] colorComponents = waypoint.getColorComponents(); + Assertions.assertEquals(0f, colorComponents[0]); + Assertions.assertEquals(0.5f, colorComponents[1]); + Assertions.assertEquals(1f, colorComponents[2]); + waypoint.setFound(""); + colorComponents = waypoint.getColorComponents(); + Assertions.assertEquals(1f, colorComponents[0]); + Assertions.assertEquals(0.5f, colorComponents[1]); + Assertions.assertEquals(0f, colorComponents[2]); + waypoint.setMissing(); + colorComponents = waypoint.getColorComponents(); + Assertions.assertEquals(0f, colorComponents[0]); + Assertions.assertEquals(0.5f, colorComponents[1]); + Assertions.assertEquals(1f, colorComponents[2]); + } +} diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointTest.java new file mode 100644 index 00000000..d8839951 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointTest.java @@ -0,0 +1,70 @@ +package de.hysky.skyblocker.utils.waypoint; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class WaypointTest { + private Waypoint.Type type; + private final float[] colorComponents = new float[]{0f, 0.5f, 1f}; + + @Test + void testDefaultConstructor() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, () -> type, colorComponents); + Assertions.assertEquals(BlockPos.ORIGIN, waypoint.pos); + Assertions.assertEquals(new Box(BlockPos.ORIGIN), waypoint.box); + Assertions.assertEquals(type, waypoint.typeSupplier.get()); + Assertions.assertEquals(0f, waypoint.colorComponents[0]); + Assertions.assertEquals(0.5f, waypoint.colorComponents[1]); + Assertions.assertEquals(1f, waypoint.colorComponents[2]); + Assertions.assertEquals(Waypoint.DEFAULT_HIGHLIGHT_ALPHA, waypoint.alpha); + Assertions.assertEquals(Waypoint.DEFAULT_LINE_WIDTH, waypoint.lineWidth); + Assertions.assertTrue(waypoint.throughWalls); + Assertions.assertTrue(waypoint.shouldRender()); + } + + @Test + void testTypeConstructor() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, Waypoint.Type.WAYPOINT, colorComponents, Waypoint.DEFAULT_HIGHLIGHT_ALPHA); + Assertions.assertEquals(Waypoint.Type.WAYPOINT, waypoint.typeSupplier.get()); + } + + @Test + void testLineWidthConstructor() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, () -> type, colorComponents, Waypoint.DEFAULT_HIGHLIGHT_ALPHA, 10f); + Assertions.assertEquals(10f, waypoint.lineWidth); + } + + @Test + void testThroughWallsConstructor() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, () -> type, colorComponents, Waypoint.DEFAULT_HIGHLIGHT_ALPHA, Waypoint.DEFAULT_LINE_WIDTH, false); + Assertions.assertFalse(waypoint.throughWalls); + } + + @Test + void testShouldRenderConstructor() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, () -> type, colorComponents, Waypoint.DEFAULT_HIGHLIGHT_ALPHA, Waypoint.DEFAULT_LINE_WIDTH, true, false); + Assertions.assertFalse(waypoint.shouldRender()); + } + + @Test + void testFound() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, () -> type, colorComponents); + Assertions.assertTrue(waypoint.shouldRender()); + waypoint.setFound(); + Assertions.assertFalse(waypoint.shouldRender()); + waypoint.setMissing(); + Assertions.assertTrue(waypoint.shouldRender()); + } + + @Test + void testType() { + Waypoint waypoint = new Waypoint(BlockPos.ORIGIN, () -> type, colorComponents); + Assertions.assertEquals(type, waypoint.typeSupplier.get()); + type = Waypoint.Type.WAYPOINT; + Assertions.assertEquals(type, waypoint.typeSupplier.get()); + type = Waypoint.Type.OUTLINED_HIGHLIGHT; + Assertions.assertEquals(type, waypoint.typeSupplier.get()); + } +} |