aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/kr/syeyoung/dungeonsguide/rpc
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/rpc
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/rpc')
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordActivity.java72
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordRelation.java42
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordUser.java40
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java250
4 files changed, 404 insertions, 0 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordActivity.java b/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordActivity.java
new file mode 100644
index 00000000..f25022f2
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordActivity.java
@@ -0,0 +1,72 @@
+/*
+ * 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.rpc;
+
+import kr.syeyoung.dungeonsguide.gamesdk.GameSDK;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.datastruct.DiscordActivity;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.EDiscordActivityType;
+import lombok.Data;
+
+@Data
+public class JDiscordActivity {
+ private EDiscordActivityType activityType;
+ private long applicationId;
+ private String name, state, details;
+ private long start, end;
+ private String largeImage, largeText, smallImage, smallText;
+ private String partyId;
+ private int partyCurr, partyMax;
+ private String matchSecret, joinSecret, spectateSecret;
+ private boolean instance;
+
+ public static JDiscordActivity fromJNA(DiscordActivity discordActivity) {
+ if (discordActivity == null) return null;
+ JDiscordActivity jDiscordActivity = new JDiscordActivity();
+ jDiscordActivity.activityType = discordActivity.activityType;
+ jDiscordActivity.applicationId = discordActivity.applicationId.longValue();
+ jDiscordActivity.name = GameSDK.readString(discordActivity.name);
+ jDiscordActivity.state = GameSDK.readString(discordActivity.state);
+ jDiscordActivity.details = GameSDK.readString(discordActivity.details);
+ if (discordActivity.assets != null) {
+ jDiscordActivity.largeImage = GameSDK.readString(discordActivity.assets.large_image);
+ jDiscordActivity.largeText = GameSDK.readString(discordActivity.assets.large_text);
+ jDiscordActivity.smallImage = GameSDK.readString(discordActivity.assets.small_image);
+ jDiscordActivity.smallText = GameSDK.readString(discordActivity.assets.small_text);
+ }
+ if (discordActivity.timestamps != null) {
+ jDiscordActivity.start = discordActivity.timestamps.start.longValue();
+ jDiscordActivity.end = discordActivity.timestamps.end.longValue();
+ }
+ if (discordActivity.secrets != null) {
+ jDiscordActivity.matchSecret= GameSDK.readString(discordActivity.secrets.match);
+ jDiscordActivity.joinSecret = GameSDK.readString(discordActivity.secrets.join);
+ jDiscordActivity.spectateSecret = GameSDK.readString(discordActivity.secrets.spectate);
+ }
+ if (discordActivity.party != null) {
+ jDiscordActivity.partyId = GameSDK.readString(discordActivity.party.id);
+ if (discordActivity.party.discordActivityParty != null) {
+ jDiscordActivity.partyCurr = discordActivity.party.discordActivityParty.current_size.intValue();
+ jDiscordActivity.partyMax = discordActivity.party.discordActivityParty.max_size.intValue();
+ }
+ }
+ jDiscordActivity.instance = discordActivity.instance;
+
+ return jDiscordActivity;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordRelation.java b/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordRelation.java
new file mode 100644
index 00000000..3086c936
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordRelation.java
@@ -0,0 +1,42 @@
+/*
+ * 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.rpc;
+
+import kr.syeyoung.dungeonsguide.gamesdk.jna.datastruct.DiscordRelationship;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.EDiscordRelationshipType;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.EDiscordStatus;
+import lombok.Data;
+
+@Data
+public class JDiscordRelation {
+ private EDiscordRelationshipType discordRelationshipType;
+ private EDiscordStatus status;
+ private JDiscordActivity discordActivity;
+ private JDiscordUser discordUser;
+
+ public static JDiscordRelation fromJNA(DiscordRelationship relationship) {
+ JDiscordRelation jDiscordRelation = new JDiscordRelation();
+ jDiscordRelation.discordUser = JDiscordUser.fromJNA(relationship.user);
+ jDiscordRelation.discordActivity = JDiscordActivity.fromJNA(relationship.presence.activity);
+ jDiscordRelation.status = relationship.presence.status;
+ jDiscordRelation.discordRelationshipType = relationship.type;
+ return jDiscordRelation;
+ }
+
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordUser.java b/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordUser.java
new file mode 100644
index 00000000..635ac405
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/rpc/JDiscordUser.java
@@ -0,0 +1,40 @@
+/*
+ * 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.rpc;
+
+import kr.syeyoung.dungeonsguide.gamesdk.GameSDK;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.datastruct.DiscordUser;
+import lombok.Data;
+
+@Data
+public class JDiscordUser {
+ private long id;
+ private String username, discriminator, avatar;
+ private boolean bot;
+
+ public static JDiscordUser fromJNA(DiscordUser discordUser) {
+ JDiscordUser jDiscordUser = new JDiscordUser();
+ jDiscordUser.id = discordUser.id.longValue();
+ jDiscordUser.username = GameSDK.readString(discordUser.username);
+ jDiscordUser.discriminator = GameSDK.readString(discordUser.discriminator);
+ jDiscordUser.avatar = GameSDK.readString(discordUser.avatar);
+ jDiscordUser.bot = discordUser.bot;
+ return jDiscordUser;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java b/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java
new file mode 100644
index 00000000..23f8433d
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java
@@ -0,0 +1,250 @@
+/*
+ * 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.rpc;
+
+import com.sun.jna.Pointer;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+import kr.syeyoung.dungeonsguide.DungeonsGuide;
+import kr.syeyoung.dungeonsguide.SkyblockStatus;
+import kr.syeyoung.dungeonsguide.dungeon.DungeonContext;
+import kr.syeyoung.dungeonsguide.events.DiscordUserJoinRequestEvent;
+import kr.syeyoung.dungeonsguide.events.DiscordUserUpdateEvent;
+import kr.syeyoung.dungeonsguide.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.gamesdk.GameSDK;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.NativeGameSDK;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.datastruct.*;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.*;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.interfacestruct.*;
+import kr.syeyoung.dungeonsguide.gamesdk.jna.typedef.*;
+import kr.syeyoung.dungeonsguide.party.PartyManager;
+import kr.syeyoung.dungeonsguide.stomp.StompHeader;
+import kr.syeyoung.dungeonsguide.stomp.StompPayload;
+import lombok.Getter;
+import net.minecraftforge.common.MinecraftForge;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class RichPresenceManager implements Runnable {
+ public static RichPresenceManager INSTANCE = new RichPresenceManager();
+ private Thread t = new Thread(this);
+
+ public RichPresenceManager() {
+ t.start();
+ }
+ @Getter
+ private NativeGameSDK nativeGameSDK;
+ @Getter
+ private IDiscordCore iDiscordCore;
+ private IDiscordActivityManager activityManager;
+ private IDiscordRelationshipManager relationshipManager;
+ private IDiscordActivityEvents.ByReference callbacks;
+ private IDiscordRelationshipEvents.ByReference relation_callbacks;
+
+ @Getter
+ private Map<Long, JDiscordRelation> relationMap = new HashMap<>();
+
+ @Getter
+ private int lastSetupCode = -99999;
+ public int setup() {
+ System.out.println("SETUP!!! "+ iDiscordCore);
+ if (iDiscordCore != null) {
+ System.out.println("DETROYED");
+ iDiscordCore.Destroy.destroy(iDiscordCore);
+ activityManager = null; callbacks = null; relation_callbacks = null; relationMap.clear();
+ }
+
+ nativeGameSDK = GameSDK.getNativeGameSDK();
+ if (nativeGameSDK == null) return -9999;
+ DiscordCreateParams discordCreateParams = new DiscordCreateParams();
+ discordCreateParams.flags = new UInt64(EDiscordCreateFlags.DiscordCreateFlags_Default.getValue());
+ discordCreateParams.client_id = new DiscordClientID(816298079732498473L);
+
+ callbacks = new IDiscordActivityEvents.ByReference();
+ callbacks.OnActivityInvite = (eventData, type, user, activity) -> {
+ try {
+ MinecraftForge.EVENT_BUS.post(new DiscordUserJoinRequestEvent(user, true));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ System.out.println("Received Join Request from "+user.id.longValue()+" ("+GameSDK.readString(user.username)+")");
+ };
+ callbacks.OnActivityJoin = (eventData, secret) -> {
+ DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().method(StompHeader.SEND)
+ .header("destination", "/app/party.askedtojoin")
+ .payload(new JSONObject().put("token", secret).toString()));
+ System.out.println("Trying to join with token "+secret);
+ };
+ callbacks.OnActivityJoinRequest = (eventData, user) -> {
+ try {
+ MinecraftForge.EVENT_BUS.post(new DiscordUserJoinRequestEvent(user, false));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ System.out.println("Received Join Request from "+user.id.longValue()+" - "+GameSDK.readString(user.username));
+ };
+ callbacks.OnActivitySpectate = (eventData, secret) -> {
+ };
+ callbacks.write();
+
+ relation_callbacks = new IDiscordRelationshipEvents.ByReference();
+ relation_callbacks.OnRefresh = (p) -> {
+ IDiscordRelationshipManager iDiscordRelationshipManager = iDiscordCore.GetRelationshipManager.getRelationshipManager(iDiscordCore);
+ iDiscordRelationshipManager.Filter.filter(iDiscordRelationshipManager, Pointer.NULL, (d, relation) -> true);
+ IntByReference intByReference = new IntByReference();
+ iDiscordRelationshipManager.Count.count(iDiscordRelationshipManager, intByReference);
+ int count = intByReference.getValue();
+ for (int i = 0; i < count; i++) {
+ DiscordRelationship discordRelationship = new DiscordRelationship();
+ iDiscordRelationshipManager.GetAt.getAt(iDiscordRelationshipManager, new UInt32(i), discordRelationship);
+
+ JDiscordRelation jDiscordRelation = JDiscordRelation.fromJNA(discordRelationship);
+ relationMap.put(jDiscordRelation.getDiscordUser().getId(), jDiscordRelation);
+ }
+ };
+ relation_callbacks.OnRelationshipUpdate = (p, rel) -> {
+ JDiscordRelation jDiscordRelation = JDiscordRelation.fromJNA(rel);
+ JDiscordRelation prev = relationMap.put(jDiscordRelation.getDiscordUser().getId(), jDiscordRelation);
+ System.out.println("Discord relation update!! "+jDiscordRelation);
+ try {
+ MinecraftForge.EVENT_BUS.post(new DiscordUserUpdateEvent(prev, jDiscordRelation));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ };
+ relation_callbacks.write();
+
+ discordCreateParams.activity_events = callbacks;
+ discordCreateParams.relationship_events = relation_callbacks; // 96
+
+ PointerByReference pointerByReference = new PointerByReference();
+ discordCreateParams.write();
+
+ EDiscordResult eDiscordResult = nativeGameSDK.DiscordCreate(new DiscordVersion(NativeGameSDK.DISCORD_VERSION), discordCreateParams, pointerByReference);
+ if (eDiscordResult != EDiscordResult.DiscordResult_Ok) return eDiscordResult.getValue();
+ if (pointerByReference.getValue() == Pointer.NULL) return -9998;
+ iDiscordCore = new IDiscordCore(pointerByReference.getValue());
+
+ iDiscordCore.SetLogHook.setLogHook(iDiscordCore, EDiscordLogLevel.DiscordLogLevel_Debug, Pointer.NULL, new IDiscordCore.LogHook() {
+ @Override
+ public void hook(Pointer hookData, EDiscordLogLevel level, String message) {
+ System.out.println(message+" - "+level+" - "+hookData);
+ }
+ });
+
+ activityManager = iDiscordCore.GetActivityManager.getActivityManager(iDiscordCore);
+ relationshipManager = iDiscordCore.GetRelationshipManager.getRelationshipManager(iDiscordCore);
+
+ return eDiscordResult.getValue();
+ }
+
+ private final SkyblockStatus skyblockStatus = DungeonsGuide.getDungeonsGuide().getSkyblockStatus();
+
+ public void respond(DiscordSnowflake userID, EDiscordActivityJoinRequestReply reply) {
+ activityManager.SendRequestReply.sendRequestReply(activityManager, userID, reply, Pointer.NULL, (callbackData, result) -> {
+ System.out.println("Discord Returned "+result+" For Replying "+reply+" To "+userID.longValue()+"L");
+ });
+ }
+
+ public void accept(DiscordSnowflake userID) {
+ activityManager.AcceptInvite.acceptInvite(activityManager, userID, Pointer.NULL, (callbackData, result) -> {
+ System.out.println("Discord Returned "+result+" For Accepting invite from "+userID.longValue()+"L");
+ });
+ }
+ public void updatePresence() {
+ if (!skyblockStatus.isOnHypixel() || !FeatureRegistry.DISCORD_RICHPRESENCE.isEnabled() || (!skyblockStatus.isOnSkyblock() && FeatureRegistry.DISCORD_RICHPRESENCE.<Boolean>getParameter("disablenotskyblock").getValue())) {
+ activityManager.ClearActivity.clearActivity(activityManager, Pointer.NULL, new NativeGameSDK.DiscordCallback() {
+ @Override
+ public void callback(Pointer callbackData, EDiscordResult result) {
+ }
+ });
+ } else {
+ String name = skyblockStatus.getDungeonName() == null ? "" : skyblockStatus.getDungeonName();
+ if (!skyblockStatus.isOnSkyblock()) name ="Somewhere on Hypixel";
+ if (name.trim().equals("Your Island")) name = "Private Island";
+
+ DiscordActivity latestDiscordActivity = new DiscordActivity();
+ latestDiscordActivity.assets = new DiscordActivityAssets();
+ latestDiscordActivity.secrets = new DiscordActivitySecrets();
+ latestDiscordActivity.party = new DiscordActivityParty();
+ latestDiscordActivity.party.discordActivityParty = new DiscordPartySize();
+ latestDiscordActivity.timestamps = new DiscordActivityTimestamps();
+ GameSDK.writeString(latestDiscordActivity.assets.large_image, "mort");
+ GameSDK.writeString(latestDiscordActivity.assets.large_text, "mort");
+ GameSDK.writeString(latestDiscordActivity.state, name);
+
+ GameSDK.writeString(latestDiscordActivity.party.id, PartyManager.INSTANCE.getPartyID() == null ? "" : PartyManager.INSTANCE.getPartyID());
+ latestDiscordActivity.party.discordActivityParty.current_size = new Int32(PartyManager.INSTANCE.getMemberCount());
+ latestDiscordActivity.party.discordActivityParty.max_size = new Int32(PartyManager.INSTANCE.getMaxParty());
+
+ if (skyblockStatus.getContext() != null) {
+ DungeonContext dungeonContext = skyblockStatus.getContext();
+ long init = dungeonContext.getInit();
+ latestDiscordActivity.timestamps.start = new DiscordTimestamp(init);
+
+ if (dungeonContext.getBossfightProcessor() != null) {
+ GameSDK.writeString(latestDiscordActivity.details, "Fighting "+dungeonContext.getBossfightProcessor().getBossName()+": "+dungeonContext.getBossfightProcessor().getCurrentPhase());
+ } else {
+ GameSDK.writeString(latestDiscordActivity.details, "Clearing Rooms");
+ }
+ } else {
+ latestDiscordActivity.timestamps.start = new DiscordTimestamp(0);
+ GameSDK.writeString(latestDiscordActivity.details, "Dungeons Guide");
+ }
+ if (PartyManager.INSTANCE.isAllowAskToJoin()) {
+ GameSDK.writeString(latestDiscordActivity.secrets.join, PartyManager.INSTANCE.getAskToJoinSecret());
+ } else {
+ GameSDK.writeString(latestDiscordActivity.secrets.join, "");
+ }
+ activityManager.UpdateActivity.updateActivity(activityManager, latestDiscordActivity, Pointer.NULL, new NativeGameSDK.DiscordCallback() {
+ @Override
+ public void callback(Pointer callbackData, EDiscordResult result) {
+ }
+ });
+ }
+ }
+
+ @Override
+ public void run() {
+ boolean setup = true;
+ int counter = 0;
+ while(!Thread.interrupted()) {
+ try {
+ if (iDiscordCore == null || setup) {
+ lastSetupCode = setup();
+ System.out.println("Discord returned "+lastSetupCode+" for setup "+EDiscordResult.fromValue(lastSetupCode));
+ setup = lastSetupCode != EDiscordResult.DiscordResult_Ok.getValue();
+ counter = 0;
+ } else {
+ EDiscordResult eDiscordResult = iDiscordCore.RunCallbacks.runCallbacks(iDiscordCore);
+ if (eDiscordResult == EDiscordResult.DiscordResult_NotRunning) {
+ setup = true;
+ } else {
+ if (counter == 0)
+ updatePresence();
+ if (++counter == 15) counter = 0;
+ }
+ }
+ Thread.sleep(16L);
+ } catch (Exception e) {e.printStackTrace();}
+ }
+ }
+}