diff options
author | msg-programs <msgdoesstuff@gmail.com> | 2023-10-31 21:03:42 +0100 |
---|---|---|
committer | msg-programs <msgdoesstuff@gmail.com> | 2023-10-31 21:03:42 +0100 |
commit | d560c4611e603fa9e72ff6842bc14518d7bdbd63 (patch) | |
tree | 36eb1e24443bc9d9fbba51e14f12e5aacfac935c /src | |
parent | 1df4ef827d8a2e2fcc3767c1f5bf961f16b7fa19 (diff) | |
parent | 5bb91104d3275283d7479f0b35c1b18be470d632 (diff) | |
download | Skyblocker-d560c4611e603fa9e72ff6842bc14518d7bdbd63.tar.gz Skyblocker-d560c4611e603fa9e72ff6842bc14518d7bdbd63.tar.bz2 Skyblocker-d560c4611e603fa9e72ff6842bc14518d7bdbd63.zip |
Merge branch 'master' of https://github.com/SkyblockerMod/Skyblocker into cleanup-2
# Conflicts:
# src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
# src/main/java/de/hysky/skyblocker/utils/Http.java
# src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainerConfigScreen.java
Pull changes from upstream master
Diffstat (limited to 'src')
90 files changed, 3876 insertions, 1911 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index bd1cd5bd..b398e9b6 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -2,22 +2,27 @@ package de.hysky.skyblocker; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import de.hysky.skyblocker.config.SkyblockerConfigManager; 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.item.*; -import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster; -import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.skyblock.item.*; +import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; 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.tabhud.TabHud; +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; -import de.hysky.skyblocker.utils.NEURepo; +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; @@ -39,7 +44,7 @@ import java.nio.file.Path; * this class. */ public class SkyblockerMod implements ClientModInitializer { - public static final String VERSION = FabricLoader.getInstance().getModContainer("skyblocker").get().getMetadata().getVersion().getFriendlyString(); + public static final String VERSION = FabricLoader.getInstance().getModContainer("skyblocker").orElseThrow().getMetadata().getVersion().getFriendlyString(); public static final String NAMESPACE = "skyblocker"; public static final Path CONFIG_DIR = FabricLoader.getInstance().getConfigDir().resolve(NAMESPACE); public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); @@ -68,14 +73,15 @@ public class SkyblockerMod implements ClientModInitializer { public void onInitializeClient() { ClientTickEvents.END_CLIENT_TICK.register(this::tick); Utils.init(); - HotbarSlotLock.init(); SkyblockerConfigManager.init(); - PriceInfoTooltip.init(); + NEURepoManager.init(); + ItemRepository.init(); + HotbarSlotLock.init(); + ItemTooltip.init(); WikiLookup.init(); - ItemRegistry.init(); - NEURepo.init(); FairySouls.init(); Relics.init(); + MythologicalRitual.init(); BackpackPreview.init(); QuickNav.init(); ItemCooldowns.init(); @@ -104,6 +110,9 @@ public class SkyblockerMod implements ClientModInitializer { ItemProtection.init(); 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 c7fc6973..145f7ec4 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/MixinPlugin.java @@ -4,13 +4,17 @@ import java.util.List; import java.util.Set; 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; 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) { @@ -26,6 +30,17 @@ 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; + } + } return true; } 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 191da283..b52d6ff5 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockEmiRecipe.java @@ -16,7 +16,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(';', '_'))); + 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())); 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 c6147016..6ed6a32a 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/emi/SkyblockerEMIPlugin.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.compatibility.emi; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.utils.ItemUtils; import dev.emi.emi.api.EmiPlugin; import dev.emi.emi.api.EmiRegistry; @@ -21,9 +21,9 @@ public class SkyblockerEMIPlugin implements EmiPlugin { @Override public void register(EmiRegistry registry) { - ItemRegistry.getItemsStream().map(EmiStack::of).forEach(registry::addEmiStack); + ItemRepository.getItemsStream().map(EmiStack::of).forEach(registry::addEmiStack); registry.addCategory(SKYBLOCK); registry.addWorkstation(SKYBLOCK, EmiStack.of(Items.CRAFTING_TABLE)); - ItemRegistry.getRecipesStream().map(SkyblockEmiRecipe::new).forEach(registry::addRecipe); + ItemRepository.getRecipesStream().map(SkyblockEmiRecipe::new).forEach(registry::addRecipe); } } diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockCraftingDisplayGenerator.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockCraftingDisplayGenerator.java index 60e39b79..33cee20b 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockCraftingDisplayGenerator.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockCraftingDisplayGenerator.java @@ -1,6 +1,6 @@ package de.hysky.skyblocker.compatibility.rei; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.skyblock.itemlist.SkyblockCraftingRecipe; import de.hysky.skyblocker.utils.ItemUtils; import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator; @@ -19,7 +19,7 @@ public class SkyblockCraftingDisplayGenerator implements DynamicDisplayGenerator public Optional<List<SkyblockCraftingDisplay>> getRecipeFor(EntryStack<?> entry) { if (!(entry.getValue() instanceof ItemStack)) return Optional.empty(); EntryStack<ItemStack> inputItem = EntryStacks.of((ItemStack) entry.getValue()); - List<SkyblockCraftingRecipe> filteredRecipes = ItemRegistry.getRecipesStream() + List<SkyblockCraftingRecipe> filteredRecipes = ItemRepository.getRecipesStream() .filter(recipe -> { ItemStack itemStack = inputItem.getValue(); ItemStack itemStack1 = recipe.getResult(); @@ -34,7 +34,7 @@ public class SkyblockCraftingDisplayGenerator implements DynamicDisplayGenerator public Optional<List<SkyblockCraftingDisplay>> getUsageFor(EntryStack<?> entry) { if (!(entry.getValue() instanceof ItemStack)) return Optional.empty(); EntryStack<ItemStack> inputItem = EntryStacks.of((ItemStack) entry.getValue()); - List<SkyblockCraftingRecipe> filteredRecipes = ItemRegistry.getRecipesStream() + List<SkyblockCraftingRecipe> filteredRecipes = ItemRepository.getRecipesStream() .filter(recipe -> { for (ItemStack item : recipe.getGrid()) { if(!ItemUtils.getItemId(item).isEmpty()) { diff --git a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java index 97651718..7ed322a0 100644 --- a/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java +++ b/src/main/java/de/hysky/skyblocker/compatibility/rei/SkyblockerREIClientPlugin.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.compatibility.rei; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; @@ -29,6 +29,6 @@ public class SkyblockerREIClientPlugin implements REIClientPlugin { @Override public void registerEntries(EntryRegistry entryRegistry) { - entryRegistry.addEntries(ItemRegistry.getItemsStream().map(EntryStacks::of).toList()); + entryRegistry.addEntries(ItemRepository.getItemsStream().map(EntryStacks::of).toList()); } } diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index de53ca0a..8119fcab 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -1,11 +1,12 @@ package de.hysky.skyblocker.config; +import de.hysky.skyblocker.skyblock.item.CustomArmorTrims; +import de.hysky.skyblocker.utils.chat.ChatFilterResult; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.config.v2.api.SerialEntry; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import de.hysky.skyblocker.skyblock.item.CustomArmorTrims; -import de.hysky.skyblocker.utils.chat.ChatFilterResult; import net.minecraft.client.resource.language.I18n; import net.minecraft.text.Text; import net.minecraft.util.Formatting; @@ -177,6 +178,9 @@ public class SkyblockerConfig { public FairySouls fairySouls = new FairySouls(); @SerialEntry + public MythologicalRitual mythologicalRitual = new MythologicalRitual(); + + @SerialEntry public ItemCooldown itemCooldown = new ItemCooldown(); @SerialEntry @@ -195,6 +199,9 @@ public class SkyblockerConfig { public ItemInfoDisplay itemInfoDisplay = new ItemInfoDisplay(); @SerialEntry + public WikiLookup wikiLookup = new WikiLookup(); + + @SerialEntry public SpecialEffects specialEffects = new SpecialEffects(); @SerialEntry @@ -207,6 +214,9 @@ public class SkyblockerConfig { public TeleportOverlay teleportOverlay = new TeleportOverlay(); @SerialEntry + public FlameOverlay flameOverlay = new FlameOverlay(); + + @SerialEntry public List<Integer> lockedSlots = new ArrayList<>(); @SerialEntry @@ -316,6 +326,11 @@ public class SkyblockerConfig { public boolean highlightOnlyNearbySouls = false; } + public static class MythologicalRitual { + @SerialEntry + public boolean enableMythologicalRitualHelper = true; + } + public static class ItemCooldown { @SerialEntry public boolean enableItemCooldowns = true; @@ -388,6 +403,14 @@ public class SkyblockerConfig { public boolean enableWitherImpact = true; } + public static class FlameOverlay { + @SerialEntry + public float flameHeight = 0f; + + @SerialEntry + public float flameOpacity = 0f; + } + public enum Direction { HORIZONTAL, VERTICAL; @@ -462,6 +485,9 @@ public class SkyblockerConfig { @SerialEntry public boolean enableMuseumDate = true; + + @SerialEntry + public boolean enableExoticTooltip = true; } public static class ItemInfoDisplay { @@ -475,6 +501,14 @@ public class SkyblockerConfig { public float itemRarityBackgroundsOpacity = 1f; } + public static class WikiLookup { + @SerialEntry + public boolean enableWikiLookup = true; + + @SerialEntry + public boolean officialWiki = false; + } + public static class SpecialEffects { @SerialEntry public boolean rareDungeonDropEffects = true; @@ -520,6 +554,9 @@ public class SkyblockerConfig { public int mapY = 2; @SerialEntry + public boolean playerSecretsTracker = false; + + @SerialEntry public boolean starredMobGlow = true; @SerialEntry @@ -552,6 +589,12 @@ public class SkyblockerConfig { public boolean noInitSecretWaypoints = false; @SerialEntry + public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; + + @SerialEntry + public boolean showSecretText = true; + + @SerialEntry public boolean enableEntranceWaypoints = true; @SerialEntry @@ -579,6 +622,12 @@ public class SkyblockerConfig { public boolean enableStonkWaypoints = true; @SerialEntry + public boolean enableAotvWaypoints = true; + + @SerialEntry + public boolean enablePearlWaypoints = true; + + @SerialEntry public boolean enableDefaultWaypoints = true; } @@ -606,7 +655,6 @@ public class SkyblockerConfig { @SerialEntry public Formatting incompleteColor = Formatting.BLUE; - } public static class LividColor { @@ -685,6 +733,12 @@ public class SkyblockerConfig { public boolean mirrorverseWaypoints = true; @SerialEntry + public boolean enigmaSoulWaypoints = false; + + @SerialEntry + public boolean highlightFoundEnigmaSouls = true; + + @SerialEntry public int mcGrubberStacks = 0; } 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 284fcb5d..88350317 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -2,6 +2,7 @@ package de.hysky.skyblocker.config.categories; import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.utils.waypoint.Waypoint.Type; import dev.isxander.yacl3.api.ButtonOption; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; @@ -43,6 +44,21 @@ public class DungeonsCategory { .controller(ConfigUtils::createBooleanController) .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"))) + .binding(defaults.locations.dungeons.secretWaypoints.waypointType, + () -> config.locations.dungeons.secretWaypoints.waypointType, + newValue -> config.locations.dungeons.secretWaypoints.waypointType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.showSecretText")) + .binding(defaults.locations.dungeons.secretWaypoints.showSecretText, + () -> config.locations.dungeons.secretWaypoints.showSecretText, + newValue -> config.locations.dungeons.secretWaypoints.showSecretText = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableEntranceWaypoints")) .binding(defaults.locations.dungeons.secretWaypoints.enableEntranceWaypoints, @@ -107,6 +123,21 @@ public class DungeonsCategory { .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableAotvWaypoints")) + .binding(defaults.locations.dungeons.secretWaypoints.enableAotvWaypoints, + () -> config.locations.dungeons.secretWaypoints.enableAotvWaypoints, + newValue -> config.locations.dungeons.secretWaypoints.enableAotvWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enablePearlWaypoints")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enablePearlWaypoints.@Tooltip"))) + .binding(defaults.locations.dungeons.secretWaypoints.enablePearlWaypoints, + () -> config.locations.dungeons.secretWaypoints.enablePearlWaypoints, + newValue -> config.locations.dungeons.secretWaypoints.enablePearlWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableDefaultWaypoints")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableDefaultWaypoints.@Tooltip"))) .binding(defaults.locations.dungeons.secretWaypoints.enableDefaultWaypoints, @@ -210,19 +241,13 @@ public class DungeonsCategory { newValue -> config.locations.dungeons.mapScaling = newValue) .controller(FloatFieldControllerBuilder::create) .build()) - .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mapX")) - .binding(defaults.locations.dungeons.mapX, - () -> config.locations.dungeons.mapX, - newValue -> config.locations.dungeons.mapX = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.mapY")) - .binding(defaults.locations.dungeons.mapY, - () -> config.locations.dungeons.mapY, - newValue -> config.locations.dungeons.mapY = newValue) - .controller(IntegerFieldControllerBuilder::create) + .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"))) + .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")) 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 4a2de529..80d6485b 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DwarvenMinesCategory.java @@ -7,7 +7,6 @@ import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; import dev.isxander.yacl3.api.OptionDescription; import dev.isxander.yacl3.api.OptionGroup; -import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHudConfigScreen; import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; @@ -74,20 +73,6 @@ public class DwarvenMinesCategory { newValue -> config.locations.dwarvenMines.dwarvenHud.enableBackground = newValue) .controller(ConfigUtils::createBooleanController) .build()) - .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x")) - .binding(defaults.locations.dwarvenMines.dwarvenHud.x, - () -> config.locations.dwarvenMines.dwarvenHud.x, - newValue -> config.locations.dwarvenMines.dwarvenHud.x = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y")) - .binding(defaults.locations.dwarvenMines.dwarvenHud.y, - () -> config.locations.dwarvenMines.dwarvenHud.y, - newValue -> config.locations.dwarvenMines.dwarvenHud.y = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) .build()) .build(); } 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 6a393868..3cbb1b94 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -2,13 +2,12 @@ package de.hysky.skyblocker.config.categories; import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.skyblock.shortcut.ShortcutsConfigScreen; +import de.hysky.skyblocker.utils.render.title.TitleContainerConfigScreen; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; -import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder; import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder; -import de.hysky.skyblocker.skyblock.shortcut.ShortcutsConfigScreen; -import de.hysky.skyblocker.utils.render.title.TitleContainerConfigScreen; import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; @@ -201,6 +200,19 @@ public class GeneralCategory { .build()) .build()) + //Mythological Ritual + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.mythologicalRitual")) + .collapsed(true) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.mythologicalRitual.enableMythologicalRitualHelper")) + .binding(defaults.general.mythologicalRitual.enableMythologicalRitualHelper, + () -> config.general.mythologicalRitual.enableMythologicalRitualHelper, + newValue -> config.general.mythologicalRitual.enableMythologicalRitualHelper = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) + //Item Cooldown .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemCooldown")) @@ -344,6 +356,14 @@ public class GeneralCategory { newValue -> config.general.itemTooltip.enableMuseumDate = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip.@Tooltip"))) + .binding(defaults.general.itemTooltip.enableExoticTooltip, + () -> config.general.itemTooltip.enableExoticTooltip, + newValue -> config.general.itemTooltip.enableExoticTooltip = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) //Item Info Display @@ -375,6 +395,28 @@ public class GeneralCategory { .build()) .build()) + //Wiki Lookup + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.wikiLookup")) + .collapsed(true) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup.@Tooltip"))) + .binding(defaults.general.wikiLookup.enableWikiLookup, + () -> config.general.wikiLookup.enableWikiLookup, + newValue -> config.general.wikiLookup.enableWikiLookup = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki.@Tooltip"))) + .binding(defaults.general.wikiLookup.officialWiki, + () -> config.general.wikiLookup.officialWiki, + newValue -> config.general.wikiLookup.officialWiki = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) + //Special Effects .group(OptionGroup.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.specialEffects")) @@ -421,34 +463,6 @@ public class GeneralCategory { newValue -> config.general.titleContainer.titleContainerScale = newValue) .controller(opt -> FloatFieldControllerBuilder.create(opt).range(30f, 140f)) .build()) - .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.titleContainer.x")) - .binding(defaults.general.titleContainer.x, - () -> config.general.titleContainer.x, - newValue -> config.general.titleContainer.x = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.titleContainer.y")) - .binding(defaults.general.titleContainer.y, - () -> config.general.titleContainer.y, - newValue -> config.general.titleContainer.y = newValue) - .controller(IntegerFieldControllerBuilder::create) - .build()) - .option(Option.<SkyblockerConfig.Direction>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.titleContainer.direction")) - .binding(defaults.general.titleContainer.direction, - () -> config.general.titleContainer.direction, - newValue -> config.general.titleContainer.direction = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) - .option(Option.<SkyblockerConfig.Alignment>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.titleContainer.alignment")) - .binding(defaults.general.titleContainer.alignment, - () -> config.general.titleContainer.alignment, - newValue -> config.general.titleContainer.alignment = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) .option(ButtonOption.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.titleContainer.config")) .text(Text.translatable("text.skyblocker.open")) @@ -503,6 +517,26 @@ public class GeneralCategory { .controller(ConfigUtils::createBooleanController) .build()) .build()) + + //Flame Overlay + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.flameOverlay")) + .collapsed(true) + .option(Option.<Float>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.flameOverlay.flameHeight")) + .binding(defaults.general.flameOverlay.flameHeight, + () -> config.general.flameOverlay.flameHeight, + newValue -> config.general.flameOverlay.flameHeight = newValue) + .controller(opt -> FloatSliderControllerBuilder.create(opt).range(0.0f, 0.5f).step(0.01f)) + .build()) + .option(Option.<Float>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.flameOverlay.flameOpacity")) + .binding(defaults.general.flameOverlay.flameOpacity, + () -> config.general.flameOverlay.flameOpacity, + newValue -> config.general.flameOverlay.flameOpacity = newValue) + .controller(opt -> FloatSliderControllerBuilder.create(opt).range(0.0f, 0.8f).step(0.1f)) + .build()) + .build()) .build(); } } 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 d87adaa2..55629a66 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java @@ -46,6 +46,21 @@ public class LocationsCategory { newValue -> config.locations.rift.mirrorverseWaypoints = 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, + () -> config.locations.rift.enigmaSoulWaypoints, + newValue -> config.locations.rift.enigmaSoulWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.highlightFoundEnigmaSouls")) + .binding(defaults.locations.rift.highlightFoundEnigmaSouls, + () -> config.locations.rift.highlightFoundEnigmaSouls, + newValue -> config.locations.rift.highlightFoundEnigmaSouls = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .option(Option.<Integer>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.mcGrubberStacks")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.rift.mcGrubberStacks.@Tooltip"))) 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 c1cbc46c..e2684115 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/QuickNavigationCategory.java @@ -26,45 +26,45 @@ public class QuickNavigationCategory { //Button 1 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 1)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button1.render, () -> config.quickNav.button1.render, newValue -> config.quickNav.button1.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button1.item.itemName, () -> config.quickNav.button1.item.itemName, newValue -> config.quickNav.button1.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button1.item.count, () -> config.quickNav.button1.item.count, newValue -> config.quickNav.button1.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button1.item.nbt, () -> config.quickNav.button1.item.nbt, newValue -> config.quickNav.button1.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button1.uiTitle, () -> config.quickNav.button1.uiTitle, newValue -> config.quickNav.button1.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button1.clickEvent, () -> config.quickNav.button1.clickEvent, newValue -> config.quickNav.button1.clickEvent = newValue) @@ -74,45 +74,45 @@ public class QuickNavigationCategory { //Button 2 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button2")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 2)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button2.render, () -> config.quickNav.button2.render, newValue -> config.quickNav.button2.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button2.item.itemName, () -> config.quickNav.button2.item.itemName, newValue -> config.quickNav.button2.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button2.item.count, () -> config.quickNav.button2.item.count, newValue -> config.quickNav.button2.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button2.item.nbt, () -> config.quickNav.button2.item.nbt, newValue -> config.quickNav.button2.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button2.uiTitle, () -> config.quickNav.button2.uiTitle, newValue -> config.quickNav.button2.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button2.clickEvent, () -> config.quickNav.button2.clickEvent, newValue -> config.quickNav.button2.clickEvent = newValue) @@ -122,45 +122,45 @@ public class QuickNavigationCategory { //Button 3 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button3")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 3)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button3.render, () -> config.quickNav.button3.render, newValue -> config.quickNav.button3.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button3.item.itemName, () -> config.quickNav.button3.item.itemName, newValue -> config.quickNav.button3.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button3.item.count, () -> config.quickNav.button3.item.count, newValue -> config.quickNav.button3.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button3.item.nbt, () -> config.quickNav.button3.item.nbt, newValue -> config.quickNav.button3.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button3.uiTitle, () -> config.quickNav.button3.uiTitle, newValue -> config.quickNav.button3.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button3.clickEvent, () -> config.quickNav.button3.clickEvent, newValue -> config.quickNav.button3.clickEvent = newValue) @@ -170,45 +170,45 @@ public class QuickNavigationCategory { //Button 4 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button4")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 4)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button4.render, () -> config.quickNav.button4.render, newValue -> config.quickNav.button4.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button4.item.itemName, () -> config.quickNav.button4.item.itemName, newValue -> config.quickNav.button4.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button4.item.count, () -> config.quickNav.button4.item.count, newValue -> config.quickNav.button4.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button4.item.nbt, () -> config.quickNav.button4.item.nbt, newValue -> config.quickNav.button4.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button4.uiTitle, () -> config.quickNav.button4.uiTitle, newValue -> config.quickNav.button4.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button4.clickEvent, () -> config.quickNav.button4.clickEvent, newValue -> config.quickNav.button4.clickEvent = newValue) @@ -218,45 +218,45 @@ public class QuickNavigationCategory { //Button 5 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button5")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 5)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button5.render, () -> config.quickNav.button5.render, newValue -> config.quickNav.button5.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button5.item.itemName, () -> config.quickNav.button5.item.itemName, newValue -> config.quickNav.button5.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button5.item.count, () -> config.quickNav.button5.item.count, newValue -> config.quickNav.button5.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button5.item.nbt, () -> config.quickNav.button5.item.nbt, newValue -> config.quickNav.button5.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button5.uiTitle, () -> config.quickNav.button5.uiTitle, newValue -> config.quickNav.button5.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button5.clickEvent, () -> config.quickNav.button5.clickEvent, newValue -> config.quickNav.button5.clickEvent = newValue) @@ -266,45 +266,45 @@ public class QuickNavigationCategory { //Button 6 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button6")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 6)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button6.render, () -> config.quickNav.button6.render, newValue -> config.quickNav.button6.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button6.item.itemName, () -> config.quickNav.button6.item.itemName, newValue -> config.quickNav.button6.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button6.item.count, () -> config.quickNav.button6.item.count, newValue -> config.quickNav.button6.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button6.item.nbt, () -> config.quickNav.button6.item.nbt, newValue -> config.quickNav.button6.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button6.uiTitle, () -> config.quickNav.button6.uiTitle, newValue -> config.quickNav.button6.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button6.clickEvent, () -> config.quickNav.button6.clickEvent, newValue -> config.quickNav.button6.clickEvent = newValue) @@ -314,45 +314,45 @@ public class QuickNavigationCategory { //Button 7 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button7")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 7)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button7.render, () -> config.quickNav.button7.render, newValue -> config.quickNav.button7.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button7.item.itemName, () -> config.quickNav.button7.item.itemName, newValue -> config.quickNav.button7.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button7.item.count, () -> config.quickNav.button7.item.count, newValue -> config.quickNav.button7.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button7.item.nbt, () -> config.quickNav.button7.item.nbt, newValue -> config.quickNav.button7.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button7.uiTitle, () -> config.quickNav.button7.uiTitle, newValue -> config.quickNav.button7.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button7.clickEvent, () -> config.quickNav.button7.clickEvent, newValue -> config.quickNav.button7.clickEvent = newValue) @@ -362,45 +362,45 @@ public class QuickNavigationCategory { //Button 8 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button8")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 8)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button8.render, () -> config.quickNav.button8.render, newValue -> config.quickNav.button8.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button8.item.itemName, () -> config.quickNav.button8.item.itemName, newValue -> config.quickNav.button8.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button8.item.count, () -> config.quickNav.button8.item.count, newValue -> config.quickNav.button8.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button8.item.nbt, () -> config.quickNav.button8.item.nbt, newValue -> config.quickNav.button8.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button8.uiTitle, () -> config.quickNav.button8.uiTitle, newValue -> config.quickNav.button8.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button8.clickEvent, () -> config.quickNav.button8.clickEvent, newValue -> config.quickNav.button8.clickEvent = newValue) @@ -410,45 +410,45 @@ public class QuickNavigationCategory { //Button 9 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button9")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 9)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button9.render, () -> config.quickNav.button9.render, newValue -> config.quickNav.button9.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button9.item.itemName, () -> config.quickNav.button9.item.itemName, newValue -> config.quickNav.button9.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button9.item.count, () -> config.quickNav.button9.item.count, newValue -> config.quickNav.button9.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button9.item.nbt, () -> config.quickNav.button9.item.nbt, newValue -> config.quickNav.button9.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button9.uiTitle, () -> config.quickNav.button9.uiTitle, newValue -> config.quickNav.button9.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button9.clickEvent, () -> config.quickNav.button9.clickEvent, newValue -> config.quickNav.button9.clickEvent = newValue) @@ -458,45 +458,45 @@ public class QuickNavigationCategory { //Button 10 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button10")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 10)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button10.render, () -> config.quickNav.button10.render, newValue -> config.quickNav.button10.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button10.item.itemName, () -> config.quickNav.button10.item.itemName, newValue -> config.quickNav.button10.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button10.item.count, () -> config.quickNav.button10.item.count, newValue -> config.quickNav.button10.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button10.item.nbt, () -> config.quickNav.button10.item.nbt, newValue -> config.quickNav.button10.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button10.uiTitle, () -> config.quickNav.button10.uiTitle, newValue -> config.quickNav.button10.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button10.clickEvent, () -> config.quickNav.button10.clickEvent, newValue -> config.quickNav.button10.clickEvent = newValue) @@ -506,45 +506,45 @@ public class QuickNavigationCategory { //Button 11 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button11")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 11)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button11.render, () -> config.quickNav.button11.render, newValue -> config.quickNav.button11.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button11.item.itemName, () -> config.quickNav.button11.item.itemName, newValue -> config.quickNav.button11.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button11.item.count, () -> config.quickNav.button11.item.count, newValue -> config.quickNav.button11.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button11.item.nbt, () -> config.quickNav.button11.item.nbt, newValue -> config.quickNav.button11.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button11.uiTitle, () -> config.quickNav.button11.uiTitle, newValue -> config.quickNav.button11.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button11.clickEvent, () -> config.quickNav.button11.clickEvent, newValue -> config.quickNav.button11.clickEvent = newValue) @@ -554,45 +554,45 @@ public class QuickNavigationCategory { //Button 12 .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button12")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button", 12)) .collapsed(true) .option(Option.<Boolean>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.render")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.render")) .binding(defaults.quickNav.button12.render, () -> config.quickNav.button12.render, newValue -> config.quickNav.button12.render = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.itemName")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.itemName")) .binding(defaults.quickNav.button12.item.itemName, () -> config.quickNav.button12.item.itemName, newValue -> config.quickNav.button12.item.itemName = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<Integer>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.count")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.count")) .binding(defaults.quickNav.button12.item.count, () -> config.quickNav.button12.item.count, newValue -> config.quickNav.button12.item.count = newValue) .controller(opt -> IntegerFieldControllerBuilder.create(opt).range(1, 64)) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.item.nbt")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.item.nbt")) .binding(defaults.quickNav.button12.item.nbt, () -> config.quickNav.button12.item.nbt, newValue -> config.quickNav.button12.item.nbt = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.uiTitle")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.uiTitle")) .binding(defaults.quickNav.button12.uiTitle, () -> config.quickNav.button12.uiTitle, newValue -> config.quickNav.button12.uiTitle = newValue) .controller(StringControllerBuilder::create) .build()) .option(Option.<String>createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button1.clickEvent")) + .name(Text.translatable("text.autoconfig.skyblocker.option.quickNav.button.clickEvent")) .binding(defaults.quickNav.button12.clickEvent, () -> config.quickNav.button12.clickEvent, newValue -> config.quickNav.button12.clickEvent = newValue) diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java index fff534b2..f68a4e94 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java @@ -2,14 +2,16 @@ package de.hysky.skyblocker.mixin; import com.llamalad7.mixinextras.injector.WrapWithCondition; import com.llamalad7.mixinextras.sugar.Local; -import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; -import dev.cbyrne.betterinject.annotations.Inject; import de.hysky.skyblocker.skyblock.FishingHelper; +import de.hysky.skyblocker.skyblock.diana.MythologicalRitual; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; import de.hysky.skyblocker.utils.Utils; +import dev.cbyrne.betterinject.annotations.Inject; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; +import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Mixin; @@ -24,7 +26,6 @@ public abstract class ClientPlayNetworkHandlerMixin { FishingHelper.onSound(packet); } - @SuppressWarnings("resource") @ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "STORE", ordinal = 0)) private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity, @Local LivingEntity collector) { DungeonSecrets.onItemPickup(itemEntity, collector, collector == MinecraftClient.getInstance().player); @@ -45,4 +46,9 @@ public abstract class ClientPlayNetworkHandlerMixin { private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) { return !Utils.isOnHypixel(); } + + @Inject(method = "onParticle", at = @At("RETURN")) + private void skyblocker$onParticle(ParticleS2CPacket packet) { + MythologicalRitual.onParticle(packet); + } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java index a6691fe8..b25db7cf 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java @@ -6,7 +6,11 @@ import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver; import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver; import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver; import de.hysky.skyblocker.skyblock.experiment.UltrasequencerSolver; -import de.hysky.skyblocker.skyblock.item.*; +import de.hysky.skyblocker.skyblock.item.ItemProtection; +import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds; +import de.hysky.skyblocker.skyblock.item.WikiLookup; +import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview; +import de.hysky.skyblocker.skyblock.item.tooltip.CompactorDeletorPreview; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; @@ -41,7 +45,7 @@ import java.util.regex.Matcher; @Mixin(HandledScreen.class) public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen { /** - * This is the slot id returned for when a click is outside of the screen's bounds + * This is the slot id returned for when a click is outside the screen's bounds */ @Unique private static final int OUT_OF_BOUNDS_SLOT = -999; @@ -61,7 +65,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen @Inject(at = @At("HEAD"), method = "keyPressed") public void skyblocker$keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) { if (this.client != null && this.focusedSlot != null && keyCode != 256 && !this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && WikiLookup.wikiLookup.matchesKey(keyCode, scanCode)) { - WikiLookup.openWiki(this.focusedSlot); + WikiLookup.openWiki(this.focusedSlot, client.player); } } @@ -78,7 +82,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen // Backpack Preview boolean shiftDown = SkyblockerConfigManager.get().general.backpackPreviewWithoutShift ^ Screen.hasShiftDown(); - if (shiftDown && getTitle().getString().equals("Storage") && focusedSlot.inventory != client.player.getInventory() && BackpackPreview.renderPreview(context, focusedSlot.getIndex(), x, y)) { + if (shiftDown && getTitle().getString().equals("Storage") && focusedSlot.inventory != client.player.getInventory() && BackpackPreview.renderPreview(context, this, focusedSlot.getIndex(), x, y)) { ci.cancel(); } @@ -140,7 +144,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen */ @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At("HEAD"), cancellable = true) private void skyblocker$onSlotInteract(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { - if (Utils.isOnSkyblock()) { + if (Utils.isOnSkyblock()) { // When you try and drop the item by picking it up then clicking outside of the screen if (slotId == OUT_OF_BOUNDS_SLOT) { ItemStack cursorStack = this.handler.getCursorStack(); @@ -174,7 +178,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen } } } - } + } } //TODO make this a util method somewhere else, eventually @@ -184,6 +188,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen @Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V")) private void skyblocker$drawItemRarityBackground(DrawContext context, Slot slot, CallbackInfo ci) { - if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y); + if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) + ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y); } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/InGameOverlayRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixin/InGameOverlayRendererMixin.java new file mode 100644 index 00000000..b957603a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/InGameOverlayRendererMixin.java @@ -0,0 +1,22 @@ +package de.hysky.skyblocker.mixin; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import net.minecraft.client.gui.hud.InGameOverlayRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(InGameOverlayRenderer.class) +public class InGameOverlayRendererMixin { + + @ModifyArg(method = "renderFireOverlay", index = 2, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/BufferBuilder;vertex(Lorg/joml/Matrix4f;FFF)Lnet/minecraft/client/render/VertexConsumer;")) + private static float configureFlameHeight(float y) { + return y - SkyblockerConfigManager.get().general.flameOverlay.flameHeight; + } + + @ModifyArg(method = "renderFireOverlay", index = 3, at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/VertexConsumer;color(FFFF)Lnet/minecraft/client/render/VertexConsumer;")) + private static float configureFlameOpacity(float opacity) { + return opacity - SkyblockerConfigManager.get().general.flameOverlay.flameOpacity; + } + +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java index 98bea52b..6b49220b 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ItemMixin.java @@ -1,22 +1,19 @@ package de.hysky.skyblocker.mixin; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(Item.class) public abstract class ItemMixin { - @WrapOperation( + @Redirect( method = {"getItemBarColor", "getItemBarStep"}, at = @At(value = "FIELD", target = "Lnet/minecraft/item/Item;maxDamage:I", opcode = Opcodes.GETFIELD) ) - private int skyblocker$handlePickoDrillBar(Item item, Operation<Integer> original, ItemStack stack) { + private int skyblocker$handlePickoDrillBar(Item item, ItemStack stack) { return stack.getMaxDamage(); } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/ItemStackMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ItemStackMixin.java index 79a37d68..c5b2438a 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ItemStackMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ItemStackMixin.java @@ -4,48 +4,90 @@ package de.hysky.skyblocker.mixin; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.ItemUtils; -import de.hysky.skyblocker.utils.ItemUtils.Durability; import de.hysky.skyblocker.utils.Utils; +import dev.cbyrne.betterinject.annotations.Inject; +import it.unimi.dsi.fastutil.ints.IntIntPair; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @Mixin(ItemStack.class) public abstract class ItemStackMixin { + + @Shadow + public abstract int getDamage(); + + @Shadow + public abstract void setDamage(int damage); + + @Unique + private int maxDamage; + @ModifyReturnValue(method = "getName", at = @At("RETURN")) private Text skyblocker$customItemNames(Text original) { - if (Utils.isOnSkyblock()) { + if (Utils.isOnSkyblock()) { return SkyblockerConfigManager.get().general.customItemNames.getOrDefault(ItemUtils.getItemUuid((ItemStack) (Object) this), original); } return original; } + /** + * Updates the durability of this item stack every tick when in the inventory. + */ + @Inject(method = "inventoryTick", at = @At("TAIL")) + private void skyblocker$updateDamage() { + if (!skyblocker$shouldProcess()) { + return; + } + skyblocker$getAndCacheDurability(); + } + @ModifyReturnValue(method = "getDamage", at = @At("RETURN")) private int skyblocker$handleDamage(int original) { - Durability dur = ItemUtils.getDurability((ItemStack) (Object) this); - if (dur != null) { - return dur.max() - dur.current(); + // If the durability is already calculated, the original value should be the damage + if (!skyblocker$shouldProcess() || maxDamage != 0) { + return original; } - return original; + return skyblocker$getAndCacheDurability() ? getDamage() : original; } @ModifyReturnValue(method = "getMaxDamage", at = @At("RETURN")) private int skyblocker$handleMaxDamage(int original) { - Durability dur = ItemUtils.getDurability((ItemStack) (Object) this); - if (dur != null) { - return dur.max(); + if (!skyblocker$shouldProcess()) { + return original; } - return original; + // If the max damage is already calculated, return it + if (maxDamage != 0) { + return maxDamage; + } + return skyblocker$getAndCacheDurability() ? maxDamage : original; } @ModifyReturnValue(method = "isDamageable", at = @At("RETURN")) private boolean skyblocker$handleDamageable(boolean original) { - Durability dur = ItemUtils.getDurability((ItemStack) (Object) this); - if (dur != null) { - return true; + return skyblocker$shouldProcess() || original; + } + + @Unique + private boolean skyblocker$shouldProcess() { + return Utils.isOnSkyblock() && SkyblockerConfigManager.get().locations.dwarvenMines.enableDrillFuel && ItemUtils.hasCustomDurability((ItemStack) (Object) this); + } + + @Unique + private boolean skyblocker$getAndCacheDurability() { + // Calculate the durability + IntIntPair durability = ItemUtils.getDurability((ItemStack) (Object) this); + // Return if calculating the durability failed + if (durability == null) { + return false; } - return original; + // Saves the calculated durability + maxDamage = durability.rightInt(); + setDamage(durability.rightInt() - durability.leftInt()); + return true; } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/yacl/DoubleFieldControllerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/yacl/DoubleFieldControllerMixin.java new file mode 100644 index 00000000..ac24c09f --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/DoubleFieldControllerMixin.java @@ -0,0 +1,27 @@ +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 new file mode 100644 index 00000000..d67993c2 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/FloatFieldControllerMixin.java @@ -0,0 +1,27 @@ +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 new file mode 100644 index 00000000..b95cbef7 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/IntegerFieldControllerMixin.java @@ -0,0 +1,31 @@ +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 new file mode 100644 index 00000000..99871e2e --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/LongFieldControllerMixin.java @@ -0,0 +1,31 @@ +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 new file mode 100644 index 00000000..17a99cfd --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/yacl/NumberFieldControllerMixin.java @@ -0,0 +1,43 @@ +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/FairySouls.java b/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java index 24465e06..cef17d8e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java @@ -1,6 +1,5 @@ package de.hysky.skyblocker.skyblock; -import com.google.common.collect.ImmutableSet; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -9,7 +8,8 @@ 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.NEURepo; +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; @@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory; import java.io.*; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; @@ -64,25 +65,10 @@ public class FairySouls { } private static void loadFairySouls() { - fairySoulsLoaded = NEURepo.runAsyncAfterLoad(() -> { - try (BufferedReader reader = new BufferedReader(new FileReader(NEURepo.LOCAL_REPO_DIR.resolve("constants").resolve("fairy_souls.json").toFile()))) { - for (Map.Entry<String, JsonElement> fairySoulJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { - if (fairySoulJson.getKey().equals("//") || fairySoulJson.getKey().equals("Max Souls")) { - if (fairySoulJson.getKey().equals("Max Souls")) { - maxSouls = fairySoulJson.getValue().getAsInt(); - } - continue; - } - ImmutableSet.Builder<BlockPos> fairySoulsForLocation = ImmutableSet.builder(); - for (JsonElement fairySoul : fairySoulJson.getValue().getAsJsonArray().asList()) { - fairySoulsForLocation.add(PosUtils.parsePosString(fairySoul.getAsString())); - } - fairySouls.put(fairySoulJson.getKey(), fairySoulsForLocation.build()); - } - LOGGER.debug("[Skyblocker] Loaded fairy soul locations"); - } catch (IOException e) { - LOGGER.error("[Skyblocker] Failed to load fairy soul locations", e); - } + 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()); try (BufferedReader reader = new BufferedReader(new FileReader(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()))) { for (Map.Entry<String, JsonElement> foundFairiesForProfileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { @@ -101,6 +87,7 @@ public class FairySouls { } 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()); }); } @@ -131,12 +118,12 @@ public class FairySouls { .then(literal("fairySouls") .then(literal("markAllInCurrentIslandFound").executes(context -> { FairySouls.markAllFairiesOnCurrentIslandFound(); - context.getSource().sendFeedback(Text.translatable("skyblocker.fairySouls.markAllFound")); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.fairySouls.markAllFound"))); return 1; })) .then(literal("markAllInCurrentIslandMissing").executes(context -> { FairySouls.markAllFairiesOnCurrentIslandMissing(); - context.getSource().sendFeedback(Text.translatable("skyblocker.fairySouls.markAllMissing")); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.fairySouls.markAllMissing"))); return 1; })))); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java index 5ea5513e..c290e5b8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/TeleportOverlay.java @@ -1,8 +1,7 @@ package de.hysky.skyblocker.skyblock; -import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.item.PriceInfoTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; @@ -27,7 +26,7 @@ public class TeleportOverlay { private static void render(WorldRenderContext wrc) { if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.teleportOverlay.enableTeleportOverlays && client.player != null && client.world != null) { ItemStack heldItem = client.player.getMainHandStack(); - String itemId = PriceInfoTooltip.getInternalNameFromNBT(heldItem, true); + String itemId = ItemTooltip.getInternalNameFromNBT(heldItem, true); NbtCompound extraAttributes = ItemUtils.getExtraAttributes(heldItem); if (itemId != null) { @@ -103,13 +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()) { - RenderSystem.polygonOffset(-1f, -10f); - RenderSystem.enablePolygonOffset(); - RenderHelper.renderFilledIfVisible(wrc, pos, COLOR_COMPONENTS, 0.5f); - - RenderSystem.polygonOffset(0f, 0f); - RenderSystem.disablePolygonOffset(); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java b/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java new file mode 100644 index 00000000..e2962702 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java @@ -0,0 +1,213 @@ +package de.hysky.skyblocker.skyblock.diana; + +import com.mojang.brigadier.Command; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.ItemUtils; +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.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.fabric.api.event.player.AttackBlockCallback; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.fabricmc.fabric.api.event.player.UseItemCallback; +import net.fabricmc.fabric.api.util.TriState; +import net.minecraft.block.Blocks; +import net.minecraft.client.MinecraftClient; +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.apache.commons.math3.stat.regression.SimpleRegression; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class MythologicalRitual { + private static final Pattern GRIFFIN_BURROW_DUG = Pattern.compile("(?<message>You dug out a Griffin Burrow!|You finished the Griffin burrow chain!) \\((?<index>\\d)/4\\)"); + private static final float[] ORANGE_COLOR_COMPONENTS = DyeColor.ORANGE.getColorComponents(); + private static long lastEchoTime; + private static final Map<BlockPos, GriffinBurrow> griffinBurrows = new HashMap<>(); + @Nullable + private static BlockPos lastDugBurrowPos; + private static GriffinBurrow previousBurrow = new GriffinBurrow(BlockPos.ORIGIN); + + public static void init() { + WorldRenderEvents.AFTER_TRANSLUCENT.register(MythologicalRitual::render); + AttackBlockCallback.EVENT.register(MythologicalRitual::onAttackBlock); + UseBlockCallback.EVENT.register(MythologicalRitual::onUseBlock); + UseItemCallback.EVENT.register(MythologicalRitual::onUseItem); + ClientReceiveMessageEvents.GAME.register(MythologicalRitual::onChatMessage); + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("diana") + .then(literal("clearGriffinBurrows").executes(context -> { + griffinBurrows.clear(); + return Command.SINGLE_SUCCESS; + })) + .then(literal("clearGriffinBurrow") + .then(argument("pos", BlockPosArgumentType.blockPos()).executes(context -> { + griffinBurrows.remove(context.getArgument("pos", BlockPos.class)); + return Command.SINGLE_SUCCESS; + })) + ) + ))); + + // Put a root burrow so echo detection works without a previous burrow + previousBurrow.confirmed = TriState.DEFAULT; + griffinBurrows.put(BlockPos.ORIGIN, previousBurrow); + } + + public static void onParticle(ParticleS2CPacket packet) { + if (isActive()) { + if (ParticleTypes.CRIT.equals(packet.getParameters().getType()) || ParticleTypes.ENCHANT.equals(packet.getParameters().getType())) { + BlockPos pos = BlockPos.ofFloored(packet.getX(), packet.getY(), packet.getZ()).down(); + if (MinecraftClient.getInstance().world == null || !MinecraftClient.getInstance().world.getBlockState(pos).isOf(Blocks.GRASS_BLOCK)) { + return; + } + GriffinBurrow burrow = griffinBurrows.computeIfAbsent(pos, GriffinBurrow::new); + if (ParticleTypes.CRIT.equals(packet.getParameters().getType())) burrow.critParticle++; + if (ParticleTypes.ENCHANT.equals(packet.getParameters().getType())) burrow.enchantParticle++; + if (burrow.critParticle >= 5 && burrow.enchantParticle >= 5 && burrow.confirmed == TriState.FALSE) { + griffinBurrows.get(pos).init(); + } + } else if (ParticleTypes.DUST.equals(packet.getParameters().getType())) { + BlockPos pos = BlockPos.ofFloored(packet.getX(), packet.getY(), packet.getZ()).down(2); + GriffinBurrow burrow = griffinBurrows.get(pos); + if (burrow == null) { + return; + } + burrow.regression.addData(packet.getX(), packet.getZ()); + double slope = burrow.regression.getSlope(); + if (Double.isNaN(slope)) { + return; + } + Vec3d nextBurrowDirection = new Vec3d(100, 0, slope * 100).normalize().multiply(100); + if (burrow.nextBurrowPlane == null) { + burrow.nextBurrowPlane = new Vec3d[4]; + } + burrow.nextBurrowPlane[0] = Vec3d.of(pos).add(nextBurrowDirection).subtract(0, 50, 0); + 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())) { + if (System.currentTimeMillis() > lastEchoTime + 10_000) { + return; + } + if (previousBurrow.echoBurrowDirection == null) { + previousBurrow.echoBurrowDirection = new Vec3d[2]; + } + previousBurrow.echoBurrowDirection[0] = previousBurrow.echoBurrowDirection[1]; + previousBurrow.echoBurrowDirection[1] = new Vec3d(packet.getX(), packet.getY(), packet.getZ()); + if (previousBurrow.echoBurrowDirection[0] == null || previousBurrow.echoBurrowDirection[1] == null) { + return; + } + Vec3d echoBurrowDirection = previousBurrow.echoBurrowDirection[1].subtract(previousBurrow.echoBurrowDirection[0]).normalize().multiply(100); + if (previousBurrow.echoBurrowPlane == null) { + previousBurrow.echoBurrowPlane = new Vec3d[4]; + } + previousBurrow.echoBurrowPlane[0] = previousBurrow.echoBurrowDirection[0].add(echoBurrowDirection).subtract(0, 50, 0); + previousBurrow.echoBurrowPlane[1] = previousBurrow.echoBurrowDirection[0].subtract(echoBurrowDirection).subtract(0, 50, 0); + previousBurrow.echoBurrowPlane[2] = previousBurrow.echoBurrowPlane[1].add(0, 100, 0); + previousBurrow.echoBurrowPlane[3] = previousBurrow.echoBurrowPlane[0].add(0, 100, 0); + } + } + } + + public static void render(WorldRenderContext context) { + if (isActive()) { + for (GriffinBurrow burrow : griffinBurrows.values()) { + if (burrow.shouldRender()) { + burrow.render(context); + } + if (burrow.confirmed != TriState.FALSE) { + if (burrow.nextBurrowPlane != null) { + RenderHelper.renderQuad(context, burrow.nextBurrowPlane, ORANGE_COLOR_COMPONENTS, 0.25F, true); + } + if (burrow.echoBurrowPlane != null) { + RenderHelper.renderQuad(context, burrow.echoBurrowPlane, ORANGE_COLOR_COMPONENTS, 0.25F, true); + } + } + } + } + } + + public static ActionResult onAttackBlock(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction) { + return onInteractBlock(pos); + } + + public static ActionResult onUseBlock(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult) { + return onInteractBlock(hitResult.getBlockPos()); + } + + @NotNull + private static ActionResult onInteractBlock(BlockPos pos) { + if (isActive() && griffinBurrows.containsKey(pos)) { + lastDugBurrowPos = pos; + } + return ActionResult.PASS; + } + + public static TypedActionResult<ItemStack> onUseItem(PlayerEntity player, World world, Hand hand) { + ItemStack stack = player.getStackInHand(hand); + if (isActive() && ItemUtils.getItemId(stack).equals("ANCESTRAL_SPADE")) { + lastEchoTime = System.currentTimeMillis(); + } + return TypedActionResult.pass(stack); + } + + public static void onChatMessage(Text message, boolean overlay) { + if (isActive() && GRIFFIN_BURROW_DUG.matcher(message.getString()).matches()) { + previousBurrow.confirmed = TriState.FALSE; + previousBurrow = griffinBurrows.get(lastDugBurrowPos); + previousBurrow.confirmed = TriState.DEFAULT; + } + } + + private static boolean isActive() { + return SkyblockerConfigManager.get().general.mythologicalRitual.enableMythologicalRitualHelper && Utils.getLocationRaw().equals("hub"); + } + + private static class GriffinBurrow extends Waypoint { + private int critParticle; + private int enchantParticle; + private TriState confirmed = TriState.FALSE; + private final SimpleRegression regression = new SimpleRegression(); + private Vec3d[] nextBurrowPlane; + @Nullable + private Vec3d[] echoBurrowDirection; + private Vec3d[] echoBurrowPlane; + + private GriffinBurrow(BlockPos pos) { + super(pos, Type.WAYPOINT, ORANGE_COLOR_COMPONENTS, 0.25F); + } + + private void init() { + confirmed = TriState.TRUE; + regression.clear(); + } + + @Override + public boolean shouldRender() { + return super.shouldRender() && confirmed == TriState.TRUE; + } + } +} 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 6369291b..689788e1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java @@ -237,12 +237,12 @@ public class CreeperBeams { // render either in a color if not created or faintly green if created public void render(WorldRenderContext wrc, float[] color) { if (toDo) { - RenderHelper.renderOutline(wrc, outlineOne, color, 3); - RenderHelper.renderOutline(wrc, outlineTwo, color, 3); + RenderHelper.renderOutline(wrc, outlineOne, color, 3, false); + RenderHelper.renderOutline(wrc, outlineTwo, color, 3, false); RenderHelper.renderLinesFromPoints(wrc, line, color, 1, 2); } else { - RenderHelper.renderOutline(wrc, outlineOne, LIME_COLOR_COMPONENTS, 1); - RenderHelper.renderOutline(wrc, outlineTwo, LIME_COLOR_COMPONENTS, 1); + 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); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java index cfb16b4d..f49a2f2e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java @@ -128,11 +128,11 @@ public class DungeonBlaze { */ private static void renderBlazeOutline(ArmorStandEntity blaze, ArmorStandEntity nextBlaze, WorldRenderContext wrc) { Box blazeBox = blaze.getBoundingBox().expand(0.3, 0.9, 0.3).offset(0, -1.1, 0); - RenderHelper.renderOutline(wrc, blazeBox, GREEN_COLOR_COMPONENTS, 5f); + RenderHelper.renderOutline(wrc, blazeBox, GREEN_COLOR_COMPONENTS, 5f, false); if (nextBlaze != null && nextBlaze.isAlive() && nextBlaze != blaze) { Box nextBlazeBox = nextBlaze.getBoundingBox().expand(0.3, 0.9, 0.3).offset(0, -1.1, 0); - RenderHelper.renderOutline(wrc, nextBlazeBox, WHITE_COLOR_COMPONENTS, 5f); + RenderHelper.renderOutline(wrc, nextBlazeBox, WHITE_COLOR_COMPONENTS, 5f, false); Vec3d blazeCenter = blazeBox.getCenter(); Vec3d nextBlazeCenter = nextBlazeBox.getCenter(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java index 4e6a5240..1e889af3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonChestProfit.java @@ -4,7 +4,8 @@ import com.google.gson.JsonObject; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.mixin.accessor.ScreenAccessor; -import de.hysky.skyblocker.skyblock.item.PriceInfoTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.ints.IntBooleanPair; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; @@ -54,7 +55,7 @@ public class DungeonChestProfit { if (!stack.isEmpty()) { String name = stack.getName().getString(); - String id = PriceInfoTooltip.getInternalNameFromNBT(stack, false); + String id = ItemTooltip.getInternalNameFromNBT(stack, false); //Regular item price if (id != null) { @@ -128,8 +129,8 @@ public class DungeonChestProfit { * was based on complete data. */ private static IntBooleanPair getItemPrice(String id) { - JsonObject bazaarPrices = PriceInfoTooltip.getBazaarPrices(); - JsonObject lbinPrices = PriceInfoTooltip.getLBINPrices(); + JsonObject bazaarPrices = TooltipInfoType.BAZAAR.getData(); + JsonObject lbinPrices = TooltipInfoType.LOWEST_BINS.getData(); if (bazaarPrices == null || lbinPrices == null) return IntBooleanPair.of(0, false); 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 69018cd4..c198238b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java @@ -57,6 +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/TicTacToe.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java index 2d56c8a0..7f249e7d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java @@ -127,7 +127,7 @@ public class TicTacToe { private static void solutionRenderer(WorldRenderContext context) { try { if (SkyblockerConfigManager.get().locations.dungeons.solveTicTacToe && nextBestMoveToMake != null) { - RenderHelper.renderOutline(context, nextBestMoveToMake, RED_COLOR_COMPONENTS, 5); + RenderHelper.renderOutline(context, nextBestMoveToMake, RED_COLOR_COMPONENTS, 5, false); } } catch (Exception e) { LOGGER.error("[Skyblocker Tic Tac Toe] Encountered an exception while rendering the tic tac toe solution!", e); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java index 259cc3f3..73d4a452 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java @@ -7,7 +7,6 @@ import net.minecraft.block.MapColor; import net.minecraft.item.map.MapIcon; import net.minecraft.item.map.MapState; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import org.jetbrains.annotations.NotNull; @@ -173,7 +172,7 @@ public class DungeonMapUtils { @NotNull public static Vector2ic getPhysicalRoomPos(double x, double z) { Vector2i physicalPos = new Vector2i(x + 8.5, z + 8.5, RoundingMode.TRUNCATE); - return physicalPos.sub(MathHelper.floorMod(physicalPos.x(), 32), MathHelper.floorMod(physicalPos.y(), 32)).sub(8, 8); + return physicalPos.sub(Math.floorMod(physicalPos.x(), 32), Math.floorMod(physicalPos.y(), 32)).sub(8, 8); } public static Vector2ic[] getPhysicalPosFromMap(Vector2ic mapEntrancePos, int mapRoomSize, Vector2ic physicalEntrancePos, Vector2ic... mapPositions) { 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 c2358689..eda08cf6 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 @@ -1,5 +1,7 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -7,15 +9,19 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; -import it.unimi.dsi.fastutil.objects.Object2ByteMap; -import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.objects.Object2ByteMap; +import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; 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; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; @@ -23,6 +29,9 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.PosArgument; +import net.minecraft.command.argument.TextArgumentType; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; @@ -32,11 +41,15 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; import net.minecraft.resource.Resource; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -46,10 +59,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.IOException; import java.io.ObjectInputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import java.util.zip.InflaterInputStream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; @@ -58,6 +75,7 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit public class DungeonSecrets { protected static final Logger LOGGER = LoggerFactory.getLogger(DungeonSecrets.class); private static final String DUNGEONS_PATH = "dungeons"; + private static final Path CUSTOM_WAYPOINTS_DIR = SkyblockerMod.CONFIG_DIR.resolve("custom_secret_waypoints.json"); /** * Maps the block identifier string to a custom numeric block id used in dungeon rooms data. * @@ -97,6 +115,10 @@ public class DungeonSecrets { private static final Map<Vector2ic, Room> rooms = new HashMap<>(); private static final Map<String, JsonElement> roomsJson = new HashMap<>(); private static final Map<String, JsonElement> waypointsJson = new HashMap<>(); + /** + * The map of dungeon room names to custom waypoints relative to the room. + */ + private static final Table<String, BlockPos, SecretWaypoint> customWaypoints = HashBasedTable.create(); @Nullable private static CompletableFuture<Void> roomsLoaded; /** @@ -119,6 +141,10 @@ public class DungeonSecrets { return roomsLoaded != null && roomsLoaded.isDone(); } + public static Stream<Room> getRoomsStream() { + return rooms.values().stream(); + } + @SuppressWarnings("unused") public static JsonObject getRoomMetadata(String room) { return roomsJson.get(room).getAsJsonObject(); @@ -129,6 +155,38 @@ public class DungeonSecrets { } /** + * @see #customWaypoints + */ + public static Map<BlockPos, SecretWaypoint> getCustomWaypoints(String room) { + return customWaypoints.row(room); + } + + /** + * @see #customWaypoints + */ + @SuppressWarnings("UnusedReturnValue") + public static SecretWaypoint addCustomWaypoint(String room, SecretWaypoint waypoint) { + return customWaypoints.put(room, waypoint.pos, waypoint); + } + + /** + * @see #customWaypoints + */ + public static void addCustomWaypoints(String room, Collection<SecretWaypoint> waypoints) { + for (SecretWaypoint waypoint : waypoints) { + addCustomWaypoint(room, waypoint); + } + } + + /** + * @see #customWaypoints + */ + @Nullable + public static SecretWaypoint removeCustomWaypoint(String room, BlockPos pos) { + return customWaypoints.remove(room, pos); + } + + /** * Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}. * Use {@link #isRoomsLoaded()} to check for completion of loading. */ @@ -138,9 +196,10 @@ public class DungeonSecrets { } // Execute with MinecraftClient as executor since we need to wait for MinecraftClient#resourceManager to be set CompletableFuture.runAsync(DungeonSecrets::load, MinecraftClient.getInstance()).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets", e); return null; }); + ClientLifecycleEvents.CLIENT_STOPPING.register(DungeonSecrets::saveCustomWaypoints); Scheduler.INSTANCE.scheduleCyclic(DungeonSecrets::update, 10); WorldRenderEvents.AFTER_TRANSLUCENT.register(DungeonSecrets::render); ClientReceiveMessageEvents.GAME.register(DungeonSecrets::onChatMessage); @@ -148,7 +207,14 @@ public class DungeonSecrets { UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> onUseBlock(world, hitResult)); ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("secrets") .then(literal("markAsFound").then(markSecretsCommand(true))) - .then(literal("markAsMissing").then(markSecretsCommand(false))))))); + .then(literal("markAsMissing").then(markSecretsCommand(false))) + .then(literal("getRelativePos").executes(DungeonSecrets::getRelativePos)) + .then(literal("getRelativeTargetPos").executes(DungeonSecrets::getRelativeTargetPos)) + .then(literal("addWaypoint").then(addCustomWaypointCommand(false))) + .then(literal("addWaypointRelatively").then(addCustomWaypointCommand(true))) + .then(literal("removeWaypoint").then(removeCustomWaypointCommand(false))) + .then(literal("removeWaypointRelatively").then(removeCustomWaypointCommand(true))) + )))); ClientPlayConnectionEvents.JOIN.register(((handler, sender, client) -> reset())); } @@ -158,7 +224,7 @@ public class DungeonSecrets { for (Map.Entry<Identifier, Resource> resourceEntry : MinecraftClient.getInstance().getResourceManager().findResources(DUNGEONS_PATH, id -> id.getPath().endsWith(".skeleton")).entrySet()) { String[] path = resourceEntry.getKey().getPath().split("/"); if (path.length != 4) { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets, invalid resource identifier {}", resourceEntry.getKey()); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets, invalid resource identifier {}", resourceEntry.getKey()); break; } String dungeon = path[1]; @@ -171,9 +237,9 @@ public class DungeonSecrets { synchronized (roomsMap) { roomsMap.put(room, rooms); } - LOGGER.debug("[Skyblocker] Loaded dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room); }).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room, e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room, e); return null; })); } @@ -181,16 +247,39 @@ public class DungeonSecrets { try (BufferedReader roomsReader = MinecraftClient.getInstance().getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/dungeonrooms.json")); BufferedReader waypointsReader = MinecraftClient.getInstance().getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/secretlocations.json"))) { loadJson(roomsReader, roomsJson); loadJson(waypointsReader, waypointsJson); - LOGGER.debug("[Skyblocker] Loaded dungeon secrets json"); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded dungeon secret waypoints json"); + } catch (Exception e) { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secret waypoints json", e); + } + })); + 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()) + ); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets json", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load custom dungeon secret waypoints", e); } })); - roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker] Loaded dungeon secrets for {} dungeon(s), {} room shapes, and {} rooms total in {} ms", ROOMS_DATA.size(), ROOMS_DATA.values().stream().mapToInt(Map::size).sum(), ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Map::size).sum(), System.currentTimeMillis() - startTime)).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e); + roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker Dungeon Secrets] Loaded dungeon secrets for {} dungeon(s), {} room shapes, {} rooms, and {} custom secret waypoints total in {} ms", ROOMS_DATA.size(), ROOMS_DATA.values().stream().mapToInt(Map::size).sum(), ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Map::size).sum(), customWaypoints.size(), System.currentTimeMillis() - startTime)).exceptionally(e -> { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets", e); return null; }); - LOGGER.info("[Skyblocker] Started loading dungeon secrets in (blocked main thread for) {} ms", System.currentTimeMillis() - startTime); + LOGGER.info("[Skyblocker Dungeon Secrets] Started loading dungeon secrets in (blocked main thread for) {} ms", System.currentTimeMillis() - startTime); + } + + private static void saveCustomWaypoints(MinecraftClient client) { + 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()) + ); + SkyblockerMod.GSON.toJson(customWaypointsJson, writer); + LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); + } catch (Exception e) { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to save custom dungeon secret waypoints", e); + } } private static int[] readRoom(Resource resource) throws RuntimeException { @@ -203,25 +292,110 @@ public class DungeonSecrets { /** * Loads the json from the given {@link BufferedReader} into the given {@link Map}. + * * @param reader the reader to read the json from - * @param map the map to load into + * @param map the map to load into */ private static void loadJson(BufferedReader reader, Map<String, JsonElement> map) { SkyblockerMod.GSON.fromJson(reader, JsonObject.class).asMap().forEach((room, jsonElement) -> map.put(room.toLowerCase().replaceAll(" ", "-"), jsonElement)); } private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, Integer>> markSecretsCommand(boolean found) { - return argument("secret", IntegerArgumentType.integer()).executes(context -> { - int secretIndex = IntegerArgumentType.getInteger(context, "secret"); + return argument("secretIndex", IntegerArgumentType.integer()).executes(context -> { + int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); if (markSecrets(secretIndex, found)) { - context.getSource().sendFeedback(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFound" : "skyblocker.dungeons.secrets.markSecretMissing", secretIndex)); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFound" : "skyblocker.dungeons.secrets.markSecretMissing", secretIndex))); } else { - context.getSource().sendError(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFoundUnable" : "skyblocker.dungeons.secrets.markSecretMissingUnable", secretIndex)); + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFoundUnable" : "skyblocker.dungeons.secrets.markSecretMissingUnable", secretIndex))); } return Command.SINGLE_SUCCESS; }); } + private static int getRelativePos(CommandContext<FabricClientCommandSource> context) { + return getRelativePos(context.getSource(), context.getSource().getPlayer().getBlockPos()); + } + + private static int getRelativeTargetPos(CommandContext<FabricClientCommandSource> context) { + if (MinecraftClient.getInstance().crosshairTarget instanceof BlockHitResult blockHitResult && blockHitResult.getType() == HitResult.Type.BLOCK) { + return getRelativePos(context.getSource(), blockHitResult.getBlockPos()); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.noTarget"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int getRelativePos(FabricClientCommandSource source, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + BlockPos relativePos = currentRoom.actualToRelative(pos); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.posMessage", currentRoom.getName(), relativePos.getX(), relativePos.getY(), relativePos.getZ()))); + } else { + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, PosArgument>> addCustomWaypointCommand(boolean relative) { + return argument("pos", BlockPosArgumentType.blockPos()) + .then(argument("secretIndex", IntegerArgumentType.integer()) + .then(argument("category", SecretWaypoint.Category.CategoryArgumentType.category()) + .then(argument("name", TextArgumentType.text()).executes(context -> { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); + return relative ? addCustomWaypointRelative(context, pos) : addCustomWaypoint(context, pos); + })) + ) + ); + } + + private static int addCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + room.addCustomWaypoint(context, room.actualToRelative(pos)); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int addCustomWaypointRelative(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + if (isCurrentRoomMatched()) { + currentRoom.addCustomWaypoint(context, pos); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, PosArgument>> removeCustomWaypointCommand(boolean relative) { + return argument("pos", BlockPosArgumentType.blockPos()) + .executes(context -> { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); + return relative ? removeCustomWaypointRelative(context, pos) : removeCustomWaypoint(context, pos); + }); + } + + private static int removeCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + room.removeCustomWaypoint(context, room.actualToRelative(pos)); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int removeCustomWaypointRelative(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + if (isCurrentRoomMatched()) { + currentRoom.removeCustomWaypoint(context, pos); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + /** * Updates the dungeon. The general idea is similar to the Dungeon Rooms Mod. * <p></p> @@ -282,7 +456,7 @@ public class DungeonSecrets { } mapEntrancePos = mapEntrancePosAndSize.left(); mapRoomSize = mapEntrancePosAndSize.rightInt(); - LOGGER.info("[Skyblocker] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos); + LOGGER.info("[Skyblocker Dungeon Secrets] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos); } Vector2ic physicalPos = DungeonMapUtils.getPhysicalRoomPos(client.player.getPos()); @@ -320,7 +494,7 @@ public class DungeonSecrets { } return newRoom; } catch (IllegalArgumentException e) { - LOGGER.error("[Skyblocker] Failed to create room", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to create room", e); } return null; } @@ -339,9 +513,16 @@ public class DungeonSecrets { * Used to detect when all secrets in a room are found. */ private static void onChatMessage(Text text, boolean overlay) { + String message = text.getString(); + if (overlay && isCurrentRoomMatched()) { - currentRoom.onChatMessage(text.getString()); + currentRoom.onChatMessage(message); } + + if (message.equals("[BOSS] Bonzo: Gratz for making it this far, but I'm basically unbeatable.") || message.equals("[BOSS] Scarf: This is where the journey ends for you, Adventurers.") + || message.equals("[BOSS] The Professor: I was burdened with terrible news recently...") || message.equals("[BOSS] Thorn: Welcome Adventurers! I am Thorn, the Spirit! And host of the Vegan Trials!") + || message.equals("[BOSS] Livid: Welcome, you've arrived right on time. I am Livid, the Master of Shadows.") || message.equals("[BOSS] Sadan: So you made it all the way here... Now you wish to defy me? Sadan?!") + || message.equals("[BOSS] Maxor: WELL! WELL! WELL! LOOK WHO'S HERE!")) reset(); } /** @@ -410,6 +591,19 @@ public class DungeonSecrets { } /** + * Gets the room at the given physical position. + * + * @param pos the physical position + * @return the room at the given physical position, or null if there is no room at the given physical position + * @see #rooms + * @see DungeonMapUtils#getPhysicalRoomPos(Vec3i) + */ + @Nullable + private static Room getRoomAtPhysical(Vec3i pos) { + return rooms.get(DungeonMapUtils.getPhysicalRoomPos(pos)); + } + + /** * Calls {@link #isRoomMatched(Room)} on {@link #currentRoom}. * * @return {@code true} if {@link #currentRoom} is not null and {@link #isRoomMatched(Room)} @@ -439,7 +633,7 @@ public class DungeonSecrets { } /** - * Resets fields when leaving a dungeon. + * Resets fields when leaving a dungeon or entering boss. */ private static void reset() { mapEntrancePos = null; 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 dd7dc91e..ecfcf496 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 @@ -1,14 +1,17 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.context.CommandContext; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.ints.IntRBTreeSet; import it.unimi.dsi.fastutil.ints.IntSortedSet; import it.unimi.dsi.fastutil.ints.IntSortedSets; -import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; @@ -21,13 +24,14 @@ import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; import net.minecraft.registry.Registries; +import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; import org.apache.commons.lang3.tuple.MutableTriple; import org.apache.commons.lang3.tuple.Triple; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.Vector2i; import org.joml.Vector2ic; @@ -72,6 +76,9 @@ public class Room { */ private TriState matched = TriState.DEFAULT; private Table<Integer, BlockPos, SecretWaypoint> secretWaypoints; + private String name; + private Direction direction; + private Vector2ic physicalCornerPos; public Room(@NotNull Type type, @NotNull Vector2ic... physicalPositions) { this.type = type; @@ -92,6 +99,13 @@ public class Room { return matched == TriState.TRUE; } + /** + * Not null if {@link #isMatched()}. + */ + public String getName() { + return name; + } + @Override public String toString() { return "Room{type=" + type + ", shape=" + shape + ", matched=" + matched + ", segments=" + Arrays.toString(segments.toArray()) + "}"; @@ -145,6 +159,79 @@ public class Room { } /** + * @see #addCustomWaypoint(int, SecretWaypoint.Category, Text, BlockPos) + */ + protected void addCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); + SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); + Text waypointName = context.getArgument("name", Text.class); + addCustomWaypoint(secretIndex, category, waypointName, pos); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName))); + } + + /** + * Adds a custom waypoint relative to this room to {@link DungeonSecrets#customWaypoints} and all existing instances of this room. + * + * @param secretIndex the index of the secret waypoint + * @param category the category of the secret waypoint + * @param waypointName the name of the secret waypoint + * @param pos the position of the secret waypoint relative to this room + */ + @SuppressWarnings("JavadocReference") + private void addCustomWaypoint(int secretIndex, SecretWaypoint.Category category, Text waypointName, BlockPos pos) { + SecretWaypoint waypoint = new SecretWaypoint(secretIndex, category, waypointName, pos); + DungeonSecrets.addCustomWaypoint(name, waypoint); + DungeonSecrets.getRoomsStream().filter(r -> name.equals(r.getName())).forEach(r -> r.addCustomWaypoint(waypoint)); + } + + /** + * Adds a custom waypoint relative to this room to this instance of the room. + * + * @param relativeWaypoint the secret waypoint relative to this room to add + */ + private void addCustomWaypoint(SecretWaypoint relativeWaypoint) { + SecretWaypoint actualWaypoint = relativeWaypoint.relativeToActual(this); + secretWaypoints.put(actualWaypoint.secretIndex, actualWaypoint.pos, actualWaypoint); + } + + /** + * @see #removeCustomWaypoint(BlockPos) + */ + protected void removeCustomWaypoint(CommandContext<FabricClientCommandSource> context, BlockPos pos) { + SecretWaypoint waypoint = removeCustomWaypoint(pos); + if (waypoint != null) { + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointRemoved", pos.getX(), pos.getY(), pos.getZ(), name, waypoint.secretIndex, waypoint.category, waypoint.name))); + } else { + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointNotFound", pos.getX(), pos.getY(), pos.getZ(), name))); + } + } + + /** + * 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 + */ + @SuppressWarnings("JavadocReference") + @Nullable + private SecretWaypoint removeCustomWaypoint(BlockPos pos) { + SecretWaypoint waypoint = DungeonSecrets.removeCustomWaypoint(name, pos); + if (waypoint != null) { + DungeonSecrets.getRoomsStream().filter(r -> name.equals(r.getName())).forEach(r -> r.removeCustomWaypoint(waypoint.secretIndex, pos)); + } + return waypoint; + } + + /** + * 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 + */ + private void removeCustomWaypoint(int secretIndex, BlockPos relativePos) { + BlockPos actualPos = relativeToActual(relativePos); + secretWaypoints.remove(secretIndex, actualPos); + } + + /** * Updates the room. * <p></p> * This method returns immediately if any of the following conditions are met: @@ -186,8 +273,8 @@ public class Room { if (pos.getY() < 66 || pos.getY() > 73) { return true; } - int x = MathHelper.floorMod(pos.getX() - 8, 32); - int z = MathHelper.floorMod(pos.getZ() - 8, 32); + int x = Math.floorMod(pos.getX() - 8, 32); + int z = Math.floorMod(pos.getZ() - 8, 32); return (x < 13 || x > 17 || z > 2 && z < 28) && (z < 13 || z > 17 || x > 2 && x < 28); } @@ -217,7 +304,7 @@ public class Room { * </ul> * <li> If there are exactly one room matching: </li> * <ul> - * <li> Call {@link #roomMatched(String, Direction, Vector2ic)}. </li> + * <li> Call {@link #roomMatched()}. </li> * <li> Discard the no longer needed fields to save memory. </li> * <li> Return {@code true} </li> * </ul> @@ -256,7 +343,10 @@ public class Room { // 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) { - roomMatched(directionRooms.getRight().get(0), directionRooms.getLeft(), directionRooms.getMiddle()); + name = directionRooms.getRight().get(0); + direction = directionRooms.getLeft(); + physicalCornerPos = directionRooms.getMiddle(); + roomMatched(); discard(); return true; } @@ -286,17 +376,18 @@ public class Room { * @param directionRooms the direction, position, and name of the room */ @SuppressWarnings("JavadocReference") - private void roomMatched(String name, Direction direction, Vector2ic physicalCornerPos) { - Table<Integer, BlockPos, SecretWaypoint> secretWaypointsMutable = HashBasedTable.create(); + private void roomMatched() { + secretWaypoints = HashBasedTable.create(); 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)); BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); - secretWaypointsMutable.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); + secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } - secretWaypoints = ImmutableTable.copyOf(secretWaypointsMutable); + DungeonSecrets.getCustomWaypoints(name).values().forEach(this::addCustomWaypoint); matched = TriState.TRUE; + DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); } @@ -323,6 +414,20 @@ public class Room { } /** + * Fails if !{@link #isMatched()} + */ + protected BlockPos actualToRelative(BlockPos pos) { + return DungeonMapUtils.actualToRelative(direction, physicalCornerPos, pos); + } + + /** + * Fails if !{@link #isMatched()} + */ + protected BlockPos relativeToActual(BlockPos pos) { + return DungeonMapUtils.relativeToActual(direction, physicalCornerPos, pos); + } + + /** * Calls {@link SecretWaypoint#render(WorldRenderContext)} on {@link #secretWaypoints all secret waypoints}. */ protected void render(WorldRenderContext context) { 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 d2a31ea3..0c2d1b34 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 @@ -1,38 +1,61 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; import com.google.gson.JsonObject; - +import com.mojang.brigadier.context.CommandContext; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; 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.command.argument.EnumArgumentType; import net.minecraft.entity.Entity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.dynamic.Codecs; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.function.ToDoubleFunction; -public class SecretWaypoint { +public class SecretWaypoint extends Waypoint { + 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), + Codecs.TEXT.fieldOf("name").forGetter(secretWaypoint -> secretWaypoint.name), + BlockPos.CODEC.fieldOf("pos").forGetter(secretWaypoint -> secretWaypoint.pos) + ).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; final int secretIndex; final Category category; - private final Text name; - private final BlockPos pos; + final Text name; private final Vec3d centerPos; - private boolean missing; SecretWaypoint(int secretIndex, JsonObject waypoint, String name, BlockPos pos) { + this(secretIndex, Category.get(waypoint), name, pos); + } + + SecretWaypoint(int secretIndex, Category category, String name, BlockPos pos) { + this(secretIndex, category, Text.of(name), pos); + } + + SecretWaypoint(int secretIndex, Category category, Text name, BlockPos pos) { + super(pos, TYPE_SUPPLIER, category.colorComponents); this.secretIndex = secretIndex; - this.category = Category.get(waypoint); - this.name = Text.of(name); - this.pos = pos; + this.category = category; + this.name = name; this.centerPos = pos.toCenterPos(); - this.missing = true; } static ToDoubleFunction<SecretWaypoint> getSquaredDistanceToFunction(Entity entity) { @@ -43,8 +66,9 @@ public class SecretWaypoint { return secretWaypoint -> entity.squaredDistanceTo(secretWaypoint.centerPos) <= 36D; } - boolean shouldRender() { - return category.isEnabled() && missing; + @Override + public boolean shouldRender() { + return super.shouldRender() && category.isEnabled(); } boolean needsInteraction() { @@ -63,40 +87,47 @@ public class SecretWaypoint { return category.isBat(); } - void setFound() { - this.missing = false; - } - - void setMissing() { - this.missing = true; - } - /** * Renders the secret waypoint, including a filled cube, a beacon beam, the name, and the distance from the player. */ - void render(WorldRenderContext context) { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, category.colorComponents, 0.5F); - Vec3d posUp = centerPos.add(0, 1, 0); - RenderHelper.renderText(context, name, posUp, true); - double distance = context.camera().getPos().distanceTo(centerPos); - RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, 1, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true); + @Override + public void render(WorldRenderContext context) { + //TODO In the future, shrink the box for wither essence and items so its more realistic + super.render(context); + + if (CONFIG.showSecretText) { + Vec3d posUp = centerPos.add(0, 1, 0); + RenderHelper.renderText(context, name, posUp, true); + double distance = context.camera().getPos().distanceTo(centerPos); + RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, 1, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true); + } + } + + @NotNull + SecretWaypoint relativeToActual(Room room) { + return new SecretWaypoint(secretIndex, category, name, room.relativeToActual(pos)); } - enum Category { - ENTRANCE(secretWaypoints -> secretWaypoints.enableEntranceWaypoints, 0, 255, 0), - SUPERBOOM(secretWaypoints -> secretWaypoints.enableSuperboomWaypoints, 255, 0, 0), - CHEST(secretWaypoints -> secretWaypoints.enableChestWaypoints, 2, 213, 250), - ITEM(secretWaypoints -> secretWaypoints.enableItemWaypoints, 2, 64, 250), - BAT(secretWaypoints -> secretWaypoints.enableBatWaypoints, 142, 66, 0), - WITHER(secretWaypoints -> secretWaypoints.enableWitherWaypoints, 30, 30, 30), - LEVER(secretWaypoints -> secretWaypoints.enableLeverWaypoints, 250, 217, 2), - FAIRYSOUL(secretWaypoints -> secretWaypoints.enableFairySoulWaypoints, 255, 85, 255), - STONK(secretWaypoints -> secretWaypoints.enableStonkWaypoints, 146, 52, 235), - DEFAULT(secretWaypoints -> secretWaypoints.enableDefaultWaypoints, 190, 255, 252); + enum Category implements StringIdentifiable { + ENTRANCE("entrance", secretWaypoints -> secretWaypoints.enableEntranceWaypoints, 0, 255, 0), + SUPERBOOM("superboom", secretWaypoints -> secretWaypoints.enableSuperboomWaypoints, 255, 0, 0), + CHEST("chest", secretWaypoints -> secretWaypoints.enableChestWaypoints, 2, 213, 250), + ITEM("item", secretWaypoints -> secretWaypoints.enableItemWaypoints, 2, 64, 250), + BAT("bat", secretWaypoints -> secretWaypoints.enableBatWaypoints, 142, 66, 0), + WITHER("wither", secretWaypoints -> secretWaypoints.enableWitherWaypoints, 30, 30, 30), + LEVER("lever", secretWaypoints -> secretWaypoints.enableLeverWaypoints, 250, 217, 2), + FAIRYSOUL("fairysoul", secretWaypoints -> secretWaypoints.enableFairySoulWaypoints, 255, 85, 255), + STONK("stonk", secretWaypoints -> secretWaypoints.enableStonkWaypoints, 146, 52, 235), + AOTV("aotv", secretWaypoints -> secretWaypoints.enableAotvWaypoints, 252, 98, 3), + PEARL("pearl", secretWaypoints -> secretWaypoints.enablePearlWaypoints, 57, 117, 125), + DEFAULT("default", secretWaypoints -> secretWaypoints.enableDefaultWaypoints, 190, 255, 252); + private static final Codec<Category> CODEC = StringIdentifiable.createCodec(Category::values); + private final String name; private final Predicate<SkyblockerConfig.SecretWaypoints> enabledPredicate; private final float[] colorComponents; - Category(Predicate<SkyblockerConfig.SecretWaypoints> enabledPredicate, int... intColorComponents) { + Category(String name, Predicate<SkyblockerConfig.SecretWaypoints> enabledPredicate, int... intColorComponents) { + this.name = name; this.enabledPredicate = enabledPredicate; colorComponents = new float[intColorComponents.length]; for (int i = 0; i < intColorComponents.length; i++) { @@ -104,19 +135,8 @@ public class SecretWaypoint { } } - private static Category get(JsonObject categoryJson) { - return switch (categoryJson.get("category").getAsString()) { - case "entrance" -> Category.ENTRANCE; - case "superboom" -> Category.SUPERBOOM; - case "chest" -> Category.CHEST; - case "item" -> Category.ITEM; - case "bat" -> Category.BAT; - case "wither" -> Category.WITHER; - case "lever" -> Category.LEVER; - case "fairysoul" -> Category.FAIRYSOUL; - case "stonk" -> Category.STONK; - default -> Category.DEFAULT; - }; + private static Category get(JsonObject waypointJson) { + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElseThrow(); } boolean needsInteraction() { @@ -138,5 +158,29 @@ public class SecretWaypoint { boolean isEnabled() { return enabledPredicate.test(SkyblockerConfigManager.get().locations.dungeons.secretWaypoints); } + + @Override + public String toString() { + return name; + } + + @Override + public String asString() { + return name; + } + + static class CategoryArgumentType extends EnumArgumentType<Category> { + public CategoryArgumentType() { + super(Category.CODEC, Category::values); + } + + public static CategoryArgumentType category() { + return new CategoryArgumentType(); + } + + public static <S> Category getCategory(CommandContext<S> context, String name) { + return context.getArgument(name, Category.class); + } + } } } 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 f4e6ef84..09cb03be 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHudConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHudConfigScreen.java @@ -62,6 +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/BackpackPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java deleted file mode 100644 index 122ffe9b..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java +++ /dev/null @@ -1,235 +0,0 @@ -package de.hysky.skyblocker.skyblock.item; - -import com.mojang.blaze3d.systems.RenderSystem; -import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.utils.Utils; -import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ingame.HandledScreen; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.*; -import net.minecraft.util.Identifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class BackpackPreview { - private static final Logger LOGGER = LoggerFactory.getLogger(BackpackPreview.class); - private static final Identifier TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/inventory_background.png"); - private static final Pattern ECHEST_PATTERN = Pattern.compile("Ender Chest.*\\((\\d+)/\\d+\\)"); - private static final Pattern BACKPACK_PATTERN = Pattern.compile("Backpack.*\\(Slot #(\\d+)\\)"); - private static final int STORAGE_SIZE = 27; - - private static final Inventory[] storage = new Inventory[STORAGE_SIZE]; - private static final boolean[] dirty = new boolean[STORAGE_SIZE]; - - private static String loaded = ""; // uuid + sb profile currently loaded - private static Path save_dir = null; - - public static void init() { - ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { - if (screen instanceof HandledScreen<?> handledScreen) { - updateStorage(handledScreen); - } - }); - } - - public static void tick() { - Utils.update(); // force update isOnSkyblock to prevent crash on disconnect - if (Utils.isOnSkyblock()) { - // save all dirty storages - saveStorage(); - // update save dir based on uuid and sb profile - String uuid = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", ""); - String profile = Utils.getProfile(); - if (profile != null && !profile.isEmpty()) { - save_dir = FabricLoader.getInstance().getConfigDir().resolve("skyblocker/backpack-preview/" + uuid + "/" + profile); - save_dir.toFile().mkdirs(); - if (loaded.equals(uuid + "/" + profile)) { - // mark currently opened storage as dirty - if (MinecraftClient.getInstance().currentScreen != null) { - String title = MinecraftClient.getInstance().currentScreen.getTitle().getString(); - int index = getStorageIndexFromTitle(title); - if (index != -1) dirty[index] = true; - } - } else { - // load storage again because uuid/profile changed - loaded = uuid + "/" + profile; - loadStorage(); - } - } - } - } - - public static void loadStorage() { - assert (save_dir != null); - for (int index = 0; index < STORAGE_SIZE; ++index) { - storage[index] = null; - dirty[index] = false; - File file = save_dir.resolve(index + ".nbt").toFile(); - if (file.isFile()) { - try { - NbtCompound root = NbtIo.read(file); - storage[index] = new DummyInventory(root); - } catch (Exception e) { - LOGGER.error("Failed to load backpack preview file: " + file.getName(), e); - } - } - } - } - - private static void saveStorage() { - assert (save_dir != null); - for (int index = 0; index < STORAGE_SIZE; ++index) { - if (dirty[index]) { - if (storage[index] != null) { - try { - NbtCompound root = new NbtCompound(); - NbtList list = new NbtList(); - for (int i = 9; i < storage[index].size(); ++i) { - ItemStack stack = storage[index].getStack(i); - NbtCompound item = new NbtCompound(); - if (stack.isEmpty()) { - item.put("id", NbtString.of("minecraft:air")); - item.put("Count", NbtInt.of(1)); - } else { - item.put("id", NbtString.of(stack.getItem().toString())); - item.put("Count", NbtInt.of(stack.getCount())); - item.put("tag", stack.getNbt()); - } - list.add(item); - } - root.put("list", list); - root.put("size", NbtInt.of(storage[index].size() - 9)); - NbtIo.write(root, save_dir.resolve(index + ".nbt").toFile()); - dirty[index] = false; - } catch (Exception e) { - LOGGER.error("Failed to save backpack preview file: " + index + ".nbt", e); - } - } - } - } - } - - public static void updateStorage(HandledScreen<?> screen) { - String title = screen.getTitle().getString(); - int index = getStorageIndexFromTitle(title); - if (index != -1) { - storage[index] = screen.getScreenHandler().slots.get(0).inventory; - dirty[index] = true; - } - } - - public static boolean renderPreview(DrawContext context, int index, int mouseX, int mouseY) { - if (index >= 9 && index < 18) index -= 9; - else if (index >= 27 && index < 45) index -= 18; - else return false; - - if (storage[index] == null) return false; - int rows = (storage[index].size() - 9) / 9; - - Screen screen = MinecraftClient.getInstance().currentScreen; - if (screen == null) return false; - int x = mouseX + 184 >= screen.width ? mouseX - 188 : mouseX + 8; - int y = Math.max(0, mouseY - 16); - - RenderSystem.disableDepthTest(); - RenderSystem.setShaderTexture(0, TEXTURE); - context.drawTexture(TEXTURE, x, y, 0, 0, 176, 7); - for (int i = 0; i < rows; ++i) { - context.drawTexture(TEXTURE, x, y + i * 18 + 7, 0, 7, 176, 18); - } - context.drawTexture(TEXTURE, x, y + rows * 18 + 7, 0, 25, 176, 7); - RenderSystem.enableDepthTest(); - - MatrixStack matrices = context.getMatrices(); - TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; - for (int i = 9; i < storage[index].size(); ++i) { - int itemX = x + (i - 9) % 9 * 18 + 8; - int itemY = y + (i - 9) / 9 * 18 + 8; - matrices.push(); - matrices.translate(0, 0, 200); - context.drawItem(storage[index].getStack(i), itemX, itemY); - context.drawItemInSlot(textRenderer, storage[index].getStack(i), itemX, itemY); - matrices.pop(); - } - - return true; - } - - private static int getStorageIndexFromTitle(String title) { - Matcher echest = ECHEST_PATTERN.matcher(title); - if (echest.find()) return Integer.parseInt(echest.group(1)) - 1; - Matcher backpack = BACKPACK_PATTERN.matcher(title); - if (backpack.find()) return Integer.parseInt(backpack.group(1)) + 8; - return -1; - } -} - -class DummyInventory implements Inventory { - private final List<ItemStack> stacks; - - public DummyInventory(NbtCompound root) { - stacks = new ArrayList<>(root.getInt("size") + 9); - for (int i = 0; i < 9; ++i) stacks.add(ItemStack.EMPTY); - root.getList("list", NbtCompound.COMPOUND_TYPE).forEach(item -> - stacks.add(ItemStack.fromNbt((NbtCompound) item)) - ); - } - - @Override - public int size() { - return stacks.size(); - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public ItemStack getStack(int slot) { - return stacks.get(slot); - } - - @Override - public ItemStack removeStack(int slot, int amount) { - return null; - } - - @Override - public ItemStack removeStack(int slot) { - return null; - } - - @Override - public void setStack(int slot, ItemStack stack) { - stacks.set(slot, stack); - } - - @Override - public void markDirty() { - } - - @Override - public boolean canPlayerUse(PlayerEntity player) { - return false; - } - - @Override - public void clear() { - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java index 1496c90f..509f79b7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorDyeColors.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -34,7 +35,7 @@ public class CustomArmorDyeColors { ItemStack heldItem = source.getPlayer().getMainHandStack(); if (hex != null && !isHexadecimalColor(hex)) { - source.sendError(Text.translatable("skyblocker.customDyeColors.invalidHex")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.invalidHex"))); return Command.SINGLE_SUCCESS; } @@ -49,24 +50,24 @@ public class CustomArmorDyeColors { if (customDyeColors.containsKey(itemUuid)) { customDyeColors.removeInt(itemUuid); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.customDyeColors.removed")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.removed"))); } else { - source.sendFeedback(Text.translatable("skyblocker.customDyeColors.neverHad")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.neverHad"))); } } else { customDyeColors.put(itemUuid, Integer.decode("0x" + hex.replace("#", "")).intValue()); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.customDyeColors.added")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.added"))); } } else { - source.sendError(Text.translatable("skyblocker.customDyeColors.noItemUuid")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.noItemUuid"))); } } else { - source.sendError(Text.translatable("skyblocker.customDyeColors.notDyeable")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.notDyeable"))); return Command.SINGLE_SUCCESS; } } else { - source.sendError(Text.translatable("skyblocker.customDyeColors.unableToSetColor")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customDyeColors.unableToSetColor"))); } return Command.SINGLE_SUCCESS; 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 9242d47b..cec84b38 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorTrims.java @@ -3,8 +3,12 @@ package de.hysky.skyblocker.skyblock.item; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.suggestion.SuggestionProvider; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.events.SkyblockEvents; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import dev.isxander.yacl3.config.v2.api.SerialEntry; @@ -105,38 +109,43 @@ public class CustomArmorTrims { if (customArmorTrims.containsKey(itemUuid)) { customArmorTrims.remove(itemUuid); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.customArmorTrims.removed")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.removed"))); } else { - source.sendFeedback(Text.translatable("skyblocker.customArmorTrims.neverHad")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.neverHad"))); } } else { // Ensure that the material & trim are valid ArmorTrimId trimId = new ArmorTrimId(material, pattern); if (TRIMS_CACHE.get(trimId) == null) { - source.sendError(Text.translatable("skyblocker.customArmorTrims.invalidMaterialOrPattern")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.invalidMaterialOrPattern"))); return Command.SINGLE_SUCCESS; } customArmorTrims.put(itemUuid, trimId); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.customArmorTrims.added")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.added"))); } } else { - source.sendError(Text.translatable("skyblocker.customArmorTrims.noItemUuid")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.noItemUuid"))); } } else { - source.sendError(Text.translatable("skyblocker.customArmorTrims.notAnArmorPiece")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.notAnArmorPiece"))); return Command.SINGLE_SUCCESS; } } else { - source.sendError(Text.translatable("skyblocker.customArmorTrims.unableToSetTrim")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customArmorTrims.unableToSetTrim"))); } return Command.SINGLE_SUCCESS; } public record ArmorTrimId(@SerialEntry Identifier material, @SerialEntry Identifier pattern) implements Pair<Identifier, Identifier> { + public static final Codec<ArmorTrimId> CODEC = RecordCodecBuilder.create(instance -> instance.group( + 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/CustomItemNames.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java index b6213eb6..e47444cf 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomItemNames.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.skyblock.item; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -42,9 +43,9 @@ public class CustomItemNames { //Remove custom item name when the text argument isn't passed customItemNames.remove(itemUuid); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.customItemNames.removed")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customItemNames.removed"))); } else { - source.sendFeedback(Text.translatable("skyblocker.customItemNames.neverHad")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customItemNames.neverHad"))); } } else { //If the text is provided then set the item's custom name to it @@ -55,13 +56,13 @@ public class CustomItemNames { customItemNames.put(itemUuid, text); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.customItemNames.added")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customItemNames.added"))); } } else { - source.sendError(Text.translatable("skyblocker.customItemNames.noItemUuid")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customItemNames.noItemUuid"))); } } else { - source.sendError(Text.translatable("skyblocker.customItemNames.unableToSetName")); + source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customItemNames.unableToSetName"))); } return Command.SINGLE_SUCCESS; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemProtection.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemProtection.java index ff88ef8d..2d929c28 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemProtection.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemProtection.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.skyblock.item; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -44,18 +45,18 @@ public class ItemProtection { protectedItems.add(itemUuid); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.itemProtection.added", heldItem.getName())); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.itemProtection.added", heldItem.getName()))); } else { protectedItems.remove(itemUuid); SkyblockerConfigManager.save(); - source.sendFeedback(Text.translatable("skyblocker.itemProtection.removed", heldItem.getName())); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.itemProtection.removed", heldItem.getName()))); } } else { - source.sendFeedback(Text.translatable("skyblocker.itemProtection.noItemUuid")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.itemProtection.noItemUuid"))); } } else { - source.sendFeedback(Text.translatable("skyblocker.itemProtection.unableToProtect")); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.itemProtection.unableToProtect"))); } return Command.SINGLE_SUCCESS; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java new file mode 100644 index 00000000..ac9b1bf0 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java @@ -0,0 +1,144 @@ +package de.hysky.skyblocker.skyblock.item; + +import java.io.ByteArrayInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Base64; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; +import com.mojang.util.UndashedUuid; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.Http; +import de.hysky.skyblocker.utils.Http.ApiResponse; +import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtList; +import net.minecraft.util.Util; + +public class MuseumItemCache { + private static final Logger LOGGER = LoggerFactory.getLogger(MuseumItemCache.class); + 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) { + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to load cached museum items", e); + } + }); + } + + private static void save() { + CompletableFuture.runAsync(() -> { + try (BufferedWriter writer = Files.newBufferedWriter(CACHE_FILE)) { + SkyblockerMod.GSON.toJson(MUSEUM_ITEM_CACHE, writer); + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to save cached museum items!", e); + } + }); + } + + 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")); + } + } + } + + 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) { + LOGGER.error("[Skyblocker] Failed to refresh museum item data for profile {}", profileId, e); + } + }); + } + + /** + * The cache is ticked upon switching skyblock servers + */ + public static void tick(String profileId) { + if (loaded.isDone()) { + String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); + 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/WikiLookup.java b/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java index d4e6a0df..38121ea3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/WikiLookup.java @@ -1,23 +1,25 @@ package de.hysky.skyblocker.skyblock.item; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.utils.ItemUtils; -import de.hysky.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Text; import net.minecraft.util.Util; import org.lwjgl.glfw.GLFW; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.concurrent.CompletableFuture; public class WikiLookup { + private static final Logger LOGGER = LoggerFactory.getLogger(WikiLookup.class); public static KeyBinding wikiLookup; - static final MinecraftClient client = MinecraftClient.getInstance(); - static String id; + private static String id; public static void init() { wikiLookup = KeyBindingHelper.registerKeyBinding(new KeyBinding( @@ -28,22 +30,22 @@ public class WikiLookup { )); } - public static String getSkyblockId(Slot slot) { + public static void getSkyblockId(Slot slot) { //Grabbing the skyblock NBT data ItemUtils.getItemIdOptional(slot.getStack()).ifPresent(newId -> id = newId); - return id; } - public static void openWiki(Slot slot) { - if (Utils.isOnSkyblock()) { - id = getSkyblockId(slot); + public static void openWiki(Slot slot, PlayerEntity player) { + if (SkyblockerConfigManager.get().general.wikiLookup.enableWikiLookup) { + getSkyblockId(slot); try { - String wikiLink = ItemRegistry.getWikiLink(id); + String wikiLink = ItemRepository.getWikiLink(id, player); CompletableFuture.runAsync(() -> Util.getOperatingSystem().open(wikiLink)); } catch (IndexOutOfBoundsException | IllegalStateException e) { - e.printStackTrace(); - if (client.player != null) - client.player.sendMessage(Text.of("Error while retrieving wiki article..."), false); + LOGGER.error("[Skyblocker] Error while retrieving wiki article...", e); + if (player != null) { + player.sendMessage(Text.of("[Skyblocker] Error while retrieving wiki article, see logs..."), false); + } } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java new file mode 100644 index 00000000..5627b56d --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java @@ -0,0 +1,204 @@ +package de.hysky.skyblocker.skyblock.item.tooltip; + +import com.mojang.blaze3d.systems.RenderSystem; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds; +import de.hysky.skyblocker.utils.Utils; +import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtInt; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtList; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.nio.file.Path; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class BackpackPreview { + private static final Logger LOGGER = LoggerFactory.getLogger(BackpackPreview.class); + private static final Identifier TEXTURE = new Identifier("textures/gui/container/generic_54.png"); + private static final Pattern ECHEST_PATTERN = Pattern.compile("Ender Chest.*\\((\\d+)/\\d+\\)"); + private static final Pattern BACKPACK_PATTERN = Pattern.compile("Backpack.*\\(Slot #(\\d+)\\)"); + private static final int STORAGE_SIZE = 27; + + private static final Storage[] storages = new Storage[STORAGE_SIZE]; + + /** + * The profile id of the currently loaded backpack preview. + */ + private static String loaded; + private static Path saveDir; + + public static void init() { + ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { + if (screen instanceof HandledScreen<?> handledScreen) { + ScreenEvents.remove(screen).register(screen1 -> updateStorage(handledScreen)); + } + }); + } + + public static void tick() { + Utils.update(); // force update isOnSkyblock to prevent crash on disconnect + if (Utils.isOnSkyblock()) { + // save all dirty storages + saveStorages(); + // update save dir based on sb profile id + String id = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", "") + "/" + Utils.getProfileId(); + if (!id.equals(loaded)) { + saveDir = SkyblockerMod.CONFIG_DIR.resolve("backpack-preview/" + id); + //noinspection ResultOfMethodCallIgnored + saveDir.toFile().mkdirs(); + // load storage again because profile id changed + loaded = id; + loadStorages(); + } + } + } + + private static void loadStorages() { + for (int index = 0; index < STORAGE_SIZE; ++index) { + storages[index] = null; + File storageFile = saveDir.resolve(index + ".nbt").toFile(); + if (storageFile.isFile()) { + try { + storages[index] = Storage.fromNbt(Objects.requireNonNull(NbtIo.read(storageFile))); + } catch (Exception e) { + LOGGER.error("Failed to load backpack preview file: " + storageFile.getName(), e); + } + } + } + } + + private static void saveStorages() { + for (int index = 0; index < STORAGE_SIZE; ++index) { + if (storages[index] != null && storages[index].dirty) { + saveStorage(index); + } + } + } + + private static void saveStorage(int index) { + try { + NbtIo.write(storages[index].toNbt(), saveDir.resolve(index + ".nbt").toFile()); + storages[index].markClean(); + } catch (Exception e) { + LOGGER.error("Failed to save backpack preview file: " + index + ".nbt", e); + } + } + + private static void updateStorage(HandledScreen<?> handledScreen) { + String title = handledScreen.getTitle().getString(); + int index = getStorageIndexFromTitle(title); + if (index != -1) { + storages[index] = new Storage(handledScreen.getScreenHandler().slots.get(0).inventory, title, true); + } + } + + public static boolean renderPreview(DrawContext context, Screen screen, int index, int mouseX, int mouseY) { + if (index >= 9 && index < 18) index -= 9; + else if (index >= 27 && index < 45) index -= 18; + else return false; + + if (storages[index] == null) return false; + int rows = (storages[index].size() - 9) / 9; + + int x = mouseX + 184 >= screen.width ? mouseX - 188 : mouseX + 8; + int y = Math.max(0, mouseY - 16); + + MatrixStack matrices = context.getMatrices(); + matrices.push(); + matrices.translate(0f, 0f, 400f); + + RenderSystem.enableDepthTest(); + context.drawTexture(TEXTURE, x, y, 0, 0, 176, rows * 18 + 17); + context.drawTexture(TEXTURE, x, y + rows * 18 + 17, 0, 215, 176, 7); + + TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + context.drawText(textRenderer, storages[index].name, x + 8, y + 6, 0x404040, false); + + matrices.translate(0f, 0f, 200f); + for (int i = 9; i < storages[index].size(); ++i) { + ItemStack currentStack = storages[index].getStack(i); + int itemX = x + (i - 9) % 9 * 18 + 8; + int itemY = y + (i - 9) / 9 * 18 + 18; + + if (SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) { + ItemRarityBackgrounds.tryDraw(currentStack, context, itemX, itemY); + } + + context.drawItem(currentStack, itemX, itemY); + context.drawItemInSlot(textRenderer, currentStack, itemX, itemY); + } + + matrices.pop(); + + return true; + } + + private static int getStorageIndexFromTitle(String title) { + Matcher echest = ECHEST_PATTERN.matcher(title); + if (echest.find()) return Integer.parseInt(echest.group(1)) - 1; + Matcher backpack = BACKPACK_PATTERN.matcher(title); + if (backpack.find()) return Integer.parseInt(backpack.group(1)) + 8; + return -1; + } + + static class Storage { + private final Inventory inventory; + private final String name; + private boolean dirty; + + private Storage(Inventory inventory, String name, boolean dirty) { + this.inventory = inventory; + this.name = name; + this.dirty = dirty; + } + + private int size() { + return inventory.size(); + } + + private ItemStack getStack(int index) { + return inventory.getStack(index); + } + + private void markClean() { + dirty = false; + } + + @NotNull + private static Storage fromNbt(NbtCompound root) { + SimpleInventory inventory = new SimpleInventory(root.getList("list", NbtCompound.COMPOUND_TYPE).stream().map(NbtCompound.class::cast).map(ItemStack::fromNbt).toArray(ItemStack[]::new)); + return new Storage(inventory, root.getString("name"), false); + } + + @NotNull + private NbtCompound toNbt() { + NbtCompound root = new NbtCompound(); + NbtList list = new NbtList(); + for (int i = 0; i < size(); ++i) { + list.add(getStack(i).writeNbt(new NbtCompound())); + } + root.put("list", list); + root.put("size", NbtInt.of(size())); + root.putString("name", name); + return root; + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CompactorDeletorPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java index 7f5b96b9..9cf0356b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CompactorDeletorPreview.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorDeletorPreview.java @@ -1,7 +1,7 @@ -package de.hysky.skyblocker.skyblock.item; +package de.hysky.skyblocker.skyblock.item.tooltip; import de.hysky.skyblocker.mixin.accessor.DrawContextInvoker; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.utils.ItemUtils; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.ints.IntObjectPair; @@ -43,7 +43,7 @@ public class CompactorDeletorPreview { NbtCompound extraAttributes = ItemUtils.getExtraAttributes(stack); if (extraAttributes == null) return false; // Get the slots and their items from the nbt, which is in the format personal_compact_<slot_number> or personal_deletor_<slot_number> - List<IntObjectPair<ItemStack>> slots = extraAttributes.getKeys().stream().filter(slot -> slot.contains(type.toLowerCase().substring(0, 7))).map(slot -> IntObjectPair.of(Integer.parseInt(slot.substring(17)), ItemRegistry.getItemStack(extraAttributes.getString(slot)))).toList(); + List<IntObjectPair<ItemStack>> slots = extraAttributes.getKeys().stream().filter(slot -> slot.contains(type.toLowerCase().substring(0, 7))).map(slot -> IntObjectPair.of(Integer.parseInt(slot.substring(17)), ItemRepository.getItemStack(extraAttributes.getString(slot)))).toList(); List<TooltipComponent> components = tooltips.stream().map(Text::asOrderedText).map(TooltipComponent::of).collect(Collectors.toList()); IntIntPair dimensions = DIMENSIONS.getOrDefault(size, DEFAULT_DIMENSION); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CompactorPreviewTooltipComponent.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorPreviewTooltipComponent.java index 513d7d72..22498c02 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/CompactorPreviewTooltipComponent.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/CompactorPreviewTooltipComponent.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.item; +package de.hysky.skyblocker.skyblock.item.tooltip; import de.hysky.skyblocker.SkyblockerMod; import it.unimi.dsi.fastutil.ints.IntIntPair; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java new file mode 100644 index 00000000..66d94890 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ExoticTooltip.java @@ -0,0 +1,96 @@ +package de.hysky.skyblocker.skyblock.item.tooltip; + +import de.hysky.skyblocker.utils.Constants; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; + +public class ExoticTooltip { + public static String getExpectedHex(String id) { + String color = TooltipInfoType.COLOR.getData().get(id).getAsString(); + if (color != null) { + String[] RGBValues = color.split(","); + return String.format("%02X%02X%02X", Integer.parseInt(RGBValues[0]), Integer.parseInt(RGBValues[1]), Integer.parseInt(RGBValues[2])); + } else { + ItemTooltip.LOGGER.warn("[Skyblocker Exotics] No expected color data found for id {}", id); + return null; + } + } + + public static boolean isException(String id, String hex) { + if (id.startsWith("LEATHER") || id.equals("GHOST_BOOTS") || Constants.SEYMOUR_IDS.contains(id)) { + return true; + } + if (id.startsWith("RANCHER")) { + return Constants.RANCHERS.contains(hex); + } + if (id.contains("ADAPTIVE_CHESTPLATE")) { + return Constants.ADAPTIVE_CHEST.contains(hex); + } else if (id.contains("ADAPTIVE")) { + return Constants.ADAPTIVE.contains(hex); + } + if (id.startsWith("REAPER")) { + return Constants.REAPER.contains(hex); + } + if (id.startsWith("FAIRY")) { + return Constants.FAIRY_HEXES.contains(hex); + } + if (id.startsWith("CRYSTAL")) { + return Constants.CRYSTAL_HEXES.contains(hex); + } + if (id.contains("SPOOK")) { + return Constants.SPOOK.contains(hex); + } + return false; + } + + public static DyeType checkDyeType(String hex) { + if (Constants.CRYSTAL_HEXES.contains(hex)) { + return DyeType.CRYSTAL; + } + if (Constants.FAIRY_HEXES.contains(hex)) { + return DyeType.FAIRY; + } + if (Constants.OG_FAIRY_HEXES.contains(hex)) { + return DyeType.OG_FAIRY; + } + if (Constants.SPOOK.contains(hex)) { + return DyeType.SPOOK; + } + if (Constants.GLITCHED.contains(hex)) { + return DyeType.GLITCHED; + } + return DyeType.EXOTIC; + } + + public static boolean intendedDyed(NbtCompound ItemData) { + return ItemData.getCompound("ExtraAttributes").contains("dye_item"); + } + + public enum DyeType implements StringIdentifiable { + CRYSTAL("crystal", Formatting.AQUA), + FAIRY("fairy", Formatting.LIGHT_PURPLE), + OG_FAIRY("og_fairy", Formatting.DARK_PURPLE), + SPOOK("spook", Formatting.RED), + GLITCHED("glitched", Formatting.BLUE), + EXOTIC("exotic", Formatting.GOLD); + private final String name; + private final Formatting formatting; + + DyeType(String name, Formatting formatting) { + this.name = name; + this.formatting = formatting; + } + + @Override + public String asString() { + return name; + } + + public MutableText getTranslatedText() { + return Text.translatable("skyblocker.exotic." + name).formatted(formatting); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/PriceInfoTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index 0f84deea..e050aff5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/PriceInfoTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -1,10 +1,10 @@ -package de.hysky.skyblocker.skyblock.item; +package de.hysky.skyblocker.skyblock.item.tooltip; -import com.google.gson.Gson; 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.utils.Http; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; @@ -12,36 +12,25 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.item.TooltipContext; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.http.HttpHeaders; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.CompletableFuture; -public class PriceInfoTooltip { - private static final Logger LOGGER = LoggerFactory.getLogger(PriceInfoTooltip.class.getName()); +public class ItemTooltip { + protected static final Logger LOGGER = LoggerFactory.getLogger(ItemTooltip.class.getName()); private static final MinecraftClient client = MinecraftClient.getInstance(); - private static JsonObject npcPricesJson; - private static JsonObject bazaarPricesJson; - private static JsonObject oneDayAvgPricesJson; - private static JsonObject threeDayAvgPricesJson; - private static JsonObject lowestPricesJson; - private static JsonObject isMuseumJson; - private static JsonObject motesPricesJson; - private static volatile boolean nullMsgSend = false; - private final static Gson gson = new Gson(); - private static final Map<String, String> apiAddresses; - private static long npcHash = 0; - private static long museumHash = 0; - private static long motesHash = 0; - - public static void onInjectTooltip(ItemStack stack, TooltipContext context, List<Text> lines) { + protected static final SkyblockerConfig.ItemTooltip config = SkyblockerConfigManager.get().general.itemTooltip; + private static volatile boolean sentNullWarning = false; + + public static void getTooltip(ItemStack stack, TooltipContext context, List<Text> lines) { if (!Utils.isOnSkyblock() || client.player == null) return; String name = getInternalNameFromNBT(stack, false); @@ -54,65 +43,47 @@ public class PriceInfoTooltip { neuName = internalID; } + if (lines.isEmpty()) { + return; + } + int count = stack.getCount(); boolean bazaarOpened = lines.stream().anyMatch(each -> each.getString().contains("Buy price:") || each.getString().contains("Sell price:")); - if (SkyblockerConfigManager.get().general.itemTooltip.enableNPCPrice) { - if (npcPricesJson == null) { - nullWarning(); - } else if (npcPricesJson.has(internalID)) { - lines.add(Text.literal(String.format("%-21s", "NPC Price:")) - .formatted(Formatting.YELLOW) - .append(getCoinsMessage(npcPricesJson.get(internalID).getAsDouble(), count))); - } - } - - if (SkyblockerConfigManager.get().general.itemTooltip.enableMotesPrice && Utils.isInTheRift()) { - if (motesPricesJson == null) { - nullWarning(); - } else if (motesPricesJson.has(internalID)) { - lines.add(Text.literal(String.format("%-20s", "Motes Price:")) - .formatted(Formatting.LIGHT_PURPLE) - .append(getMotesMessage(motesPricesJson.get(internalID).getAsInt(), count))); - } + if (TooltipInfoType.NPC.isTooltipEnabledAndHasOrNullWarning(internalID)) { + lines.add(Text.literal(String.format("%-21s", "NPC Price:")) + .formatted(Formatting.YELLOW) + .append(getCoinsMessage(TooltipInfoType.NPC.getData().get(internalID).getAsDouble(), count))); } boolean bazaarExist = false; - if (SkyblockerConfigManager.get().general.itemTooltip.enableBazaarPrice && !bazaarOpened) { - if (bazaarPricesJson == null) { - nullWarning(); - } else if (bazaarPricesJson.has(name)) { - JsonObject getItem = bazaarPricesJson.getAsJsonObject(name); - lines.add(Text.literal(String.format("%-18s", "Bazaar buy Price:")) - .formatted(Formatting.GOLD) - .append(getItem.get("buyPrice").isJsonNull() - ? Text.literal("No data").formatted(Formatting.RED) - : getCoinsMessage(getItem.get("buyPrice").getAsDouble(), count))); - lines.add(Text.literal(String.format("%-19s", "Bazaar sell Price:")) - .formatted(Formatting.GOLD) - .append(getItem.get("sellPrice").isJsonNull() - ? Text.literal("No data").formatted(Formatting.RED) - : getCoinsMessage(getItem.get("sellPrice").getAsDouble(), count))); - bazaarExist = true; - } + if (TooltipInfoType.BAZAAR.isTooltipEnabledAndHasOrNullWarning(name) && !bazaarOpened) { + JsonObject getItem = TooltipInfoType.BAZAAR.getData().getAsJsonObject(name); + lines.add(Text.literal(String.format("%-18s", "Bazaar buy Price:")) + .formatted(Formatting.GOLD) + .append(getItem.get("buyPrice").isJsonNull() + ? Text.literal("No data").formatted(Formatting.RED) + : getCoinsMessage(getItem.get("buyPrice").getAsDouble(), count))); + lines.add(Text.literal(String.format("%-19s", "Bazaar sell Price:")) + .formatted(Formatting.GOLD) + .append(getItem.get("sellPrice").isJsonNull() + ? Text.literal("No data").formatted(Formatting.RED) + : getCoinsMessage(getItem.get("sellPrice").getAsDouble(), count))); + bazaarExist = true; } // bazaarOpened & bazaarExist check for lbin, because Skytils keeps some bazaar item data in lbin api boolean lbinExist = false; - if (SkyblockerConfigManager.get().general.itemTooltip.enableLowestBIN && !bazaarOpened && !bazaarExist) { - if (lowestPricesJson == null) { - nullWarning(); - } else if (lowestPricesJson.has(name)) { - lines.add(Text.literal(String.format("%-19s", "Lowest BIN Price:")) - .formatted(Formatting.GOLD) - .append(getCoinsMessage(lowestPricesJson.get(name).getAsDouble(), count))); - lbinExist = true; - } + if (TooltipInfoType.LOWEST_BINS.isTooltipEnabledAndHasOrNullWarning(name) && !bazaarOpened && !bazaarExist) { + lines.add(Text.literal(String.format("%-19s", "Lowest BIN Price:")) + .formatted(Formatting.GOLD) + .append(getCoinsMessage(TooltipInfoType.LOWEST_BINS.getData().get(name).getAsDouble(), count))); + lbinExist = true; } if (SkyblockerConfigManager.get().general.itemTooltip.enableAvgBIN) { - if (threeDayAvgPricesJson == null || oneDayAvgPricesJson == null) { + if (TooltipInfoType.ONE_DAY_AVERAGE.getData() == null || TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) { nullWarning(); } else { /* @@ -142,16 +113,16 @@ public class PriceInfoTooltip { } if (!neuName.isEmpty() && lbinExist) { - SkyblockerConfig.Average type = SkyblockerConfigManager.get().general.itemTooltip.avg; + SkyblockerConfig.Average type = config.avg; // "No data" line because of API not keeping old data, it causes NullPointerException if (type == SkyblockerConfig.Average.ONE_DAY || type == SkyblockerConfig.Average.BOTH) { lines.add( Text.literal(String.format("%-19s", "1 Day Avg. Price:")) .formatted(Formatting.GOLD) - .append(oneDayAvgPricesJson.get(neuName) == null + .append(TooltipInfoType.ONE_DAY_AVERAGE.getData().get(neuName) == null ? Text.literal("No data").formatted(Formatting.RED) - : getCoinsMessage(oneDayAvgPricesJson.get(neuName).getAsDouble(), count) + : getCoinsMessage(TooltipInfoType.ONE_DAY_AVERAGE.getData().get(neuName).getAsDouble(), count) ) ); } @@ -159,9 +130,9 @@ public class PriceInfoTooltip { lines.add( Text.literal(String.format("%-19s", "3 Day Avg. Price:")) .formatted(Formatting.GOLD) - .append(threeDayAvgPricesJson.get(neuName) == null + .append(TooltipInfoType.THREE_DAY_AVERAGE.getData().get(neuName) == null ? Text.literal("No data").formatted(Formatting.RED) - : getCoinsMessage(threeDayAvgPricesJson.get(neuName).getAsDouble(), count) + : getCoinsMessage(TooltipInfoType.THREE_DAY_AVERAGE.getData().get(neuName).getAsDouble(), count) ) ); } @@ -169,35 +140,68 @@ public class PriceInfoTooltip { } } - if (SkyblockerConfigManager.get().general.itemTooltip.enableMuseumDate && !bazaarOpened) { - if (isMuseumJson == null) { - nullWarning(); - } else { - String timestamp = getTimestamp(stack); - - if (isMuseumJson.has(internalID)) { - String itemCategory = isMuseumJson.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()) { - lines.add(Text.literal(String.format("%-21s", "Obtained: ")) - .formatted(Formatting.LIGHT_PURPLE) - .append(Text.literal(timestamp).formatted(Formatting.RED))); + if (TooltipInfoType.MOTES.isTooltipEnabledAndHasOrNullWarning(internalID)) { + lines.add(Text.literal(String.format("%-20s", "Motes Price:")) + .formatted(Formatting.LIGHT_PURPLE) + .append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), count))); + } + + if (TooltipInfoType.MUSEUM.isTooltipEnabled() && !bazaarOpened) { + 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()) { + lines.add(Text.literal(String.format("%-21s", "Obtained: ")) + .formatted(Formatting.LIGHT_PURPLE) + .append(Text.literal(timestamp).formatted(Formatting.RED))); + } + } + + if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.getNbt() != null) { + final NbtElement color = stack.getNbt().getCompound("display").get("color"); + + if (color != null) { + String colorHex = String.format("%06X", Integer.parseInt(color.asString())); + String expectedHex = ExoticTooltip.getExpectedHex(internalID); + + boolean correctLine = false; + for (Text text : lines) { + String existingTooltip = text.getString() + " "; + if (existingTooltip.startsWith("Color: ")) { + correctLine = true; + + addExoticTooltip(lines, internalID, stack.getNbt(), colorHex, expectedHex, existingTooltip); + break; + } + } + + if (!correctLine) { + addExoticTooltip(lines, internalID, stack.getNbt(), colorHex, expectedHex, ""); } } } } - private static void nullWarning() { - if (!nullMsgSend && client.player != null) { - client.player.sendMessage(Text.translatable("skyblocker.itemTooltip.nullMessage"), false); - nullMsgSend = true; + private static void addExoticTooltip(List<Text> lines, String internalID, NbtCompound nbt, String colorHex, String expectedHex, String existingTooltip) { + if (expectedHex != null && !colorHex.equalsIgnoreCase(expectedHex) && !ExoticTooltip.isException(internalID, colorHex) && !ExoticTooltip.intendedDyed(nbt)) { + final ExoticTooltip.DyeType type = ExoticTooltip.checkDyeType(colorHex); + lines.add(1, Text.literal(existingTooltip + Formatting.DARK_GRAY + "(").append(type.getTranslatedText()).append(Formatting.DARK_GRAY + ")")); + } + } + + public static void nullWarning() { + if (!sentNullWarning && client.player != null) { + client.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.itemTooltip.nullMessage")), false); + sentNullWarning = true; } } @@ -233,6 +237,7 @@ public class PriceInfoTooltip { return ""; } + // TODO What in the world is this? public static String getInternalNameFromNBT(ItemStack stack, boolean internalIDOnly) { NbtCompound ea = ItemUtils.getExtraAttributes(stack); @@ -261,7 +266,7 @@ public class PriceInfoTooltip { } case "PET" -> { if (ea.contains("petInfo")) { - JsonObject petInfo = gson.fromJson(ea.getString("petInfo"), JsonObject.class); + JsonObject petInfo = SkyblockerMod.GSON.fromJson(ea.getString("petInfo"), JsonObject.class); return "LVL_1_" + petInfo.get("tier").getAsString() + "_" + petInfo.get("type").getAsString(); } } @@ -339,86 +344,36 @@ public class PriceInfoTooltip { public static void init() { Scheduler.INSTANCE.scheduleCyclic(() -> { if (!Utils.isOnSkyblock() && 0 < minute++) { - nullMsgSend = false; + sentNullWarning = false; return; } List<CompletableFuture<Void>> futureList = new ArrayList<>(); - if (SkyblockerConfigManager.get().general.itemTooltip.enableAvgBIN) { - SkyblockerConfig.Average type = SkyblockerConfigManager.get().general.itemTooltip.avg; - - if (type == SkyblockerConfig.Average.BOTH || oneDayAvgPricesJson == null || threeDayAvgPricesJson == null || minute % 5 == 0) { - futureList.add(CompletableFuture.runAsync(() -> { - oneDayAvgPricesJson = downloadPrices("1 day avg"); - threeDayAvgPricesJson = downloadPrices("3 day avg"); - })); + + TooltipInfoType.NPC.downloadIfEnabled(futureList); + TooltipInfoType.BAZAAR.downloadIfEnabled(futureList); + TooltipInfoType.LOWEST_BINS.downloadIfEnabled(futureList); + + if (config.enableAvgBIN) { + SkyblockerConfig.Average type = config.avg; + + if (type == SkyblockerConfig.Average.BOTH || TooltipInfoType.ONE_DAY_AVERAGE.getData() == null || TooltipInfoType.THREE_DAY_AVERAGE.getData() == null || minute % 5 == 0) { + TooltipInfoType.ONE_DAY_AVERAGE.download(futureList); + TooltipInfoType.THREE_DAY_AVERAGE.download(futureList); } else if (type == SkyblockerConfig.Average.ONE_DAY) { - futureList.add(CompletableFuture.runAsync(() -> oneDayAvgPricesJson = downloadPrices("1 day avg"))); + TooltipInfoType.ONE_DAY_AVERAGE.download(futureList); } else if (type == SkyblockerConfig.Average.THREE_DAY) { - futureList.add(CompletableFuture.runAsync(() -> threeDayAvgPricesJson = downloadPrices("3 day avg"))); + TooltipInfoType.THREE_DAY_AVERAGE.download(futureList); } } - if (SkyblockerConfigManager.get().general.itemTooltip.enableLowestBIN || SkyblockerConfigManager.get().locations.dungeons.dungeonChestProfit.enableProfitCalculator) - futureList.add(CompletableFuture.runAsync(() -> lowestPricesJson = downloadPrices("lowest bins"))); - - if (SkyblockerConfigManager.get().general.itemTooltip.enableBazaarPrice || SkyblockerConfigManager.get().locations.dungeons.dungeonChestProfit.enableProfitCalculator) - futureList.add(CompletableFuture.runAsync(() -> bazaarPricesJson = downloadPrices("bazaar"))); - - if (SkyblockerConfigManager.get().general.itemTooltip.enableNPCPrice && npcPricesJson == null) - futureList.add(CompletableFuture.runAsync(() -> npcPricesJson = downloadPrices("npc"))); - - if (SkyblockerConfigManager.get().general.itemTooltip.enableMuseumDate && isMuseumJson == null) - futureList.add(CompletableFuture.runAsync(() -> isMuseumJson = downloadPrices("museum"))); - if (SkyblockerConfigManager.get().general.itemTooltip.enableMotesPrice && motesPricesJson == null) - futureList.add(CompletableFuture.runAsync(() -> motesPricesJson = downloadPrices("motes"))); + TooltipInfoType.MOTES.downloadIfEnabled(futureList); + TooltipInfoType.MUSEUM.downloadIfEnabled(futureList); + TooltipInfoType.COLOR.downloadIfEnabled(futureList); minute++; - CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])) - .whenComplete((unused, throwable) -> nullMsgSend = false); + CompletableFuture.allOf(futureList.toArray(CompletableFuture[]::new)) + .whenComplete((unused, throwable) -> sentNullWarning = false); }, 1200, true); } - - private static JsonObject downloadPrices(String type) { - try { - String url = apiAddresses.get(type); - - if (type.equals("npc") || type.equals("museum") || type.equals("motes")) { - HttpHeaders headers = Http.sendHeadRequest(url); - long combinedHash = Http.getEtag(headers).hashCode() + Http.getLastModified(headers).hashCode(); - - switch (type) { - case "npc": if (npcHash == combinedHash) return npcPricesJson; else npcHash = combinedHash; - case "museum": if (museumHash == combinedHash) return isMuseumJson; else museumHash = combinedHash; - case "motes": if (motesHash == combinedHash) return motesPricesJson; else motesHash = combinedHash; - } - } - - String apiResponse = Http.sendGetRequest(url); - - return new Gson().fromJson(apiResponse, JsonObject.class); - } catch (Exception e) { - LOGGER.warn("[Skyblocker] Failed to download " + type + " prices!", e); - return null; - } - } - - public static JsonObject getBazaarPrices() { - return bazaarPricesJson; - } - - public static JsonObject getLBINPrices() { - return lowestPricesJson; - } - - static { - apiAddresses = new HashMap<>(); - apiAddresses.put("1 day avg", "https://moulberry.codes/auction_averages_lbin/1day.json"); - apiAddresses.put("3 day avg", "https://moulberry.codes/auction_averages_lbin/3day.json"); - apiAddresses.put("bazaar", "https://hysky.de/api/bazaar"); - apiAddresses.put("lowest bins", "https://hysky.de/api/auctions/lowestbins"); - apiAddresses.put("npc", "https://hysky.de/api/npcprice"); - apiAddresses.put("museum", "https://hysky.de/api/museum"); - apiAddresses.put("motes", "https://hysky.de/api/motesprice"); - } }
\ No newline at end of file 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 new file mode 100644 index 00000000..086fcb00 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java @@ -0,0 +1,145 @@ +package de.hysky.skyblocker.skyblock.item.tooltip; + +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.utils.Http; +import de.hysky.skyblocker.utils.Utils; +import org.jetbrains.annotations.Nullable; + +import java.net.http.HttpHeaders; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; + +public enum TooltipInfoType implements Runnable { + NPC("https://hysky.de/api/npcprice", itemTooltip -> itemTooltip.enableNPCPrice, true), + BAZAAR("https://hysky.de/api/bazaar", itemTooltip -> itemTooltip.enableBazaarPrice || SkyblockerConfigManager.get().locations.dungeons.dungeonChestProfit.enableProfitCalculator, itemTooltip -> itemTooltip.enableBazaarPrice, false), + LOWEST_BINS("https://hysky.de/api/auctions/lowestbins", itemTooltip -> itemTooltip.enableLowestBIN || SkyblockerConfigManager.get().locations.dungeons.dungeonChestProfit.enableProfitCalculator, itemTooltip -> itemTooltip.enableLowestBIN, false), + 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), + COLOR("https://hysky.de/api/color", itemTooltip -> itemTooltip.enableExoticTooltip, true); + + private final String address; + private final Predicate<SkyblockerConfig.ItemTooltip> dataEnabled; + private final Predicate<SkyblockerConfig.ItemTooltip> tooltipEnabled; + private JsonObject data; + private final boolean cacheable; + private long hash; + + /** + * @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 + */ + TooltipInfoType(String address, Predicate<SkyblockerConfig.ItemTooltip> enabled, boolean cacheable) { + this(address, enabled, enabled, null, cacheable); + } + + /** + * @param address the address to download the data from + * @param dataEnabled the predicate to check if data should be downloaded + * @param tooltipEnabled the predicate to check if the tooltip should be shown + * @param cacheable whether the data should be cached + */ + TooltipInfoType(String address, Predicate<SkyblockerConfig.ItemTooltip> dataEnabled, Predicate<SkyblockerConfig.ItemTooltip> tooltipEnabled, boolean cacheable) { + this(address, dataEnabled, tooltipEnabled, null, cacheable); + } + + /** + * @param address the address to download the data from + * @param dataEnabled the predicate to check if data should be downloaded + * @param tooltipEnabled the predicate to check if the tooltip should be shown + * @param data the data + * @param cacheable whether the data should be cached + */ + TooltipInfoType(String address, Predicate<SkyblockerConfig.ItemTooltip> dataEnabled, Predicate<SkyblockerConfig.ItemTooltip> tooltipEnabled, @Nullable JsonObject data, boolean cacheable) { + this.address = address; + this.dataEnabled = dataEnabled; + this.tooltipEnabled = tooltipEnabled; + this.data = data; + this.cacheable = cacheable; + } + + /** + * @return whether the data should be downloaded + */ + private boolean isDataEnabled() { + return dataEnabled.test(ItemTooltip.config); + } + + /** + * @return whether the tooltip should be shown + */ + public boolean isTooltipEnabled() { + return tooltipEnabled.test(ItemTooltip.config); + } + + public JsonObject getData() { + return data; + } + + /** + * Checks if the data has the given member name and sends a warning message if data is null. + * + * @param memberName the member name to check + * @return whether the data has the given member name or not + */ + public boolean hasOrNullWarning(String memberName) { + if (data == null) { + ItemTooltip.nullWarning(); + return false; + } else return data.has(memberName); + } + + /** + * Checks if the tooltip is enabled and the data has the given member name and sends a warning message if data is null. + * + * @param memberName the member name to check + * @return whether the tooltip is enabled and the data has the given member name or not + */ + public boolean isTooltipEnabledAndHasOrNullWarning(String memberName) { + return isTooltipEnabled() && hasOrNullWarning(memberName); + } + + /** + * Downloads the data if it is enabled. + * + * @param futureList the list to add the future to + */ + public void downloadIfEnabled(List<CompletableFuture<Void>> futureList) { + if (isDataEnabled()) { + download(futureList); + } + } + + /** + * Downloads the data. + * + * @param futureList the list to add the future to + */ + public void download(List<CompletableFuture<Void>> futureList) { + futureList.add(CompletableFuture.runAsync(this)); + } + + /** + * Downloads the data. + */ + @Override + public void run() { + try { + if (cacheable) { + HttpHeaders headers = Http.sendHeadRequest(address); + long hash = Http.getEtag(headers).hashCode() + Http.getLastModified(headers).hashCode(); + if (this.hash == hash) return; + else this.hash = hash; + } + data = SkyblockerMod.GSON.fromJson(Http.sendGetRequest(address), JsonObject.class); + } catch (Exception e) { + ItemTooltip.LOGGER.warn("[Skyblocker] Failed to download " + this + " prices!", e); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java index afdcaca8..5570c4f7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java @@ -38,7 +38,7 @@ public class ItemListWidget extends RecipeBookWidget { this.searchField = ((RecipeBookWidgetAccessor) this).getSearchField(); int x = (this.parentWidth - 147) / 2 - this.leftOffset; int y = (this.parentHeight - 166) / 2; - if (ItemRegistry.filesImported) { + if (ItemRepository.filesImported()) { this.results = new SearchResultsWidget(this.client, x, y); this.updateSearchResult(); } @@ -57,7 +57,7 @@ public class ItemListWidget extends RecipeBookWidget { context.drawTexture(TEXTURE, i, j, 1, 1, 147, 166); this.searchField = ((RecipeBookWidgetAccessor) this).getSearchField(); - if (!ItemRegistry.filesImported && !this.searchField.isFocused() && this.searchField.getText().isEmpty()) { + if (!ItemRepository.filesImported() && !this.searchField.isFocused() && this.searchField.getText().isEmpty()) { Text hintText = (Text.literal("Loading...")).formatted(Formatting.ITALIC).formatted(Formatting.GRAY); context.drawTextWithShadow(this.client.textRenderer, hintText, i + 25, j + 14, -1); } else if (!this.searchField.isFocused() && this.searchField.getText().isEmpty()) { @@ -66,7 +66,7 @@ public class ItemListWidget extends RecipeBookWidget { } else { this.searchField.render(context, mouseX, mouseY, delta); } - if (ItemRegistry.filesImported) { + if (ItemRepository.filesImported()) { if (results == null) { int x = (this.parentWidth - 147) / 2 - this.leftOffset; int y = (this.parentHeight - 166) / 2; @@ -81,14 +81,14 @@ public class ItemListWidget extends RecipeBookWidget { @Override public void drawTooltip(DrawContext context, int x, int y, int mouseX, int mouseY) { - if (this.isOpen() && ItemRegistry.filesImported && results != null) { + if (this.isOpen() && ItemRepository.filesImported() && results != null) { this.results.drawTooltip(context, mouseX, mouseY); } } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.isOpen() && this.client.player != null && !this.client.player.isSpectator() && ItemRegistry.filesImported && this.searchField != null && results != null) { + if (this.isOpen() && this.client.player != null && !this.client.player.isSpectator() && ItemRepository.filesImported() && this.searchField != null && results != null) { if (this.searchField.mouseClicked(mouseX, mouseY, button)) { this.results.closeRecipeView(); this.searchField.setFocused(true); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRegistry.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRegistry.java deleted file mode 100644 index b958a85d..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRegistry.java +++ /dev/null @@ -1,129 +0,0 @@ -package de.hysky.skyblocker.skyblock.itemlist; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import de.hysky.skyblocker.utils.ItemUtils; -import de.hysky.skyblocker.utils.NEURepo; -import net.minecraft.client.MinecraftClient; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.text.Text; -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.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -public class ItemRegistry { - protected static final Logger LOGGER = LoggerFactory.getLogger(ItemRegistry.class); - protected static final Path ITEM_LIST_DIR = NEURepo.LOCAL_REPO_DIR.resolve("items"); - - protected static final List<ItemStack> items = new ArrayList<>(); - protected static final Map<String, ItemStack> itemsMap = new HashMap<>(); - protected static final List<SkyblockCraftingRecipe> recipes = new ArrayList<>(); - public static final MinecraftClient client = MinecraftClient.getInstance(); - public static boolean filesImported = false; - - public static void init() { - NEURepo.runAsyncAfterLoad(ItemStackBuilder::loadPetNums); - NEURepo.runAsyncAfterLoad(ItemRegistry::importItemFiles); - } - - private static void importItemFiles() { - List<JsonObject> jsonObjs = new ArrayList<>(); - - File dir = ITEM_LIST_DIR.toFile(); - File[] files = dir.listFiles(); - if (files == null) { - return; - } - for (File file : files) { - Path path = ITEM_LIST_DIR.resolve(file.getName()); - try { - String fileContent = Files.readString(path); - jsonObjs.add(JsonParser.parseString(fileContent).getAsJsonObject()); - } catch (Exception e) { - LOGGER.error("Failed to read file " + path, e); - } - } - - for (JsonObject jsonObj : jsonObjs) { - String internalName = jsonObj.get("internalname").getAsString(); - ItemStack itemStack = ItemStackBuilder.parseJsonObj(jsonObj); - items.add(itemStack); - itemsMap.put(internalName, itemStack); - } - for (JsonObject jsonObj : jsonObjs) - if (jsonObj.has("recipe")) { - recipes.add(SkyblockCraftingRecipe.fromJsonObject(jsonObj)); - } - - items.sort((lhs, rhs) -> { - String lhsInternalName = ItemUtils.getItemId(lhs); - String lhsFamilyName = lhsInternalName.replaceAll(".\\d+$", ""); - String rhsInternalName = ItemUtils.getItemId(rhs); - String rhsFamilyName = rhsInternalName.replaceAll(".\\d+$", ""); - if (lhsFamilyName.equals(rhsFamilyName)) { - if (lhsInternalName.length() != rhsInternalName.length()) - return lhsInternalName.length() - rhsInternalName.length(); - else return lhsInternalName.compareTo(rhsInternalName); - } - return lhsFamilyName.compareTo(rhsFamilyName); - }); - filesImported = true; - } - - public static String getWikiLink(String internalName) { - try { - String fileContent = Files.readString(ITEM_LIST_DIR.resolve(internalName + ".json")); - JsonObject fileJson = JsonParser.parseString(fileContent).getAsJsonObject(); - //TODO optional official or unofficial wiki link - try { - return fileJson.get("info").getAsJsonArray().get(1).getAsString(); - } catch (IndexOutOfBoundsException e) { - return fileJson.get("info").getAsJsonArray().get(0).getAsString(); - } - } catch (IOException | NullPointerException e) { - LOGGER.error("Failed to read item file " + internalName + ".json", e); - if (client.player != null) { - client.player.sendMessage(Text.of("Can't locate a wiki article for this item..."), false); - } - return null; - } - } - - public static List<SkyblockCraftingRecipe> getRecipes(String internalName) { - List<SkyblockCraftingRecipe> result = new ArrayList<>(); - for (SkyblockCraftingRecipe recipe : recipes) { - if (ItemUtils.getItemId(recipe.result).equals(internalName)) result.add(recipe); - } - for (SkyblockCraftingRecipe recipe : recipes) - for (ItemStack ingredient : recipe.grid) { - if (!ingredient.getItem().equals(Items.AIR) && ItemUtils.getItemId(ingredient).equals(internalName)) { - result.add(recipe); - break; - } - } - return result; - } - - public static Stream<SkyblockCraftingRecipe> getRecipesStream() { - return recipes.stream(); - } - - public static Stream<ItemStack> getItemsStream() { - return items.stream(); - } - - public static ItemStack getItemStack(String internalName) { - return itemsMap.get(internalName); - } -} - diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java new file mode 100644 index 00000000..bd2ac27a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemRepository.java @@ -0,0 +1,137 @@ +package de.hysky.skyblocker.skyblock.itemlist; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.NEURepoManager; +import io.github.moulberry.repo.data.NEUCraftingRecipe; +import io.github.moulberry.repo.data.NEUItem; +import io.github.moulberry.repo.data.NEURecipe; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +public class ItemRepository { + protected static final Logger LOGGER = LoggerFactory.getLogger(ItemRepository.class); + + private static final List<ItemStack> items = new ArrayList<>(); + private static final Map<String, ItemStack> itemsMap = new HashMap<>(); + private static final List<SkyblockCraftingRecipe> recipes = new ArrayList<>(); + private static boolean filesImported = false; + + public static void init() { + NEURepoManager.runAsyncAfterLoad(ItemStackBuilder::loadPetNums); + NEURepoManager.runAsyncAfterLoad(ItemRepository::importItemFiles); + } + + private static void importItemFiles() { + NEURepoManager.NEU_REPO.getItems().getItems().values().forEach(ItemRepository::loadItem); + NEURepoManager.NEU_REPO.getItems().getItems().values().forEach(ItemRepository::loadRecipes); + + items.sort((lhs, rhs) -> { + String lhsInternalName = ItemUtils.getItemId(lhs); + String lhsFamilyName = lhsInternalName.replaceAll(".\\d+$", ""); + String rhsInternalName = ItemUtils.getItemId(rhs); + String rhsFamilyName = rhsInternalName.replaceAll(".\\d+$", ""); + if (lhsFamilyName.equals(rhsFamilyName)) { + if (lhsInternalName.length() != rhsInternalName.length()) + return lhsInternalName.length() - rhsInternalName.length(); + else return lhsInternalName.compareTo(rhsInternalName); + } + return lhsFamilyName.compareTo(rhsFamilyName); + }); + filesImported = true; + } + + private static void loadItem(NEUItem item) { + ItemStack stack = ItemStackBuilder.fromNEUItem(item); + items.add(stack); + itemsMap.put(item.getSkyblockItemId(), stack); + } + + private static void loadRecipes(NEUItem item) { + for (NEURecipe recipe : item.getRecipes()) { + if (recipe instanceof NEUCraftingRecipe neuCraftingRecipe) { + recipes.add(SkyblockCraftingRecipe.fromNEURecipe(neuCraftingRecipe)); + } + } + } + + public static String getWikiLink(String internalName, PlayerEntity player) { + NEUItem item = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(internalName); + if (item == null || item.getInfo().isEmpty()) { + warnNoWikiLink(player); + return null; + } + + List<String> info = item.getInfo(); + String wikiLink0 = info.get(0); + String wikiLink1 = info.size() > 1 ? info.get(1) : ""; + String wikiDomain = SkyblockerConfigManager.get().general.wikiLookup.officialWiki ? "https://wiki.hypixel.net" : "https://hypixel-skyblock.fandom.com"; + if (wikiLink0.startsWith(wikiDomain)) { + return wikiLink0; + } else if (wikiLink1.startsWith(wikiDomain)) { + return wikiLink1; + } + warnNoWikiLink(player); + return null; + } + + private static void warnNoWikiLink(PlayerEntity player) { + if (player != null) { + player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.wikiLookup.noArticleFound")), false); + } + } + + public static List<SkyblockCraftingRecipe> getRecipes(String internalName) { + List<SkyblockCraftingRecipe> result = new ArrayList<>(); + for (SkyblockCraftingRecipe recipe : recipes) { + if (ItemUtils.getItemId(recipe.getResult()).equals(internalName)) result.add(recipe); + } + for (SkyblockCraftingRecipe recipe : recipes) { + for (ItemStack ingredient : recipe.getGrid()) { + if (!ingredient.getItem().equals(Items.AIR) && ItemUtils.getItemId(ingredient).equals(internalName)) { + result.add(recipe); + break; + } + } + } + return result; + } + + public static boolean filesImported() { + return filesImported; + } + + public static void setFilesImported(boolean filesImported) { + ItemRepository.filesImported = filesImported; + } + + public static List<ItemStack> getItems() { + return items; + } + + public static Stream<ItemStack> getItemsStream() { + return items.stream(); + } + + @Nullable + public static ItemStack getItemStack(String internalName) { + return itemsMap.get(internalName); + } + + public static Stream<SkyblockCraftingRecipe> getRecipesStream() { + return recipes.stream(); + } +} + diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java index 34e4a0e7..cc7c0bc1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java @@ -1,45 +1,41 @@ package de.hysky.skyblocker.skyblock.itemlist; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import de.hysky.skyblocker.utils.ItemUtils; -import de.hysky.skyblocker.utils.NEURepo; +import de.hysky.skyblocker.utils.NEURepoManager; +import io.github.moulberry.repo.constants.PetNumbers; +import io.github.moulberry.repo.data.NEUItem; +import io.github.moulberry.repo.data.Rarity; import net.minecraft.item.FireworkRocketItem; import net.minecraft.item.ItemStack; import net.minecraft.nbt.*; import net.minecraft.text.Text; import net.minecraft.util.Pair; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ItemStackBuilder { - private final static Path PETNUMS_PATH = NEURepo.LOCAL_REPO_DIR.resolve("constants/petnums.json"); - private static JsonObject petNums; + private static Map<String, Map<Rarity, PetNumbers>> petNums; public static void loadPetNums() { try { - petNums = JsonParser.parseString(Files.readString(PETNUMS_PATH)).getAsJsonObject(); + petNums = NEURepoManager.NEU_REPO.getConstants().getPetNumbers(); } catch (Exception e) { - ItemRegistry.LOGGER.error("Failed to load petnums.json"); + ItemRepository.LOGGER.error("Failed to load petnums.json"); } } - public static ItemStack parseJsonObj(JsonObject obj) { - String internalName = obj.get("internalname").getAsString(); + public static ItemStack fromNEUItem(NEUItem item) { + String internalName = item.getSkyblockItemId(); List<Pair<String, String>> injectors = new ArrayList<>(petData(internalName)); NbtCompound root = new NbtCompound(); - root.put("Count", NbtByte.of((byte)1)); + root.put("Count", NbtByte.of((byte) 1)); - String id = obj.get("itemid").getAsString(); - int damage = obj.get("damage").getAsInt(); + String id = item.getMinecraftItemId(); + int damage = item.getDamage(); root.put("id", NbtString.of(ItemFixerUpper.convertItemId(id, damage))); NbtCompound tag = new NbtCompound(); @@ -52,16 +48,14 @@ public class ItemStackBuilder { NbtCompound display = new NbtCompound(); tag.put("display", display); - String name = injectData(obj.get("displayname").getAsString(), injectors); + String name = injectData(item.getDisplayName(), injectors); display.put("Name", NbtString.of(Text.Serializer.toJson(Text.of(name)))); NbtList lore = new NbtList(); display.put("Lore", lore); - obj.get("lore").getAsJsonArray().forEach(el -> - lore.add(NbtString.of(Text.Serializer.toJson(Text.of(injectData(el.getAsString(), injectors))))) - ); + item.getLore().forEach(el -> lore.add(NbtString.of(Text.Serializer.toJson(Text.of(injectData(el, injectors)))))); - String nbttag = obj.get("nbttag").getAsString(); + String nbttag = item.getNbttag(); // add skull texture Matcher skullUuid = Pattern.compile("(?<=SkullOwner:\\{)Id:\"(.{36})\"").matcher(nbttag); Matcher skullTexture = Pattern.compile("(?<=Properties:\\{textures:\\[0:\\{Value:)\"(.+?)\"").matcher(nbttag); @@ -94,53 +88,54 @@ public class ItemStackBuilder { } // Add firework star color - Matcher explosionColorMatcher = Pattern.compile("\\{Explosion:\\{(?:Type:[0-9a-z]+,)?Colors:\\[(?<color>[0-9]+)\\]\\}").matcher(nbttag); + Matcher explosionColorMatcher = Pattern.compile("\\{Explosion:\\{(?:Type:[0-9a-z]+,)?Colors:\\[(?<color>[0-9]+)]\\}").matcher(nbttag); if (explosionColorMatcher.find()) { NbtCompound explosion = new NbtCompound(); explosion.putInt("Type", FireworkRocketItem.Type.SMALL_BALL.getId()); //Forget about the actual ball type because it probably doesn't matter - explosion.putIntArray("Colors", new int[] { Integer.parseInt(explosionColorMatcher.group("color")) }); + explosion.putIntArray("Colors", new int[]{Integer.parseInt(explosionColorMatcher.group("color"))}); tag.put("Explosion", explosion); } return ItemStack.fromNbt(root); } - // TODO: fix stats for GOLDEN_DRAGON (lv1 -> lv200) private static List<Pair<String, String>> petData(String internalName) { List<Pair<String, String>> list = new ArrayList<>(); String petName = internalName.split(";")[0]; - if (!internalName.contains(";") || !petNums.has(petName)) return list; - - list.add(new Pair<>("\\{LVL\\}", "1 ➡ 100")); - - final String[] rarities = { - "COMMON", - "UNCOMMON", - "RARE", - "EPIC", - "LEGENDARY", - "MYTHIC" + if (!internalName.contains(";") || !petNums.containsKey(petName)) return list; + + final Rarity[] rarities = { + Rarity.COMMON, + Rarity.UNCOMMON, + Rarity.RARE, + Rarity.EPIC, + Rarity.LEGENDARY, + Rarity.MYTHIC, }; - String rarity = rarities[Integer.parseInt(internalName.split(";")[1])]; - JsonObject data = petNums.get(petName).getAsJsonObject().get(rarity).getAsJsonObject(); + Rarity rarity = rarities[Integer.parseInt(internalName.split(";")[1])]; + PetNumbers data = petNums.get(petName).get(rarity); - JsonObject statNumsMin = data.get("1").getAsJsonObject().get("statNums").getAsJsonObject(); - JsonObject statNumsMax = data.get("100").getAsJsonObject().get("statNums").getAsJsonObject(); - Set<Map.Entry<String, JsonElement>> entrySet = statNumsMin.entrySet(); - for (Map.Entry<String, JsonElement> entry : entrySet) { + int minLevel = data.getLowLevel(); + int maxLevel = data.getHighLevel(); + list.add(new Pair<>("\\{LVL\\}", minLevel + " ➡ " + maxLevel)); + + Map<String, Double> statNumsMin = data.getStatsAtLowLevel().getStatNumbers(); + Map<String, Double> statNumsMax = data.getStatsAtHighLevel().getStatNumbers(); + Set<Map.Entry<String, Double>> entrySet = statNumsMin.entrySet(); + for (Map.Entry<String, Double> entry : entrySet) { String key = entry.getKey(); - String left = "\\{" + key+ "\\}"; - String right = statNumsMin.get(key).getAsString() + " ➡ " + statNumsMax.get(key).getAsString(); + String left = "\\{" + key + "\\}"; + String right = statNumsMin.get(key) + " ➡ " + statNumsMax.get(key); list.add(new Pair<>(left, right)); } - JsonArray otherNumsMin = data.get("1").getAsJsonObject().get("otherNums").getAsJsonArray(); - JsonArray otherNumsMax = data.get("100").getAsJsonObject().get("otherNums").getAsJsonArray(); + List<Double> otherNumsMin = data.getStatsAtLowLevel().getOtherNumbers(); + List<Double> otherNumsMax = data.getStatsAtHighLevel().getOtherNumbers(); for (int i = 0; i < otherNumsMin.size(); ++i) { String left = "\\{" + i + "\\}"; - String right = otherNumsMin.get(i).getAsString() + " ➡ " + otherNumsMax.get(i).getAsString(); + String right = otherNumsMin.get(i) + " ➡ " + otherNumsMax.get(i); list.add(new Pair<>(left, right)); } @@ -148,8 +143,9 @@ public class ItemStackBuilder { } private static String injectData(String string, List<Pair<String, String>> injectors) { - for (Pair<String, String> injector : injectors) + for (Pair<String, String> injector : injectors) { string = string.replaceAll(injector.getLeft(), injector.getRight()); + } return string; } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java index 8a266d65..44e336d9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java @@ -72,7 +72,7 @@ public class SearchResultsWidget implements Drawable { if (!searchText.equals(this.searchText)) { this.searchText = searchText; this.searchResults.clear(); - for (ItemStack entry : ItemRegistry.items) { + for (ItemStack entry : ItemRepository.getItems()) { String name = entry.getName().toString().toLowerCase(Locale.ENGLISH); if (entry.getNbt() == null) { continue; @@ -93,16 +93,16 @@ public class SearchResultsWidget implements Drawable { SkyblockCraftingRecipe recipe = this.recipeResults.get(this.currentPage); for (ResultButtonWidget button : resultButtons) button.clearItemStack(); - resultButtons.get(5).setItemStack(recipe.grid.get(0)); - resultButtons.get(6).setItemStack(recipe.grid.get(1)); - resultButtons.get(7).setItemStack(recipe.grid.get(2)); - resultButtons.get(10).setItemStack(recipe.grid.get(3)); - resultButtons.get(11).setItemStack(recipe.grid.get(4)); - resultButtons.get(12).setItemStack(recipe.grid.get(5)); - resultButtons.get(15).setItemStack(recipe.grid.get(6)); - resultButtons.get(16).setItemStack(recipe.grid.get(7)); - resultButtons.get(17).setItemStack(recipe.grid.get(8)); - resultButtons.get(14).setItemStack(recipe.result); + resultButtons.get(5).setItemStack(recipe.getGrid().get(0)); + resultButtons.get(6).setItemStack(recipe.getGrid().get(1)); + resultButtons.get(7).setItemStack(recipe.getGrid().get(2)); + resultButtons.get(10).setItemStack(recipe.getGrid().get(3)); + resultButtons.get(11).setItemStack(recipe.getGrid().get(4)); + resultButtons.get(12).setItemStack(recipe.getGrid().get(5)); + resultButtons.get(15).setItemStack(recipe.getGrid().get(6)); + resultButtons.get(16).setItemStack(recipe.getGrid().get(7)); + resultButtons.get(17).setItemStack(recipe.getGrid().get(8)); + resultButtons.get(14).setItemStack(recipe.getResult()); } else { for (int i = 0; i < resultButtons.size(); ++i) { int index = this.currentPage * resultButtons.size() + i; @@ -122,7 +122,7 @@ public class SearchResultsWidget implements Drawable { RenderSystem.disableDepthTest(); if (this.displayRecipes) { //Craft text - usually a requirement for the recipe - String craftText = this.recipeResults.get(this.currentPage).craftText; + String craftText = this.recipeResults.get(this.currentPage).getCraftText(); if (textRenderer.getWidth(craftText) > MAX_TEXT_WIDTH) { drawTooltip(textRenderer, context, craftText, this.parentX + 11, this.parentY + 31, mouseX, mouseY); craftText = textRenderer.trimToWidth(craftText, MAX_TEXT_WIDTH) + ELLIPSIS; @@ -130,7 +130,7 @@ public class SearchResultsWidget implements Drawable { context.drawTextWithShadow(textRenderer, craftText, this.parentX + 11, this.parentY + 31, 0xffffffff); //Item name - Text resultText = this.recipeResults.get(this.currentPage).result.getName(); + Text resultText = this.recipeResults.get(this.currentPage).getResult().getName(); if (textRenderer.getWidth(Formatting.strip(resultText.getString())) > MAX_TEXT_WIDTH) { drawTooltip(textRenderer, context, resultText, this.parentX + 11, this.parentY + 43, mouseX, mouseY); resultText = Text.literal(getLegacyFormatting(resultText.getString()) + textRenderer.trimToWidth(Formatting.strip(resultText.getString()), MAX_TEXT_WIDTH) + ELLIPSIS).setStyle(resultText.getStyle()); @@ -202,7 +202,7 @@ public class SearchResultsWidget implements Drawable { if (internalName.isEmpty()) { continue; } - List<SkyblockCraftingRecipe> recipes = ItemRegistry.getRecipes(internalName); + List<SkyblockCraftingRecipe> recipes = ItemRepository.getRecipes(internalName); if (!recipes.isEmpty()) { this.recipeResults = recipes; this.currentPage = 0; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SkyblockCraftingRecipe.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SkyblockCraftingRecipe.java index b738dfef..f5b379dc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SkyblockCraftingRecipe.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SkyblockCraftingRecipe.java @@ -1,6 +1,7 @@ package de.hysky.skyblocker.skyblock.itemlist; -import com.google.gson.JsonObject; +import io.github.moulberry.repo.data.NEUCraftingRecipe; +import io.github.moulberry.repo.data.NEUIngredient; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import org.slf4j.Logger; @@ -11,37 +12,31 @@ import java.util.List; public class SkyblockCraftingRecipe { private static final Logger LOGGER = LoggerFactory.getLogger(SkyblockCraftingRecipe.class); - String craftText = ""; - final List<ItemStack> grid = new ArrayList<>(9); - ItemStack result; - - public static SkyblockCraftingRecipe fromJsonObject(JsonObject jsonObj) { - SkyblockCraftingRecipe recipe = new SkyblockCraftingRecipe(); - if (jsonObj.has("crafttext")) recipe.craftText = jsonObj.get("crafttext").getAsString(); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("A1").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("A2").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("A3").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("B1").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("B2").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("B3").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("C1").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("C2").getAsString())); - recipe.grid.add(getItemStack(jsonObj.getAsJsonObject("recipe").get("C3").getAsString())); - recipe.result = ItemRegistry.itemsMap.get(jsonObj.get("internalname").getAsString()); + private final String craftText; + private final List<ItemStack> grid = new ArrayList<>(9); + private ItemStack result; + + public SkyblockCraftingRecipe(String craftText) { + this.craftText = craftText; + } + + public static SkyblockCraftingRecipe fromNEURecipe(NEUCraftingRecipe neuCraftingRecipe) { + SkyblockCraftingRecipe recipe = new SkyblockCraftingRecipe(neuCraftingRecipe.getExtraText() != null ? neuCraftingRecipe.getExtraText() : ""); + for (NEUIngredient input : neuCraftingRecipe.getInputs()) { + recipe.grid.add(getItemStack(input)); + } + recipe.result = getItemStack(neuCraftingRecipe.getOutput()); return recipe; } - private static ItemStack getItemStack(String internalName) { - try { - if (internalName.length() > 0) { - int count = internalName.split(":").length == 1 ? 1 : Integer.parseInt(internalName.split(":")[1]); - internalName = internalName.split(":")[0]; - ItemStack itemStack = ItemRegistry.itemsMap.get(internalName).copy(); - itemStack.setCount(count); - return itemStack; + private static ItemStack getItemStack(NEUIngredient input) { + if (input != NEUIngredient.SENTINEL_EMPTY) { + ItemStack stack = ItemRepository.getItemStack(input.getItemId()); + if (stack != null) { + return stack.copyWithCount((int) input.getAmount()); + } else { + LOGGER.warn("[Skyblocker Recipe] Unable to find item {}", input.getItemId()); } - } catch (Exception e) { - LOGGER.error("[Skyblocker-Recipe] " + internalName, e); } return Items.AIR.getDefaultStack(); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java new file mode 100644 index 00000000..744edd4c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -0,0 +1,183 @@ +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 net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.text.Text; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; + +public class EnigmaSouls { + private static final Logger LOGGER = LoggerFactory.getLogger(EnigmaSouls.class); + 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 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(); + + private static CompletableFuture<Void> soulsLoaded; + + static void load(MinecraftClient client) { + //Load waypoints + soulsLoaded = CompletableFuture.runAsync(() -> { + try (BufferedReader reader = client.getResourceManager().openAsReader(WAYPOINTS_JSON)) { + JsonObject file = JsonParser.parseReader(reader).getAsJsonObject(); + JsonArray waypoints = file.get("waypoints").getAsJsonArray(); + + 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()); + } + + } catch (IOException e) { + LOGGER.error("[Skyblocker] There was an error while loading enigma soul waypoints!", e); + } + + //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())); + } + + FOUND_SOULS.put(profile.getKey(), foundSoulsOnProfile); + } + } catch (NoSuchFileException ignored) { + } catch (IOException e) { + LOGGER.error("[Skyblocker] There was an error while loading found enigma souls!", e); + } + }); + } + + static void save(MinecraftClient client) { + JsonObject json = new JsonObject(); + + for (Map.Entry<String, ObjectOpenHashSet<BlockPos>> foundSoulsForProfile : FOUND_SOULS.entrySet()) { + JsonArray foundSoulsJson = new JsonArray(); + + for (BlockPos foundSoul : foundSoulsForProfile.getValue()) { + foundSoulsJson.add(PosUtils.getPosString(foundSoul)); + } + + json.add(foundSoulsForProfile.getKey(), foundSoulsJson); + } + + try (BufferedWriter writer = Files.newBufferedWriter(FOUND_SOULS_FILE)) { + SkyblockerMod.GSON.toJson(json, writer); + } catch (IOException e) { + LOGGER.error("[Skyblocker] There was an error while saving found enigma souls!", e); + } + } + + static void render(WorldRenderContext wrc) { + 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); + } else if (config.highlightFoundEnigmaSouls) { + RenderHelper.renderFilledThroughWallsWithBeaconBeam(wrc, pos, RED, 0.5f); + } + } + } + } + + static void onMessage(Text text, boolean overlay) { + 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(); + } + } + + static void registerCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(literal(SkyblockerMod.NAMESPACE) + .then(literal("rift") + .then(literal("enigmaSouls") + .then(literal("markAllFound").executes(context -> { + markAllFound(); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.rift.enigmaSouls.markAllFound"))); + + return Command.SINGLE_SUCCESS; + })) + .then(literal("markAllMissing").executes(context -> { + markAllMissing(); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.rift.enigmaSouls.markAllMissing"))); + + return Command.SINGLE_SUCCESS; + }))))); + } + + private static void markClosestSoulAsFound() { + ClientPlayerEntity player = MinecraftClient.getInstance().player; + + 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(); + } +} 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 06181349..7dda741f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/MirrorverseWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/MirrorverseWaypoints.java @@ -17,61 +17,59 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; +import java.util.concurrent.CompletableFuture; public class MirrorverseWaypoints { private static final Logger LOGGER = LoggerFactory.getLogger("skyblocker"); - private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); - private static final Identifier WAYPOINTS_JSON = new Identifier(SkyblockerMod.NAMESPACE, "mirrorverse_waypoints.json"); + 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 final float[] COLOR_COMPONENTS = DyeColor.RED.getColorComponents(); - static { - loadWaypoints(); - } + private static CompletableFuture<Void> waypointsLoaded; /** * Loads the waypoint locations into memory */ - private static void loadWaypoints() { - try (BufferedReader reader = CLIENT.getResourceManager().openAsReader(WAYPOINTS_JSON)) { - JsonObject file = JsonParser.parseReader(reader).getAsJsonObject(); - JsonArray sections = file.get("sections").getAsJsonArray(); + 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(); - /// Lava Path - JsonArray lavaPathWaypoints = sections.get(0).getAsJsonObject().get("waypoints").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()); - } + 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()); + } - /// Upside Down Parkour - JsonArray upsideDownParkourWaypoints = sections.get(1).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()); - } + 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()); + } - /// Turbulator Parkour - JsonArray turbulatorParkourWaypoints = sections.get(2).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()); + 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()); + } + } catch (IOException e) { + LOGGER.error("[Skyblocker] Mirrorverse Waypoints failed to load ;(", e); } - - } catch (IOException e) { - LOGGER.info("[Skyblocker] Mirrorverse Waypoints failed to load ;("); - e.printStackTrace(); - } + }); } 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) { + if (Utils.isInTheRift() && SkyblockerConfigManager.get().locations.rift.mirrorverseWaypoints && waypointsLoaded.isDone()) { for (BlockPos pos : LAVA_PATH_WAYPOINTS) { RenderHelper.renderFilledIfVisible(wrc, pos, COLOR_COMPONENTS, 0.5f); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java index b39151d3..02b694b6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java @@ -2,6 +2,9 @@ package de.hysky.skyblocker.skyblock.rift; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; public class TheRift { @@ -13,6 +16,12 @@ public class TheRift { public static void init() { WorldRenderEvents.AFTER_TRANSLUCENT.register(MirrorverseWaypoints::render); WorldRenderEvents.AFTER_TRANSLUCENT.register(EffigyWaypoints::render); + WorldRenderEvents.AFTER_TRANSLUCENT.register(EnigmaSouls::render); + ClientLifecycleEvents.CLIENT_STARTED.register(MirrorverseWaypoints::load); + ClientLifecycleEvents.CLIENT_STARTED.register(EnigmaSouls::load); + ClientLifecycleEvents.CLIENT_STOPPING.register(EnigmaSouls::save); + ClientReceiveMessageEvents.GAME.register(EnigmaSouls::onMessage); + ClientCommandRegistrationCallback.EVENT.register(EnigmaSouls::registerCommands); Scheduler.INSTANCE.scheduleCyclic(EffigyWaypoints::updateEffigies, SkyblockerConfigManager.get().slayer.vampireSlayer.effigyUpdateFrequency); Scheduler.INSTANCE.scheduleCyclic(TwinClawsIndicator::updateIce, SkyblockerConfigManager.get().slayer.vampireSlayer.holyIceUpdateFrequency); Scheduler.INSTANCE.scheduleCyclic(ManiaIndicator::updateMania, SkyblockerConfigManager.get().slayer.vampireSlayer.maniaUpdateFrequency); 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 e5223874..aaf4d77c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/spidersden/Relics.java @@ -8,6 +8,7 @@ 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; @@ -105,12 +106,12 @@ public class Relics { .then(literal("relics") .then(literal("markAllFound").executes(context -> { Relics.markAllFound(); - context.getSource().sendFeedback(Text.translatable("skyblocker.relics.markAllFound")); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.relics.markAllFound"))); return 1; })) .then(literal("markAllMissing").executes(context -> { Relics.markAllMissing(); - context.getSource().sendFeedback(Text.translatable("skyblocker.relics.markAllMissing")); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.relics.markAllMissing"))); return 1; })))); } 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/GardenSkillsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/GardenSkillsWidget.java index e7058fd6..41eee8d6 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 @@ -24,9 +24,11 @@ public class GardenSkillsWidget extends Widget { // group 1: skill name and level // group 2: progress to next level (without "%") private static final Pattern SKILL_PATTERN = Pattern - .compile("\\S*: (?<skill>[A-Za-z]* [0-9]*): (?<progress>\\S*)%"); - // same, but with leading space - private static final Pattern MS_PATTERN = Pattern.compile("\\S*: (?<skill>[A-Za-z]* [0-9]*): (?<progress>\\S*)%"); + .compile("Skills: (?<skill>[A-Za-z]* [0-9]*): (?<progress>[0-9.MAX]*)%?"); + + // same, more or less + private static final Pattern MS_PATTERN = Pattern + .compile("Milestone: (?<milestone>[A-Za-z ]* [0-9]*): (?<progress>[0-9.]*)%"); public GardenSkillsWidget() { super(TITLE, Formatting.YELLOW.getColorValue()); @@ -43,9 +45,14 @@ public class GardenSkillsWidget extends Widget { String strpcnt = m.group("progress"); String skill = m.group("skill"); - float pcnt = Float.parseFloat(strpcnt); - pc = new ProgressComponent(Ico.LANTERN, Text.of(skill), pcnt, - Formatting.GOLD.getColorValue()); + if (strpcnt.equals("MAX")) { + pc = 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, + Formatting.GOLD.getColorValue()); + } } this.addComponent(pc); @@ -66,10 +73,10 @@ public class GardenSkillsWidget extends Widget { pc2 = new ProgressComponent(); } else { String strpcnt = m.group("progress"); - String skill = m.group("skill"); + String milestone = m.group("milestone"); float pcnt = Float.parseFloat(strpcnt); - pc2 = new ProgressComponent(Ico.MILESTONE, Text.of(skill), pcnt, + pc2 = new ProgressComponent(Ico.MILESTONE, Text.of(milestone), pcnt, Formatting.GREEN.getColorValue()); } 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..c0648eba --- /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 fbeb448c..94eacf49 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Constants.java +++ b/src/main/java/de/hysky/skyblocker/utils/Constants.java @@ -1,8 +1,56 @@ package de.hysky.skyblocker.utils; +import java.util.List; +import java.util.function.IntFunction; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +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"; + IntFunction<UnaryOperator<Style>> WITH_COLOR = color -> style -> style.withColor(color); + Supplier<MutableText> PREFIX = () -> Text.empty() + .append(Text.literal("[").formatted(Formatting.GRAY)) + .append(Text.literal("S").styled(WITH_COLOR.apply(0x00ff4c))) + .append(Text.literal("k").styled(WITH_COLOR.apply(0x02fa60))) + .append(Text.literal("y").styled(WITH_COLOR.apply(0x04f574))) + .append(Text.literal("b").styled(WITH_COLOR.apply(0x07ef88))) + .append(Text.literal("l").styled(WITH_COLOR.apply(0x09ea9c))) + .append(Text.literal("o").styled(WITH_COLOR.apply(0x0be5af))) + .append(Text.literal("c").styled(WITH_COLOR.apply(0x0de0c3))) + .append(Text.literal("k").styled(WITH_COLOR.apply(0x10dad7))) + .append(Text.literal("e").styled(WITH_COLOR.apply(0x12d5eb))) + .append(Text.literal("r").styled(WITH_COLOR.apply(0x14d0ff))) + .append(Text.literal("] ").formatted(Formatting.GRAY)); + + + List<String> SEYMOUR_IDS = List.of("VELVET_TOP_HAT", "CASHMERE_JACKET", "SATIN_TROUSERS", "OXFORD_SHOES"); + + // Exotic Hexes + List<String> CRYSTAL_HEXES = List.of("1F0030", "46085E", "54146E", "5D1C78", "63237D", "6A2C82", "7E4196", "8E51A6", "9C64B3", "A875BD", + "B88BC9", "C6A3D4", "D9C1E3", "E5D1ED", "EFE1F5", "FCF3FF"); + List<String> FAIRY_HEXES = List.of("330066", "4C0099", "660033", "660066", "6600CC", "7F00FF", "99004C", "990099", "9933FF", "B266FF", + "CC0066", "CC00CC", "CC99FF", "E5CCFF", "FF007F", "FF00FF", "FF3399", "FF33FF", "FF66B2", "FF66FF", "FF99CC", "FF99FF", "FFCCE5", + "FFCCFF"); + List<String> OG_FAIRY_HEXES = List.of("FF99FF", "FFCCFF", "E5CCFF", "CC99FF", "CC00CC", "FF00FF", "FF33FF", "FF66FF", + "B266FF", "9933FF", "7F00FF", "660066", "6600CC", "4C0099", "330066", "990099", "660033", "99004C", "CC0066", + "660033", "99004C", "FFCCE5", "660033", "FFCCE5", "FF99CC", "FFCCE5", "FF99CC", "FF66B2"); + List<String> GLITCHED = List.of("FFDC51", "F7DA33", "606060", "E7413C", "45413C", "4A14B7", "1793C4", "000000", "E75C3C", "65605A", + "5D2FB9", "17A8C4", "E76E3C", "88837E", "8969C8", "1CD4E4"); // Glitched through other means such as Shark Scale upgrade color + List<String> SPOOK = List.of("000000", "070008", "0E000F", "150017", "1B001F", "220027", "29002E", "300036", "37003E", "3E0046", + "45004D", "4C0055", "52005D", "590065", "60006C", "670074", "6E007C", "750084", "7C008B", "830093", + "89009B", "9000A3", "9700AA", "993399", "9E00B2"); + + // List of exceptions + List<String> RANCHERS = List.of("CC5500", "000000", "0"); + List<String> REAPER = List.of("1B1B1B", "FF0000"); + List<String> ADAPTIVE_CHEST = List.of("3ABE78", "82E3D8", "BFBCB2", "D579FF", "FF4242", "FFC234"); + List<String> ADAPTIVE = List.of("169F57", "2AB5A5", "6E00A0", "BB0000", "BFBCB2", "FFF7E6"); } diff --git a/src/main/java/de/hysky/skyblocker/utils/Http.java b/src/main/java/de/hysky/skyblocker/utils/Http.java index e0b9ecf8..4c8a3ada 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Http.java +++ b/src/main/java/de/hysky/skyblocker/utils/Http.java @@ -5,6 +5,7 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.net.URI; import java.net.http.HttpClient; +import java.net.http.HttpClient.Redirect; import java.net.http.HttpClient.Version; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; @@ -15,6 +16,8 @@ import java.time.Duration; import java.util.zip.GZIPInputStream; import java.util.zip.InflaterInputStream; +import org.jetbrains.annotations.NotNull; + import de.hysky.skyblocker.SkyblockerMod; import net.minecraft.SharedConstants; @@ -22,12 +25,19 @@ import net.minecraft.SharedConstants; * @implNote All http requests are sent using HTTP 2 */ 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 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() .header("Accept", "application/json") @@ -39,9 +49,11 @@ public class Http { HttpResponse<InputStream> response = HTTP_CLIENT.send(request, BodyHandlers.ofInputStream()); InputStream decodedInputStream = getDecodedInputStream(response); + String body = new String(decodedInputStream.readAllBytes()); + HttpHeaders headers = response.headers(); - return body; + return new ApiResponse(body, response.statusCode(), getCacheStatus(headers), getAge(headers)); } public static HttpHeaders sendHeadRequest(String url) throws IOException, InterruptedException { @@ -52,13 +64,26 @@ public class Http { .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(); } - private static InputStream getDecodedInputStream(HttpResponse<InputStream> response) { - String encoding = getContentEncoding(response); + 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 + */ + 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 "": @@ -75,8 +100,8 @@ public class Http { } } - private static String getContentEncoding(HttpResponse<InputStream> response) { - return response.headers().firstValue("Content-Encoding").orElse(""); + private static String getContentEncoding(HttpHeaders headers) { + return headers.firstValue("Content-Encoding").orElse(""); } public static String getEtag(HttpHeaders headers) { @@ -86,4 +111,35 @@ public class Http { 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> + */ + 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"); + } + + @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/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index fa04acf8..ed46677d 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.utils; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import de.hysky.skyblocker.config.SkyblockerConfigManager; +import it.unimi.dsi.fastutil.ints.IntIntPair; import net.minecraft.client.MinecraftClient; import net.minecraft.client.item.TooltipContext; import net.minecraft.item.ItemStack; @@ -12,34 +12,34 @@ import net.minecraft.util.Formatting; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import java.util.regex.Pattern; public class ItemUtils { - private final static Pattern WHITESPACES = Pattern.compile("^\\s*$"); public static final String EXTRA_ATTRIBUTES = "ExtraAttributes"; public static final String ID = "id"; public static final String UUID = "uuid"; + public static final Pattern NOT_DURABILITY = Pattern.compile("[^0-9 /]"); + public static final Predicate<String> FUEL_PREDICATE = line -> line.contains("Fuel: "); - public static List<Text> getTooltip(ItemStack item) { + public static List<Text> getTooltips(ItemStack item) { MinecraftClient client = MinecraftClient.getInstance(); return client.player == null || item == null ? Collections.emptyList() : item.getTooltip(client.player, TooltipContext.Default.BASIC); } - public static List<String> getTooltipStrings(ItemStack item) { - List<Text> lines = getTooltip(item); - List<String> list = new ArrayList<>(); - - for (Text line : lines) { + @Nullable + public static String getTooltip(ItemStack item, Predicate<String> predicate) { + for (Text line : getTooltips(item)) { String string = line.getString(); - if (!WHITESPACES.matcher(string).matches()) - list.add(string); + if (predicate.test(string)) { + return string; + } } - return list; + return null; } /** @@ -98,49 +98,35 @@ public class ItemUtils { * Gets the UUID of the item stack from the {@code ExtraAttributes} NBT tag. * * @param stack the item stack to get the UUID from - * @return the UUID of the item stack, or null if the item stack is null or does not have a UUID + * @return the UUID of the item stack, or an empty string if the item stack is null or does not have a UUID */ public static String getItemUuid(@NotNull ItemStack stack) { NbtCompound extraAttributes = getExtraAttributes(stack); return extraAttributes != null ? extraAttributes.getString(UUID) : ""; } + public static boolean hasCustomDurability(@NotNull ItemStack stack) { + NbtCompound extraAttributes = getExtraAttributes(stack); + return extraAttributes != null && (extraAttributes.contains("drill_fuel") || extraAttributes.getString(ID).equals("PICKONIMBUS")); + } + @Nullable - public static Durability getDurability(@NotNull ItemStack stack) { - if (!Utils.isOnSkyblock() || !SkyblockerConfigManager.get().locations.dwarvenMines.enableDrillFuel || stack.isEmpty()) { - return null; - } + public static IntIntPair getDurability(@NotNull ItemStack stack) { + NbtCompound extraAttributes = getExtraAttributes(stack); + if (extraAttributes == null) return null; + + // TODO Calculate drill durability based on the drill_fuel flag, fuel_tank flag, and hotm level + // TODO Cache the max durability and only update the current durability on inventory tick - if (getExtraAttributesOptional(stack).filter(extraAttributes -> extraAttributes.contains("drill_fuel") || extraAttributes.getString(ItemUtils.ID).equals("PICKONIMBUS")).isEmpty()) { - return null; + int pickonimbusDurability = extraAttributes.getInt("pickonimbus_durability"); + if (pickonimbusDurability > 0) { + return IntIntPair.of(pickonimbusDurability, 5000); } - int current = 0; - int max = 0; - String clearFormatting; - - for (String line : ItemUtils.getTooltipStrings(stack)) { - clearFormatting = Formatting.strip(line); - if (line.contains("Fuel: ")) { - if (clearFormatting != null) { - String clear = Pattern.compile("[^0-9 /]").matcher(clearFormatting).replaceAll("").trim(); - String[] split = clear.split("/"); - current = Integer.parseInt(split[0]); - max = Integer.parseInt(split[1]) * 1000; - return new Durability(current, max); - } - } else if (line.contains("uses.")) { - if (clearFormatting != null) { - int startIndex = clearFormatting.lastIndexOf("after") + 6; - int endIndex = clearFormatting.indexOf("uses", startIndex); - if (startIndex >= 0 && endIndex > startIndex) { - String usesString = clearFormatting.substring(startIndex, endIndex).trim(); - current = Integer.parseInt(usesString); - max = 5000; - } - return new Durability(current, max); - } - } + String drillFuel = Formatting.strip(getTooltip(stack, FUEL_PREDICATE)); + if (drillFuel != null) { + String[] drillFuelStrings = NOT_DURABILITY.matcher(drillFuel).replaceAll("").trim().split("/"); + return IntIntPair.of(Integer.parseInt(drillFuelStrings[0]), Integer.parseInt(drillFuelStrings[1]) * 1000); } return null; @@ -153,7 +139,4 @@ public class ItemUtils { throw new RuntimeException(e); } } - - public record Durability(int current, int max) { - } } diff --git a/src/main/java/de/hysky/skyblocker/utils/NEURepo.java b/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java index 9bc6b245..6d78b3f3 100644 --- a/src/main/java/de/hysky/skyblocker/utils/NEURepo.java +++ b/src/main/java/de/hysky/skyblocker/utils/NEURepoManager.java @@ -1,7 +1,8 @@ package de.hysky.skyblocker.utils; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; +import io.github.moulberry.repo.NEURepository; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.minecraft.client.MinecraftClient; @@ -21,11 +22,15 @@ import java.util.concurrent.CompletableFuture; /** * 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. */ -public class NEURepo { - private static final Logger LOGGER = LoggerFactory.getLogger(NEURepo.class); +public class NEURepoManager { + private static final Logger LOGGER = LoggerFactory.getLogger(NEURepoManager.class); public static final String REMOTE_REPO_URL = "https://github.com/NotEnoughUpdates/NotEnoughUpdates-REPO.git"; - public static final Path LOCAL_REPO_DIR = SkyblockerMod.CONFIG_DIR.resolve("item-repo"); - private static final CompletableFuture<Void> REPO_INITIALIZED = initRepository(); + /** + * Use {@link #NEU_REPO}. + */ + private static final Path LOCAL_REPO_DIR = SkyblockerMod.CONFIG_DIR.resolve("item-repo"); // TODO rename to NotEnoughUpdates-REPO + private static final CompletableFuture<Void> REPO_INITIALIZED = loadRepository(); + public static final NEURepository NEU_REPO = NEURepository.of(LOCAL_REPO_DIR); /** * Adds command to update repository manually from ingame. @@ -41,18 +46,19 @@ public class NEURepo { })))); } - private static CompletableFuture<Void> initRepository() { + private static CompletableFuture<Void> loadRepository() { return CompletableFuture.runAsync(() -> { try { - if (Files.isDirectory(NEURepo.LOCAL_REPO_DIR)) { - try (Git localRepo = Git.open(NEURepo.LOCAL_REPO_DIR.toFile())) { + if (Files.isDirectory(NEURepoManager.LOCAL_REPO_DIR)) { + try (Git localRepo = Git.open(NEURepoManager.LOCAL_REPO_DIR.toFile())) { localRepo.pull().setRebase(true).call(); LOGGER.info("[Skyblocker] NEU Repository Updated"); } } else { - Git.cloneRepository().setURI(REMOTE_REPO_URL).setDirectory(NEURepo.LOCAL_REPO_DIR.toFile()).setBranchesToClone(List.of("refs/heads/master")).setBranch("refs/heads/master").call().close(); + Git.cloneRepository().setURI(REMOTE_REPO_URL).setDirectory(NEURepoManager.LOCAL_REPO_DIR.toFile()).setBranchesToClone(List.of("refs/heads/master")).setBranch("refs/heads/master").call().close(); LOGGER.info("[Skyblocker] NEU Repository Downloaded"); } + NEU_REPO.reload(); } catch (TransportException e){ LOGGER.error("[Skyblocker] Transport operation failed. Most likely unable to connect to the remote NEU repo on github", e); } catch (RepositoryNotFoundException e) { @@ -67,15 +73,15 @@ public class NEURepo { private static void deleteAndDownloadRepository() { CompletableFuture.runAsync(() -> { try { - ItemRegistry.filesImported = false; - File dir = NEURepo.LOCAL_REPO_DIR.toFile(); + ItemRepository.setFilesImported(false); + File dir = NEURepoManager.LOCAL_REPO_DIR.toFile(); recursiveDelete(dir); } catch (Exception ex) { if (MinecraftClient.getInstance().player != null) - MinecraftClient.getInstance().player.sendMessage(Text.translatable("skyblocker.updaterepository.failed"), false); + MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.updaterepository.failed")), false); return; } - initRepository(); + loadRepository(); }); } diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index c1b4223f..71e08865 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -3,7 +3,8 @@ package de.hysky.skyblocker.utils; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import de.hysky.skyblocker.events.SkyblockEvents; -import de.hysky.skyblocker.skyblock.item.PriceInfoTooltip; +import de.hysky.skyblocker.skyblock.item.MuseumItemCache; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.skyblock.rift.TheRift; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -19,6 +20,7 @@ import net.minecraft.client.network.PlayerListEntry; import net.minecraft.scoreboard.*; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,19 +33,32 @@ 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 following fields store data returned from /locraw: {@link #profile}, {@link #server}, {@link #gameType}, {@link #locationRaw}, and {@link #map}. + * The profile name parsed from the player list. */ - @SuppressWarnings("JavadocDeclaration") + @NotNull private static String profile = ""; + /** + * The profile id parsed from the chat. + */ + @NotNull + private static String profileId = ""; + /** + * The following fields store data returned from /locraw: {@link #server}, {@link #gameType}, {@link #locationRaw}, and {@link #map}. + */ + @SuppressWarnings("JavadocDeclaration") + @NotNull private static String server = ""; + @NotNull private static String gameType = ""; + @NotNull private static String locationRaw = ""; + @NotNull private static String map = ""; private static long clientWorldJoinTime = 0; private static boolean sentLocRaw = false; @@ -64,7 +79,7 @@ public class Utils { } public static boolean isInDungeons() { - return isInDungeons; + return getLocationRaw().equals(DUNGEONS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); } public static boolean isInTheRift() { @@ -78,13 +93,20 @@ public class Utils { /** * @return the profile parsed from the player list. */ + @NotNull public static String getProfile() { return profile; } + @NotNull + public static String getProfileId() { + return profileId; + } + /** * @return the server parsed from /locraw. */ + @NotNull public static String getServer() { return server; } @@ -92,6 +114,7 @@ public class Utils { /** * @return the game type parsed from /locraw. */ + @NotNull public static String getGameType() { return gameType; } @@ -99,6 +122,7 @@ public class Utils { /** * @return the location raw parsed from /locraw. */ + @NotNull public static String getLocationRaw() { return locationRaw; } @@ -106,6 +130,7 @@ public class Utils { /** * @return the map parsed from /locraw. */ + @NotNull public static String getMap() { return map; } @@ -139,7 +164,6 @@ public class Utils { sidebar = Collections.emptyList(); } else { isOnSkyblock = false; - isInDungeons = false; return; } } @@ -155,7 +179,7 @@ public class Utils { if (!isOnSkyblock) { if (!isInjected) { isInjected = true; - ItemTooltipCallback.EVENT.register(PriceInfoTooltip::onInjectTooltip); + ItemTooltipCallback.EVENT.register(ItemTooltip::getTooltip); } isOnSkyblock = true; SkyblockEvents.JOIN.invoker().onSkyblockJoin(); @@ -163,7 +187,6 @@ public class Utils { } else { onLeaveSkyblock(); } - isInDungeons = fabricLoader.isDevelopmentEnvironment() || isOnSkyblock && string.contains("The Catacombs"); } else if (isOnHypixel) { isOnHypixel = false; onLeaveSkyblock(); @@ -180,7 +203,6 @@ public class Utils { private static void onLeaveSkyblock() { if (isOnSkyblock) { isOnSkyblock = false; - isInDungeons = false; SkyblockEvents.LEAVE.invoker().onSkyblockLeave(); } } @@ -312,7 +334,7 @@ public class Utils { } /** - * Parses the /locraw reply from the server + * Parses the /locraw reply from the server and updates the player's profile id * * @return not display the message in chat is the command is sent by the mod */ @@ -338,6 +360,13 @@ public class Utils { return shouldFilter; } } + + if (isOnSkyblock && message.startsWith("Profile ID: ")) { + profileId = message.replace("Profile ID: ", ""); + + MuseumItemCache.tick(profileId); + } + return true; } 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 4630149c..064b564c 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -1,10 +1,7 @@ package de.hysky.skyblocker.utils.render; -import com.mojang.blaze3d.platform.GlStateManager.DstFactor; -import com.mojang.blaze3d.platform.GlStateManager.SrcFactor; import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.mixin.accessor.BeaconBlockEntityRendererInvoker; -import me.x150.renderer.render.Renderer3d; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; @@ -22,11 +19,8 @@ import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; import org.joml.Matrix3f; import org.joml.Matrix4f; -import org.joml.Vector3f; import org.lwjgl.opengl.GL11; -import java.awt.*; - public class RenderHelper { private static final Vec3d ONE = new Vec3d(1, 1, 1); private static final int MAX_OVERWORLD_BUILD_HEIGHT = 319; @@ -39,20 +33,46 @@ public class RenderHelper { 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)) { - Renderer3d.renderThroughWalls(); - renderFilled(context, pos, colorComponents, alpha); - Renderer3d.stopRenderThroughWalls(); + renderFilled(context, Vec3d.of(pos), ONE, colorComponents, alpha, true); } } 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, pos, colorComponents, alpha); + renderFilled(context, Vec3d.of(pos), ONE, colorComponents, alpha, false); } } - - private static void renderFilled(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) { - Renderer3d.renderFilled(context.matrixStack(), new Color(colorComponents[0], colorComponents[1], colorComponents[2], alpha), Vec3d.of(pos), ONE); + + 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); + 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) { @@ -78,7 +98,7 @@ public class RenderHelper { * Renders the outline of a box with the specified color components and line width. * This does not use renderer since renderer draws outline using debug lines with a fixed width. */ - public static void renderOutline(WorldRenderContext context, Box box, float[] colorComponents, float lineWidth) { + public static void renderOutline(WorldRenderContext context, Box box, float[] colorComponents, float lineWidth, boolean throughWalls) { if (FrustumUtils.isVisible(box)) { MatrixStack matrices = context.matrixStack(); Vec3d camera = context.camera().getPos(); @@ -90,6 +110,7 @@ public class RenderHelper { RenderSystem.lineWidth(lineWidth); RenderSystem.disableCull(); RenderSystem.enableDepthTest(); + RenderSystem.depthFunc(throughWalls ? GL11.GL_ALWAYS : GL11.GL_LEQUAL); matrices.push(); matrices.translate(-camera.getX(), -camera.getY(), -camera.getZ()); @@ -102,6 +123,7 @@ public class RenderHelper { RenderSystem.lineWidth(1f); RenderSystem.enableCull(); RenderSystem.disableDepthTest(); + RenderSystem.depthFunc(GL11.GL_LEQUAL); } } @@ -109,6 +131,8 @@ public class RenderHelper { * Draws lines from point to point.<br><br> * <p> * Tip: To draw lines from the center of a block, offset the X, Y and Z each by 0.5 + * <p> + * Note: This is super messed up when drawing long lines. Tried different normals and {@link DrawMode#LINES} but nothing worked. * * @param context The WorldRenderContext which supplies the matrices and tick delta * @param points The points from which to draw lines between @@ -125,7 +149,7 @@ public class RenderHelper { Tessellator tessellator = RenderSystem.renderThreadTesselator(); BufferBuilder buffer = tessellator.getBuffer(); - Matrix4f projectionMatrix = matrices.peek().getPositionMatrix(); + Matrix4f positionMatrix = matrices.peek().getPositionMatrix(); Matrix3f normalMatrix = matrices.peek().getNormalMatrix(); GL11.glEnable(GL11.GL_LINE_SMOOTH); @@ -135,21 +159,18 @@ public class RenderHelper { RenderSystem.setShaderColor(1f, 1f, 1f, 1f); RenderSystem.lineWidth(lineWidth); RenderSystem.enableBlend(); - RenderSystem.blendFunc(SrcFactor.SRC_ALPHA, DstFactor.ONE_MINUS_SRC_ALPHA); + RenderSystem.defaultBlendFunc(); RenderSystem.disableCull(); RenderSystem.enableDepthTest(); buffer.begin(DrawMode.LINE_STRIP, VertexFormats.LINES); for (int i = 0; i < points.length; i++) { - Vec3d point = points[i]; - Vec3d nextPoint = (i + 1 == points.length) ? points[i - 1] : points[i + 1]; - Vector3f normalVec = new Vector3f((float) nextPoint.getX(), (float) nextPoint.getY(), (float) nextPoint.getZ()).sub((float) point.getX(), (float) point.getY(), (float) point.getZ()).normalize(); - + Vec3d normalVec = points[(i + 1) % points.length].subtract(points[i]).normalize(); buffer - .vertex(projectionMatrix, (float) point.getX(), (float) point.getY(), (float) point.getZ()) + .vertex(positionMatrix, (float) points[i].getX(), (float) points[i].getY(), (float) points[i].getZ()) .color(colorComponents[0], colorComponents[1], colorComponents[2], alpha) - .normal(normalMatrix, normalVec.x, normalVec.y, normalVec.z) + .normal(normalMatrix, (float) normalVec.x, (float) normalVec.y, (float) normalVec.z) .next(); } @@ -158,30 +179,57 @@ public class RenderHelper { matrices.pop(); GL11.glDisable(GL11.GL_LINE_SMOOTH); RenderSystem.lineWidth(1f); - RenderSystem.disableBlend(); + RenderSystem.enableCull(); + } + + public static void renderQuad(WorldRenderContext context, Vec3d[] points, float[] colorComponents, float alpha, boolean throughWalls) { + Vec3d camera = context.camera().getPos(); + MatrixStack matrices = context.matrixStack(); + + matrices.push(); + matrices.translate(-camera.x, -camera.y, -camera.z); + + Tessellator tessellator = RenderSystem.renderThreadTesselator(); + BufferBuilder buffer = tessellator.getBuffer(); + Matrix4f positionMatrix = matrices.peek().getPositionMatrix(); + + RenderSystem.setShader(GameRenderer::getPositionColorProgram); + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); + RenderSystem.disableCull(); + RenderSystem.depthFunc(throughWalls ? GL11.GL_ALWAYS : GL11.GL_LEQUAL); + + buffer.begin(DrawMode.QUADS, VertexFormats.POSITION_COLOR); + for (int i = 0; i < 4; i++) { + buffer.vertex(positionMatrix, (float) points[i].getX(), (float) points[i].getY(), (float) points[i].getZ()).color(colorComponents[0], colorComponents[1], colorComponents[2], alpha).next(); + } + tessellator.draw(); + RenderSystem.enableCull(); - RenderSystem.disableDepthTest(); + RenderSystem.depthFunc(GL11.GL_LEQUAL); + + matrices.pop(); } - public static void renderText(WorldRenderContext context, Text text, Vec3d pos, boolean seeThrough) { - renderText(context, text, pos, 1, seeThrough); + public static void renderText(WorldRenderContext context, Text text, Vec3d pos, boolean throughWalls) { + renderText(context, text, pos, 1, throughWalls); } - public static void renderText(WorldRenderContext context, Text text, Vec3d pos, float scale, boolean seeThrough) { - renderText(context, text, pos, scale, 0, seeThrough); + public static void renderText(WorldRenderContext context, Text text, Vec3d pos, float scale, boolean throughWalls) { + renderText(context, text, pos, scale, 0, throughWalls); } - public static void renderText(WorldRenderContext context, Text text, Vec3d pos, float scale, float yOffset, boolean seeThrough) { - renderText(context, text.asOrderedText(), pos, scale, yOffset, seeThrough); + public static void renderText(WorldRenderContext context, Text text, Vec3d pos, float scale, float yOffset, boolean throughWalls) { + renderText(context, text.asOrderedText(), pos, scale, yOffset, throughWalls); } /** * Renders text in the world space. * - * @param seeThrough Whether the text should be able to be seen through walls or not. + * @param throughWalls whether the text should be able to be seen through walls or not. */ - public static void renderText(WorldRenderContext context, OrderedText text, Vec3d pos, float scale, float yOffset, boolean seeThrough) { + public static void renderText(WorldRenderContext context, OrderedText text, Vec3d pos, float scale, float yOffset, boolean throughWalls) { MatrixStack matrices = context.matrixStack(); Vec3d camera = context.camera().getPos(); TextRenderer textRenderer = client.textRenderer; @@ -201,7 +249,7 @@ public class RenderHelper { BufferBuilder buffer = tessellator.getBuffer(); VertexConsumerProvider.Immediate consumers = VertexConsumerProvider.immediate(buffer); - RenderSystem.depthFunc(seeThrough ? GL11.GL_ALWAYS : GL11.GL_LEQUAL); + RenderSystem.depthFunc(throughWalls ? GL11.GL_ALWAYS : GL11.GL_LEQUAL); textRenderer.draw(text, xOffset, yOffset, 0xFFFFFFFF, false, positionMatrix, consumers, TextRenderer.TextLayerType.SEE_THROUGH, 0, LightmapTextureManager.MAX_LIGHT_COORDINATE); consumers.draw(); 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 d824c546..cab18a50 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 @@ -3,8 +3,13 @@ package de.hysky.skyblocker.utils.render.title; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.RenderHelper; +import dev.isxander.yacl3.api.ConfigCategory; +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.OptionGroup; +import dev.isxander.yacl3.gui.YACLScreen; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.resource.language.I18n; import net.minecraft.client.util.math.Vector2f; import net.minecraft.text.Text; import net.minecraft.util.Formatting; @@ -21,6 +26,7 @@ public class TitleContainerConfigScreen extends Screen { private float hudX = SkyblockerConfigManager.get().general.titleContainer.x; private float hudY = SkyblockerConfigManager.get().general.titleContainer.y; private final Screen parent; + private boolean changedScale; protected TitleContainerConfigScreen() { this(null); @@ -153,17 +159,32 @@ public class TitleContainerConfigScreen extends Screen { } if (keyCode == GLFW.GLFW_KEY_EQUAL) { SkyblockerConfigManager.get().general.titleContainer.titleContainerScale += 10; + changedScale = true; } if (keyCode == GLFW.GLFW_KEY_MINUS) { SkyblockerConfigManager.get().general.titleContainer.titleContainerScale -= 10; + changedScale = true; } return super.keyPressed(keyCode, scanCode, modifiers); } + @Override 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/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java new file mode 100644 index 00000000..e7858f05 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -0,0 +1,99 @@ +package de.hysky.skyblocker.utils.waypoint; + +import de.hysky.skyblocker.utils.render.RenderHelper; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; + +import java.util.function.Supplier; + +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; + private boolean shouldRender; + + protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents) { + this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA); + } + + 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); + } + + protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha, float lineWidth) { + this(pos, typeSupplier, colorComponents, alpha, lineWidth, true); + } + + protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha, float lineWidth, boolean throughWalls) { + this(pos, typeSupplier, colorComponents, alpha, lineWidth, throughWalls, true); + } + + protected Waypoint(BlockPos pos, Supplier<Type> typeSupplier, float[] colorComponents, float alpha, float lineWidth, boolean throughWalls, boolean shouldRender) { + this.pos = pos; + this.box = new Box(pos); + this.typeSupplier = typeSupplier; + this.colorComponents = colorComponents; + this.alpha = alpha; + this.lineWidth = lineWidth; + this.throughWalls = throughWalls; + this.shouldRender = shouldRender; + } + + public boolean shouldRender() { + return shouldRender; + } + + public void setFound() { + this.shouldRender = false; + } + + public void setMissing() { + this.shouldRender = true; + } + + public void render(WorldRenderContext context) { + switch (typeSupplier.get()) { + case WAYPOINT -> RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); + case OUTLINED_WAYPOINT -> { + RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); + RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + } + case HIGHLIGHT -> RenderHelper.renderFilledThroughWalls(context, pos, colorComponents, alpha); + case OUTLINED_HIGHLIGHT -> { + RenderHelper.renderFilledThroughWalls(context, pos, colorComponents, alpha); + RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + } + case OUTLINE -> RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + } + } + + public enum Type { + WAYPOINT, + OUTLINED_WAYPOINT, + HIGHLIGHT, + OUTLINED_HIGHLIGHT, + OUTLINE; + + @Override + public String toString() { + return switch (this) { + case WAYPOINT -> "Waypoint"; + case OUTLINED_WAYPOINT -> "Outlined Waypoint"; + case HIGHLIGHT -> "Highlight"; + case OUTLINED_HIGHLIGHT -> "Outlined Highlight"; + case OUTLINE -> "Outline"; + }; + } + } +} diff --git a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json index d5e38345..a0a97c67 100644 --- a/src/main/resources/assets/skyblocker/dungeons/secretlocations.json +++ b/src/main/resources/assets/skyblocker/dungeons/secretlocations.json @@ -263,6 +263,13 @@ "z":21 }, { + "secretName":"1 - Pearl", + "category":"pearl", + "x":25, + "y":75, + "z":27 + }, + { "secretName":"1 - Item", "category":"item", "x":27, @@ -835,6 +842,13 @@ "z":21 }, { + "secretName":"2 - AOTV", + "category":"aotv", + "x":25, + "y":76, + "z":22 + }, + { "secretName":"2 - Stonk", "category":"stonk", "x":23, @@ -1713,13 +1727,6 @@ ], "Redstone-Key-3":[ { - "secretName":"1 - Redstone Skull (right click)", - "category":"lever", - "x":10, - "y":70, - "z":26 - }, - { "secretName":"1 - Superboom", "category":"superboom", "x":20, @@ -1727,13 +1734,6 @@ "z":7 }, { - "secretName":"1 - Redstone Skull (right click)", - "category":"lever", - "x":19, - "y":66, - "z":7 - }, - { "secretName":"1 - Lever behind Crypt", "category":"lever", "x":5, @@ -1748,6 +1748,20 @@ "z":6 }, { + "secretName":"2 - Redstone Skull (right click)", + "category":"lever", + "x":10, + "y":70, + "z":26 + }, + { + "secretName":"2 - Redstone Skull (right click)", + "category":"lever", + "x":19, + "y":66, + "z":7 + }, + { "secretName":"2 - Place Skull", "category":"lever", "x":27, @@ -2945,9 +2959,9 @@ { "secretName":"6 - Stonk", "category":"stonk", - "x":17, + "x":18, "y":70, - "z":15 + "z":14 }, { "secretName":"6 - Pressure Plate 2", @@ -3059,6 +3073,13 @@ "z":5 }, { + "secretName":"2 - AOTV", + "category":"aotv", + "x":77, + "y":82, + "z":16 + }, + { "secretName":"2 - Wither Essence", "category":"wither", "x":79, @@ -3110,6 +3131,13 @@ "z":9 }, { + "secretName":"3 - AOTV", + "category":"aotv", + "x":7, + "y":80, + "z":15 + }, + { "secretName":"3 - Superboom", "category":"superboom", "x":6, @@ -3226,6 +3254,13 @@ "z":24 }, { + "secretName":"1/2 - AOTV", + "category":"aotv", + "x":84, + "y":91, + "z":26 + }, + { "secretName":"1 - Bat", "category":"bat", "x":81, @@ -3800,6 +3835,13 @@ "z":51 }, { + "secretName":"5 - AOTV", + "category":"aotv", + "x":16, + "y":81, + "z":53 + }, + { "secretName":"5 - Chest", "category":"chest", "x":31, @@ -4072,6 +4114,13 @@ "z":30 }, { + "secretName":"5 - AOTV", + "category":"aotv", + "x":52, + "y":78, + "z":9 + }, + { "secretName":"5 - Crypt", "category":"superboom", "x":52, @@ -4846,6 +4895,13 @@ "z":52 }, { + "secretName":"2 - AOTV", + "category":"aotv", + "x":45, + "y":78, + "z":47 + }, + { "secretName":"2 - Chest", "category":"chest", "x":46, @@ -4881,6 +4937,13 @@ "z":41 }, { + "secretName":"5 - Pearl", + "category":"pearl", + "x":15, + "y":84, + "z":56 + }, + { "secretName":"5 - Stonk", "category":"stonk", "x":18, @@ -5081,6 +5144,13 @@ "z":61 }, { + "secretName": "7 - AOTV", + "category":"aotv", + "x":39, + "y":84, + "z":58 + }, + { "secretName":"7 - Chest", "category":"chest", "x":41, @@ -5332,6 +5402,13 @@ "z":43 }, { + "secretName":"3/4 - AOTV", + "category":"aotv", + "x":49, + "y":83, + "z":36 + }, + { "secretName":"3 - Chest", "category":"chest", "x":49, @@ -5553,6 +5630,13 @@ "z":15 }, { + "secretName":"5 - Pearl", + "category":"pearl", + "x":8, + "y":59, + "z":14 + }, + { "secretName":"5 - Entrance", "category":"entrance", "x":25, @@ -5835,6 +5919,13 @@ } ], "Double-Stair-3":[ + { + "secretName":"1 - Pearl", + "category":"pearl", + "x":24, + "y":72, + "z":11 + }, { "secretName":"1 - Wither Essence", "category":"wither", diff --git a/src/main/resources/assets/skyblocker/lang/en_ca.json b/src/main/resources/assets/skyblocker/lang/en_ca.json index 94458ed9..5ecbd676 100644 --- a/src/main/resources/assets/skyblocker/lang/en_ca.json +++ b/src/main/resources/assets/skyblocker/lang/en_ca.json @@ -8,23 +8,24 @@ "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", "text.autoconfig.skyblocker.option.general.bars.barpositions.defenceBarPosition": "Defence Bar Position", - "skyblocker.customDyeColors.notDyeable": "§b[§6Skyblocker§b] §cThis item isn't a dyeable armour piece!", - "skyblocker.customDyeColors.added": "§b[§6Skyblocker§b] §fSet a custom dye colour for your currently held item!", - "skyblocker.customDyeColors.noItemUuid": "§b[§6Skyblocker§b] §cYou must be holding an item that has a uuid in order to set a custom dye colour!", - "skyblocker.customArmorTrims.neverHad": "§b[§6Skyblocker§b] §fThis item doesn't have an armour trim set, but why not add one? ;)", - "skyblocker.customArmorTrims.added": "§b[§6Skyblocker§b] §fSet a custom armour trim for your currently held item!", - "skyblocker.customArmorTrims.unableToSetTrim": "§b[§6Skyblocker§b] §cUnable to set a custom armour trim :( (Are you in skyblock?, are you holding an item?)", - "skyblocker.customDyeColors.invalidHex": "§b[§6Skyblocker§b] §cInvalid HEX colour code!", - "skyblocker.customDyeColors.removed": "§b[§6Skyblocker§b] §fRemoved this item's custom dye colour.", - "skyblocker.customDyeColors.neverHad": "§b[§6Skyblocker§b] §fThis item doesn't have a custom dye colour set, but why not add one? ;)", - "skyblocker.customDyeColors.unableToSetColor": "§b[§6Skyblocker§b] §cUnable to set a custom dye colour :( (Are you in skyblock?, are you holding an item?)", - "skyblocker.customArmorTrims.notAnArmorPiece": "§b[§6Skyblocker§b] §cThis item isn't an armour piece!", - "skyblocker.customArmorTrims.removed": "§b[§6Skyblocker§b] §fRemoved this item's custom armour trim.", - "skyblocker.customArmorTrims.noItemUuid": "§b[§6Skyblocker§b] §cYou must be holding an item that has a uuid in order to set a custom armour trim!", + "skyblocker.customDyeColors.notDyeable": "§cThis item isn't a dyeable armour piece!", + "skyblocker.customDyeColors.added": "§fSet a custom dye colour for your currently held item!", + "skyblocker.customDyeColors.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom dye colour!", + "skyblocker.customArmorTrims.neverHad": "§fThis item doesn't have an armour trim set, but why not add one? ;)", + "skyblocker.customArmorTrims.added": "§fSet a custom armour trim for your currently held item!", + "skyblocker.customArmorTrims.unableToSetTrim": "§cUnable to set a custom armour trim :( (Are you in skyblock?, are you holding an item?)", + "skyblocker.customDyeColors.invalidHex": "§cInvalid HEX colour code!", + "skyblocker.customDyeColors.removed": "§fRemoved this item's custom dye colour.", + "skyblocker.customDyeColors.neverHad": "§fThis item doesn't have a custom dye colour set, but why not add one? ;)", + "skyblocker.customDyeColors.unableToSetColor": "§cUnable to set a custom dye colour :( (Are you in skyblock?, are you holding an item?)", + "skyblocker.customArmorTrims.notAnArmorPiece": "§cThis item isn't an armour piece!", + "skyblocker.customArmorTrims.removed": "§fRemoved this item's custom armour trim.", + "skyblocker.customArmorTrims.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom armour trim!", "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.enableProfitCalculator.@Tooltip": "Displays the profit of a dungeon chest in the chest screen's title.\nGreen if there's profit.\nRed if there isn't profit.\nGrey if you don't gain or lose anything.\nBlue if calculations were based on incomplete data.", "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.neutralColor": "Neutral Colour", "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.profitColor": "Profit Colour", "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.lossColor": "Loss Colour", "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor": "Incomplete Colour", - "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor.@Tooltip": "The colour to display when the price data is incomplete." + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor.@Tooltip": "The colour to display when the price data is incomplete.", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds.@Tooltip": "Displays a coloured background behind an item, the colour represents the item's rarity." } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 3d0c010f..31e7bb9c 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -38,6 +38,8 @@ "text.autoconfig.skyblocker.option.general.fairySouls.highlightFoundSouls": "Highlight found fairy souls", "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls": "Only highlight nearby fairy souls", "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls.@Tooltip": "When enabled only fairy souls in a radius of 50 blocks are highlighted", + "text.autoconfig.skyblocker.option.general.mythologicalRitual": "Mythological Ritual Helper", + "text.autoconfig.skyblocker.option.general.mythologicalRitual.enableMythologicalRitualHelper": "Enable Mythological Ritual Helper", "text.autoconfig.skyblocker.option.general.itemCooldown": "Item Cooldown", "text.autoconfig.skyblocker.option.general.itemCooldown.enableItemCooldowns": "Enable Item Cooldown", "text.autoconfig.skyblocker.option.general.shortcuts": "Shortcuts", @@ -75,12 +77,19 @@ "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.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", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo": "Attribute Shard Info", "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.itemRarityBackgroundsOpacity": "Item Rarity Backgrounds Opacity", + "text.autoconfig.skyblocker.option.general.wikiLookup": "Wiki Lookup", + "text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup": "Enable Wiki Lookup", + "text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup.@Tooltip": "Opens the wiki page of the hovered item with the F4 key.", + "text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki": "Use Official Wiki", + "text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki.@Tooltip": "Use the official wiki instead of the Fandom wiki.", "text.autoconfig.skyblocker.option.general.specialEffects": "Special Effects", "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects": "Rare Dungeon Drop Effects", "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects.@Tooltip": "Adds a special visual effect triggered upon obtaining rare dungeon loot!", @@ -90,10 +99,6 @@ "text.autoconfig.skyblocker.option.general.titleContainer": "Title Container", "text.autoconfig.skyblocker.option.general.titleContainer.@Tooltip": "Used to display multiple titles at once, Example use: Vampire Slayer", "text.autoconfig.skyblocker.option.general.titleContainer.titleContainerScale": "Title Container Scale", - "text.autoconfig.skyblocker.option.general.titleContainer.x": "Title Container X Position", - "text.autoconfig.skyblocker.option.general.titleContainer.y": "Title Container Y Position", - "text.autoconfig.skyblocker.option.general.titleContainer.direction": "Title Container Orientation", - "text.autoconfig.skyblocker.option.general.titleContainer.alignment": "Title Container Horizontal Alignment", "text.autoconfig.skyblocker.option.general.titleContainer.config": "Title Container Placement Config...", "text.autoconfig.skyblocker.option.general.teleportOverlay": "Teleport Overlay", "text.autoconfig.skyblocker.option.general.teleportOverlay.enableTeleportOverlays": "Enable Teleport Overlays", @@ -102,8 +107,13 @@ "text.autoconfig.skyblocker.option.general.teleportOverlay.enableEtherTransmission": "Enable Ether Transmission Overlay", "text.autoconfig.skyblocker.option.general.teleportOverlay.enableSinrecallTransmission": "Enable Sinrecall Transmission Overlay", "text.autoconfig.skyblocker.option.general.teleportOverlay.enableWitherImpact": "Enable Wither Impact Overlay", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cItem price information on tooltip will renew in max 60 seconds. If not, check latest.log", + "text.autoconfig.skyblocker.option.general.flameOverlay": "Flame Overlay", + "text.autoconfig.skyblocker.option.general.flameOverlay.flameHeight": "Flame Height", + "text.autoconfig.skyblocker.option.general.flameOverlay.flameOpacity": "Flame Opacity", + "skyblocker.itemTooltip.nullMessage": "§cItem price information on tooltip will renew in max 60 seconds. If not, check latest.log", "skyblocker.itemTooltip.noData": "§cNo Data", + + "skyblocker.wikiLookup.noArticleFound": "§rUnable to locate a wiki article for this item...", "text.autoconfig.skyblocker.category.richPresence": "Discord Rich Presence", "text.autoconfig.skyblocker.option.richPresence.info": "Skyblock Info", @@ -115,104 +125,16 @@ "text.autoconfig.skyblocker.option.richPresence.enableRichPresence": "Enabled", "text.autoconfig.skyblocker.option.richPresence.customMessage": "Custom Message", - "text.autoconfig.skyblocker.category.quickNav" : "Quick Navigation", - "text.autoconfig.skyblocker.option.quickNav.enableQuickNav" : "Enable Quick Navigation", - "text.autoconfig.skyblocker.option.quickNav.button1" : "Button 1", - "text.autoconfig.skyblocker.option.quickNav.button1.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button1.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button2" : "Button 2", - "text.autoconfig.skyblocker.option.quickNav.button2.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button2.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button2.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button2.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button3" : "Button 3", - "text.autoconfig.skyblocker.option.quickNav.button3.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button3.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button3.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button3.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button4" : "Button 4", - "text.autoconfig.skyblocker.option.quickNav.button4.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button4.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button4.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button4.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button5" : "Button 5", - "text.autoconfig.skyblocker.option.quickNav.button5.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button5.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button5.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button5.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button6" : "Button 6", - "text.autoconfig.skyblocker.option.quickNav.button6.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button6.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button6.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button6.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button7" : "Button 7", - "text.autoconfig.skyblocker.option.quickNav.button7.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button7.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button7.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button7.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button8" : "Button 8", - "text.autoconfig.skyblocker.option.quickNav.button8.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button8.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button8.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button8.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button9" : "Button 9", - "text.autoconfig.skyblocker.option.quickNav.button9.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button9.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button9.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button9.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button10" : "Button 10", - "text.autoconfig.skyblocker.option.quickNav.button10.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button10.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button10.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button10.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button11" : "Button 11", - "text.autoconfig.skyblocker.option.quickNav.button11.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button11.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button11.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button11.clickEvent" : "Click event", - "text.autoconfig.skyblocker.option.quickNav.button12" : "Button 12", - "text.autoconfig.skyblocker.option.quickNav.button12.render" : "Render", - "text.autoconfig.skyblocker.option.quickNav.button12.item" : "Item", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName" : "Item name", - "text.autoconfig.skyblocker.option.quickNav.button12.item.count" : "Item Count", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt" : "NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle" : "UI Title", - "text.autoconfig.skyblocker.option.quickNav.button12.clickEvent" : "Click event", + "text.autoconfig.skyblocker.category.quickNav": "Quick Navigation", + "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "Enable Quick Navigation", + "text.autoconfig.skyblocker.option.quickNav.button": "Button %d", + "text.autoconfig.skyblocker.option.quickNav.button.render": "Render", + "text.autoconfig.skyblocker.option.quickNav.button.item": "Item", + "text.autoconfig.skyblocker.option.quickNav.button.item.itemName": "Item ID", + "text.autoconfig.skyblocker.option.quickNav.button.item.count": "Item Count", + "text.autoconfig.skyblocker.option.quickNav.button.item.nbt": "NBT", + "text.autoconfig.skyblocker.option.quickNav.button.uiTitle": "UI Title", + "text.autoconfig.skyblocker.option.quickNav.button.clickEvent": "Click event", "text.autoconfig.skyblocker.option.general.itemList": "Item List", "text.autoconfig.skyblocker.option.general.itemList.enableItemList": "Enable Item List", @@ -230,6 +152,9 @@ "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", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableChestWaypoints" : "Enable Chest Waypoints", @@ -239,6 +164,9 @@ "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableLeverWaypoints" : "Enable Lever Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableFairySoulWaypoints" : "Enable Fairy Soul Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableStonkWaypoints" : "Enable Stonk Waypoints", + "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableAotvWaypoints" : "Enable AOTV Waypoints", + "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enablePearlWaypoints": "Enable Pearl Waypoints", + "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enablePearlWaypoints.@Tooltip": "With these waypoints, you throw a pearl towards the block and at the same time AOTV up.", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableDefaultWaypoints" : "Enable Default Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableDefaultWaypoints.@Tooltip" : "This includes all waypoints that do not belong to a category.", "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit": "Dungeon Chest Profit Calculator", @@ -260,8 +188,6 @@ "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.mapX": "Map X", - "text.autoconfig.skyblocker.option.locations.dungeons.mapY": "Map Y", "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", @@ -293,11 +219,12 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[2]": "\nClassic: Shows name and percentage in a very simple box.", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.screen": "Dwarven HUD Config...", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Enable Background", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", "text.autoconfig.skyblocker.option.locations.rift": "The Rift", "text.autoconfig.skyblocker.option.locations.rift.mirrorverseWaypoints": "Enable Mirrorverse Waypoints", + "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", "text.autoconfig.skyblocker.option.locations.rift.mcGrubberStacks": "McGrubber Stacks", "text.autoconfig.skyblocker.option.locations.rift.mcGrubberStacks.@Tooltip": "Used for calculating Motes sell prices.", @@ -340,23 +267,44 @@ "text.autoconfig.skyblocker.option.general.hideEmptyTooltips": "Hide empty item tooltips in menus", "text.autoconfig.skyblocker.option.general.hideStatusEffectOverlay": "Hide Status Effect Overlay", - "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §cUpdating local repository failed. Remove files manually and restart game.", + "skyblocker.updaterepository.failed": "§cUpdating local repository failed. Remove files manually and restart game.", + + "skyblocker.dungeons.secrets.physicalEntranceNotFound": "§cDungeon Entrance Room coordinates not found. Please go back to the green Entrance Room.", + "skyblocker.dungeons.secrets.markSecretFound": "§rMarked secret #%d as found.", + "skyblocker.dungeons.secrets.markSecretMissing": "§rMarked secret #%d as missing.", + "skyblocker.dungeons.secrets.markSecretFoundUnable": "§cUnable to mark secret #%d as found.", + "skyblocker.dungeons.secrets.markSecretMissingUnable": "§cUnable to mark secret #%d as missing.", + "skyblocker.dungeons.secrets.posMessage": "§rRoom: %s, X: %d, Y: %d, Z: %d", + "skyblocker.dungeons.secrets.noTarget": "§cNo target block found! (Are you pointing at a block in range?)", + "skyblocker.dungeons.secrets.notMatched": "§cThe current room is not matched! (Are you in a dungeon room?)", + "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.dungeons.secrets.physicalEntranceNotFound": "§b[§6Skyblocker§b] §cDungeon Entrance Room coordinates not found. Please go back to the green Entrance Room.", - "skyblocker.dungeons.secrets.markSecretFound": "§b[§6Skyblocker§b] §rMarked secret #%d as found.", - "skyblocker.dungeons.secrets.markSecretMissing": "§b[§6Skyblocker§b] §rMarked secret #%d as missing.", - "skyblocker.dungeons.secrets.markSecretFoundUnable": "§b[§6Skyblocker§b] §cUnable to mark secret #%d as found.", - "skyblocker.dungeons.secrets.markSecretMissingUnable": "§b[§6Skyblocker§b] §cUnable to mark secret #%d as missing.", + "skyblocker.exotic.crystal": "CRYSTAL", + "skyblocker.exotic.fairy": "FAIRY", + "skyblocker.exotic.og_fairy": "OG_FAIRY", + "skyblocker.exotic.spook": "SPOOK", + "skyblocker.exotic.glitched": "GLITCHED", + "skyblocker.exotic.exotic": "EXOTIC", "skyblocker.fishing.reelNow": "Reel in now!", "skyblocker.rift.healNow": "Heal now!", "skyblocker.rift.iceNow": "Ice now!", "skyblocker.rift.mania": "Mania!", "skyblocker.rift.stakeNow": "Stake now!", - "skyblocker.fairySouls.markAllFound": "§b[§6Skyblocker§b] §rMarked all fairy souls in the current island as found", - "skyblocker.fairySouls.markAllMissing": "§b[§6Skyblocker§b] §rMarked all fairy souls in the current island as missing", - "skyblocker.relics.markAllFound": "§b[§6Skyblocker§b] §rMarked all relics as found", - "skyblocker.relics.markAllMissing": "§b[§6Skyblocker§b] §rMarked all relics as missing", + "skyblocker.rift.enigmaSouls.markAllFound": "§rMarked all enigma souls as found!", + "skyblocker.rift.enigmaSouls.markAllMissing": "§rMarked all enigma souls as missing!", + "skyblocker.fairySouls.markAllFound": "§rMarked all fairy souls in the current island as found", + "skyblocker.fairySouls.markAllMissing": "§rMarked all fairy souls in the current island as missing", + "skyblocker.relics.markAllFound": "§rMarked all relics as found", + "skyblocker.relics.markAllMissing": "§rMarked all relics as missing", "skyblocker.shortcuts.config": "Shortcuts Config", "skyblocker.shortcuts.notLoaded": "§c§lShortcuts not loaded yet", "skyblocker.shortcuts.command.target": "Target Command", @@ -369,36 +317,36 @@ "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.customItemNames.removed": "§b[§6Skyblocker§b] §fRemoved this item's custom name.", - "skyblocker.customItemNames.neverHad": "§b[§6Skyblocker§b] §fThis item doesn't have a custom name set, but why not add one? ;)", - "skyblocker.customItemNames.added": "§b[§6Skyblocker§b] §fSet a custom name for your currently held item!", - "skyblocker.customItemNames.noItemUuid": "§b[§6Skyblocker§b] §cYou must be holding an item that has a uuid in order to set a custom name!", - "skyblocker.customItemNames.unableToSetName": "§b[§6Skyblocker§b] §cUnable to set a custom item name :( (Are you in skyblock?, are you holding an item?)", + "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? ;)", + "skyblocker.customItemNames.added": "§fSet a custom name for your currently held item!", + "skyblocker.customItemNames.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom name!", + "skyblocker.customItemNames.unableToSetName": "§cUnable to set a custom item name :( (Are you in skyblock?, are you holding an item?)", - "skyblocker.customDyeColors.invalidHex": "§b[§6Skyblocker§b] §cInvalid HEX color code!", - "skyblocker.customDyeColors.notDyeable": "§b[§6Skyblocker§b] §cThis item isn't a dyeable armor piece!", - "skyblocker.customDyeColors.removed": "§b[§6Skyblocker§b] §fRemoved this item's custom dye color.", - "skyblocker.customDyeColors.neverHad": "§b[§6Skyblocker§b] §fThis item doesn't have a custom dye color set, but why not add one? ;)", - "skyblocker.customDyeColors.added": "§b[§6Skyblocker§b] §fSet a custom dye color for your currently held item!", - "skyblocker.customDyeColors.noItemUuid": "§b[§6Skyblocker§b] §cYou must be holding an item that has a uuid in order to set a custom dye color!", - "skyblocker.customDyeColors.unableToSetColor": "§b[§6Skyblocker§b] §cUnable to set a custom dye color :( (Are you in skyblock?, are you holding an item?)", + "skyblocker.customDyeColors.invalidHex": "§cInvalid HEX color code!", + "skyblocker.customDyeColors.notDyeable": "§cThis item isn't a dyeable armor piece!", + "skyblocker.customDyeColors.removed": "§fRemoved this item's custom dye color.", + "skyblocker.customDyeColors.neverHad": "§fThis item doesn't have a custom dye color set, but why not add one? ;)", + "skyblocker.customDyeColors.added": "§fSet a custom dye color for your currently held item!", + "skyblocker.customDyeColors.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom dye color!", + "skyblocker.customDyeColors.unableToSetColor": "§cUnable to set a custom dye color :( (Are you in skyblock?, are you holding an item?)", - "skyblocker.customArmorTrims.invalidMaterialOrPattern": "§b[§6Skyblocker§b] §cYou supplied either an invalid material, or an invalid trim pattern!", - "skyblocker.customArmorTrims.notAnArmorPiece": "§b[§6Skyblocker§b] §cThis item isn't an armor piece!", - "skyblocker.customArmorTrims.removed": "§b[§6Skyblocker§b] §fRemoved this item's custom armor trim.", - "skyblocker.customArmorTrims.neverHad": "§b[§6Skyblocker§b] §fThis item doesn't have a armor trim set, but why not add one? ;)", - "skyblocker.customArmorTrims.added": "§b[§6Skyblocker§b] §fSet a custom armor trim for your currently held item!", - "skyblocker.customArmorTrims.noItemUuid": "§b[§6Skyblocker§b] §cYou must be holding an item that has a uuid in order to set a custom armor trim!", - "skyblocker.customArmorTrims.unableToSetTrim": "§b[§6Skyblocker§b] §cUnable to set a custom armor trim :( (Are you in skyblock?, are you holding an item?)", + "skyblocker.customArmorTrims.invalidMaterialOrPattern": "§cYou supplied either an invalid material, or an invalid trim pattern!", + "skyblocker.customArmorTrims.notAnArmorPiece": "§cThis item isn't an armor piece!", + "skyblocker.customArmorTrims.removed": "§fRemoved this item's custom armor trim.", + "skyblocker.customArmorTrims.neverHad": "§fThis item doesn't have a armor trim set, but why not add one? ;)", + "skyblocker.customArmorTrims.added": "§fSet a custom armor trim for your currently held item!", + "skyblocker.customArmorTrims.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom armor trim!", + "skyblocker.customArmorTrims.unableToSetTrim": "§cUnable to set a custom armor trim :( (Are you in skyblock?, are you holding an item?)", "skyblocker.quiverWarning.50Left": "You only have 50 Arrows left in your Quiver!", "skyblocker.quiverWarning.10Left": "You only have 10 Arrows left in your Quiver!", "skyblocker.quiverWarning.empty": "You don't have any more Arrows left in your Quiver!", - "skyblocker.itemProtection.added": "§b[§6Skyblocker§b] §fYour %s will now be protected! §o*your item now feels a little safer :')*", - "skyblocker.itemProtection.removed": "§b[§6Skyblocker§b] §fYour %s will §nno longer be protected§f :( - §lBeware of the dangers in doing this!", - "skyblocker.itemProtection.noItemUuid": "§b[§6Skyblocker§b] §cYou must be holding an item that has a uuid in order to protect it!", - "skyblocker.itemProtection.unableToProtect": "§b[§6Skyblocker§b] §cUnable to protect this item :( (Are you in skyblock?, are you holding an item?)", + "skyblocker.itemProtection.added": "§fYour %s will now be protected! §o*your item now feels a little safer :')*", + "skyblocker.itemProtection.removed": "§fYour %s will §nno longer be protected§f :( - §lBeware of the dangers in doing this!", + "skyblocker.itemProtection.noItemUuid": "§cYou must be holding an item that has a uuid in order to protect it!", + "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 diff --git a/src/main/resources/assets/skyblocker/lang/es_es.json b/src/main/resources/assets/skyblocker/lang/es_es.json index faa77b85..87de5ab2 100644 --- a/src/main/resources/assets/skyblocker/lang/es_es.json +++ b/src/main/resources/assets/skyblocker/lang/es_es.json @@ -40,30 +40,13 @@ "text.autoconfig.skyblocker.option.richPresence.customMessage": "Mensaje Personalizado", "text.autoconfig.skyblocker.category.quickNav": "Navegación Rápida", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "Habilitar Navegación Rápida", - "text.autoconfig.skyblocker.option.quickNav.button1": "Botón 1", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button3": "Botón 3", - "text.autoconfig.skyblocker.option.quickNav.button4": "Botón 4", - "text.autoconfig.skyblocker.option.quickNav.button5": "Botón 5", - "text.autoconfig.skyblocker.option.quickNav.button6": "Botón 6", - "text.autoconfig.skyblocker.option.quickNav.button7": "Botón 7", "text.autoconfig.skyblocker.option.messages.hideImplosion": "Ocultar el mensaje de Implosion", "text.autoconfig.skyblocker.option.messages.hideCombo": "Ocultar Mensajes de Combos", "text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper.@Tooltip": "Obscurece los cofres que ya han sido abiertos.", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Habilitar Fondo", "text.autoconfig.skyblocker.option.general.itemTooltip": "Información extra de los objetos", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cEl precio en la información en los objetos se actualiza cada 60 segundos. De lo contrario revisa lastest.log", + "skyblocker.itemTooltip.nullMessage": "§cEl precio en la información en los objetos se actualiza cada 60 segundos. De lo contrario revisa lastest.log", "text.autoconfig.skyblocker.option.richPresence.info.@Tooltip": "Este valor no importa si estas ciclando", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button2": "Botón 2", - "text.autoconfig.skyblocker.option.quickNav.button2.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button3.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName": "Nombre del objeto", "text.autoconfig.skyblocker.option.messages.hideAds": "Ocultar anuncios del Chat Publico", "text.autoconfig.skyblocker.option.messages.hideTeleportPad": "Ocultar mensajes del Pad de Teletransporte", "text.autoconfig.skyblocker.option.messages.hideAutopet": "Ocultar mensajes del Autopet", @@ -82,8 +65,6 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.solveFetchur": "Resolver Fetchur", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "Interfaz de Dwarven", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "Habilitado", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", "text.autoconfig.skyblocker.category.messages": "Mensajes", "text.autoconfig.skyblocker.option.messages.chatFilterResult.PASS": "Deshabilitado", "text.autoconfig.skyblocker.option.messages.chatFilterResult.FILTER": "Filtro", @@ -93,48 +74,9 @@ "text.autoconfig.skyblocker.option.messages.hideAOTE": "Ocultar Mensajes de la AOTE", "text.autoconfig.skyblocker.option.messages.hideMana": "Ocultar los Mensajes del Consumo de Maná de la Barra de Acción", "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "Da una mejor experiencia con FancyBar", - "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §cLa actualización del repositorio local fallo. Elimina los archivos manualmente y reinicia el juego.", - "text.autoconfig.skyblocker.option.quickNav.button11": "Botón 11", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button4.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button5.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button6.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8": "Botón 8", - "text.autoconfig.skyblocker.option.quickNav.button9": "Botón 9", - "text.autoconfig.skyblocker.option.quickNav.button10": "Botón 10", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button7.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button8.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button9.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button10.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button11.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle": "Titulo de la Interfaz", - "text.autoconfig.skyblocker.option.quickNav.button12": "Botón 12", - "text.autoconfig.skyblocker.option.quickNav.button12.item": "Objeto", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName": "Nombre del objeto", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle": "Titulo de la Interfaz" + "skyblocker.updaterepository.failed": "§cLa actualización del repositorio local fallo. Elimina los archivos manualmente y reinicia el juego.", + "text.autoconfig.skyblocker.option.general.shortcuts.enableShortcuts": "Habilitar atajos", + "text.autoconfig.skyblocker.option.general.shortcuts.enableShortcuts.@Tooltip": "Solo funciona en Hypixel. Edita atajos ejecutando \"/skyblocker shortcuts\". Al menos una de las siguientes opciones debe ser activada para surgir efecto.", + "text.autoconfig.skyblocker.option.general.shortcuts": "Atajos", + "text.autoconfig.skyblocker.option.general.compactorDeletorPreview": "Habilitar la previsualización del compactador/eliminador" } diff --git a/src/main/resources/assets/skyblocker/lang/fr_fr.json b/src/main/resources/assets/skyblocker/lang/fr_fr.json index 8da7809a..207852ac 100644 --- a/src/main/resources/assets/skyblocker/lang/fr_fr.json +++ b/src/main/resources/assets/skyblocker/lang/fr_fr.json @@ -23,7 +23,7 @@ "text.autoconfig.skyblocker.option.general.hitbox": "Boites de collisions", "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "Hitbox 1.8 de la terre labourée", "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "Hitbox 1.8 du levier", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cLes informations sur le prix des objets vont s'actualiser dans 60 secondes maximum. Sinon consultez le fichier latest.log", + "skyblocker.itemTooltip.nullMessage": "§cLes informations sur le prix des objets vont s'actualiser dans 60 secondes maximum. Sinon consultez le fichier latest.log", "skyblocker.itemTooltip.noData": "§cPas de données", "text.autoconfig.skyblocker.category.richPresence": "Rich Presence Discord", "text.autoconfig.skyblocker.option.richPresence.info": "Information à afficher", @@ -52,8 +52,6 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "ATH mine des nains", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "Activé", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Activer l'arrière-plan", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", "text.autoconfig.skyblocker.category.messages": "Messages", "text.autoconfig.skyblocker.option.messages.hideAbility": "Cacher le rechargement des capacités", "text.autoconfig.skyblocker.option.messages.hideHeal": "Cacher les messages de soin", @@ -67,7 +65,6 @@ "text.autoconfig.skyblocker.option.messages.hideMana": "Cacher les messages de consommation de mana de la barre d'action", "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "Permet une meilleure expérience avec les barres", "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "Taille de la Carte", - "text.autoconfig.skyblocker.option.quickNav.button1.render": "Render", "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", @@ -78,8 +75,6 @@ "text.autoconfig.skyblocker.option.general.bars.barpositions.LAYER2": "Couche 2", "text.autoconfig.skyblocker.option.general.bars.barpositions.RIGHT": "Droite", "text.autoconfig.skyblocker.option.general.itemTooltip.avg.ONE_DAY": "Prix pour 1 jour", - "text.autoconfig.skyblocker.option.locations.dungeons.mapX": "Carte X", - "text.autoconfig.skyblocker.option.locations.dungeons.mapY": "Carte Y", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style": "Style du HUD", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[0]": "Simple : Montre le nom et le pourcentage.", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[1]": "Détaillé : Montre le nom, pourcentage, barre de progression et une icone.", @@ -99,15 +94,7 @@ "text.autoconfig.skyblocker.option.richPresence.info.LOCATION": "LIEU", "text.autoconfig.skyblocker.category.quickNav": "Navigation rapide", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "Activer la navigation rapide", - "text.autoconfig.skyblocker.option.quickNav.button1": "Bouton 1", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button2": "Bouton 2", - "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §cLa mise à jour de la repository a échoué. Supprimez les fichiers manuellement et relancez le jeu.", + "skyblocker.updaterepository.failed": "§cLa mise à jour de la repository a échoué. Supprimez les fichiers manuellement et relancez le jeu.", "skyblocker.fishing.reelNow": "Enroulez la ligne !", "text.autoconfig.skyblocker.option.general.fishing.enableFishingHelper": "Activer l'assistant de pêche", "text.autoconfig.skyblocker.option.general.fishing": "Assistant de pêche", @@ -115,93 +102,6 @@ "text.autoconfig.skyblocker.option.general.itemTooltip.avg.BOTH": "Les deux", "text.autoconfig.skyblocker.option.richPresence.info.PURSE": "PORTE-MONNAIE", "text.autoconfig.skyblocker.option.richPresence.info.BITS": "BITS", - "text.autoconfig.skyblocker.option.quickNav.button4.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button4.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button7": "Bouton 7", - "text.autoconfig.skyblocker.option.quickNav.button2.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button2.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button2.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button9.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button9.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button9.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button10": "Bouton 10", - "text.autoconfig.skyblocker.option.quickNav.button10.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button10.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button10.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button3.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button3.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button2.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button3": "Bouton 3", - "text.autoconfig.skyblocker.option.quickNav.button3.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button3.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button4": "Bouton 4", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button4.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button4.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button5": "Bouton 5", - "text.autoconfig.skyblocker.option.quickNav.button5.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button5.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button5.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button5.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button6": "Bouton 6", - "text.autoconfig.skyblocker.option.quickNav.button6.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button6.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button6.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button6.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button7.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button7.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button7.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button7.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button8": "Bouton 8", - "text.autoconfig.skyblocker.option.quickNav.button8.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button8.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button8.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button8.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button9": "Bouton 9", - "text.autoconfig.skyblocker.option.quickNav.button10.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button11": "Bouton 11", - "text.autoconfig.skyblocker.option.quickNav.button11.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button11.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button11.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button11.clickEvent": "Evènement de clic", - "text.autoconfig.skyblocker.option.quickNav.button12": "Bouton 12", - "text.autoconfig.skyblocker.option.quickNav.button12.render": "Render", - "text.autoconfig.skyblocker.option.quickNav.button12.item": "Item", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName": "Nom de l'item", - "text.autoconfig.skyblocker.option.quickNav.button12.item.count": "Nombre d'items", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle": "Titre du menu", - "text.autoconfig.skyblocker.option.quickNav.button12.clickEvent": "Evènement de clic", "text.autoconfig.skyblocker.option.general.experiments": "Aide aux expériences de la table d'expérimentation", "text.autoconfig.skyblocker.option.general.experiments.enableChronomatronSolver": "Activer l'aide au Chronomatron", "text.autoconfig.skyblocker.option.general.experiments.enableSuperpairsSolver": "Activer l'aide aux Superpairs", diff --git a/src/main/resources/assets/skyblocker/lang/id_id.json b/src/main/resources/assets/skyblocker/lang/id_id.json index 52a6f9bb..f0dbc967 100644 --- a/src/main/resources/assets/skyblocker/lang/id_id.json +++ b/src/main/resources/assets/skyblocker/lang/id_id.json @@ -17,7 +17,7 @@ "text.autoconfig.skyblocker.option.messages.hideAds": "Sembunyikan Iklan dari Chat Publik", "text.autoconfig.skyblocker.option.general.itemTooltip.enableNPCPrice": "Aktifkan Harga NPC", "text.autoconfig.skyblocker.option.general.itemTooltip.enableLowestBIN": "Aktifkan Harga BIN Terendah", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cInformasi harga item yang ditampilkan dalam tooltip akan diperbarui dalam jangka waktu maks. 60 detik. Jika pembaharuan gagal silahkan check latest.log", + "skyblocker.itemTooltip.nullMessage": "§cInformasi harga item yang ditampilkan dalam tooltip akan diperbarui dalam jangka waktu maks. 60 detik. Jika pembaharuan gagal silahkan check latest.log", "text.autoconfig.skyblocker.option.general.itemTooltip.enableAvgBIN": "Aktifkan Rata-rata Harga BIN", "text.autoconfig.skyblocker.option.general.itemTooltip.avg": "Tipe Rata-rata", "text.autoconfig.skyblocker.option.general.itemTooltip.enableBazaarPrice": "Aktifkan Harga Jual Beli Bazaar", diff --git a/src/main/resources/assets/skyblocker/lang/ja_jp.json b/src/main/resources/assets/skyblocker/lang/ja_jp.json index a0456936..629bc1de 100644 --- a/src/main/resources/assets/skyblocker/lang/ja_jp.json +++ b/src/main/resources/assets/skyblocker/lang/ja_jp.json @@ -23,7 +23,7 @@ "text.autoconfig.skyblocker.option.general.hitbox": "ヒットボックス", "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "バージョン1.8での作物のヒットボックスを使う", "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "バージョン1.8でのレバーのヒットボックスを使う", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b]§cツールチップ上のアイテムの値段は最大60秒ごとに更新されます。されていない場合はlatest.logを確認してください", + "skyblocker.itemTooltip.nullMessage": "§cツールチップ上のアイテムの値段は最大60秒ごとに更新されます。されていない場合はlatest.logを確認してください", "text.autoconfig.skyblocker.category.richPresence": "discordに自分のゲームアクティビティを表示する", "text.autoconfig.skyblocker.option.richPresence.info": "skyblockの情報", "text.autoconfig.skyblocker.option.richPresence.info.@Tooltip": "この値はあなたがサイクリングしている場合は重要ではありません", @@ -49,8 +49,6 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "ドワーフマインでのHUD", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "有効", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "バックグラウンド表示を有効にする", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", "text.autoconfig.skyblocker.category.messages": "メッセージ", "text.autoconfig.skyblocker.option.messages.hideAbility": "アビリティのクールダウンを非表示にする", "text.autoconfig.skyblocker.option.messages.hideHeal": "回復メッセージを非表示にする", @@ -62,5 +60,72 @@ "text.autoconfig.skyblocker.option.messages.hideCombo": "Comboのメッセージを非表示にする", "text.autoconfig.skyblocker.option.messages.hideAutopet": "Autopetのメッセージを非表示にする", "text.autoconfig.skyblocker.option.messages.hideMana": "マナの使用表示をアクションバーから非表示にする", - "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "FancyBarでより良くできます" + "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "FancyBarでより良くできます", + "key.skyblocker.toggleB": "tabを開いたときのHUDの表示メニューを種別Bに変更する", + "key.skyblocker.toggleA": "tabを開いたときのHUDの表示メニューを種別Aに変更する", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableTeleportOverlays": "テレポート先の表示を有効にする", + "text.autoconfig.skyblocker.option.general.teleportOverlay": "テレポート先の表示", + "text.autoconfig.skyblocker.option.general.tabHud.nameSorting.@Tooltip": "アルファベット順のソートは名前をABC順に並べますがデフォルトソートは並び替えをしません。", + "text.autoconfig.skyblocker.option.general.tabHud.plainPlayerNames.@Tooltip": "有効にすることでpublic islandにおいてプレイヤー名をhypixel独自の修飾なしに表示します。", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo": "Attribute Ahardの情報の表示", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo.@Tooltip": "Attributeのレベルをアイテムの数とアイテムの頭文字に表示します。", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay": "アイテムの情報ディスプレイ", + "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects.@Tooltip": "ダンジョンでレアなアイテムを手に入れたときに特別なエフェクトを出します!", + "text.autoconfig.skyblocker.option.general.itemCooldown": "アイテムのクールダウン", + "text.autoconfig.skyblocker.option.general.itemCooldown.enableItemCooldowns": "アイテムのクールダウン表示を有効にする", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandShortcuts": "コマンドショートカットを有効にする", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandShortcuts.@Tooltip": "1単語だけで構成されるコマンドのためのショートカット。「/skyblocker shortcuts」で編集してください。使用するにはこの設定が有効になっている必要があります.", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts": "コマンドの引数のショートカット", + "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningInDungeons": "ダンジョン内でQuiverの通知を有効にする", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts.@Tooltip": "複数の単語で構成されるコマンドの1以上の単語を置き換えるショートカット。「/skyblocker shortcuts」で編集できます。使用するにはこの設定が有効になっている必要があります。", + "text.autoconfig.skyblocker.option.general.shortcuts.config": "ショートカットの設定...", + "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningAfterDungeon": "ダンジョンが終わった後のQuiverの通知を有効にする", + "text.autoconfig.skyblocker.option.general.tabHud.plainPlayerNames": "そのままのプレイヤー名", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.ONE_DAY": "今日の平均の値段", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.BOTH": "両方", + "text.autoconfig.skyblocker.option.general.titleContainer.config": "タイトルコンテナの置き方の設定...", + "text.autoconfig.skyblocker.option.general.experiments.enableSuperpairsSolver": "Superpairsのソルバーを有効にするか", + "text.autoconfig.skyblocker.option.general.experiments.enableUltrasequencerSolver": "Ultrasequencerのソルバーを有効にするか", + "text.autoconfig.skyblocker.option.general.experiments": "experimentation tableのソルバー", + "text.autoconfig.skyblocker.option.general.experiments.enableChronomatronSolver": "chronomatronのソルバーを有効にするか", + "text.autoconfig.skyblocker.option.general.titleContainer.@Tooltip": "いくつかの表示を一度に表示するときに使います。(例:Vampire Slayer)", + "text.autoconfig.skyblocker.option.general.titleContainer": "画面に表示するタイトルコンテナ", + "text.autoconfig.skyblocker.option.general.titleContainer.titleContainerScale": "タイトルコンテナの大きさ", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightFoundSouls": "見つけたフェアリーソウルもハイライトする", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls": "近くにあるフェアリーソウルだけをハイライトする", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls.@Tooltip": "50ブルック以内にフェアリーソウルがあるときだけハイライトされます", + "text.autoconfig.skyblocker.option.general.fishing": "フィッシングヘルパー", + "text.autoconfig.skyblocker.option.general.fishing.enableFishingHelper": "フィッシングヘルパーを有効にするか", + "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale": "tab HUDの要素の大きさ", + "key.skyblocker.defaultTgl": "tabを開いたときに表示されるHUDをデフォルトに戻す", + "text.autoconfig.skyblocker.option.general.tabHud": "ファンシーなtab HUD", + "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale.@Tooltip": "バニラGUIとの比 (%)で設定します", + "text.autoconfig.skyblocker.option.general.tabHud.tabHudEnabled": "ファンシーなtab HUDを有効にする", + "text.autoconfig.skyblocker.option.general.fairySouls": "フェアリーソウルヘルパー", + "text.autoconfig.skyblocker.option.general.fairySouls.enableFairySoulsHelper": "フェアリーソウルヘルパーを有効にするか", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMotesPrice.@Tooltip": "The Riftディメンションにいるときにアイテムの売値をmotesで表示する。", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMotesPrice": "売値をmotesで表示", + "text.autoconfig.skyblocker.option.general.etherwarpOverlay": "Etherwarp移動先の表示", + "text.autoconfig.skyblocker.option.general.quiverWarning": "Quiverの通知", + "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarning": "Quiverの通知を有効にする", + "text.autoconfig.skyblocker.option.general.shortcuts": "ショートカット", + "text.autoconfig.skyblocker.option.general.shortcuts.enableShortcuts": "ショートカットを有効にする", + "text.autoconfig.skyblocker.option.general.tabHud.nameSorting": "プレイヤー名の並び替えの方式", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.THREE_DAY": "この3日間での平均の値段", + "text.autoconfig.skyblocker.option.general.acceptReparty": "リパーティーの自動受諾", + "text.autoconfig.skyblocker.option.general.specialEffects": "特別なエフェクト", + "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects": "レアなダンジョンドロップのエフェクト", + "text.autoconfig.skyblocker.option.general.compactorDeletorPreview": "CompatorとDeletorのプレビューを有効にする", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds": "アイテムのレアリティを背景にする", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds.@Tooltip": "アイテムスロットの背景をそのアイテムのレアリティに応じた色で表示します。", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundsOpacity": "アイテムのレアリティ背景の不透明度", + "text.autoconfig.skyblocker.option.general.bars.barpositions.LAYER1": "レイヤー1", + "text.skyblocker.open": "開く", + "text.skyblocker.quit_config_sure": "このまま設定画面を閉じてよろしいですか?変更は保存されません!", + "text.skyblocker.quit_discard": "このまま閉じる", + "text.skyblocker.quit_config": "変更が保存されていません", + "text.autoconfig.skyblocker.option.general.bars.barpositions.LAYER2": "レイヤー2", + "text.autoconfig.skyblocker.option.general.bars.barpositions.RIGHT": "右側", + "text.autoconfig.skyblocker.option.general.bars.barpositions.NONE": "オフ", + "text.autoconfig.skyblocker.option.general.shortcuts.enableShortcuts.@Tooltip": "バニラでもどこでも動きます。「/skyblocker shortcuts」で編集でき、使用するには少なくともこの下の設定のうちの一つが有効になっている必要があります。" } diff --git a/src/main/resources/assets/skyblocker/lang/ko_kr.json b/src/main/resources/assets/skyblocker/lang/ko_kr.json index 4cfbab47..7834ca4c 100644 --- a/src/main/resources/assets/skyblocker/lang/ko_kr.json +++ b/src/main/resources/assets/skyblocker/lang/ko_kr.json @@ -30,7 +30,7 @@ "text.autoconfig.skyblocker.option.general.hitbox": "히트박스", "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "1.8 농지 히트박스 활성화", "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "1.8 레버 히트박스 활성화", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §c아이템 가격 툴팁이 최대 60초 이내에 갱신됩니다. 갱신되지 않을 시 latest.log 를 확인하세요.", + "skyblocker.itemTooltip.nullMessage": "§c아이템 가격 툴팁이 최대 60초 이내에 갱신됩니다. 갱신되지 않을 시 latest.log 를 확인하세요.", "skyblocker.itemTooltip.noData": "§c데이터 없음", "text.autoconfig.skyblocker.category.richPresence": "디스코드 Rich Presence", "text.autoconfig.skyblocker.option.richPresence.info": "스카이블록 정보", @@ -43,102 +43,6 @@ "text.autoconfig.skyblocker.option.richPresence.customMessage": "사용자 지정 메시지", "text.autoconfig.skyblocker.category.quickNav": "즐겨찾기", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "즐겨찾기 활성화", - "text.autoconfig.skyblocker.option.quickNav.button1": "버튼 1", - "text.autoconfig.skyblocker.option.quickNav.button1.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button2": "버튼 2", - "text.autoconfig.skyblocker.option.quickNav.button2.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button2.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button2.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button2.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button3": "버튼 3", - "text.autoconfig.skyblocker.option.quickNav.button3.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button3.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button3.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button3.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button4": "버튼 4", - "text.autoconfig.skyblocker.option.quickNav.button4.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button4.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button4.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button4.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button5": "버튼 5", - "text.autoconfig.skyblocker.option.quickNav.button5.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button5.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button5.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button5.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button6": "버튼 6", - "text.autoconfig.skyblocker.option.quickNav.button6.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button6.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button6.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button6.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button7": "버튼 7", - "text.autoconfig.skyblocker.option.quickNav.button7.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button7.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button7.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button7.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button8": "버튼 8", - "text.autoconfig.skyblocker.option.quickNav.button8.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button8.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button8.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button8.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button9": "버튼 9", - "text.autoconfig.skyblocker.option.quickNav.button9.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button9.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button9.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button9.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button10": "버튼 10", - "text.autoconfig.skyblocker.option.quickNav.button10.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button10.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button10.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button10.clickEvent": "클릭 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button11": "버튼 11", - "text.autoconfig.skyblocker.option.quickNav.button11.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button11.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button11.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button11.clickEvent": "클릑 이벤트", - "text.autoconfig.skyblocker.option.quickNav.button12": "버튼 12", - "text.autoconfig.skyblocker.option.quickNav.button12.render": "렌더", - "text.autoconfig.skyblocker.option.quickNav.button12.item": "아이템", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName": "아이템 이름", - "text.autoconfig.skyblocker.option.quickNav.button12.item.count": "아이템 개수", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle": "UI 제목", - "text.autoconfig.skyblocker.option.quickNav.button12.clickEvent": "클릭 이벤트", "text.autoconfig.skyblocker.option.general.itemList": "아이템 목록", "text.autoconfig.skyblocker.option.general.itemList.enableItemList": "아이템 목록 활성화", "text.autoconfig.skyblocker.category.locations": "위치", @@ -161,8 +65,6 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "Dwarven HUD", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "활성화됨", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "배경 활성화", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", "text.autoconfig.skyblocker.category.messages": "메시지", "text.autoconfig.skyblocker.option.messages.chatFilterResult.PASS": "비활성화됨", "text.autoconfig.skyblocker.option.messages.chatFilterResult.FILTER": "필터", diff --git a/src/main/resources/assets/skyblocker/lang/nb_no.json b/src/main/resources/assets/skyblocker/lang/nb_no.json index e44d492f..44d95570 100644 --- a/src/main/resources/assets/skyblocker/lang/nb_no.json +++ b/src/main/resources/assets/skyblocker/lang/nb_no.json @@ -36,111 +36,15 @@ "text.autoconfig.skyblocker.option.richPresence.customMessage": "Egendefinert melding", "text.autoconfig.skyblocker.category.quickNav": "Rask navigering", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "Aktiver hurtignavigering", - "text.autoconfig.skyblocker.option.quickNav.button1.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count": "Gjenstand Teller", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button2": "Knapp 2", - "text.autoconfig.skyblocker.option.quickNav.button2.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button2.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button2.item.count": "Gjenstand Teller", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button2.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button3": "Knapp 3", - "text.autoconfig.skyblocker.option.quickNav.button3.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button3.item.count": "Gjenstand Teller", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button3.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button4": "Knapp 4", - "text.autoconfig.skyblocker.option.quickNav.button4.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button4.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button4.item.count": "Gjenstand Teller", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button5": "Knapp 5", - "text.autoconfig.skyblocker.option.quickNav.button5.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button5.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button5.item.count": "Gjenstand Teller", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt": "NBT", "key.categories.skyblocker": "SkyBlocker", "key.hotbarSlotLock": "Slot lås (Hotbar)", "text.autoconfig.skyblocker.category.general": "Generelt", "text.autoconfig.skyblocker.option.general.bars": "Helse, mana, forsvar og XP-barer", "text.autoconfig.skyblocker.option.general.bars.barpositions.experienceBarPosition": "Experience Bar stilling", "text.autoconfig.skyblocker.option.general.itemTooltip.avg.@Tooltip": "Du kan velge hvor mange dager med gjennomsnittspris som skal være", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cVareprisinformasjon på verktøytips fornyes om maks 60 sekunder. Hvis ikke, sjekk latest.log", - "text.autoconfig.skyblocker.option.quickNav.button1": "Knapp 1", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button3.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button6.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button8.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button10.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button12.item": "Gjenstand", + "skyblocker.itemTooltip.nullMessage": "§cVareprisinformasjon på verktøytips fornyes om maks 60 sekunder. Hvis ikke, sjekk latest.log", "text.autoconfig.skyblocker.option.general.itemList.enableItemList": "Aktiver gjenstad liste", "text.autoconfig.skyblocker.option.locations.dungeons.blazeSolver": "Løs Blaze-puslespillet", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button5.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button6": "Knapp 6", - "text.autoconfig.skyblocker.option.quickNav.button6.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button6.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button6.item.count": "Gjenstand mengde", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button7": "Knapp 7", - "text.autoconfig.skyblocker.option.quickNav.button7.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button7.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button7.item.count": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button7.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button8": "Knapp 8", - "text.autoconfig.skyblocker.option.quickNav.button8.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button8.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button8.item.count": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button9": "Knapp 8", - "text.autoconfig.skyblocker.option.quickNav.button9.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button9.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button9.item.count": "Gjenstand navn", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button9.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button10": "Knapp 1", - "text.autoconfig.skyblocker.option.quickNav.button10.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button10.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button10.item.count": "Gjenstand Mengde", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button11": "Knapp 1", - "text.autoconfig.skyblocker.option.quickNav.button11.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button11.item": "Gjenstand", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button11.item.count": "Gjenstand Mengde", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button11.clickEvent": "Klikk hendelse", - "text.autoconfig.skyblocker.option.quickNav.button12": "Knapp 1", - "text.autoconfig.skyblocker.option.quickNav.button12.render": "Rendering", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName": "Gjenstand Navn", - "text.autoconfig.skyblocker.option.quickNav.button12.item.count": "Gjenstand Mengde", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle": "UI Tittel", - "text.autoconfig.skyblocker.option.quickNav.button12.clickEvent": "Klikk hendelse", "text.autoconfig.skyblocker.option.general.itemList": "Gjenstand liste", "text.autoconfig.skyblocker.option.locations.dungeons": "Dungeons", "text.autoconfig.skyblocker.category.locations": "Lokasjoner", diff --git a/src/main/resources/assets/skyblocker/lang/pt_br.json b/src/main/resources/assets/skyblocker/lang/pt_br.json new file mode 100644 index 00000000..d0371642 --- /dev/null +++ b/src/main/resources/assets/skyblocker/lang/pt_br.json @@ -0,0 +1,242 @@ +{ + "key.skyblocker.toggleB": "Alternar HUD da tab para tela B", + "key.skyblocker.defaultTgl": "Trocar HUD da tab para padrão", + "key.skyblocker.toggleA": "Alternar HUD da tab para tela A", + "key.wikiLookup": "Olhar na Wiki", + "text.autoconfig.skyblocker.category.general": "Geral", + "text.autoconfig.skyblocker.option.general.bars": "Barra de Vida, Mana, Defesa & XP", + "text.autoconfig.skyblocker.option.general.bars.enableBars": "Ativar Barras", + "text.autoconfig.skyblocker.option.general.bars.barpositions.LAYER1": "Camada 1", + "text.autoconfig.skyblocker.option.general.bars.barpositions.LAYER2": "Camada 2", + "text.autoconfig.skyblocker.option.general.bars.barpositions.RIGHT": "Direita", + "text.autoconfig.skyblocker.option.general.bars.barpositions.NONE": "Desativado", + "text.autoconfig.skyblocker.option.general.bars.barpositions.healthBarPosition": "Posição da Barra de Vida", + "text.autoconfig.skyblocker.option.general.bars.barpositions.defenceBarPosition": "Posição da Barra de Defesa", + "text.autoconfig.skyblocker.option.general.bars.barpositions.experienceBarPosition": "Posição da Barra de Experiência", + "text.autoconfig.skyblocker.option.general.experiments": "Solucionador de Experimentos", + "text.autoconfig.skyblocker.option.general.experiments.enableSuperpairsSolver": "Ativar Solucionador de Superpairs", + "text.autoconfig.skyblocker.option.general.experiments.enableUltrasequencerSolver": "Ativar Solucionador de Ultrasequencer", + "text.autoconfig.skyblocker.option.general.tabHud.nameSorting": "Método de Organizar Nome de Player", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMotesPrice": "Ativar Preço de Motes", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableNPCPrice": "Ativar Preço de NPC", + "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects.@Tooltip": "Adiciona um efeito especial visual acionado quando é obtido um loot raro de dungeon!", + "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "Ativar hitbox de farmland do 1.8", + "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "Ativar hitbox de alavanca do 1.8", + "text.autoconfig.skyblocker.option.general.titleContainer": "Contêiner de Título", + "text.autoconfig.skyblocker.option.general.titleContainer.titleContainerScale": "Escala de Contêiner de Título", + "text.autoconfig.skyblocker.option.general.teleportOverlay": "Overlay de Teleporte", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableWeirdTransmission": "Ativar Overlay de Transmissão Estranho", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableInstantTransmission": "Ativar Overlay de Transmissão Instantâneo", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableSinrecallTransmission": "Ativar Overlay de Transmissão de Sinrecall", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableWitherImpact": "Ativar Overlay de Impacto de Wither", + "skyblocker.itemTooltip.noData": "§cSem Dados", + "text.autoconfig.skyblocker.option.richPresence.info": "Informação do Skyblock", + "text.autoconfig.skyblocker.option.richPresence.info.PURSE": "BOLSA", + "text.autoconfig.skyblocker.option.richPresence.info.@Tooltip": "Esse valor não importa se você está passando por um ciclo", + "text.autoconfig.skyblocker.option.richPresence.cycleMode": "Informação de Ciclo do Skyblock", + "text.autoconfig.skyblocker.option.richPresence.enableRichPresence": "Ativado", + "text.autoconfig.skyblocker.option.richPresence.customMessage": "Mensagem Personalizada", + "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "Ativar Navegação Rápida", + "key.hotbarSlotLock": "Trancar Slot (Hotbar)", + "text.autoconfig.skyblocker.title": "Configurações do Skyblocker", + "text.autoconfig.skyblocker.option.general.bars.barpositions": "Configurar Posições das Barras", + "text.autoconfig.skyblocker.option.general.bars.barpositions.manaBarPosition": "Posição da Barra de Mana", + "text.autoconfig.skyblocker.option.general.experiments.enableChronomatronSolver": "Ativar Solucionador de Chronomatron", + "text.autoconfig.skyblocker.option.general.acceptReparty": "Aceitar Automaticamente Reparty", + "text.autoconfig.skyblocker.option.general.shortcuts": "Atalhos", + "text.autoconfig.skyblocker.option.general.shortcuts.enableShortcuts": "Ativar Atalhos", + "text.autoconfig.skyblocker.option.general.tabHud.plainPlayerNames": "Nomes de Players Simples", + "text.autoconfig.skyblocker.option.general.tabHud.plainPlayerNames.@Tooltip": "Ative para mostrar nomes de player sem formatação especial em ilhas publicas.", + "text.autoconfig.skyblocker.option.general.specialEffects": "Efeitos Especial", + "text.autoconfig.skyblocker.option.general.specialEffects.rareDungeonDropEffects": "Efeito de Drop Raro de Dungeon", + "text.autoconfig.skyblocker.option.general.titleContainer.@Tooltip": "Usado para mostrar vários títulos de uma vez, Exemplo de uso: Vampire Slayer", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableTeleportOverlays": "Ativar Overlays de Teleporte", + "text.autoconfig.skyblocker.option.general.teleportOverlay.enableEtherTransmission": "Ativar Overlay de Transmissão Éter", + "skyblocker.itemTooltip.nullMessage": "§cA Informação do preço do item no tooltip irá se renovar no máximo 60 segundos. Caso contrário, cheque \"latest.log\"", + "text.autoconfig.skyblocker.option.richPresence.info.LOCATION": "LOCALIZAÇÃO", + "text.autoconfig.skyblocker.category.quickNav": "Navegação Rápida", + "key.categories.skyblocker": "Skyblocker", + "text.autoconfig.skyblocker.option.general.etherwarpOverlay": "Overlay de Etherwarp", + "text.autoconfig.skyblocker.option.general.fishing": "Assistente de Pesca", + "text.autoconfig.skyblocker.option.general.fishing.enableFishingHelper": "Ativar Assistente de Pesca", + "text.autoconfig.skyblocker.option.general.fairySouls": "Assistente de Alma das Fadas", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightFoundSouls": "Destacar alma das fadas encontradas", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls": "Apenas destacar alma das fadas por perto", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandShortcuts": "Ativar Atalhos de Comando", + "text.autoconfig.skyblocker.option.general.shortcuts.enableShortcuts.@Tooltip": "Funciona em qualquer lugar, até mesmo no vanilla! Edite atalhos com \"/skyblocker shortcuts\". Pelo menos uma das opções tem que está ativo para tomar efeito.", + "text.autoconfig.skyblocker.option.general.tabHud": "HUD do tab Bonito", + "text.autoconfig.skyblocker.option.general.tabHud.tabHudEnabled": "Ativar HUD do tab Bonito", + "text.autoconfig.skyblocker.option.general.itemTooltip": "Tooltip do Item", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableAvgBIN": "Ativar Preço Mediano do BIN", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.THREE_DAY": "Preço de 3 dias", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.BOTH": "Ambos", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableLowestBIN": "Ativar Menor Preço do BIN", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.@Tooltip": "Você pode escolher quantos dias de preço médio para ser", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay": "Exibição de Informação do Item", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo": "Informação de Fragmento de Atributo", + "text.autoconfig.skyblocker.category.richPresence": "Discord Rich Presence", + "text.autoconfig.skyblocker.option.richPresence.info.BITS": "BITS", + "text.autoconfig.skyblocker.category.messages": "Mensagens", + "text.autoconfig.skyblocker.option.messages.hideImplosion": "Esconder Mensagem de Implosão", + "text.autoconfig.skyblocker.option.messages.hideMoltenWave": "Esconder Mensagem do Molten Wave", + "text.autoconfig.skyblocker.option.messages.hideAds": "Esconder Anúncios do Chat Público", + "text.autoconfig.skyblocker.option.messages.hideCombo": "Esconder Mensagens de Combo", + "text.autoconfig.skyblocker.option.messages.hideAutopet": "Esconder Mensagens de Autopet", + "text.autoconfig.skyblocker.option.messages.hideMana": "Esconder Mensagens de Consumo de Mana da Barra de Ação", + "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "Oferece uma experiência melhor com FancyBar", + "text.autoconfig.skyblocker.option.messages.hideShowOff.@Tooltip": "Filtra mensagens do comando /show", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.enableEffigyWaypoints": "Ativar Waypoints de Effigy", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.compactEffigyWaypoints": "Compactar Waypoints de Effigy", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.effigyUpdateFrequency.@Tooltip": "Quanto menor o valor, maior será a frequência de atualizações, o que irá talvez causa lag.", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.enableHolyIceIndicator": "Ativar Indicador de Gelo Santo", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.holyIceIndicatorTickDelay": "Atraso (Ticks) do Indicador de Gelo Santo", + "skyblocker.shortcuts.config": "Configurações de atalhos", + "skyblocker.shortcuts.new": "Novo Atalho", + "skyblocker.shortcuts.deleteQuestion": "Você tem certeza que quer remover esse atalho?", + "emi.category.skyblocker.skyblock": "Skyblock", + "text.autoconfig.skyblocker.option.general.backpackPreviewWithoutShift": "Ver preview da mochila sem segurar Shift", + "skyblocker.shortcuts.commandSuggestionTooltip": "Devido às limitações do Minecraft, sugestões de comando vai apenas funcionar após o reiniciamento do jogo.", + "skyblocker.shortcuts.deleteWarning": "Atalho '%s' vai ser perdido para sempre! (Por um longo tempo!)", + "skyblocker.shortcuts.notLoaded": "§c§lAtalhos ainda não foram carregados", + "text.autoconfig.skyblocker.category.locations": "Localizações", + "text.autoconfig.skyblocker.option.general.fairySouls.enableFairySoulsHelper": "Ativar Assistente de Alma das Fadas", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls.@Tooltip": "Quando ativado, somente a alma das fadas em um raio de 50 blocos são destacados", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandShortcuts.@Tooltip": "Atalhos para comandos consistindo em apenas uma palavra. Edite atalhos com \"/skyblocker shortcuts\". Atalhos tem que está ativos para tomar efeito.", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg": "Tipo Mediano", + "text.autoconfig.skyblocker.option.general.itemTooltip.avg.ONE_DAY": "Preço de 1 dia", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableBazaarPrice": "Ativar Preço de compra/venda do Bazar", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumDate": "Ativar Museu & Data", + "text.autoconfig.skyblocker.option.messages.hideAOTE": "Esconder Mensagens do AOTE", + "text.autoconfig.skyblocker.option.messages.hideTeleportPad": "Esconder Mensagens do Pad de Teleporte", + "text.autoconfig.skyblocker.option.messages.hideShowOff": "Esconder Mensagens de Show Off", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.effigyUpdateFrequency": "Frequência de Atualização (Ticks) de Waypoints de Effigy", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.holyIceUpdateFrequency.@Tooltip": "Quanto menor o valor, maior será a frequência de atualizações, o que irá talvez causa lag.", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.steakStakeUpdateFrequency.@Tooltip": "Quanto menor o valor, maior será a frequência de atualizações, o que irá talvez causa lag.", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.maniaUpdateFrequency.@Tooltip": "Quanto menor o valor, maior será a frequência de atualizações, o que irá talvez causa lag.", + "text.autoconfig.skyblocker.option.general.hideEmptyTooltips": "Esconder tooltips vazio de itens nos menus", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts": "Ativar Atalhos de Argumentos de Comando", + "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningInDungeons": "Ativar Aviso de Aljava em Dungeons", + "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningAfterDungeon": "Ativar Aviso de Aljava Após uma Dungeon", + "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale": "Fator de escala do HUD de tab Bonito", + "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale.@Tooltip": "Valor em %, relativo a sua escala vanilla do GUI", + "text.autoconfig.skyblocker.option.general.hitbox": "Hitboxes", + "skyblocker.relics.markAllFound": "§rTodas as relíquias foram marcadas como encontradas", + "skyblocker.shortcuts.command.target": "Comando alvo", + "skyblocker.shortcuts.command.replacement": "Comando de substituição", + "skyblocker.shortcuts.commandArg.target": "Argumento do comando alvo", + "skyblocker.shortcuts.commandArg.replacement": "Argumento do comando de substituição", + "skyblocker.customDyeColors.invalidHex": "§cCódigo de cor HEX invalido!", + "skyblocker.customItemNames.unableToSetName": "§cNão foi possível colocar um nome personalizado no item :( (Você está no skyblock?, Você está segurando um item?)", + "skyblocker.customDyeColors.notDyeable": "§cEsse item não é uma peça de armadura pintável!", + "skyblocker.customDyeColors.removed": "§fRemovido a cor personalizada desse item.", + "skyblocker.quiverWarning.50Left": "Você tem apenas 50 flechas restantes no seu Aljava!", + "skyblocker.customArmorTrims.neverHad": "§fEsse item ainda não tem um acabamento personalizado de armadura colocada, por que não coloca uma? ;)", + "skyblocker.customArmorTrims.unableToSetTrim": "§cNão foi possível colocar um acabamento personalizado na armadura :( (Você está no skyblock?, Você está segurando um item?)", + "skyblocker.quiverWarning.10Left": "Você tem apenas 10 flechas restantes no seu Aljava!", + "skyblocker.quiverWarning.empty": "Você não tem nenhuma flecha no seu Aljava!", + "text.autoconfig.skyblocker.option.general.quiverWarning": "Aviso de Aljava", + "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarning": "Ativar Aviso de Aljava", + "skyblocker.customArmorTrims.notAnArmorPiece": "§cEsse item não é uma peça de armadura!", + "skyblocker.customArmorTrims.added": "§fColoque um acabamento personalizado de armadura para o item que você está segurando!", + "skyblocker.customItemNames.neverHad": "§fEsse item ainda não tem um nome personalizado colocado, por que não colocar um? ;)", + "skyblocker.relics.markAllMissing": "§rTodas as relíquias foram marcadas como pendentes", + "skyblocker.dungeons.secrets.markSecretFound": "§r#%d segredo marcado como encontrado.", + "skyblocker.dungeons.secrets.markSecretMissing": "§r#%d segredo marcado como pendente.", + "skyblocker.customArmorTrims.noItemUuid": "§cVocê tem que tá segurando um item que tenha um uuid para poder colocar um acabamento personalizado na armadura!", + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts.@Tooltip": "Atalhos que trocam uma ou mais palavra(s)/argumento(s) de um comando com múltiplas palavras/argumentos. Edite atalhos com \"/skyblocker shortcuts\". Atalhos tem que está ativos para tomar efeito.", + "text.autoconfig.skyblocker.option.general.compactorDeletorPreview": "Ativar Preview do Compactador/Deletador", + "text.autoconfig.skyblocker.option.general.tabHud.nameSorting.@Tooltip": "Ordenando nomes em ordem alfabética enquanto Padrão não tem uma ordem particular.", + "text.autoconfig.skyblocker.option.general.itemTooltip.enableMotesPrice.@Tooltip": "Mostrar os preços de venda dos Motes de um item enquanto está no The Rift.", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo.@Tooltip": "Mostra o nível do atributo como uma contagem de stack e os iniciais do nome do atributo.", + "text.autoconfig.skyblocker.category.slayer": "Slayers", + "skyblocker.updaterepository.failed": "§cAtualização do repositório local falhou. Remova os arquivos manualmente e reinicie o jogo.", + "text.autoconfig.skyblocker.option.general.hideStatusEffectOverlay": "Esconder Overlay de Status de Efeitos", + "text.autoconfig.skyblocker.option.general.itemList.enableItemList": "Ativar Lista de Itens", + "text.autoconfig.skyblocker.option.general.itemList": "Lista de Itens", + "text.skyblocker.open": "Abrir", + "text.skyblocker.quit_config": "Mudanças Não Salvas", + "text.skyblocker.quit_config_sure": "Você tem certeza que quer sair de editar as configurações? Mudanças não vão ser salvas!", + "text.skyblocker.quit_discard": "Sair & Descartar Mudanças", + "text.autoconfig.skyblocker.option.general.shortcuts.config": "Configurações de Atalhos...", + "text.autoconfig.skyblocker.option.general.flameOverlay": "Overlay de Chama", + "text.autoconfig.skyblocker.option.general.flameOverlay.flameHeight": "Altura da Chama", + "text.autoconfig.skyblocker.option.general.flameOverlay.flameOpacity": "Opacidade da Chama", + "text.autoconfig.skyblocker.option.general.itemCooldown": "Cooldown de Item", + "text.autoconfig.skyblocker.option.general.itemCooldown.enableItemCooldowns": "Ativar Cooldown de Item", + "text.autoconfig.skyblocker.option.general.titleContainer.config": "Configuração de Colocação do Contêiner de Título...", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgroundsOpacity": "Opacidade do Fundos de Raridade de Item", + "text.autoconfig.skyblocker.option.general.wikiLookup": "Olhar na Wiki", + "text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup": "Ativar Olhar na Wiki", + "text.autoconfig.skyblocker.option.general.wikiLookup.enableWikiLookup.@Tooltip": "Abrir a pagina da wiki do item com o mouse em cima com F4.", + "text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki": "Usar Wiki Oficial", + "text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki.@Tooltip": "Usar a wiki oficial em vez da wiki do Fandom.", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds": "Fundos de Raridade de Item", + "text.autoconfig.skyblocker.option.general.itemInfoDisplay.itemRarityBackgrounds.@Tooltip": "Mostra um fundo colorido atrás de um item, a cor representa a raridade do item.", + "text.autoconfig.skyblocker.option.locations.dungeons.mapScreen": "Configuração da posição do mapa da dungeon...", + "text.autoconfig.skyblocker.option.locations.dungeons.solveThreeWeirdos": "Guia para Puzzle dos Three Weridos", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[0]": "Simples: Exibe nome e porcentagem.", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.neutralThreshold": "Limite neutro", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.profitColor": "Cor do lucro", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.lossColor": "Cor de prejuízo", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor": "Cor incompleta", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.incompleteColor.@Tooltip": "A cor exibida quando a data de preço é incompleta.", + "text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper.@Tooltip": "Acinzentar os baús que já foram abertos.", + "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.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", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.holyIceUpdateFrequency": "Frequência de atualização de indicador do Holy Ice (Em Ticks)", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.enableManiaIndicator": "Ativar indicador de Mania Block", + "skyblocker.dungeons.secrets.markSecretFoundUnable": "§cImpossibilitado de marcar segredo #%d como encontrado.", + "skyblocker.dungeons.secrets.markSecretMissingUnable": "§cImpossibilitado de marcar segredo #%d como pendente.", + "skyblocker.rift.healNow": "Cure agora!", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.enableDrillFuel": "Ativar combustível da broca", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.solveFetchur": "Guia para Fetchur", + "text.autoconfig.skyblocker.option.locations.rift": "A fenda", + "text.autoconfig.skyblocker.option.locations.rift.mirrorverseWaypoints": "Ativar marcadores do Mirrorverse", + "text.autoconfig.skyblocker.option.locations.dungeons.blazeSolver": "Guia para puzzle do Blaze", + "text.autoconfig.skyblocker.option.locations.dungeons.blazeSolver.@Tooltip": "Cria uma caixa em cor verde para o blaze correto além de desenhar uma linha, e cria uma caixa para o próximo blaze a ser morto em cor branca.", + "text.autoconfig.skyblocker.option.locations.dungeons.creeperSolver": "Guia para puzzle dos feixes de Creeper", + "text.autoconfig.skyblocker.option.locations.dungeons.creeperSolver.@Tooltip": "Contornar os melhores feixes para fazer o alvo atingir.", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText": "Texto da cor do Livid", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.solvePuzzler": "Guia para puzzle do Puzzler", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "Interface da mina dos anões", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "Ativado", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style": "Estilo para a interface", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[2]": "\nClássico: Exibe nome e porcentagem em uma caixa super simples.", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Ativar fundo", + "text.autoconfig.skyblocker.option.locations.rift.mcGrubberStacks": "Pilhas de McGrubber", + "text.autoconfig.skyblocker.option.messages.chatFilterResult.PASS": "Desativado", + "text.autoconfig.skyblocker.option.messages.chatFilterResult.FILTER": "Filtro", + "text.autoconfig.skyblocker.option.messages.chatFilterResult.ACTION_BAR": "Mover para Action Bar", + "text.autoconfig.skyblocker.option.messages.hideAbility": "Esconder tempo de espera de habilidade", + "text.autoconfig.skyblocker.option.messages.hideHeal": "Esconder mensagens de cura", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.enableSteakStakeIndicator": "Ativar indicador estaca de carne", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.steakStakeUpdateFrequency": "Frequência de atualização de estanca de carne (Em Ticks)", + "skyblocker.rift.iceNow": "Gelo agora!", + "skyblocker.rift.mania": "Mania!", + "skyblocker.rift.stakeNow": "Estaca agora!", + "skyblocker.fairySouls.markAllFound": "§rMarcada todas as almas de fadas na ilha atual como encontradas", + "text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper": "Guia para Croesus", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.neutralColor": "Cor do neutro", + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.neutralThreshold.@Tooltip": "O limite abaixo do qual o lucro é declarado neutro.", + "text.autoconfig.skyblocker.option.locations.dungeons.solveTrivia": "Guia para puzzle do Trivia", + "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveStartsWith": "Guia de \"começa com\"", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer": "Caçador de Vampiros", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.enableHealingMelonIndicator": "Ativar indicador de Healing Melon", + "skyblocker.fishing.reelNow": "Entre agora!", + "text.autoconfig.skyblocker.option.locations.dungeons.solveTicTacToe.@Tooltip": "Coloca uma caixa vermelha em volta do próximo melhor movimento para você fazer!", + "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Texto o qual será mandado no chat durante a luta contra Livid. A linha \"[cor]\" vai ser preenchida com a cor do Livid.", + "text.autoconfig.skyblocker.option.locations.dwarvenMines": "Mina dos anões", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[1]": "\nBonito: Exibe nome, porcentagem, barra de progresso e um ícone.", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.screen": "Configurações da interface da mina dos anões...", + "text.autoconfig.skyblocker.option.locations.rift.mcGrubberStacks.@Tooltip": "Usado para calcular preço de venda de Motes.", + "skyblocker.fairySouls.markAllMissing": "§rMarcada todas as almas de fadas na ilha atual como pendentes", + "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." +} diff --git a/src/main/resources/assets/skyblocker/lang/ru_ru.json b/src/main/resources/assets/skyblocker/lang/ru_ru.json index 5ef92494..980c130a 100644 --- a/src/main/resources/assets/skyblocker/lang/ru_ru.json +++ b/src/main/resources/assets/skyblocker/lang/ru_ru.json @@ -26,7 +26,7 @@ "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveColor": "Показывать Решение Select Colored", "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveOrder": "Показывать Решение Click In Order", "text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveStartsWith": "Показывать Решение Starts With", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cИнформация о цене предмета обновится менее чем через 60 секунд. Если нет, проверьте latest.log", + "skyblocker.itemTooltip.nullMessage": "§cИнформация о цене предмета обновится менее чем через 60 секунд. Если нет, проверьте latest.log", "text.autoconfig.skyblocker.option.messages.hideTeleportPad": "Скрывать сообщения Teleport Pad", "text.autoconfig.skyblocker.option.general.itemTooltip.enableAvgBIN": "Показать средние цены на BIN", "text.autoconfig.skyblocker.option.general.itemTooltip.avg": "Период времени (для средней цены)", @@ -55,7 +55,6 @@ "text.autoconfig.skyblocker.option.general.backpackPreviewWithoutShift": "Просматривать содержимое рюкзаков без удержания кнопки Shift", "text.autoconfig.skyblocker.option.general.bars.barpositions.NONE": "Выключена", "text.autoconfig.skyblocker.option.general.bars.barpositions.manaBarPosition": "Расположение полоски маны", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "Предмет", "skyblocker.fishing.reelNow": "Тяни!", "text.autoconfig.skyblocker.option.messages.hideAutopet": "Скрывать сообщения Autopet", "text.autoconfig.skyblocker.option.messages.hideMana": "Скрывать сообщения о расходе маны из Action Bar", @@ -74,133 +73,34 @@ "text.autoconfig.skyblocker.option.richPresence.info.LOCATION": "LOCATION", "text.autoconfig.skyblocker.category.quickNav": "Быстрый Доступ", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "Включить Быстрый Доступ", - "text.autoconfig.skyblocker.option.quickNav.button1": "Кнопка 1", - "text.autoconfig.skyblocker.option.quickNav.button2": "Кнопка 2", - "text.autoconfig.skyblocker.option.quickNav.button3": "Кнопка 3", "text.autoconfig.skyblocker.option.general.tabHud": "Красивое TAB меню", "key.skyblocker.defaultTgl": "Показывать стандартное меню TAB", "text.autoconfig.skyblocker.option.general.tabHud.tabHudEnabled": "Включить красивое TAB меню", "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale": "Размер TAB меню", "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale.@Tooltip": "Значение в %, по отношению к размеру интерфейса игры", - "text.autoconfig.skyblocker.option.quickNav.button2.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button3.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button6.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button8.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button11.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button11.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button12.clickEvent": "Команда по щелчку", "text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper.@Tooltip": "Уже открытые сундуки будут закрашены серым.", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Текст, который будет отправлен в чат во время боя с Livid. Вместо \"[color]\" отправится цвет босса.", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[1]": "Красивый: Показывает название, процент и шкалу выполнения, а также иконку.", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[1]": "\nКрасивый: Показывает название, процент и шкалу выполнения, а также иконку.", "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "Размер Карты", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button5.item": "Предмет", "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.enableLividColor": "Включить Цвет Босса 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.lividColorText": "Текст О Цвете Livid", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", - "text.autoconfig.skyblocker.option.locations.dungeons.mapX": "Карта по X", - "text.autoconfig.skyblocker.option.locations.dungeons.mapY": "Карта по Y", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style": "Стиль HUD", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[0]": "Упрощенный: Показывает название и процент выполнения.", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[2]": "Классический: Показывает название и процент выполнения в простом тёмном квадрате.", + "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.style.@Tooltip[2]": "\nКлассический: Показывает название и процент выполнения в простом тёмном квадрате.", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Включить Фон", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "Включить", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "Dwarven HUD (Интерфейс Гномьих Шахт)", "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "Выглядит лучше, когда включены полоски Skyblocker (здоровья, маны и т.д.)", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent": "Команда по щелчку", "text.autoconfig.skyblocker.option.locations.barn": "Barn (Ферма)", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "Название Кнопки", "text.autoconfig.skyblocker.option.messages.chatFilterResult.ACTION_BAR": "Переместить в action bar", "text.autoconfig.skyblocker.option.locations.barn.solveHungryHiker": "Показывать Решение Hungry Hiker", "text.autoconfig.skyblocker.option.locations.barn.solveTreasureHunter": "Показывать Решение Treasure Hunter", "text.autoconfig.skyblocker.option.messages.chatFilterResult.FILTER": "Скрыть", "text.autoconfig.skyblocker.option.messages.chatFilterResult.PASS": "Не скрывать", - "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §cОшибка в обновлении местного репозитория. Перезапустите игру, удалив файлы вручную.", + "skyblocker.updaterepository.failed": "§cОшибка в обновлении местного репозитория. Перезапустите игру, удалив файлы вручную.", "text.autoconfig.skyblocker.option.richPresence.info.BITS": "BITS", - "text.autoconfig.skyblocker.option.quickNav.button2.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button2.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button2.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button3.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button3.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button5.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button5.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button6": "Кнопка 6", - "text.autoconfig.skyblocker.option.quickNav.button6.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button6.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button7": "Кнопка 7", - "text.autoconfig.skyblocker.option.quickNav.button7.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button7.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button7.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button8": "Кнопка 8", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button8.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button6.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button7.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button8.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button3.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button4": "Кнопка 4", - "text.autoconfig.skyblocker.option.quickNav.button4.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button4.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button4.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button4.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button5": "Кнопка 5", - "text.autoconfig.skyblocker.option.quickNav.button5.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button8.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button9": "Кнопка 9", - "text.autoconfig.skyblocker.option.quickNav.button9.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button9.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button9.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button10": "Кнопка 10", - "text.autoconfig.skyblocker.option.quickNav.button9.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button10.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button10.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button10.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button10.clickEvent": "Команда по щелчку", - "text.autoconfig.skyblocker.option.quickNav.button11": "Кнопка 11", - "text.autoconfig.skyblocker.option.quickNav.button11.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button11.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle": "Название Кнопки", - "text.autoconfig.skyblocker.option.quickNav.button12": "Кнопка 12", - "text.autoconfig.skyblocker.option.quickNav.button12.render": "Отображать", - "text.autoconfig.skyblocker.option.quickNav.button12.item": "Предмет", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName": "ID Предмета", - "text.autoconfig.skyblocker.option.quickNav.button12.item.count": "Количество", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt": "NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle": "Название Кнопки", "text.autoconfig.skyblocker.option.locations.dungeons.croesusHelper": "Помощь в меню Croesus", "text.autoconfig.skyblocker.option.general.experiments": "Помощь в Экспериментах", "text.autoconfig.skyblocker.option.general.experiments.enableUltrasequencerSolver": "Решать Ultrasequencer", @@ -249,5 +149,6 @@ "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarning": "Включить предупреждение о нехватке стрел", "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningInDungeons": "Включить предупреждение о нехватке стрел (только в данжах)", "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarningAfterDungeon": "Включить предупреждение о нехватке стрел (после прохождения данжа)", - "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts": "Включить сокращения аргументов команд" + "text.autoconfig.skyblocker.option.general.shortcuts.enableCommandArgShortcuts": "Включить сокращения аргументов команд", + "text.autoconfig.skyblocker.option.slayer.vampireSlayer.maniaUpdateFrequency.@Tooltip": "Чем меньше значение, тем чаще происходит обновление, что может привести к лагам." } diff --git a/src/main/resources/assets/skyblocker/lang/tr_tr.json b/src/main/resources/assets/skyblocker/lang/tr_tr.json index 8dee9a26..f6b31dec 100644 --- a/src/main/resources/assets/skyblocker/lang/tr_tr.json +++ b/src/main/resources/assets/skyblocker/lang/tr_tr.json @@ -10,7 +10,7 @@ "text.autoconfig.skyblocker.option.general.itemTooltip.enableBazaarPrice": "Pazar alış/satış fiyatını göster", "text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumDate": "Müze ve tarih bilgisini göster", "text.autoconfig.skyblocker.option.general.hitbox": "Hitbox'lar", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cEşya açıklamasındaki ürün fiyat bilgisi en fazla 60 saniye içinde yenilenecektir. Aksi takdirde latest.log dosyasını kontrol edin", + "skyblocker.itemTooltip.nullMessage": "§cEşya açıklamasındaki ürün fiyat bilgisi en fazla 60 saniye içinde yenilenecektir. Aksi takdirde latest.log dosyasını kontrol edin", "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "1.8 tarım hitboxlarını etkinleştir", "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "1.8 şalter hitboxunu etkinleştir", "skyblocker.itemTooltip.noData": "§cVeri yok", @@ -39,8 +39,6 @@ "text.autoconfig.skyblocker.option.messages.hideMana": "Aksiyon barındaki mana tüketimlerini gizle", "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "FancyBar ile daha iyi bir deneyim sunar", "text.autoconfig.skyblocker.option.general.hideEmptyTooltips": "Menülerdeki boş eşya açıklamalarını gizle", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "Y", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "X", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "Arka planı göster", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "Etkinleştir", "text.autoconfig.skyblocker.option.general.itemTooltip.avg.@Tooltip": "Kaç günlük ortalamanın gösterileceğini seçebilirsiniz", @@ -60,7 +58,7 @@ "text.autoconfig.skyblocker.option.general.bars.barpositions.defenceBarPosition": "Defans barı konumu", "text.autoconfig.skyblocker.option.general.bars.barpositions.experienceBarPosition": "Tecrübe barı konumu", "key.categories.skyblocker": "Skyblocker", - "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §cYerel depo güncellenemedi. Dosyaları manuel olarak silip oyunu tekrar başlatın.", + "skyblocker.updaterepository.failed": "§cYerel depo güncellenemedi. Dosyaları manuel olarak silip oyunu tekrar başlatın.", "text.autoconfig.skyblocker.option.general.fishing": "Balık Tutma Yardımcısı", "text.autoconfig.skyblocker.option.general.fishing.enableFishingHelper": "Balık tutma yardımcısını aktifleştir", "text.autoconfig.skyblocker.category.messages": "Mesajlar", diff --git a/src/main/resources/assets/skyblocker/lang/zh_cn.json b/src/main/resources/assets/skyblocker/lang/zh_cn.json index d322b371..4a3abde3 100644 --- a/src/main/resources/assets/skyblocker/lang/zh_cn.json +++ b/src/main/resources/assets/skyblocker/lang/zh_cn.json @@ -30,7 +30,7 @@ "text.autoconfig.skyblocker.option.general.hitbox": "碰撞箱", "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "启用1.8的农田碰撞箱", "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "启用1.8的拉杆碰撞箱", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §c物品提示里的价格信息会在最多60秒内更新。如果没有,请检查latest.log", + "skyblocker.itemTooltip.nullMessage": "§c物品提示里的价格信息会在最多60秒内更新。如果没有,请检查latest.log", "skyblocker.itemTooltip.noData": "§c没有数据", "text.autoconfig.skyblocker.category.richPresence": "Discord活动状态", "text.autoconfig.skyblocker.option.richPresence.info": "Skyblock信息", @@ -43,18 +43,6 @@ "text.autoconfig.skyblocker.option.richPresence.customMessage": "自定义消息", "text.autoconfig.skyblocker.category.quickNav": "快速导航", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "启用快速导航", - "text.autoconfig.skyblocker.option.quickNav.button1": "热键1", - "text.autoconfig.skyblocker.option.quickNav.button2": "热键2", - "text.autoconfig.skyblocker.option.quickNav.button3": "热键3", - "text.autoconfig.skyblocker.option.quickNav.button4": "热键4", - "text.autoconfig.skyblocker.option.quickNav.button5": "热键5", - "text.autoconfig.skyblocker.option.quickNav.button6": "热键6", - "text.autoconfig.skyblocker.option.quickNav.button7": "热键7", - "text.autoconfig.skyblocker.option.quickNav.button8": "热键8", - "text.autoconfig.skyblocker.option.quickNav.button9": "热键9", - "text.autoconfig.skyblocker.option.quickNav.button10": "热键10", - "text.autoconfig.skyblocker.option.quickNav.button11": "热键11", - "text.autoconfig.skyblocker.option.quickNav.button12": "热键12", "text.autoconfig.skyblocker.option.general.itemList": "物品列表", "text.autoconfig.skyblocker.option.general.itemList.enableItemList": "启用物品列表", "text.autoconfig.skyblocker.category.locations": "位置", @@ -79,8 +67,6 @@ "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud": "矮人矿井 HUD", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enabled": "启用", "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.enableBackground": "启用背景", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.x": "HUD所在横向位置", - "text.autoconfig.skyblocker.option.locations.dwarvenMines.dwarvenHud.y": "HUD所在纵向位置", "text.autoconfig.skyblocker.category.messages": "消息", "text.autoconfig.skyblocker.option.messages.chatFilterResult.PASS": "禁用", "text.autoconfig.skyblocker.option.messages.chatFilterResult.FILTER": "启用", @@ -96,93 +82,9 @@ "text.autoconfig.skyblocker.option.messages.hideAutopet": "隐藏自动宠物消息", "text.autoconfig.skyblocker.option.messages.hideMana": "在动作栏中隐藏法力消耗信息", "text.autoconfig.skyblocker.option.messages.hideMana.@Tooltip": "已被更好的属性条代替", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button4.item.nbt": "物品NBT", "text.autoconfig.skyblocker.option.general.hideEmptyTooltips": "隐藏菜单中分隔符的物品信息", "text.autoconfig.skyblocker.option.locations.dungeons.mapScaling": "地图界面大小", - "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §c更新本地数据存储库失败,请手动删库并重启游戏", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button1.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button2.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button2.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button2.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button2.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button2.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button2.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button2.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button3.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button3.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button3.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button3.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button3.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button3.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button4.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button4.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button4.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button4.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button4.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button5.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button5.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button5.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button5.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button5.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button5.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button5.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button6.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button6.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button6.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button6.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button6.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button6.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button7.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button7.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button7.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button7.item.count": "热键物品显示数量", - "text.autoconfig.skyblocker.option.quickNav.button7.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button8.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button8.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button8.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button8.item.count": "热键物品显示数量", - "text.autoconfig.skyblocker.option.quickNav.button8.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button8.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button8.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button9.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button9.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button9.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button9.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button9.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button9.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button10.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button10.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button10.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button10.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button10.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button10.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button12.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button11.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button11.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button11.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button11.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button11.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button11.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button11.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button12.render": "是否显示该热键", - "text.autoconfig.skyblocker.option.quickNav.button12.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button12.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button12.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button12.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button12.uiTitle": "快捷界面标题", - "text.autoconfig.skyblocker.option.quickNav.button3.item": "热键所显示物品", - "text.autoconfig.skyblocker.option.quickNav.button4.item.count": "物品数量", - "text.autoconfig.skyblocker.option.quickNav.button6.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button7.clickEvent": "点击时所执行的命令", - "text.autoconfig.skyblocker.option.quickNav.button9.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button10.clickEvent": "点击时所执行的命令", + "skyblocker.updaterepository.failed": "§c更新本地数据存储库失败,请手动删库并重启游戏", "text.autoconfig.skyblocker.option.general.fishing": "钓鱼助手", "text.autoconfig.skyblocker.option.general.fishing.enableFishingHelper": "启用钓鱼助手", "skyblocker.fishing.reelNow": "收竿!", @@ -193,8 +95,6 @@ "text.autoconfig.skyblocker.option.locations.dungeons.lividColor.lividColorText.@Tooltip": "Livid Boss战时发送到聊天栏的信息, 字段 “[color]” 将被替换为真 Livid 的颜色", "key.skyblocker.defaultTgl": "将tab键所显示的列表改为默认空岛生存列表", "text.autoconfig.skyblocker.option.general.tabHud.tabHudEnabled": "启用更好的Tab HUD", - "text.autoconfig.skyblocker.option.locations.dungeons.mapX": "地图所在横向位置", - "text.autoconfig.skyblocker.option.locations.dungeons.mapY": "地图所在纵向位置", "text.autoconfig.skyblocker.option.general.tabHud": "更好的Tab HUD", "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale": "更好的Tab HUD缩放大小", "text.autoconfig.skyblocker.option.general.tabHud.tabHudScale.@Tooltip": "相对于原版 GUI 的百分比大小", @@ -243,5 +143,14 @@ "text.autoconfig.skyblocker.option.general.quiverWarning": "箭袋提示", "text.autoconfig.skyblocker.option.general.quiverWarning.enableQuiverWarning": "启用箭袋提示", "text.autoconfig.skyblocker.option.general.itemInfoDisplay": "物品信息显示", - "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.enableProfitCalculator": "启用利润计算器" + "text.autoconfig.skyblocker.option.locations.dungeons.dungeonChestProfit.enableProfitCalculator": "启用利润计算器", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls.@Tooltip": "当此功能启用时, 在玩家半径50格以内的仙女之魂将被高亮", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightFoundSouls": "将已找到的仙女之魂高亮", + "text.autoconfig.skyblocker.option.general.fairySouls.highlightOnlyNearbySouls": "仅高亮附近的仙女之魂", + "text.skyblocker.quit_discard": "不保存退出", + "text.skyblocker.quit_config": "修改未保存", + "text.skyblocker.quit_config_sure": "确定退出吗? 你的修改将不会被保存!", + "text.autoconfig.skyblocker.option.general.wikiLookup": "查阅 wiki", + "text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki": "使用Hypixel官方 Wiki", + "text.autoconfig.skyblocker.option.general.wikiLookup.officialWiki.@Tooltip": "在查阅时使用Hypixel 官方 wiki 代替 Fandom wiki" } diff --git a/src/main/resources/assets/skyblocker/lang/zh_tw.json b/src/main/resources/assets/skyblocker/lang/zh_tw.json index 1f53842b..d412de9c 100644 --- a/src/main/resources/assets/skyblocker/lang/zh_tw.json +++ b/src/main/resources/assets/skyblocker/lang/zh_tw.json @@ -33,13 +33,10 @@ "text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumDate": "顯示博物館与日期訊息", "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "啟用1.8的控制桿判定箱", "text.autoconfig.skyblocker.option.general.hitbox": "判定箱", - "skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §c物品資訊裡面的價格訊息會在最多60秒內更新。如果沒有,請檢查latest.log", + "skyblocker.itemTooltip.nullMessage": "§c物品資訊裡面的價格訊息會在最多60秒內更新。如果沒有,請檢查latest.log", "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "啟用1.8的耕地判定箱", "text.autoconfig.skyblocker.category.quickNav": "快速導航", "text.autoconfig.skyblocker.option.quickNav.enableQuickNav": "啟用快速導航", - "text.autoconfig.skyblocker.option.quickNav.button1": "熱鍵1", - "text.autoconfig.skyblocker.option.quickNav.button1.render": "是否顯示該熱鍵", - "text.autoconfig.skyblocker.option.quickNav.button1.item": "熱鍵所顯示物品", "text.autoconfig.skyblocker.option.locations.dungeons.enableMap": "啟用 Dungeon 地圖", "text.autoconfig.skyblocker.option.locations.barn.solveTreasureHunter": "Treasure Hunter 助手", "text.autoconfig.skyblocker.option.locations.dwarvenMines.enableDrillFuel": "顯示電鑽燃料", @@ -51,11 +48,6 @@ "text.autoconfig.skyblocker.option.richPresence.info.LOCATION": "位置", "text.autoconfig.skyblocker.option.richPresence.info.@Tooltip": "如果您正在循環模式,這個值將不會生效", "text.autoconfig.skyblocker.option.richPresence.customMessage": "自訂訊息", - "text.autoconfig.skyblocker.option.quickNav.button1.item.itemName": "物品ID", - "text.autoconfig.skyblocker.option.quickNav.button1.item.count": "物品數量", - "text.autoconfig.skyblocker.option.quickNav.button1.item.nbt": "物品NBT", - "text.autoconfig.skyblocker.option.quickNav.button1.uiTitle": "快捷介面標題", - "text.autoconfig.skyblocker.option.quickNav.button1.clickEvent": "點擊時所執行的指令", "text.autoconfig.skyblocker.option.locations.dwarvenMines.solveFetchur": "Fetchur 所需物品提示", "text.autoconfig.skyblocker.option.messages.chatFilterResult.ACTION_BAR": "移至動作欄", "text.autoconfig.skyblocker.option.messages.chatFilterResult.PASS": "關閉", diff --git a/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json b/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json new file mode 100644 index 00000000..5c428fed --- /dev/null +++ b/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json @@ -0,0 +1,215 @@ +{ + "credit": "Official Hypixel Wiki - https://wiki.hypixel.net", + "waypoints": [ + { + "x": -15, + "y": 91, + "z": 94 + }, + { + "x": -27, + "y": 71, + "z": 90 + }, + { + "x": -6, + "y": 60, + "z": 226 + }, + { + "x": -142, + "y": 68, + "z": 174 + }, + { + "x": -137, + "y": 51, + "z": 120 + }, + { + "x": -129, + "y": 72, + "z": 77 + }, + { + "x": -27, + "y": 89, + "z": 136 + }, + { + "x": -137, + "y": 133, + "z": 156 + }, + { + "x": -108, + "y": 117, + "z": 123 + }, + { + "x": -115, + "y": 69, + "z": 61 + }, + { + "x": 43, + "y": 91, + "z": 56 + }, + { + "x": -168, + "y": 81, + "z": 12 + }, + { + "x": -204, + "y": 75, + "z": 49 + }, + { + "x": -93, + "y": 73, + "z": 36 + }, + { + "x": -102, + "y": 72, + "z": -103 + }, + { + "x": -34, + "y": 71, + "z": -88 + }, + { + "x": -106, + "y": 78, + "z": -101 + }, + { + "x": -95, + "y": 76, + "z": -82 + }, + { + "x": -94, + "y": 70, + "z": -84 + }, + { + "x": -38, + "y": 44, + "z": 130 + }, + { + "x": -88, + "y": 79, + "z": -102 + }, + { + "x": -76, + "y": 90, + "z": -149 + }, + { + "x": -106, + "y": 249, + "z": -149 + }, + { + "x": -74, + "y": 65, + "z": -119 + }, + { + "x": -77, + "y": 72, + "z": -176 + }, + { + "x": -21, + "y": 72, + "z": -18 + }, + { + "x": -88, + "y": 20, + "z": 0 + }, + { + "x": 27, + "y": 71, + "z": -77 + }, + { + "x": 42, + "y": 88, + "z": -91 + }, + { + "x": 47, + "y": 68, + "z": -59 + }, + { + "x": -34, + "y": 66, + "z": -25 + }, + { + "x": -23, + "y": 84, + "z": -92 + }, + { + "x": 40, + "y": 70, + "z": 27 + }, + { + "x": 38, + "y": 63, + "z": -198 + }, + { + "x": 3, + "y": 68, + "z": -204 + }, + { + "x": -161, + "y": 98, + "z": -72 + }, + { + "x": 255, + "y": 74, + "z": 160 + }, + { + "x": 262, + "y": 118, + "z": 94 + }, + { + "x": 182, + "y": 92, + "z": 124 + }, + { + "x": 266, + "y": 60, + "z": 145 + }, + { + "x": 232, + "y": 94, + "z": 168 + }, + { + "x": 256, + "y": 130, + "z": 75 + } + ] +}
\ No newline at end of file diff --git a/src/main/resources/assets/skyblocker/mirrorverse_waypoints.json b/src/main/resources/assets/skyblocker/rift/mirrorverse_waypoints.json index 2bc0296e..4c8f1007 100644 --- a/src/main/resources/assets/skyblocker/mirrorverse_waypoints.json +++ b/src/main/resources/assets/skyblocker/rift/mirrorverse_waypoints.json @@ -1,4 +1,5 @@ { + "credit": "TylertheTurtled", "sections": [ { "name": "Lava Path", diff --git a/src/main/resources/assets/skyblocker/textures/gui/inventory_background.png b/src/main/resources/assets/skyblocker/textures/gui/inventory_background.png Binary files differdeleted file mode 100644 index fb588907..00000000 --- a/src/main/resources/assets/skyblocker/textures/gui/inventory_background.png +++ /dev/null diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 86481bf3..b55214d5 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -5,7 +5,7 @@ "name": "Skyblocker", "description": "Hypixel Skyblock Mod", "authors": ["xMrVizzy", "d3dx9", "LifeIsAParadox"], - "contributors": ["ExternalTime", "Zailer43", "TacoMonkey", "KonaeAkira", "Fix3dll", "null2264", "HyperSoop", "edgarogh", "TheColdPot", "Julienraptor01", "ADON15c", "catandA", "kevinthegreat1", "AzureAaron", "msg-programs", "lantice3720"], + "contributors": ["ExternalTime", "Zailer43", "TacoMonkey", "KonaeAkira", "Fix3dll", "null2264", "HyperSoop", "edgarogh", "TheColdPot", "Julienraptor01", "ADON15c", "catandA", "kevinthegreat1", "AzureAaron", "msg-programs", "lantice3720", "Futuremappermydud", "koloiyolo", "viciscat", "Grayray75", "alexiayaa"], "contact": { "homepage": "https://hysky.de", "sources": "https://github.com/SkyblockerMod/Skyblocker", @@ -38,7 +38,7 @@ "depends": { "fabricloader": ">=0.14.22", "fabric-api": ">=0.89.1+1.20.2", - "yet_another_config_lib_v3": ">=3.2.0+1.20.2", + "yet_another_config_lib_v3": ">=3.2.1+1.20.2", "minecraft": "~1.20.2" }, "conflicts": { diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index efca46f7..5bafb324 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -16,6 +16,7 @@ "GenericContainerScreenHandlerMixin", "HandledScreenMixin", "InGameHudMixin", + "InGameOverlayRendererMixin", "InventoryScreenMixin", "ItemMixin", "ItemStackMixin", @@ -35,7 +36,12 @@ "accessor.PlayerListHudAccessor", "accessor.RecipeBookWidgetAccessor", "accessor.ScreenAccessor", - "accessor.WorldRendererAccessor" + "accessor.WorldRendererAccessor", + "yacl.DoubleFieldControllerMixin", + "yacl.FloatFieldControllerMixin", + "yacl.IntegerFieldControllerMixin", + "yacl.LongFieldControllerMixin", + "yacl.NumberFieldControllerMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java b/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java index 36b65cae..2709aba4 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/item/ArmorTrimIdSerializationTest.java @@ -1,27 +1,32 @@ package de.hysky.skyblocker.skyblock.item; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; + +import de.hysky.skyblocker.skyblock.item.CustomArmorTrims.ArmorTrimId; import net.minecraft.util.Identifier; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class ArmorTrimIdSerializationTest { - private final Gson gson = new GsonBuilder().registerTypeAdapter(Identifier.class, new Identifier.Serializer()).create(); + private final Gson gson = new Gson(); @Test void serialize() { - CustomArmorTrims.ArmorTrimId armorTrimId = new CustomArmorTrims.ArmorTrimId(new Identifier("material_id"), new Identifier("pattern_id")); - String json = gson.toJson(armorTrimId); + ArmorTrimId armorTrimId = new ArmorTrimId(new Identifier("material_id"), new Identifier("pattern_id")); + JsonElement json = ArmorTrimId.CODEC.encodeStart(JsonOps.INSTANCE, armorTrimId).result().orElseThrow(); String expectedJson = "{\"material\":\"minecraft:material_id\",\"pattern\":\"minecraft:pattern_id\"}"; - Assertions.assertEquals(expectedJson, json); + + Assertions.assertEquals(expectedJson, json.toString()); } @Test void deserialize() { String json = "{\"material\":\"minecraft:material_id\",\"pattern\":\"minecraft:pattern_id\"}"; - CustomArmorTrims.ArmorTrimId armorTrimId = gson.fromJson(json, CustomArmorTrims.ArmorTrimId.class); - CustomArmorTrims.ArmorTrimId expectedArmorTrimId = new CustomArmorTrims.ArmorTrimId(new Identifier("material_id"), new Identifier("pattern_id")); + ArmorTrimId armorTrimId = ArmorTrimId.CODEC.parse(JsonOps.INSTANCE, gson.fromJson(json, JsonElement.class)).result().orElseThrow(); + ArmorTrimId expectedArmorTrimId = new ArmorTrimId(new Identifier("material_id"), new Identifier("pattern_id")); + Assertions.assertEquals(expectedArmorTrimId, armorTrimId); } } |