diff options
19 files changed, 772 insertions, 3 deletions
diff --git a/options.txt b/options.txt index f359abbb..200b71ef 100755 --- a/options.txt +++ b/options.txt @@ -5,14 +5,14 @@ gamma:100000.0 saturation:0.0 renderDistance:4 guiScale:2 -particles:0 +particles:2 bobView:true anaglyph3d:false maxFps:60 fboEnable:true difficulty:3 fancyGraphics:false -ao:1 +ao:0 renderClouds:false resourcePacks:[] incompatibleResourcePacks:[] diff --git a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java index f73a778e..a0adf7b9 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java @@ -12,6 +12,9 @@ import kr.syeyoung.dungeonsguide.dungeon.roomfinder.DungeonRoomInfoRegistry; import kr.syeyoung.dungeonsguide.e; import kr.syeyoung.dungeonsguide.events.DungeonLeftEvent; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; +import kr.syeyoung.dungeonsguide.features.impl.party.FeatureViewPlayerOnJoin; +import kr.syeyoung.dungeonsguide.features.impl.party.api.ApiFetchur; +import kr.syeyoung.dungeonsguide.features.impl.party.api.PlayerProfile; import kr.syeyoung.dungeonsguide.party.PartyManager; import kr.syeyoung.dungeonsguide.roomprocessor.GeneralRoomProcessor; import kr.syeyoung.dungeonsguide.utils.AhUtils; @@ -24,6 +27,7 @@ import net.minecraft.command.ICommandSender; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatStyle; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; @@ -40,7 +44,9 @@ import java.security.cert.CertificateException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; +import java.util.Optional; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.zip.GZIPOutputStream; public class CommandDungeonsGuide extends CommandBase { @@ -330,6 +336,24 @@ public class CommandDungeonsGuide extends CommandBase { sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §cAn error occured while writing rundata "+e.getMessage())); e.printStackTrace(); } + } else if (args[0].equals("fetch")) { + try { + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §eProfile Viewer Test: ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(args[1]))))); + } catch (Exception e) { + e.printStackTrace(); + } + } else if (args[0].equals("fetchbynick")) { + try { + ApiFetchur.fetchUUIDAsync(args[1]) + .thenAccept(a -> { + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §eProfile Viewer Test: ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); + }); + + } catch (Exception e) { + e.printStackTrace(); + } + } else if (args[0].equals("purge")) { + ApiFetchur.purgeCache(); } else { sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg §7-§fOpens configuration gui")); sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg gui §7-§fOpens configuration gui")); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/FeatureListener.java b/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/FeatureListener.java index 54d107ed..7148b054 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/FeatureListener.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/eventlistener/FeatureListener.java @@ -209,6 +209,19 @@ public class FeatureListener { } @SubscribeEvent + public void onChatGlobal(ClientChatReceivedEvent postRender) { + try { + for (AbstractFeature abstractFeature : FeatureRegistry.getFeatureList()) { + if (abstractFeature instanceof ChatListenerGlobal) { + ((ChatListenerGlobal) abstractFeature).onChat(postRender); + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + @SubscribeEvent public void dungeonTooltip(ItemTooltipEvent event) { try { SkyblockStatus skyblockStatus = e.getDungeonsGuide().getSkyblockStatus(); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java index f2046130..ac8610e9 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java @@ -10,6 +10,8 @@ import kr.syeyoung.dungeonsguide.features.impl.boss.terminal.FeatureTerminalSolv import kr.syeyoung.dungeonsguide.features.impl.dungeon.*; import kr.syeyoung.dungeonsguide.features.impl.etc.*; import kr.syeyoung.dungeonsguide.features.impl.etc.ability.FeatureAbilityCooldown; +import kr.syeyoung.dungeonsguide.features.impl.party.APIKey; +import kr.syeyoung.dungeonsguide.features.impl.party.FeatureViewPlayerOnJoin; import kr.syeyoung.dungeonsguide.features.impl.secret.FeatureActions; import kr.syeyoung.dungeonsguide.features.impl.secret.FeatureFreezePathfind; import kr.syeyoung.dungeonsguide.features.impl.secret.FeatureMechanicBrowse; @@ -82,6 +84,9 @@ public class FeatureRegistry { public static final FeaturePenguins ETC_PENGUIN = register(new FeaturePenguins()); + public static final APIKey PARTYKICKER_APIKEY = register(new APIKey()); + public static final FeatureViewPlayerOnJoin PARTYKICKER_VIEWPLAYER = register(new FeatureViewPlayerOnJoin()); + public static final FeatureWarningOnPortal BOSSFIGHT_WARNING_ON_PORTAL = register(new FeatureWarningOnPortal()); public static final SimpleFeature BOSSFIGHT_CHESTPRICE = register(new FeatureChestPrice()); public static final FeatureAutoReparty BOSSFIGHT_AUTOREPARTY = register(new FeatureAutoReparty()); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/APIKey.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/APIKey.java new file mode 100644 index 00000000..ed708ec5 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/APIKey.java @@ -0,0 +1,25 @@ +package kr.syeyoung.dungeonsguide.features.impl.party; + +import kr.syeyoung.dungeonsguide.features.FeatureParameter; +import kr.syeyoung.dungeonsguide.features.SimpleFeature; +import kr.syeyoung.dungeonsguide.features.listener.ChatListener; +import kr.syeyoung.dungeonsguide.features.listener.ChatListenerGlobal; +import net.minecraftforge.client.event.ClientChatReceivedEvent; + +public class APIKey extends SimpleFeature implements ChatListenerGlobal { + + public APIKey() { + super("Party Kicker", "API KEY", "Set api key. Disabling this feature does nothing","partykicker.apikey"); + parameters.put("apikey", new FeatureParameter<String>("apikey", "API Key", "API key", "","string")); + } + + public String getAPIKey() { + return this.<String>getParameter("apikey").getValue(); + } + + + @Override + public void onChat(ClientChatReceivedEvent clientChatReceivedEvent) { + // ay set apikey + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/FeatureViewPlayerOnJoin.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/FeatureViewPlayerOnJoin.java new file mode 100644 index 00000000..f7e2f020 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/FeatureViewPlayerOnJoin.java @@ -0,0 +1,163 @@ +package kr.syeyoung.dungeonsguide.features.impl.party; + +import io.github.moulberry.hychat.HyChat; +import io.github.moulberry.hychat.chat.ChatManager; +import io.github.moulberry.hychat.gui.GuiChatBox; +import kr.syeyoung.dungeonsguide.features.FeatureRegistry; +import kr.syeyoung.dungeonsguide.features.SimpleFeature; +import kr.syeyoung.dungeonsguide.features.impl.party.api.ApiFetchur; +import kr.syeyoung.dungeonsguide.features.impl.party.api.PlayerProfile; +import kr.syeyoung.dungeonsguide.features.listener.ChatListener; +import kr.syeyoung.dungeonsguide.features.listener.GuiPostRenderListener; +import kr.syeyoung.dungeonsguide.gui.MPanel; +import lombok.Getter; +import lombok.SneakyThrows; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.*; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.event.HoverEvent; +import net.minecraft.util.ChatComponentStyle; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatStyle; +import net.minecraft.util.IChatComponent; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.Loader; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public class FeatureViewPlayerOnJoin extends SimpleFeature implements GuiPostRenderListener, ChatListener { + + public FeatureViewPlayerOnJoin() { + super("Party Kicker", "View player stats when join", "view player rendering when joining/someone joins the party", "partykicker.viewstats", true); + } + + private Rectangle popupRect; + private String lastuid; // actually current uid + private Future<Optional<PlayerProfile>> profileFuture; + @SneakyThrows + @Override + public void onGuiPostRender(GuiScreenEvent.DrawScreenEvent.Post rendered) { + if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChat)) { + popupRect = null; + profileFuture = null; + return; + } + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + IChatComponent ichatcomponent = getHoveredComponent(scaledResolution); + String uid = null; + if (ichatcomponent != null && ichatcomponent.getChatStyle().getChatHoverEvent() instanceof HoverEventRenderPlayer) { + uid = ((HoverEventRenderPlayer) ichatcomponent.getChatStyle().getChatHoverEvent()).getUuid(); + } + + if (!((popupRect != null && popupRect.contains(mouseX, mouseY)) || uid != null && uid.equals(lastuid))) { + popupRect = null; + profileFuture = null; + lastuid = null; + } + + if (uid != null && !uid.equals(lastuid) && (popupRect==null || !popupRect.contains(mouseX, mouseY))) { + popupRect = null; + profileFuture = null; + lastuid = uid; + } + if (lastuid == null) return; + + + if (popupRect == null) { + popupRect = new Rectangle(mouseX, mouseY, 100, 200); + if (popupRect.y + popupRect.height > scaledResolution.getScaledHeight()) { + popupRect.y -= popupRect.y + popupRect.height - scaledResolution.getScaledHeight(); + } + } + + if (profileFuture == null) { + profileFuture = ApiFetchur.fetchMostRecentProfileAsync(lastuid, FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); + } + + MPanel.clip(scaledResolution, popupRect.x, popupRect.y, popupRect.width, popupRect.height); + + GL11.glEnable(GL11.GL_SCISSOR_TEST); + GlStateManager.pushMatrix(); + GlStateManager.translate(popupRect.x, popupRect.y, 0); + Gui.drawRect(0,0, popupRect.width, popupRect.height, 0xFF000000); + System.out.println(lastuid + " - "+uid); + if (!profileFuture.isDone()) { + Minecraft.getMinecraft().fontRendererObj.drawString("Fetching data...", 5,5, 0xFFFFFFFF); + } else { + Optional<PlayerProfile> playerProfile = profileFuture.get(); + if (playerProfile.isPresent()) { + Minecraft.getMinecraft().fontRendererObj.drawString(playerProfile.get().getMemberUID(), 5,5, 0xFFFFFFFF); + } else { + Minecraft.getMinecraft().fontRendererObj.drawString("User could not be found", 5,5, 0xFFFFFFFF); + } + } + GlStateManager.popMatrix(); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + + public IChatComponent getHoveredComponent(ScaledResolution scaledResolution) { + IChatComponent ichatcomponent = null; + if (Loader.isModLoaded("hychat")) { + try { + ChatManager chatManager = HyChat.getInstance().getChatManager(); + GuiChatBox guiChatBox = chatManager.getFocusedChat(); + + int x = guiChatBox.getX(scaledResolution); + int y = guiChatBox.getY(scaledResolution); + ichatcomponent = guiChatBox.chatArray.getHoveredComponent(guiChatBox.getSelectedTab().getChatLines(), Mouse.getX(), Mouse.getY(), x, y); + } catch (Throwable t) {} + } + if (ichatcomponent == null) { + ichatcomponent = Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatComponent(Mouse.getX(), Mouse.getY()); + } + return ichatcomponent; + } + + @Override + public void onChat(ClientChatReceivedEvent clientChatReceivedEvent) { + } + + public static class HoverEventRenderPlayer extends HoverEvent { + @Getter + private String uuid; + public HoverEventRenderPlayer(String uuid) { + super(Action.SHOW_TEXT, new ChatComponentText("")); + this.uuid = uuid; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + HoverEventRenderPlayer that = (HoverEventRenderPlayer) o; + return Objects.equals(uuid, that.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), uuid); + } + + private IChatComponent cached; + + @Override + public IChatComponent getValue() { + if (cached == null) + return cached = new ChatComponentText("").setChatStyle(new ChatStyle().setChatHoverEvent(new HoverEvent(Action.SHOW_TEXT, new ChatComponentText(uuid)))); + return cached; + } + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java new file mode 100644 index 00000000..00ede47d --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java @@ -0,0 +1,320 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import com.google.gson.*; +import kr.syeyoung.dungeonsguide.utils.TextUtils; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import org.apache.commons.io.IOUtils; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.*; + +public class ApiFetchur { + private static final Gson gson = new Gson(); + + private static final Map<String, CachedData<PlayerProfile>> playerProfileCache = new HashMap<>(); + private static final Map<String, CachedData<String>> nicknameToUID = new HashMap<>(); + private static final ExecutorService ex = Executors.newFixedThreadPool(4); + + public static void purgeCache() { + playerProfileCache.clear(); + nicknameToUID.clear(); + } + + @Data + @AllArgsConstructor + public static class CachedData<T> { + private final long expire; + private final T data; + } + + public static JsonObject getJson(String url) throws IOException { + URLConnection connection = new URL(url).openConnection(); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + return gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonObject.class); + } + + public static CompletableFuture<Optional<PlayerProfile>> fetchMostRecentProfileAsync(String uid, String apiKey) { + if (playerProfileCache.containsKey(uid)) { + CachedData<PlayerProfile> cachedData = playerProfileCache.get(uid); + if (cachedData.expire > System.currentTimeMillis()) { + return CompletableFuture.completedFuture(Optional.ofNullable(cachedData.data)); + } + playerProfileCache.remove(uid); + } + + CompletableFuture<Optional<PlayerProfile>> completableFuture = new CompletableFuture<>(); + ex.submit(() -> { + try { + Optional<PlayerProfile> playerProfile = fetchMostRecentProfile(uid, apiKey); + playerProfileCache.put(uid, new CachedData<PlayerProfile>(System.currentTimeMillis()+1000*60*30, playerProfile.orElse(null))); + completableFuture.complete(playerProfile); + return; + } catch (IOException e) { + e.printStackTrace(); + } + playerProfileCache.put(uid, new CachedData<PlayerProfile>(System.currentTimeMillis()+1000*60*30, null)); + completableFuture.complete(Optional.empty()); + }); + return completableFuture; + } + + public static CompletableFuture<Optional<String>> fetchUUIDAsync(String nickname) { + if (nicknameToUID.containsKey(nickname)) { + CachedData<String> cachedData = nicknameToUID.get(nickname); + if (cachedData.expire > System.currentTimeMillis()) { + return CompletableFuture.completedFuture(Optional.ofNullable(cachedData.data)); + } + nicknameToUID.remove(nickname); + } + + + CompletableFuture<Optional<String>> completableFuture = new CompletableFuture<>(); + + ex.submit(() -> { + try { + Optional<String> playerProfile = fetchUUID(nickname); + nicknameToUID.put(nickname, new CachedData<String>(System.currentTimeMillis()+1000*60*60,playerProfile.orElse(null))); + completableFuture.complete(playerProfile); + return; + } catch (IOException e) { + e.printStackTrace(); + } + nicknameToUID.put(nickname, new CachedData<String>(System.currentTimeMillis()+1000*60*30, null)); + completableFuture.complete(Optional.empty()); + }); + + return completableFuture; + } + + public static Optional<String> fetchUUID(String nickname) throws IOException { + JsonObject json = getJson("https://api.mojang.com/users/profiles/minecraft/"+nickname); + if (json.has("error")) return Optional.empty(); + return Optional.of(TextUtils.insertDashUUID(json.get("id").getAsString())); + } + + public static List<PlayerProfile> fetchPlayerProfiles(String uid, String apiKey) throws IOException { + JsonObject json = getJson("https://api.hypixel.net/skyblock/profiles?uuid="+uid+"&key="+apiKey); + if (!json.get("success").getAsBoolean()) return new ArrayList<>(); + JsonArray profiles = json.getAsJsonArray("profiles"); + String dashTrimmed = uid.replace("-", ""); + + ArrayList<PlayerProfile> playerProfiles = new ArrayList<>(); + for (JsonElement jsonElement : profiles) { + JsonObject semiProfile = jsonElement.getAsJsonObject(); + if (!semiProfile.has(dashTrimmed)) continue; + playerProfiles.add(parseProfile(semiProfile, dashTrimmed)); + } + return playerProfiles; + } + + public static Optional<PlayerProfile> fetchMostRecentProfile(String uid, String apiKey) throws IOException { + JsonObject json = getJson("https://api.hypixel.net/skyblock/profiles?uuid="+uid+"&key="+apiKey); + if (!json.get("success").getAsBoolean()) return Optional.empty(); + JsonArray profiles = json.getAsJsonArray("profiles"); + String dashTrimmed = uid.replace("-", ""); + + JsonObject profile = null; + long lastSave = Long.MIN_VALUE; + for (JsonElement jsonElement : profiles) { + JsonObject semiProfile = jsonElement.getAsJsonObject(); + if (!semiProfile.getAsJsonObject("members").has(dashTrimmed)) continue; + long lastSave2 = semiProfile.getAsJsonObject("members").getAsJsonObject(dashTrimmed).get("last_save").getAsLong(); + if (lastSave2 > lastSave) { + profile = semiProfile; + lastSave = lastSave2; + } + } + + if (profile == null) return Optional.empty(); + + return Optional.of(parseProfile(profile, dashTrimmed)); + } + + public static int getOrDefault(JsonObject jsonObject, String key, int value) { + if (jsonObject == null || !jsonObject.has(key) || jsonObject.get(key) instanceof JsonNull) return value; + return jsonObject.get(key).getAsInt(); + } + public static long getOrDefault(JsonObject jsonObject, String key, long value) { + if (jsonObject == null || !jsonObject.has(key) || jsonObject.get(key) instanceof JsonNull) return value; + return jsonObject.get(key).getAsLong(); + } + public static double getOrDefault(JsonObject jsonObject, String key, double value) { + if (jsonObject == null || !jsonObject.has(key) || jsonObject.get(key) instanceof JsonNull) return value; + return jsonObject.get(key).getAsDouble(); + } + public static String getOrDefault(JsonObject jsonObject, String key, String value) { + if (jsonObject == null || !jsonObject.has(key) || jsonObject.get(key) instanceof JsonNull) return value; + return jsonObject.get(key).getAsString(); + } + public static NBTTagCompound parseBase64NBT(String nbt) throws IOException { + return CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(nbt))); + } + + public static ItemStack deserializeNBT(NBTTagCompound nbtTagCompound) { + if (nbtTagCompound.hasNoTags()) return null; + ItemStack itemStack = new ItemStack(Blocks.stone); + itemStack.deserializeNBT(nbtTagCompound); + return itemStack; + } + + public static PlayerProfile parseProfile(JsonObject profile, String dashTrimmed) throws IOException { + PlayerProfile playerProfile = new PlayerProfile(); + playerProfile.setProfileUID(getOrDefault(profile, "profile_id", "")); + playerProfile.setMemberUID(dashTrimmed); + playerProfile.setProfileName(getOrDefault(profile, "cute_name", "")); + + JsonObject playerData = profile.getAsJsonObject("members").getAsJsonObject(dashTrimmed); + playerProfile.setLastSave(getOrDefault(playerData, "last_save", 0L)); + playerProfile.setFairySouls(getOrDefault(playerData, "fairy_souls_collected", 0)); + playerProfile.setFairyExchanges(getOrDefault(playerData, "fairy_exchanges", 0)); + + if (playerData.has("inv_armor")) { + playerProfile.setCurrentArmor(new PlayerProfile.Armor()); + NBTTagCompound armor = parseBase64NBT(playerData.getAsJsonObject("inv_armor") + .get("data") + .getAsString()); + NBTTagList array = armor.getTagList("i", 10); + for (int i = 0; i < 4; i++) { + NBTTagCompound item = array.getCompoundTagAt(i); + playerProfile.getCurrentArmor().getArmorSlots()[i] = deserializeNBT(item); + } + } + + if (playerData.has("wardrobe_contents")) { + NBTTagCompound armor = parseBase64NBT(playerData.getAsJsonObject("wardrobe_contents").get("data").getAsString()); + NBTTagList array = armor.getTagList("i", 10); + for (int i = 0; i < array.tagCount(); i++) { + if (i % 4 == 0) playerProfile.getWardrobe().add(new PlayerProfile.Armor()); + NBTTagCompound item = array.getCompoundTagAt(i); + playerProfile.getWardrobe().get(i/4).getArmorSlots()[i%4] = deserializeNBT(item); + } + + } + playerProfile.setSelectedWardrobe(getOrDefault(playerData, "wardrobe_equipped_slot", -1)); + + if (playerData.has("inv_contents")) { + NBTTagCompound armor = parseBase64NBT(playerData.getAsJsonObject("inv_contents").get("data").getAsString()); + NBTTagList array = armor.getTagList("i", 10); + playerProfile.setInventory(new ItemStack[array.tagCount()]); + for (int i = 0; i < array.tagCount(); i++) { + NBTTagCompound item = array.getCompoundTagAt(i); + playerProfile.getInventory()[i] = deserializeNBT(item); + } + } + if (playerData.has("ender_chest_contents")) { + NBTTagCompound armor = parseBase64NBT(playerData.getAsJsonObject("ender_chest_contents").get("data").getAsString()); + NBTTagList array = armor.getTagList("i", 10); + playerProfile.setEnderchest(new ItemStack[array.tagCount()]); + for (int i = 0; i < array.tagCount(); i++) { + NBTTagCompound item = array.getCompoundTagAt(i); + playerProfile.getEnderchest()[i] = deserializeNBT(item); + } + } + if (playerData.has("talisman_bag")) { + NBTTagCompound armor = parseBase64NBT(playerData.getAsJsonObject("talisman_bag").get("data").getAsString()); + NBTTagList array = armor.getTagList("i", 10); + playerProfile.setTalismans(new ItemStack[array.tagCount()]); + for (int i = 0; i < array.tagCount(); i++) { + NBTTagCompound item = array.getCompoundTagAt(i); + playerProfile.getTalismans()[i] = deserializeNBT(item); + } + } + + for (Skill value : Skill.values()) { + playerProfile.getSkillXp().put(value, getOrDefault(playerData, "experience_skill_"+value.getJsonName(), 0.0)); + } + + if (playerData.has("pets")) { + for (JsonElement pets : playerData.getAsJsonArray("pets")) { + JsonObject pet = pets.getAsJsonObject(); + Pet petObj = new Pet(); + petObj.setActive(pet.get("active").getAsBoolean()); + petObj.setExp(getOrDefault(pet, "exp", 0.0)); + petObj.setHeldItem(getOrDefault(pet, "heldItem", null)); + petObj.setSkin(getOrDefault(pet, "skin", null)); + petObj.setType(getOrDefault(pet, "type", null)); + petObj.setUuid(getOrDefault(pet, "uuid", null)); + + playerProfile.getPets().add(petObj); + } + } + + if (playerData.has("dungeons") && playerData.getAsJsonObject("dungeons").has("dungeon_types")) { + JsonObject types = playerData.getAsJsonObject("dungeons") + .getAsJsonObject("dungeon_types"); + for (DungeonType value : DungeonType.values()) { + DungeonStat dungeonStat = new DungeonStat(); + DungeonSpecificData<DungeonStat> dungeonSpecificData = new DungeonSpecificData<>(value, dungeonStat); + playerProfile.getDungeonStats().put(value, dungeonSpecificData); + + if (!types.has(value.getJsonName())) continue; + + JsonObject dungeonObj = types.getAsJsonObject(value.getJsonName()); + + dungeonStat.setHighestCompleted(getOrDefault(dungeonObj, "highest_tier_completed", -1)); + + for (Integer validFloor : value.getValidFloors()) { + DungeonStat.PlayedFloor playedFloor = new DungeonStat.PlayedFloor(); + playedFloor.setBestScore(getOrDefault(dungeonObj.getAsJsonObject("best_score"), ""+validFloor, 0)); + playedFloor.setCompletions(getOrDefault(dungeonObj.getAsJsonObject("tier_completions"), ""+validFloor, 0)); + playedFloor.setFastestTime(getOrDefault(dungeonObj.getAsJsonObject("fastest_time"), ""+validFloor, -1)); + playedFloor.setFastestTimeS(getOrDefault(dungeonObj.getAsJsonObject("fastest_time_s"), ""+validFloor, -1)); + playedFloor.setFastestTimeSPlus(getOrDefault(dungeonObj.getAsJsonObject("fastest_time_s_plus"), ""+validFloor, -1)); + playedFloor.setMobsKilled(getOrDefault(dungeonObj.getAsJsonObject("mobs_killed"), ""+validFloor, 0)); + playedFloor.setMostMobsKilled(getOrDefault(dungeonObj.getAsJsonObject("most_mobs_killed"), ""+validFloor, 0)); + playedFloor.setMostHealing(getOrDefault(dungeonObj.getAsJsonObject("most_healing"), ""+validFloor, 0)); + playedFloor.setTimes_played(getOrDefault(dungeonObj.getAsJsonObject("times_played"), ""+validFloor, 0)); + playedFloor.setWatcherKills(getOrDefault(dungeonObj.getAsJsonObject("watcher_kills"), ""+validFloor, 0)); + + for (DungeonClass dungeonClass : DungeonClass.values()) { + DungeonStat.PlayedFloor.ClassStatistics classStatistics = new DungeonStat.PlayedFloor.ClassStatistics(); + classStatistics.setMostDamage(getOrDefault(dungeonObj.getAsJsonObject("most_damage_"+dungeonClass.getJsonName()), ""+validFloor, 0)); + ClassSpecificData<DungeonStat.PlayedFloor.ClassStatistics> classStatisticsClassSpecificData = new ClassSpecificData<>(dungeonClass, classStatistics); + + playedFloor.getClassStatistics().put(dungeonClass, classStatisticsClassSpecificData); + } + + FloorSpecificData<DungeonStat.PlayedFloor> playedFloorFloorSpecificData = new FloorSpecificData<>(validFloor, playedFloor); + dungeonStat.getPlays().put(validFloor, playedFloorFloorSpecificData); + } + + dungeonStat.setExperience(getOrDefault(dungeonObj, "experience", 0)); + + + } + } + if (playerData.has("dungeons") && playerData.getAsJsonObject("dungeons").has("player_classes")) { + JsonObject classes = playerData.getAsJsonObject("dungeons") + .getAsJsonObject("player_classes"); + for (DungeonClass dungeonClass : DungeonClass.values()) { + PlayerProfile.PlayerClassData classStatistics = new PlayerProfile.PlayerClassData(); + classStatistics.setExperience(getOrDefault(classes.getAsJsonObject(dungeonClass.getJsonName()), "experience", 0)); + ClassSpecificData<PlayerProfile.PlayerClassData> classStatisticsClassSpecificData = new ClassSpecificData<>(dungeonClass, classStatistics); + + playerProfile.getPlayerClassData().put(dungeonClass, classStatisticsClassSpecificData); + } + } + if (playerData.has("dungeons")) { + String id = getOrDefault(playerData, "selected_dungeon_class", null); + DungeonClass dungeonClass = DungeonClass.getClassByJsonName(id); + playerProfile.setSelectedClass(dungeonClass); + } + + return playerProfile; + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ClassSpecificData.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ClassSpecificData.java new file mode 100644 index 00000000..e7b7abc4 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ClassSpecificData.java @@ -0,0 +1,11 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class ClassSpecificData<T> { + private DungeonClass dungeonClass; + private T data; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonClass.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonClass.java new file mode 100644 index 00000000..a1d63f05 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonClass.java @@ -0,0 +1,30 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +@Getter +public enum DungeonClass { + MAGE("mage"), ARCHER("archer"), HEALER("healer"), TANK("tank"), BERSERK("berserk"); + + + private String jsonName; + private DungeonClass(String jsonName) { + this.jsonName = jsonName; + } + + private static final Map<String, DungeonClass> jsonNameToClazz = new HashMap<>(); + static { + for (DungeonClass value : values()) { + jsonNameToClazz.put(value.getJsonName(), value); + } + } + + public static DungeonClass getClassByJsonName(String name) { + return jsonNameToClazz.get(name); + } + +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonSpecificData.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonSpecificData.java new file mode 100644 index 00000000..63187676 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonSpecificData.java @@ -0,0 +1,11 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class DungeonSpecificData<T> { + private final DungeonType type; + private final T data; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonStat.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonStat.java new file mode 100644 index 00000000..c8702e72 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonStat.java @@ -0,0 +1,36 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class DungeonStat { + private int highestCompleted; + private double experience; + + private Map<Integer, FloorSpecificData<PlayedFloor>> plays = new HashMap<>(); + @Data + public static class PlayedFloor { + private int times_played; + private int completions; + private int watcherKills; + + private int fastestTime; + private int fastestTimeS; + private int fastestTimeSPlus; + private int bestScore; + + private int mostMobsKilled; + private int mobsKilled; + + private Map<DungeonClass, ClassSpecificData<ClassStatistics>> classStatistics = new HashMap<>(); + @Data + public static class ClassStatistics { + private double mostDamage; + } + + private double mostHealing; + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonType.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonType.java new file mode 100644 index 00000000..bf86e97e --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/DungeonType.java @@ -0,0 +1,21 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import com.google.common.collect.Sets; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Set; + +@Getter +@AllArgsConstructor +public enum DungeonType { + CATACOMBS("catacombs", "The Catacombs", + Sets.newHashSet(0,1,2,3,4,5,6,7)), + MASTER_CATACOMBS("master_catacombs", "MasterMode Catacombs", Sets.newHashSet( + 1,2,3,4,5,6 + )); + + private final String jsonName; + private final String familiarName; + private final Set<Integer> validFloors ; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/FloorSpecificData.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/FloorSpecificData.java new file mode 100644 index 00000000..54824406 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/FloorSpecificData.java @@ -0,0 +1,11 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class FloorSpecificData<T> { + private final int floor; + private final T data; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/Pet.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/Pet.java new file mode 100644 index 00000000..3ffac6ba --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/Pet.java @@ -0,0 +1,13 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.Data; + +@Data +public class Pet { + private String uuid; + private String type; + private double exp; + private boolean active; + private String heldItem; + private String skin; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/PlayerProfile.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/PlayerProfile.java new file mode 100644 index 00000000..7cc38a3e --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/PlayerProfile.java @@ -0,0 +1,53 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.Data; +import net.minecraft.item.ItemStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +public class PlayerProfile { + private String profileUID; + private String memberUID; + private String profileName; + + private long lastSave; + + private int fairySouls; + private int fairyExchanges; + + private Armor currentArmor; + private List<Armor> wardrobe = new ArrayList<>(); + private int selectedWardrobe = -1; + + private ItemStack[] inventory; + private ItemStack[] enderchest; + private ItemStack[] talismans; + + @Data + public static class Armor { + private final ItemStack[] armorSlots = new ItemStack[4]; + + public ItemStack getHelmet() { return armorSlots[3]; } + public ItemStack getChestPlate() { return armorSlots[2]; } + public ItemStack getLeggings() { return armorSlots[1]; } + public ItemStack getBoots() { return armorSlots[0]; } + } + + private Map<DungeonType, DungeonSpecificData<DungeonStat>> dungeonStats = new HashMap<>(); + + private Map<DungeonClass, ClassSpecificData<PlayerClassData>> playerClassData = new HashMap<>(); + private DungeonClass selectedClass; + @Data + public static class PlayerClassData { + private double experience; + } + + private Map<Skill, Double> skillXp = new HashMap<>(); + + private List<Pet> pets = new ArrayList<>(); + +}
\ No newline at end of file diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/Skill.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/Skill.java new file mode 100644 index 00000000..fd88144b --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/Skill.java @@ -0,0 +1,14 @@ +package kr.syeyoung.dungeonsguide.features.impl.party.api; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum Skill { + RUNECRAFTING("runecrafting", "Runecrafting"), COMBAT("combat", "Combat"), MINING("mining", "Mining"), ALCHEMY("alchemy", "Alchemy"), FARMING("farming", "Farming"), TAMING("taming", "Taming"), ENCHANTING("enchanting", "Enchanting"), FISHING("fishing", "Fishing"), FORAGING("foraging", "Foraging"), CARPENTRY("carpentry", "Carpentry"); + + private final String jsonName; + private final String friendlyName; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/listener/ChatListenerGlobal.java b/src/main/java/kr/syeyoung/dungeonsguide/features/listener/ChatListenerGlobal.java new file mode 100644 index 00000000..423de9b2 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/listener/ChatListenerGlobal.java @@ -0,0 +1,7 @@ +package kr.syeyoung.dungeonsguide.features.listener; + +import net.minecraftforge.client.event.ClientChatReceivedEvent; + +public interface ChatListenerGlobal { + void onChat(ClientChatReceivedEvent clientChatReceivedEvent); +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/gui/MPanel.java b/src/main/java/kr/syeyoung/dungeonsguide/gui/MPanel.java index 6e8a29f5..78e02013 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/gui/MPanel.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/gui/MPanel.java @@ -116,7 +116,7 @@ public class MPanel { } } - public void clip(ScaledResolution resolution, int x, int y, int width, int height) { + public static void clip(ScaledResolution resolution, int x, int y, int width, int height) { if (width < 0 || height < 0) return; int scale = resolution.getScaleFactor(); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/utils/TextUtils.java b/src/main/java/kr/syeyoung/dungeonsguide/utils/TextUtils.java index acfc430f..a7b4a598 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/utils/TextUtils.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/utils/TextUtils.java @@ -89,5 +89,17 @@ public class TextUtils { return stringBuilder.toString(); } + public static String insertDashUUID(String uuid) { + StringBuilder sb = new StringBuilder(uuid); + sb.insert(8, "-"); + sb = new StringBuilder(sb.toString()); + sb.insert(13, "-"); + sb = new StringBuilder(sb.toString()); + sb.insert(18, "-"); + sb = new StringBuilder(sb.toString()); + sb.insert(23, "-"); + + return sb.toString(); + } }
\ No newline at end of file |