aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/kr/syeyoung/dungeonsguide/features
diff options
context:
space:
mode:
authorsyeyoung <cyong06@naver.com>2021-08-10 23:35:14 +0900
committersyeyoung <cyong06@naver.com>2021-08-10 23:35:14 +0900
commita48cb5c96e16fae589cb7d4f09146a17b3787924 (patch)
treef96af8b3c438357dad8ea6e0b223ce5351e82212 /src/main/java/kr/syeyoung/dungeonsguide/features
parent3f2a8ec601bdc43bbb2a48ef61e372e4c907ce8d (diff)
downloadSkyblock-Dungeons-Guide-a48cb5c96e16fae589cb7d4f09146a17b3787924.tar.gz
Skyblock-Dungeons-Guide-a48cb5c96e16fae589cb7d4f09146a17b3787924.tar.bz2
Skyblock-Dungeons-Guide-a48cb5c96e16fae589cb7d4f09146a17b3787924.zip
Better Rich Presence
Diffstat (limited to 'src/main/java/kr/syeyoung/dungeonsguide/features')
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java8
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/ImageTexture.java120
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyInviteViewer.java318
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyJoinRequest.java60
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/onlinealarm/PlayingDGAlarm.java171
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserJoinRequestListener.java26
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserUpdateListener.java25
7 files changed, 727 insertions, 1 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java
index ee81ee2f..55e2753b 100644
--- a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java
@@ -28,6 +28,8 @@ import kr.syeyoung.dungeonsguide.features.impl.boss.terminal.FeatureSimonSaysSol
import kr.syeyoung.dungeonsguide.features.impl.boss.terminal.FeatureTerminalSolvers;
import kr.syeyoung.dungeonsguide.features.impl.cosmetics.FeatureNicknameColor;
import kr.syeyoung.dungeonsguide.features.impl.cosmetics.FeatureNicknamePrefix;
+import kr.syeyoung.dungeonsguide.features.impl.discord.inviteViewer.PartyInviteViewer;
+import kr.syeyoung.dungeonsguide.features.impl.discord.onlinealarm.PlayingDGAlarm;
import kr.syeyoung.dungeonsguide.features.impl.dungeon.*;
import kr.syeyoung.dungeonsguide.features.impl.etc.*;
import kr.syeyoung.dungeonsguide.features.impl.etc.ability.FeatureAbilityCooldown;
@@ -76,11 +78,15 @@ public class FeatureRegistry {
public static final FeatureRoomDebugInfo ADVANCED_DEBUG_ROOM = register(new FeatureRoomDebugInfo());
public static final FeatureDebuggableMap ADVANCED_DEBUGGABLE_MAP = register(new FeatureDebuggableMap());
public static final FeatureRoomCoordDisplay ADVANCED_COORDS = register(new FeatureRoomCoordDisplay());
- public static final SimpleFeature ADVANCED_RICHPRESENCE = register(new SimpleFeature("Misc", "Discord RPC", "Discord rich presence with ASK-TO-JOIN Support!\n\nSimply type /dg asktojoin or /dg atj to toggle whether ask-to-join would be presented as option on discord!", "advanced.richpresence", true) {
+
+ public static final SimpleFeature DISCORD_RICHPRESENCE = register(new SimpleFeature("Discord", "Discord RPC", "Enable Discord rich presence", "advanced.richpresence", true) {
{
parameters.put("disablenotskyblock", new FeatureParameter<Boolean>("disablenotskyblock", "Disable When not on Skyblock", "Disable When not on skyblock", false, "boolean"));
}
});
+ public static final PartyInviteViewer DISCORD_ASKTOJOIN = register(new PartyInviteViewer());
+ public static final PlayingDGAlarm DISCORD_ONLINEALARM = register(new PlayingDGAlarm());
+
public static final SimpleFeature SOLVER_RIDDLE = register(new SimpleFeature("Solver.Any Floor", "Riddle", "Highlights the correct box after clicking on all 3 weirdos", "solver.riddle"));
public static final SimpleFeature SOLVER_KAHOOT = register(new SimpleFeature("Solver.Floor 4+", "Quiz", "Highlights the correct solution for trivia puzzle", "solver.trivia"));
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/ImageTexture.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/ImageTexture.java
new file mode 100644
index 00000000..62ee2913
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/ImageTexture.java
@@ -0,0 +1,120 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.features.impl.discord.inviteViewer;
+
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
+import net.minecraft.client.renderer.texture.DynamicTexture;
+import net.minecraft.client.renderer.texture.TextureManager;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.util.ResourceLocation;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Iterator;
+
+@Data
+public class ImageTexture {
+ private String url;
+ private BufferedImage image;
+ private DynamicTexture previewTexture;
+ private ResourceLocation resourceLocation;
+
+ private int width;
+ private int height;
+ private int frames;
+ private int size;
+
+ @Getter @Setter
+ private int lastFrame = 0;
+
+ public void buildGLThings() {
+ previewTexture = new DynamicTexture(image);
+ resourceLocation = Minecraft.getMinecraft().getTextureManager().getDynamicTextureLocation("dgurl/"+url, previewTexture);
+ }
+
+ public ImageTexture(String url) throws IOException {
+ this.url = url;
+
+ URL urlObj = new URL(url);
+ HttpURLConnection huc = (HttpURLConnection) urlObj.openConnection();
+ huc.addRequestProperty("User-Agent", "DungeonsGuideMod (dungeons.guide, 1.0)");
+ ImageInputStream imageInputStream = ImageIO.createImageInputStream(huc.getInputStream());
+ Iterator<ImageReader> readers = ImageIO.getImageReaders(imageInputStream);
+ if(!readers.hasNext()) throw new IOException("No image reader what" + url);
+ ImageReader reader = readers.next();
+ reader.setInput(imageInputStream);
+ frames = reader.getNumImages(true);
+ BufferedImage dummyFrame = reader.read(0);
+ width = dummyFrame.getWidth(); height = dummyFrame.getHeight();
+
+
+ image = new BufferedImage(width, height * frames, dummyFrame.getType());
+ Graphics2D graphics2D = image.createGraphics();
+
+ for (int i = 0; i < frames; i++) {
+ BufferedImage bufferedImage = reader.read(i);
+ graphics2D.drawImage(bufferedImage, 0, i*height, null);
+ }
+ reader.dispose(); imageInputStream.close(); huc.disconnect();
+ }
+
+ public void drawFrame(int frame, int x, int y, int width, int height) {
+ if (getResourceLocation() == null)
+ buildGLThings();
+
+ TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
+ textureManager.bindTexture(getResourceLocation());
+
+ GlStateManager.color(1, 1, 1, 1.0F);
+
+ Tessellator tessellator = Tessellator.getInstance();
+ WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+ worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX);
+ worldrenderer.pos((double)x, (double)(y + height), 0.0D)
+ .tex(0,((frame+1) * height)/ ((double)frames * height)).endVertex();
+ worldrenderer.pos((double)(x + width), (double)(y + height), 0.0D)
+ .tex(1, ((frame+1) * height)/ ((double)frames * height)).endVertex();
+ worldrenderer.pos((double)(x + width), (double)y, 0.0D)
+ .tex(1,(frame * height)/ ((double)frames * height)).endVertex();
+ worldrenderer.pos((double)x, (double)y, 0.0D)
+ .tex(0, (frame * height) / ((double)frames * height)).endVertex();
+ tessellator.draw();
+ }
+
+ public void drawFrameAndIncrement(int x, int y, int width, int height) {
+ drawFrame(lastFrame, x,y,width,height);
+ lastFrame++;
+ if (lastFrame >= frames) lastFrame = 0;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyInviteViewer.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyInviteViewer.java
new file mode 100644
index 00000000..6676eae2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyInviteViewer.java
@@ -0,0 +1,318 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.features.impl.discord.inviteViewer;
+
+import kr.syeyoung.dungeonsguide.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.events.DiscordUserJoinRequestEvent;
+import kr.syeyoung.dungeonsguide.features.SimpleFeature;
+import kr.syeyoung.dungeonsguide.features.listener.*;
+import kr.syeyoung.dungeonsguide.rpc.RichPresenceManager;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.EDiscordActivityJoinRequestReply;
+import kr.syeyoung.dungeonsguide.utils.TextUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.texture.TextureManager;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.*;
+
+public class PartyInviteViewer extends SimpleFeature implements GuiPostRenderListener, ScreenRenderListener, TickListener, GuiClickListener, DiscordUserJoinRequestListener {
+ public PartyInviteViewer() {
+ super("Discord", "Party Invite Viewer","Simply type /dg asktojoin or /dg atj to toggle whether ask-to-join would be presented as option on discord!\n\nRequires Discord RPC to be enabled", "discord.party_invite_viewer");
+ }
+
+ @Override
+ public boolean isDisyllable() {
+ return false;
+ }
+
+ @Override
+ public void onGuiPostRender(GuiScreenEvent.DrawScreenEvent.Post rendered) {
+ renderRequests(true);
+ }
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ try {
+ renderRequests(false);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ @Override
+ public void onTick() {
+ try {
+ List<PartyJoinRequest> partyJoinRequestList = new ArrayList<>();
+ boolean isOnHypixel = DungeonsGuide.getDungeonsGuide().getSkyblockStatus().isOnHypixel();
+ for (PartyJoinRequest joinRequest:joinRequests) {
+ if (joinRequest.getTtl() != -1) {
+ joinRequest.setTtl(joinRequest.getTtl() - 1);
+ if (joinRequest.getTtl() == 0 || !isOnHypixel) {
+ partyJoinRequestList.add(joinRequest);
+ }
+ } else if (!isOnHypixel){
+// DiscordRPC.discordRespond(joinRequest.getDiscordUser().userId, DiscordRPC.DiscordReply.NO);
+ partyJoinRequestList.add(joinRequest);
+ } else if (joinRequest.getExpire() < System.currentTimeMillis()) {
+ partyJoinRequestList.add(joinRequest);
+ }
+ }
+ joinRequests.removeAll(partyJoinRequestList);
+ } catch (Throwable e) {e.printStackTrace();}
+ }
+
+
+ @Override
+ public void onMouseInput(GuiScreenEvent.MouseInputEvent.Pre mouseInputEvent) {
+ int mouseX = Mouse.getX();
+ int mouseY = Minecraft.getMinecraft().displayHeight - Mouse.getY() +3;
+ for (PartyJoinRequest joinRequest:joinRequests) {
+ if (joinRequest.getWholeRect() != null && joinRequest.getWholeRect().contains(mouseX, mouseY)) {
+ mouseInputEvent.setCanceled(true);
+
+ if (Mouse.getEventButton() == -1) return;
+
+ if (joinRequest.getReply() != null) {
+ joinRequests.remove(joinRequest);
+ return;
+ }
+
+ if (!joinRequest.isInvite()) {
+ if (joinRequest.getAcceptRect().contains(mouseX, mouseY)) {
+ joinRequest.setReply(PartyJoinRequest.Reply.ACCEPT);
+ joinRequest.setTtl(60);
+ RichPresenceManager.INSTANCE.respond(joinRequest.getDiscordUser().id, EDiscordActivityJoinRequestReply.DiscordActivityJoinRequestReply_Yes);
+ return;
+ }
+
+ if (joinRequest.getDenyRect().contains(mouseX, mouseY)) {
+ joinRequest.setReply(PartyJoinRequest.Reply.DENY);
+ joinRequest.setTtl(60);
+ RichPresenceManager.INSTANCE.respond(joinRequest.getDiscordUser().id, EDiscordActivityJoinRequestReply.DiscordActivityJoinRequestReply_No);
+ return;
+ }
+
+ if (joinRequest.getIgnoreRect().contains(mouseX, mouseY)) {
+ joinRequest.setReply(PartyJoinRequest.Reply.IGNORE);
+ joinRequest.setTtl(60);
+ RichPresenceManager.INSTANCE.respond(joinRequest.getDiscordUser().id, EDiscordActivityJoinRequestReply.DiscordActivityJoinRequestReply_Ignore);
+ return;
+ }
+ } else {
+ if (joinRequest.getAcceptRect().contains(mouseX, mouseY)) {
+ joinRequest.setReply(PartyJoinRequest.Reply.ACCEPT);
+ joinRequest.setTtl(60);
+ RichPresenceManager.INSTANCE.accept(joinRequest.getDiscordUser().id);
+ return;
+ }
+
+ if (joinRequest.getDenyRect().contains(mouseX, mouseY)) {
+ joinRequest.setReply(PartyJoinRequest.Reply.DENY);
+ joinRequest.setTtl(60);
+ return;
+ }
+ }
+
+ return;
+ }
+ }
+ }
+
+
+
+ public CopyOnWriteArrayList<PartyJoinRequest> joinRequests = new CopyOnWriteArrayList<>();
+
+ ExecutorService executorService = Executors.newFixedThreadPool(3);
+ public Map<String, Future<ImageTexture>> futureMap = new HashMap<>();
+ public Map<String, ImageTexture> imageMap = new HashMap<>();
+
+ public Future<ImageTexture> loadImage(String url) {
+ if (imageMap.containsKey(url)) return CompletableFuture.completedFuture(imageMap.get(url));
+ if (futureMap.containsKey(url)) return futureMap.get(url);
+ Future<ImageTexture> future = executorService.submit(() -> {
+ try {
+ ImageTexture imageTexture = new ImageTexture(url);
+ imageMap.put(url, imageTexture);
+ return imageTexture;
+ } catch (Exception e) {
+ throw e;
+ }
+ });
+ futureMap.put(url,future);
+ return future;
+ }
+
+
+ public void renderRequests(boolean hover) {
+ try {
+ GlStateManager.pushMatrix();
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ GlStateManager.scale(1.0 / sr.getScaleFactor(), 1.0 / sr.getScaleFactor(), 1.0);
+ int height = 90;
+ int gap = 5;
+ int x = 5;
+ int y = 5;
+ for (PartyJoinRequest partyJoinRequest : joinRequests) {
+ renderRequest(partyJoinRequest, x, y, 350,height, hover);
+ y += height + gap;
+ }
+ GlStateManager.popMatrix();
+ GlStateManager.enableBlend();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+
+ public void renderRequest(PartyJoinRequest partyJoinRequest, int x, int y, int width, int height, boolean hover) {
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+
+ int mouseX = Mouse.getX();
+ int mouseY = Minecraft.getMinecraft().displayHeight - Mouse.getY() +3;
+
+ partyJoinRequest.getWholeRect().setBounds(x,y,width,height);
+
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(x,y,0);
+
+ Gui.drawRect(0, 0,width,height, 0xFF23272a);
+ Gui.drawRect(2, 2, width-2, height-2, 0XFF2c2f33);
+ {
+ String avatar = "https://cdn.discordapp.com/avatars/"+Long.toUnsignedString(partyJoinRequest.getDiscordUser().id.longValue())+"/"+partyJoinRequest.getAvatar()+"."+(partyJoinRequest.getAvatar().startsWith("a_") ? "gif":"png");
+ Future<ImageTexture> loadedImageFuture = loadImage(avatar);
+ ImageTexture loadedImage = null;
+ if (loadedImageFuture.isDone()) {
+ try {
+ loadedImage = loadedImageFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+ if (loadedImage != null) {
+ loadedImage.drawFrameAndIncrement( 7,7,height-14,height-14);
+ } else {
+ Gui.drawRect(7, 7, height - 7, height-7, 0xFF4E4E4E);
+ }
+ }
+
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(height +3,7, 0);
+
+ GlStateManager.pushMatrix();
+ GlStateManager.scale(3.0,3.0,1.0);
+ fr.drawString(partyJoinRequest.getUsername()+"", 0,0, 0xFFFFFFFF, true);
+ GlStateManager.popMatrix();
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(fr.getStringWidth(partyJoinRequest.getUsername()+"") * 3 + 1, (int)(fr.FONT_HEIGHT*1.5), 0);
+ fr.drawString("#"+partyJoinRequest.getDiscriminator(), 0,0,0xFFaaaaaa, true);
+ GlStateManager.popMatrix();
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, fr.FONT_HEIGHT * 3 + 5, 0);
+ GlStateManager.scale(1.0,1.0,1.0);
+ if (partyJoinRequest.isInvite())
+ fr.drawString("§ewants to you to join their party! ("+(TextUtils.formatTime(partyJoinRequest.getExpire() - System.currentTimeMillis()))+")", 0,0,0xFFFFFFFF,false);
+ else
+ fr.drawString("wants to join your party! ("+(TextUtils.formatTime(partyJoinRequest.getExpire() - System.currentTimeMillis()))+")", 0,0,0xFFFFFFFF,false);
+ GlStateManager.popMatrix();
+ GlStateManager.popMatrix();
+ if (partyJoinRequest.getReply() == null) {
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(height + 3, height - 32, 0);
+ int widthForTheThing = (width - height) / 3;
+ GlStateManager.pushMatrix();
+ String text = "Accept";
+ partyJoinRequest.getAcceptRect().setBounds(x + height + 3, y + height - 25, widthForTheThing - 10, 25);
+ Gui.drawRect(0, 0, widthForTheThing - 10, 25, hover && partyJoinRequest.getAcceptRect().contains(mouseX, mouseY) ? 0xFF859DF0 : 0xFF7289da);
+ GlStateManager.translate((widthForTheThing - 10 - fr.getStringWidth(text) * 2) / 2, 15 - fr.FONT_HEIGHT, 0);
+
+ GlStateManager.scale(2.0f, 2.0f, 1.0f);
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString(text, 0, 0, 0xFFFFFFFF);
+ GlStateManager.popMatrix();
+ GlStateManager.translate(widthForTheThing, 0, 0);
+ partyJoinRequest.getDenyRect().setBounds(x + height + 3 + widthForTheThing, y + height - 25, widthForTheThing - 10, 25);
+ Gui.drawRect(0, 0, widthForTheThing - 10, 25, hover && partyJoinRequest.getDenyRect().contains(mouseX, mouseY) ? 0xFFAEC0CB : 0xFF99aab5);
+ GlStateManager.pushMatrix();
+ text = "Deny";
+ GlStateManager.translate((widthForTheThing - 10 - fr.getStringWidth(text) * 2) / 2, 15 - fr.FONT_HEIGHT, 0);
+ GlStateManager.scale(2.0f, 2.0f, 1.0f);
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString(text, 0, 0, 0xFFFFFFFF);
+ GlStateManager.popMatrix();
+ if (!partyJoinRequest.isInvite()) {
+ GlStateManager.translate(widthForTheThing, 0, 0);
+ partyJoinRequest.getIgnoreRect().setBounds(x + height + 3 + widthForTheThing + widthForTheThing, y + height - 25, widthForTheThing - 10, 25);
+ Gui.drawRect(0, 0, widthForTheThing - 10, 25, hover && partyJoinRequest.getIgnoreRect().contains(mouseX, mouseY) ? 0xFFAEC0CB : 0xFF99aab5); // AEC0CB
+
+ GlStateManager.pushMatrix();
+ text = "Ignore";
+ GlStateManager.translate((widthForTheThing - 10 - fr.getStringWidth(text) * 2) / 2, 15 - fr.FONT_HEIGHT, 0);
+ GlStateManager.scale(2.0f, 2.0f, 1.0f);
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString(text, 0, 0, 0xFFFFFFFF);
+ GlStateManager.popMatrix();
+ }
+ GlStateManager.popMatrix();
+ } else {
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(height + 3, height - 28, 0);
+ GlStateManager.scale(2.0f,2.0f,1.0f);
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ fr.drawString(partyJoinRequest.getReply().getPast()+" the invite.",0,0,0xFFFFFFFF);
+ GlStateManager.popMatrix();
+ }
+ GlStateManager.popMatrix();
+ }
+
+ @Override
+ public void onDiscordUserJoinRequest(DiscordUserJoinRequestEvent event) {
+ PartyJoinRequest partyInvite = new PartyJoinRequest();
+ partyInvite.setDiscordUser(event.getDiscordUser());
+ partyInvite.setExpire(System.currentTimeMillis() + 30000L);
+ partyInvite.setInvite(event.isInvite());
+ joinRequests.add(partyInvite);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyJoinRequest.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyJoinRequest.java
new file mode 100644
index 00000000..b95da68a
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/inviteViewer/PartyJoinRequest.java
@@ -0,0 +1,60 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.features.impl.discord.inviteViewer;
+
+import kr.syeyoung.dungeonsguide.gamesdk.GameSDK;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.datastruct.DiscordUser;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+
+import java.awt.*;
+
+@Data
+public class PartyJoinRequest {
+ private DiscordUser discordUser;
+
+ public void setDiscordUser(DiscordUser discordUser) {
+ this.discordUser = discordUser;
+ username = GameSDK.readString(discordUser.username);
+ discriminator = GameSDK.readString(discordUser.discriminator);
+ avatar = GameSDK.readString(discordUser.avatar);
+ System.out.println(username+"/"+discriminator+"/"+avatar);
+ }
+
+ private String username, discriminator, avatar;
+ private long expire;
+
+ private Rectangle wholeRect = new Rectangle();
+ private Rectangle acceptRect = new Rectangle();
+ private Rectangle denyRect = new Rectangle();
+ private Rectangle ignoreRect = new Rectangle();
+
+ private boolean isInvite;
+ private int ttl = -1;
+ private Reply reply;
+
+ @AllArgsConstructor
+ public enum Reply {
+ ACCEPT("Accepted"), DENY("Denied"), IGNORE("Ignored");
+
+ @Getter
+ private final String past;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/onlinealarm/PlayingDGAlarm.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/onlinealarm/PlayingDGAlarm.java
new file mode 100644
index 00000000..d003b165
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/discord/onlinealarm/PlayingDGAlarm.java
@@ -0,0 +1,171 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.features.impl.discord.onlinealarm;
+
+import kr.syeyoung.dungeonsguide.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.events.DiscordUserUpdateEvent;
+import kr.syeyoung.dungeonsguide.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.features.SimpleFeature;
+import kr.syeyoung.dungeonsguide.features.impl.discord.inviteViewer.ImageTexture;
+import kr.syeyoung.dungeonsguide.features.listener.DiscordUserUpdateListener;
+import kr.syeyoung.dungeonsguide.features.listener.ScreenRenderListener;
+import kr.syeyoung.dungeonsguide.features.listener.TickListener;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.EDiscordRelationshipType;
+import kr.syeyoung.dungeonsguide.rpc.JDiscordActivity;
+import kr.syeyoung.dungeonsguide.rpc.JDiscordRelation;
+import kr.syeyoung.dungeonsguide.utils.TextUtils;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.texture.TextureManager;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class PlayingDGAlarm extends SimpleFeature implements DiscordUserUpdateListener, ScreenRenderListener, TickListener {
+ public PlayingDGAlarm() {
+ super("Discord", "Friend Online Notification","Notifies you in bottom when your discord friend has launched a Minecraft with DG!\n\nRequires the Friend's Discord RPC to be enabled", "discord.playingalarm");
+ }
+ private List<PlayerOnline> notif = new CopyOnWriteArrayList<>();
+
+ @Override
+ public void onTick() {
+ try {
+ List<PlayerOnline> partyJoinRequestList = new ArrayList<>();
+ boolean isOnHypixel = DungeonsGuide.getDungeonsGuide().getSkyblockStatus().isOnHypixel();
+ for (PlayerOnline joinRequest:notif) {
+ if (!isOnHypixel){
+ partyJoinRequestList.add(joinRequest);
+ } else if (joinRequest.getEnd() < System.currentTimeMillis()) {
+ partyJoinRequestList.add(joinRequest);
+ }
+ }
+ notif.removeAll(partyJoinRequestList);
+ } catch (Throwable e) {e.printStackTrace();}
+ }
+
+
+
+ @Override
+ public void drawScreen(float partialTicks) {
+ try {
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0,0,100);
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ GlStateManager.scale(1.0 / sr.getScaleFactor(), 1.0 / sr.getScaleFactor(), 1.0);
+ int height = 90;
+ int gap = 5;
+ int x = Minecraft.getMinecraft().displayWidth-350-gap;
+ int y = Minecraft.getMinecraft().displayHeight-(height+gap)*notif.size();
+ for (PlayerOnline partyJoinRequest : notif) {
+ renderRequest(partyJoinRequest, x, y, 350,height);
+ y += height + gap;
+ }
+ GlStateManager.popMatrix();
+ GlStateManager.enableBlend();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ public void renderRequest(PlayerOnline online, int x, int y, int width, int height) {
+ GlStateManager.pushMatrix();
+ online.setEnd(System.currentTimeMillis()+600000);
+ GlStateManager.translate(x,y,0);
+
+ Gui.drawRect(0, 0,width,height, 0xFF23272a);
+ Gui.drawRect(2, 2, width-2, height-2, 0XFF2c2f33);
+ {
+ String avatar = "https://cdn.discordapp.com/avatars/"+Long.toUnsignedString(online.getJDiscordRelation().getDiscordUser().getId())+"/"+online.getJDiscordRelation().getDiscordUser().getAvatar()+"."+(online.getJDiscordRelation().getDiscordUser().getAvatar().startsWith("a_") ? "gif":"png");
+ Future<ImageTexture> loadedImageFuture = FeatureRegistry.DISCORD_ASKTOJOIN.loadImage(avatar);
+ ImageTexture loadedImage = null;
+ if (loadedImageFuture.isDone()) {
+ try {
+ loadedImage = loadedImageFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+ if (loadedImage != null) {
+ loadedImage.drawFrameAndIncrement( 7,7,height-14,height-14);
+ } else {
+ Gui.drawRect(7, 7, height - 7, height-7, 0xFF4E4E4E);
+ }
+ }
+
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(height +3,7, 0);
+
+ GlStateManager.pushMatrix();
+ GlStateManager.scale(3.0,3.0,1.0);
+ fr.drawString(online.getJDiscordRelation().getDiscordUser().getUsername()+"", 0,0, 0xFFFFFFFF, true);
+ GlStateManager.popMatrix();
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(fr.getStringWidth(online.getJDiscordRelation().getDiscordUser().getUsername()+"") * 3 + 1, (int)(fr.FONT_HEIGHT*1.5), 0);
+ fr.drawString("#"+online.getJDiscordRelation().getDiscordUser().getDiscriminator(), 0,0,0xFFaaaaaa, true);
+ GlStateManager.popMatrix();
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, fr.FONT_HEIGHT * 3 + 5, 0);
+ GlStateManager.scale(1.0,1.0,1.0);
+ fr.drawString("Started Playing Skyblock! (Dismissed in "+(TextUtils.formatTime(online.getEnd() - System.currentTimeMillis()))+")", 0,0,0xFFFFFFFF,false);
+ GlStateManager.popMatrix();
+ GlStateManager.popMatrix();
+ GlStateManager.popMatrix();
+ }
+
+
+ @Data @AllArgsConstructor
+ public static class PlayerOnline {
+ private JDiscordRelation jDiscordRelation;
+ private long end;
+ }
+
+ @Override
+ public void onDiscordUserUpdate(DiscordUserUpdateEvent event) {
+ JDiscordRelation prev = event.getPrev(), current = event.getCurrent();
+ if (!isDisplayable(prev) && isDisplayable(current)) {
+ notif.add(new PlayerOnline(current, System.currentTimeMillis()+600000));
+ }
+ }
+
+ public boolean isDisplayable(JDiscordRelation jDiscordRelation) {
+ EDiscordRelationshipType relationshipType = jDiscordRelation.getDiscordRelationshipType();
+ if (relationshipType == EDiscordRelationshipType.DiscordRelationshipType_Blocked) return false;
+ if (relationshipType == EDiscordRelationshipType.DiscordRelationshipType_None) return false;
+ if (relationshipType == EDiscordRelationshipType.DiscordRelationshipType_PendingIncoming) return false;
+ if (relationshipType == EDiscordRelationshipType.DiscordRelationshipType_PendingOutgoing) return false;
+
+ JDiscordActivity jDiscordActivity = jDiscordRelation.getDiscordActivity();
+ return jDiscordActivity.getApplicationId() == 816298079732498473L;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserJoinRequestListener.java b/src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserJoinRequestListener.java
new file mode 100644
index 00000000..d48331d5
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserJoinRequestListener.java
@@ -0,0 +1,26 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.features.listener;
+
+import kr.syeyoung.dungeonsguide.events.DiscordUserJoinRequestEvent;
+import kr.syeyoung.dungeonsguide.events.DiscordUserUpdateEvent;
+
+public interface DiscordUserJoinRequestListener {
+ void onDiscordUserJoinRequest(DiscordUserJoinRequestEvent event);
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserUpdateListener.java b/src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserUpdateListener.java
new file mode 100644
index 00000000..d376a21d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/features/listener/DiscordUserUpdateListener.java
@@ -0,0 +1,25 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.features.listener;
+
+import kr.syeyoung.dungeonsguide.events.DiscordUserUpdateEvent;
+
+public interface DiscordUserUpdateListener {
+ void onDiscordUserUpdate(DiscordUserUpdateEvent event);
+}