diff options
Diffstat (limited to 'src/main')
52 files changed, 489 insertions, 216 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 5178a777..b398e9b6 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -7,6 +7,7 @@ import de.hysky.skyblocker.skyblock.*; import de.hysky.skyblocker.skyblock.diana.MythologicalRitual; import de.hysky.skyblocker.skyblock.dungeon.*; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; +import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud; import de.hysky.skyblocker.skyblock.item.*; import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview; @@ -20,6 +21,7 @@ import de.hysky.skyblocker.skyblock.spidersden.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.utils.ApiUtils; import de.hysky.skyblocker.utils.NEURepoManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.chat.ChatMessageListener; @@ -109,6 +111,8 @@ public class SkyblockerMod implements ClientModInitializer { CreeperBeams.init(); ItemRarityBackgrounds.init(); MuseumItemCache.init(); + SecretsTracker.init(); + ApiUtils.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..2475d0d3 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java @@ -30,14 +30,14 @@ public class MixinPlugin implements IMixinConfigPlugin { 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; } } diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index 84b9e9ca..ae852252 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -554,6 +554,9 @@ public class SkyblockerConfig { public int mapY = 2; @SerialEntry + public boolean playerSecretsTracker = false; + + @SerialEntry public boolean starredMobGlow = true; @SerialEntry @@ -584,10 +587,10 @@ public class SkyblockerConfig { @SerialEntry public boolean noInitSecretWaypoints = false; - + @SerialEntry public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; - + @SerialEntry public boolean showSecretText = true; @@ -617,10 +620,10 @@ public class SkyblockerConfig { @SerialEntry public boolean enableStonkWaypoints = true; - + @SerialEntry public boolean enableAotvWaypoints = true; - + @SerialEntry public boolean enablePearlWaypoints = true; @@ -731,10 +734,10 @@ public class SkyblockerConfig { public static class Rift { @SerialEntry public boolean mirrorverseWaypoints = 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 cb390a71..007d974c 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")) @@ -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,6 +242,14 @@ public class DungeonsCategory { .controller(FloatFieldControllerBuilder::create) .build()) .option(Option.<Boolean>createBuilder() + .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) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.starredMobGlow")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.starredMobGlow.@Tooltip"))) .binding(defaults.locations.dungeons.starredMobGlow, @@ -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/LocationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java index 5e662fcc..55629a66 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")) @@ -70,7 +70,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..f9032c27 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")) 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/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/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/FloatFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java index d67993c2..3a82c92a 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java @@ -15,7 +15,7 @@ import net.minecraft.text.Text; 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); } diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java index b95cbef7..51dd4890 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java @@ -14,16 +14,16 @@ 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 index 99871e2e..f744c310 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/LongFieldControllerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/LongFieldControllerMixin.java @@ -14,16 +14,16 @@ 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 index 17a99cfd..010f9a26 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/yacl/NumberFieldControllerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/NumberFieldControllerMixin.java @@ -17,7 +17,7 @@ import net.minecraft.util.math.MathHelper; 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 { @@ -26,16 +26,16 @@ public abstract class NumberFieldControllerMixin<T extends Number> implements IS 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/FairySouls.java b/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java index cef17d8e..3e1220b0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java @@ -30,6 +30,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -70,7 +72,7 @@ public class FairySouls { 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()); - 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()) { @@ -83,7 +85,7 @@ public class FairySouls { 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); } @@ -92,7 +94,7 @@ public class FairySouls { } private static void saveFoundFairySouls(MinecraftClient client) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()))) { + 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 +108,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); @@ -180,8 +181,10 @@ public class FairySouls { } public static void markAllFairiesOnCurrentIslandFound() { - initializeFoundFairiesForCurrentProfileAndLocation(); - foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).addAll(fairySouls.get(Utils.getLocationRaw())); + if (fairySouls.get(Utils.getLocationRaw()) != null) { + initializeFoundFairiesForCurrentProfileAndLocation(); + foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).addAll(fairySouls.get(Utils.getLocationRaw())); + } } public static void markAllFairiesOnCurrentIslandMissing() { 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/diana/MythologicalRitual.java b/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java index e2962702..f36a8a24 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java @@ -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/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/secrets/SecretsTracker.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java new file mode 100644 index 00000000..0690952e --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java @@ -0,0 +1,174 @@ +package de.hysky.skyblocker.skyblock.dungeon.secrets; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; +import de.hysky.skyblocker.skyblock.tabhud.widget.DungeonPlayerWidget; +import de.hysky.skyblocker.utils.ApiUtils; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.Http; +import de.hysky.skyblocker.utils.Http.ApiResponse; +import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.ints.IntIntPair; +import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Tracks the amount of secrets players get every run + */ +public class SecretsTracker { + private static final Logger LOGGER = LoggerFactory.getLogger(SecretsTracker.class); + private static final Pattern TEAM_SCORE_PATTERN = Pattern.compile(" +Team Score: [0-9]+ \\([A-z+]+\\)"); + + private static volatile TrackedRun currentRun = null; + private static volatile TrackedRun lastRun = null; + private static volatile long lastRunEnded = 0L; + + public static void init() { + ClientReceiveMessageEvents.GAME.register(SecretsTracker::onMessage); + } + + //If -1 is somehow encountered, it would be very rare, so I just disregard its possibility for now + //people would probably recognize if it was inaccurate so yeah + private static void calculate(RunPhase phase) { + switch (phase) { + case START -> CompletableFuture.runAsync(() -> { + TrackedRun newlyStartedRun = new TrackedRun(); + + //Initialize players in new run + for (int i = 0; i < 5; i++) { + String playerName = getPlayerNameAt(i + 1); + + //The player name will be blank if there isn't a player at that index + if (!playerName.isEmpty()) { + + //If the player was a part of the last run (and didn't have -1 secret count) and that run ended less than 5 mins ago then copy the secrets over + if (lastRun != null && System.currentTimeMillis() <= lastRunEnded + 300_000 && lastRun.secretCounts().getOrDefault(playerName, -1) != -1) { + newlyStartedRun.secretCounts().put(playerName, lastRun.secretCounts().getInt(playerName)); + } else { + newlyStartedRun.secretCounts().put(playerName, getPlayerSecrets(playerName).leftInt()); + } + } + } + + currentRun = newlyStartedRun; + }); + + case END -> CompletableFuture.runAsync(() -> { + //In case the game crashes from something + if (currentRun != null) { + Object2ObjectOpenHashMap<String, IntIntPair> secretsFound = new Object2ObjectOpenHashMap<>(); + + //Update secret counts + for (Entry<String> entry : currentRun.secretCounts().object2IntEntrySet()) { + String playerName = entry.getKey(); + int startingSecrets = entry.getIntValue(); + IntIntPair secretsNow = getPlayerSecrets(playerName); + int secretsPlayerFound = secretsNow.leftInt() - startingSecrets; + + secretsFound.put(playerName, IntIntPair.of(secretsPlayerFound, secretsNow.rightInt())); + entry.setValue(secretsNow.leftInt()); + } + + //Print the results all in one go, so its clean and less of a chance of it being broken up + for (Map.Entry<String, IntIntPair> entry : secretsFound.entrySet()) { + sendResultMessage(entry.getKey(), entry.getValue().leftInt(), entry.getValue().rightInt(), true); + } + + //Swap the current and last run as well as mark the run end time + lastRunEnded = System.currentTimeMillis(); + lastRun = currentRun; + currentRun = null; + } else { + sendResultMessage(null, -1, -1, false); + } + }); + } + } + + private static void sendResultMessage(String player, int secrets, int cacheAge, boolean success) { + PlayerEntity playerEntity = MinecraftClient.getInstance().player; + if (playerEntity != null) { + if (success) { + playerEntity.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secretsTracker.feedback", Text.literal(player).styled(Constants.WITH_COLOR.apply(0xf57542)), "§7" + secrets, getCacheText(cacheAge)))); + } else { + playerEntity.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secretsTracker.failFeedback"))); + } + } + } + + private static Text getCacheText(int cacheAge) { + return Text.literal("\u2139").styled(style -> style.withColor(cacheAge == -1 ? 0x218bff : 0xeac864).withHoverEvent( + new HoverEvent(HoverEvent.Action.SHOW_TEXT, cacheAge == -1 ? Text.translatable("skyblocker.api.cache.MISS") : Text.translatable("skyblocker.api.cache.HIT", cacheAge)))); + } + + private static void onMessage(Text text, boolean overlay) { + if (Utils.isInDungeons() && SkyblockerConfigManager.get().locations.dungeons.playerSecretsTracker) { + String message = Formatting.strip(text.getString()); + + try { + if (message.equals("[NPC] Mort: Here, I found this map when I first entered the dungeon.")) calculate(RunPhase.START); + if (TEAM_SCORE_PATTERN.matcher(message).matches()) calculate(RunPhase.END); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Encountered an unknown error while trying to track player secrets!", e); + } + } + } + + private static String getPlayerNameAt(int index) { + Matcher matcher = PlayerListMgr.regexAt(1 + (index - 1) * 4, DungeonPlayerWidget.PLAYER_PATTERN); + + return matcher != null ? matcher.group("name") : ""; + } + + private static IntIntPair getPlayerSecrets(String name) { + String uuid = ApiUtils.name2Uuid(name); + + if (!uuid.isEmpty()) { + try (ApiResponse response = Http.sendHypixelRequest("player", "?uuid=" + uuid)) { + return IntIntPair.of(getSecretCountFromAchievements(JsonParser.parseString(response.content()).getAsJsonObject()), response.age()); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Encountered an error while trying to fetch {} secret count!", name + "'s", e); + } + } + + return IntIntPair.of(-1, -1); + } + + /** + * Gets a player's secret count from their hypixel achievements + */ + private static int getSecretCountFromAchievements(JsonObject playerJson) { + JsonObject player = playerJson.get("player").getAsJsonObject(); + JsonObject achievements = (player.has("achievements")) ? player.get("achievements").getAsJsonObject() : null; + return (achievements != null && achievements.has("skyblock_treasure_hunter")) ? achievements.get("skyblock_treasure_hunter").getAsInt() : 0; + } + + /** + * This will either reflect the value at the start or the end depending on when this is called + */ + private record TrackedRun(Object2IntOpenHashMap<String> secretCounts) { + private TrackedRun() { + this(new Object2IntOpenHashMap<>()); + } + } + + private enum RunPhase { + START, END + } +} 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/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..da357738 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java @@ -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 cb11d702..5873ee28 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,18 @@ 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 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 +60,7 @@ public class MuseumItemCache { } }); } - + private static void save() { CompletableFuture.runAsync(() -> { try (BufferedWriter writer = Files.newBufferedWriter(CACHE_FILE)) { @@ -70,42 +70,40 @@ public class MuseumItemCache { } }); } - + private static void updateData4ProfileMember(String uuid, String profileId) { CompletableFuture.runAsync(() -> { - try { - ApiResponse response = Http.sendHypixelRequest("skyblock/museum", "?profile=" + profileId); - + 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")); } } } - + MUSEUM_ITEM_CACHE.get(uuid).put(profileId, new ProfileMuseumData(System.currentTimeMillis(), itemIds)); save(); - + LOGGER.info("[Skyblocker] Successfully updated museum item cache for profile {}", profileId); } } catch (Exception e) { @@ -113,7 +111,7 @@ public class MuseumItemCache { } }); } - + /** * The cache is ticked upon switching skyblock servers */ @@ -123,22 +121,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(); - + 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/rift/EffigyWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EffigyWaypoints.java index a0e1a0f2..7ebf44b0 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()); 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/spidersden/Relics.java b/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java index aaf4d77c..df68c57b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java @@ -29,6 +29,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -68,7 +70,7 @@ 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()) { @@ -77,7 +79,7 @@ public class Relics { 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 +87,7 @@ public class Relics { } private static void saveFoundRelics(MinecraftClient client) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json").toFile()))) { + 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(); 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/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/DungeonPlayerWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java index be1a3c6e..d71eb190 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java @@ -27,7 +27,7 @@ public class DungeonPlayerWidget extends Widget { // group 3: level (or nothing, if pre dungeon start) // this regex filters out the ironman icon as well as rank prefixes and emblems // \[\d*\] (?:\[[A-Za-z]+\] )?(?<name>[A-Za-z0-9_]*) (?:.* )?\((?<class>\S*) ?(?<level>[LXVI]*)\) - private static final Pattern PLAYER_PATTERN = Pattern + public static final Pattern PLAYER_PATTERN = Pattern .compile("\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?<name>[A-Za-z0-9_]*) (?:.* )?\\((?<class>\\S*) ?(?<level>[LXVI]*)\\)"); private static final HashMap<String, ItemStack> ICOS = new HashMap<>(); 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/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/utils/ApiUtils.java b/src/main/java/de/hysky/skyblocker/utils/ApiUtils.java new file mode 100644 index 00000000..0121f8ad --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/ApiUtils.java @@ -0,0 +1,53 @@ +package de.hysky.skyblocker.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonParser; +import com.mojang.util.UndashedUuid; + +import de.hysky.skyblocker.utils.Http.ApiResponse; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.session.Session; + +/* + * Contains only basic helpers for using Http APIs + */ +public class ApiUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(ApiUtils.class); + /** + * 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..e0a5bb5a 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\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 eabb02e4..82ab6c5e 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Http.java +++ b/src/main/java/de/hysky/skyblocker/utils/Http.java @@ -32,11 +32,11 @@ public class Http { .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,14 +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()); - - return new ApiResponse(body, response.statusCode(), getCacheStatus(response.headers())); + 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()) @@ -61,15 +63,15 @@ 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 String sendName2UuidRequest(String name) throws IOException, InterruptedException { - return sendGetRequest(NAME_2_UUID + name); + + 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 @@ -78,10 +80,10 @@ public class Http { 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 "": @@ -97,37 +99,47 @@ 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 * * @see <a href="https://developers.cloudflare.com/cache/concepts/default-cache-behavior/#cloudflare-cache-responses">Cloudflare Cache Docs</a> */ - public static String getCacheStatus(HttpHeaders headers) { + 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) { - + 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"); } + + @Override + public void close() { + //Allows for nice syntax when dealing with api requests in try catch blocks + //Maybe one day we'll have some resources to free + } } } 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 b1a347f9..02b1637b 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -33,10 +33,10 @@ import java.util.List; public class Utils { private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class); private static final String ALTERNATE_HYPIXEL_ADDRESS = System.getProperty("skyblocker.alternateHypixelAddress", ""); + private static final String DUNGEONS_LOCATION = "dungeon"; private static final String PROFILE_PREFIX = "Profile: "; private static boolean isOnHypixel = false; private static boolean isOnSkyblock = false; - private static boolean isInDungeons = false; private static boolean isInjected = false; /** * The profile name parsed from the player list. @@ -79,7 +79,7 @@ public class Utils { } public static boolean isInDungeons() { - return isInDungeons; + return getLocationRaw().equals(DUNGEONS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); } public static boolean isInTheRift() { @@ -164,7 +164,6 @@ public class Utils { sidebar = Collections.emptyList(); } else { isOnSkyblock = false; - isInDungeons = false; return; } } @@ -188,7 +187,6 @@ public class Utils { } else { onLeaveSkyblock(); } - isInDungeons = fabricLoader.isDevelopmentEnvironment() || isOnSkyblock && string.contains("The Catacombs"); } else if (isOnHypixel) { isOnHypixel = false; onLeaveSkyblock(); @@ -205,7 +203,6 @@ public class Utils { private static void onLeaveSkyblock() { if (isOnSkyblock) { isOnSkyblock = false; - isInDungeons = false; SkyblockEvents.LEAVE.invoker().onSkyblockLeave(); } } @@ -366,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..e4cfea1b 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -42,16 +42,16 @@ public class RenderHelper { 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); @@ -61,11 +61,11 @@ public class RenderHelper { RenderSystem.enableDepthTest(); RenderSystem.depthFunc(throughWalls ? GL11.GL_ALWAYS : GL11.GL_LEQUAL); RenderSystem.disableCull(); - + buffer.begin(DrawMode.TRIANGLE_STRIP, VertexFormats.POSITION_COLOR); 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(); 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/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index c51c035f..6d94b69b 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -188,6 +188,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", @@ -282,6 +284,12 @@ "skyblocker.dungeons.secrets.customWaypointAdded": "§rAdded a custom waypoint at X: %d, Y: %d, Z: %d for room %s secret #%d of category %s with name '%s'.", "skyblocker.dungeons.secrets.customWaypointRemoved": "§rRemoved custom waypoint at X: %d, Y: %d, Z: %d for room %s secret #%d of category %s with name '%s'.", "skyblocker.dungeons.secrets.customWaypointNotFound": "§cNo custom waypoint found at X: %d, Y: %d, Z: %d for room %s.", + + "skyblocker.dungeons.secretsTracker.feedback": "%s§f found %s§f secrets. %s", + "skyblocker.dungeons.secretsTracker.failFeedback": "§cUnable to calculate the amount of secrets everybody did this run!", + + "skyblocker.api.cache.HIT": "This data was cached!\nIt's %d seconds old.", + "skyblocker.api.cache.MISS": "This data wasn't cached!", "skyblocker.exotic.crystal": "CRYSTAL", "skyblocker.exotic.fairy": "FAIRY", @@ -345,4 +353,4 @@ "skyblocker.itemProtection.unableToProtect": "§cUnable to protect this item :( (Are you in skyblock?, are you holding an item?)", "emi.category.skyblocker.skyblock": "Skyblock" -} +}
\ No newline at end of file |