Skip to content

Commit

Permalink
Merge pull request #783 from SkyblockerMod/api-changes
Browse files Browse the repository at this point in the history
Api changes the Aaron of the Azure color made
  • Loading branch information
AzureAaron authored Jun 22, 2024
2 parents d6b220a + 7e3ed3e commit d12504e
Show file tree
Hide file tree
Showing 13 changed files with 560 additions and 62 deletions.
3 changes: 2 additions & 1 deletion src/main/java/de/hysky/skyblocker/SkyblockerMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,10 @@ public void onInitializeClient() {
VisitorHelper.init();
ItemRarityBackgrounds.init();
MuseumItemCache.init();
PetCache.init();
SecretsTracker.init();
ApiAuthentication.init();
ApiUtils.init();
ProfileUtils.init();
Debug.init();
Kuudra.init();
RenderHelper.init();
Expand Down
36 changes: 27 additions & 9 deletions src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import com.mojang.blaze3d.systems.RenderSystem;
import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.PetCache;
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.garden.VisitorHelper;
import de.hysky.skyblocker.skyblock.item.ItemProtection;
import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds;
import de.hysky.skyblocker.skyblock.item.MuseumItemCache;
import de.hysky.skyblocker.skyblock.item.WikiLookup;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
import de.hysky.skyblocker.skyblock.item.slottext.SlotTextManager;
Expand All @@ -36,6 +38,7 @@
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand Down Expand Up @@ -248,17 +251,32 @@ protected HandledScreenMixin(Text title) {
ci.cancel();
return;
}
if (this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) {
VisitorHelper.onSlotClick(slot, slotId, title, genericContainerScreenHandler.getSlot(13).getStack());

// Prevent selling to NPC shops
ItemStack sellStack = this.handler.slots.get(49).getStack();
if (sellStack.getName().getString().equals("Sell Item") || ItemUtils.getLoreLineIf(sellStack, text -> text.contains("buyback")) != null) {
if (slotId != 49 && ItemProtection.isItemProtected(stack)) {
ci.cancel();
return;

switch (this.handler) {
case GenericContainerScreenHandler genericContainerScreenHandler when genericContainerScreenHandler.getRows() == 6 -> {
VisitorHelper.onSlotClick(slot, slotId, title, genericContainerScreenHandler.getSlot(13).getStack());

// Prevent selling to NPC shops
ItemStack sellStack = this.handler.slots.get(49).getStack();
if (sellStack.getName().getString().equals("Sell Item") || ItemUtils.getLoreLineIf(sellStack, text -> text.contains("buyback")) != null) {
if (slotId != 49 && ItemProtection.isItemProtected(stack)) {
ci.cancel();
return;
}
}
}

case GenericContainerScreenHandler genericContainerScreenHandler when title.equals(MuseumItemCache.DONATION_CONFIRMATION_SCREEN_TITLE) -> {
//Museum Item Cache donation tracking
MuseumItemCache.handleClick(slot, slotId, genericContainerScreenHandler.slots);
}

case null, default -> {}
}

//Pet Caching
if (button == GLFW.GLFW_MOUSE_BUTTON_LEFT && title.startsWith("Pets")) {
PetCache.handlePetEquip(slot, slotId);
}
if (currentSolver != null) {
Expand Down
51 changes: 47 additions & 4 deletions src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package de.hysky.skyblocker.mixins;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import de.hysky.skyblocker.SkyblockerMod;
import com.mojang.serialization.JsonOps;

import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.injected.SkyblockerStack;
import de.hysky.skyblocker.skyblock.PetCache.PetInfo;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
Expand Down Expand Up @@ -165,6 +167,7 @@ public String getNeuName() {
}

// Transformation to API format.
//TODO future - remove this and just handle it directly for the NEU id conversion because this whole system is confusing and hard to follow
if (customData.contains("is_shiny")) {
return "ISSHINY_" + customDataString;
}
Expand All @@ -178,12 +181,14 @@ public String getNeuName() {
return "ENCHANTMENT_" + enchant.toUpperCase(Locale.ENGLISH) + "_" + enchants.getInt(enchant);
}
}

case "PET" -> {
if (customData.contains("petInfo")) {
JsonObject petInfo = SkyblockerMod.GSON.fromJson(customData.getString("petInfo"), JsonObject.class);
return "LVL_1_" + petInfo.get("tier").getAsString() + "_" + petInfo.get("type").getAsString();
PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow();
return "LVL_1_" + petInfo.tier() + "_" + petInfo.type();
}
}

case "POTION" -> {
String enhanced = customData.contains("enhanced") ? "_ENHANCED" : "";
String extended = customData.contains("extended") ? "_EXTENDED" : "";
Expand All @@ -193,6 +198,7 @@ public String getNeuName() {
+ enhanced + extended + splash).toUpperCase(Locale.ENGLISH);
}
}

case "RUNE" -> {
if (customData.contains("runes")) {
NbtCompound runes = customData.getCompound("runes");
Expand All @@ -201,6 +207,7 @@ public String getNeuName() {
return rune.toUpperCase(Locale.ENGLISH) + "_RUNE_" + runes.getInt(rune);
}
}

case "ATTRIBUTE_SHARD" -> {
if (customData.contains("attributes")) {
NbtCompound shards = customData.getCompound("attributes");
Expand All @@ -209,6 +216,42 @@ public String getNeuName() {
return customDataString + "-" + shard.toUpperCase(Locale.ENGLISH) + "_" + shards.getInt(shard);
}
}

case "NEW_YEAR_CAKE" -> {
return customDataString + "_" + customData.getInt("new_years_cake");
}

case "PARTY_HAT_CRAB", "PARTY_HAT_CRAB_ANIMATED", "BALLOON_HAT_2024" -> {
return customDataString + "_" + customData.getString("party_hat_color").toUpperCase(Locale.ENGLISH);
}

case "PARTY_HAT_SLOTH" -> {
return customDataString + "_" + customData.getString("party_hat_emoji").toUpperCase(Locale.ENGLISH);
}

case "CRIMSON_HELMET", "CRIMSON_CHESTPLATE", "CRIMSON_LEGGINGS", "CRIMSON_BOOTS" -> {
NbtCompound attributes = customData.getCompound("attributes");

if (attributes.contains("magic_find") && attributes.contains("veteran")) {
return customDataString + "-MAGIC_FIND-VETERAN";
}
}

case "AURORA_HELMET", "AURORA_CHESTPLATE", "AURORA_LEGGINGS", "AURORA_BOOTS" -> {
NbtCompound attributes = customData.getCompound("attributes");

if (attributes.contains("mana_pool") && attributes.contains("mana_regeneration")) {
return customDataString + "-MANA_POOL-MANA_REGENERATION";
}
}

case "TERROR_HELMET", "TERROR_CHESTPLATE", "TERROR_LEGGINGS", "TERROR_BOOTS" -> {
NbtCompound attributes = customData.getCompound("attributes");

if (attributes.contains("lifeline") && attributes.contains("mana_pool")) {
return customDataString + "-LIFELINE-MANA_POOL";
}
}
}
return customDataString;
}
Expand Down
149 changes: 149 additions & 0 deletions src/main/java/de/hysky/skyblocker/skyblock/PetCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package de.hysky.skyblocker.skyblock;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
import java.util.Optional;

import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;

import com.google.gson.JsonParser;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;

import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.screen.slot.Slot;

/**
* Doesn't work with auto pet right now because thats complicated.
*
* Want support? Ask the Admins for a Mod API event or open your pets menu.
*/
public class PetCache {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("pet_cache.json");
private static final Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>> CACHED_PETS = new Object2ObjectOpenHashMap<>();

/**
* Used in case the server lags to prevent the screen tick check from overwriting the clicked pet logic
*/
private static boolean shouldLook4Pets;

public static void init() {
load();

ScreenEvents.BEFORE_INIT.register((_client, screen, _scaledWidth, _scaledHeight) -> {
if (Utils.isOnSkyblock() && screen instanceof GenericContainerScreen genericContainerScreen) {
if (genericContainerScreen.getTitle().getString().startsWith("Pets")) {
shouldLook4Pets = true;

ScreenEvents.afterTick(screen).register(screen1 -> {
if (shouldLook4Pets) {
for (Slot slot : genericContainerScreen.getScreenHandler().slots) {
ItemStack stack = slot.getStack();

if (!stack.isEmpty() && ItemUtils.getLoreLineIf(stack, line -> line.equals("Click to despawn!")) != null) {
shouldLook4Pets = false;
parsePet(stack, false);

break;
}
}
}
});
}
}
});
}

private static void load() {
CompletableFuture.runAsync(() -> {
try (BufferedReader reader = Files.newBufferedReader(FILE)) {
CACHED_PETS.putAll(PetInfo.SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow());
} catch (NoSuchFileException ignored) {
} catch (Exception e) {
LOGGER.error("[Skyblocker Pet Cache] Failed to load saved pet!", e);
}
});
}

private static void save() {
CompletableFuture.runAsync(() -> {
try (BufferedWriter writer = Files.newBufferedWriter(FILE)) {
SkyblockerMod.GSON.toJson(PetInfo.SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, CACHED_PETS).getOrThrow(), writer);
} catch (Exception e) {
LOGGER.error("[Skyblocker Pet Cache] Failed to save pet data to the cache!", e);
}
});
}

public static void handlePetEquip(Slot slot, int slotId) {
//Ignore inventory clicks
if (slotId >= 0 && slotId <= 53) {
ItemStack stack = slot.getStack();

if (!stack.isEmpty()) parsePet(stack, true);
}
}

private static void parsePet(ItemStack stack, boolean clicked) {
String id = ItemUtils.getItemId(stack);
String profileId = Utils.getProfileId();

if (id.equals("PET") && !profileId.isEmpty()) {
NbtCompound customData = ItemUtils.getCustomData(stack);

//Should never fail, all pets must have this but you never know with Hypixel
try {
PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow();
shouldLook4Pets = false;

Object2ObjectOpenHashMap<String, PetInfo> playerData = CACHED_PETS.computeIfAbsent(Utils.getUndashedUuid(), _uuid -> new Object2ObjectOpenHashMap<>());

//Handle deselecting pets
if (clicked && getCurrentPet() != null && getCurrentPet().uuid().orElse("").equals(petInfo.uuid().orElse(""))) {
playerData.remove(profileId);
} else {
playerData.put(profileId, petInfo);
}

save();
} catch (Exception e) {
LOGGER.error(LogUtils.FATAL_MARKER, "[Skyblocker Pet Cache] Failed to parse pet's pet info!", e);
}
}
}

@Nullable
public static PetInfo getCurrentPet() {
String uuid = Utils.getUndashedUuid();
String profileId = Utils.getProfileId();

return CACHED_PETS.containsKey(uuid) && CACHED_PETS.get(uuid).containsKey(profileId) ? CACHED_PETS.get(uuid).get(profileId) : null;
}

public record PetInfo(String type, double exp, String tier, Optional<String> uuid) {
public static final Codec<PetInfo> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.STRING.fieldOf("type").forGetter(PetInfo::type),
Codec.DOUBLE.fieldOf("exp").forGetter(PetInfo::exp),
Codec.STRING.fieldOf("tier").forGetter(PetInfo::tier),
Codec.STRING.optionalFieldOf("uuid").forGetter(PetInfo::uuid))
.apply(instance, PetInfo::new));
private static final Codec<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING,
Codec.unboundedMap(Codec.STRING, CODEC).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new)
).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new);
}
}
Loading

0 comments on commit d12504e

Please sign in to comment.