FIELD_ORDER = Collections.unmodifiableList(Arrays.asList(
+ "state",
+ "details",
+ "startTimestamp",
+ "endTimestamp",
+ "largeImageKey",
+ "largeImageText",
+ "smallImageKey",
+ "smallImageText",
+ "partyId",
+ "partySize",
+ "partyMax",
+ "matchSecret",
+ "joinSecret",
+ "spectateSecret",
+ "instance"
+ ));
+
+ public DiscordRichPresence(String encoding) {
+ super();
+ setStringEncoding(encoding);
+ }
+
+ public DiscordRichPresence() {
+ this("UTF-8");
+ }
+
+ /**
+ * The user's current party status.
+ *
Example: "Looking to Play", "Playing Solo", "In a Group"
+ *
+ * Maximum: 128 characters
+ */
+ public String state;
+
+ /**
+ * What the player is currently doing.
+ *
Example: "Competitive - Captain's Mode", "In Queue", "Unranked PvP"
+ *
+ *
Maximum: 128 characters
+ */
+ public String details;
+
+ /**
+ * Unix timestamp (seconds) for the start of the game.
+ *
Example: 1507665886
+ */
+ public long startTimestamp;
+
+ /**
+ * Unix timestamp (seconds) for the start of the game.
+ *
Example: 1507665886
+ */
+ public long endTimestamp;
+
+ /**
+ * Name of the uploaded image for the large profile artwork.
+ *
Example: "default"
+ *
+ *
Maximum: 32 characters
+ */
+ public String largeImageKey;
+
+ /**
+ * Tooltip for the largeImageKey.
+ *
Example: "Blade's Edge Arena", "Numbani", "Danger Zone"
+ *
+ *
Maximum: 128 characters
+ */
+ public String largeImageText;
+
+ /**
+ * Name of the uploaded image for the small profile artwork.
+ *
Example: "rogue"
+ *
+ *
Maximum: 32 characters
+ */
+ public String smallImageKey;
+
+ /**
+ * Tooltip for the smallImageKey.
+ *
Example: "Rogue - Level 100"
+ *
+ *
Maximum: 128 characters
+ */
+ public String smallImageText;
+
+ /**
+ * ID of the player's party, lobby, or group.
+ *
Example: "ae488379-351d-4a4f-ad32-2b9b01c91657"
+ *
+ *
Maximum: 128 characters
+ */
+ public String partyId;
+
+ /**
+ * Current size of the player's party, lobby, or group.
+ *
Example: 1
+ */
+ public int partySize;
+
+ /**
+ * Maximum size of the player's party, lobby, or group.
+ *
Example: 5
+ */
+ public int partyMax;
+
+ /**
+ * Unique hashed string for Spectate and Join.
+ * Required to enable match interactive buttons in the user's presence.
+ *
Example: "MmhuZToxMjMxMjM6cWl3amR3MWlqZA=="
+ *
+ *
Maximum: 128 characters
+ */
+ public String matchSecret;
+
+ /**
+ * Unique hashed string for Spectate button.
+ * This will enable the "Spectate" button on the user's presence if whitelisted.
+ *
Example: "MTIzNDV8MTIzNDV8MTMyNDU0"
+ *
+ *
Maximum: 128 characters
+ */
+ public String joinSecret;
+
+ /**
+ * Unique hashed string for chat invitations and Ask to Join.
+ * This will enable the "Ask to Join" button on the user's presence if whitelisted.
+ *
Example: "MTI4NzM0OjFpMmhuZToxMjMxMjM="
+ *
+ *
Maximum: 128 characters
+ */
+ public String spectateSecret;
+
+ /**
+ * Marks the matchSecret as a game session with a specific beginning and end.
+ * Boolean value of 0 or 1.
+ *
Example: 1
+ */
+ public byte instance;
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ if (!(o instanceof DiscordRichPresence))
+ return false;
+ DiscordRichPresence presence = (DiscordRichPresence) o;
+ return startTimestamp == presence.startTimestamp
+ && endTimestamp == presence.endTimestamp
+ && partySize == presence.partySize
+ && partyMax == presence.partyMax
+ && instance == presence.instance
+ && Objects.equals(state, presence.state)
+ && Objects.equals(details, presence.details)
+ && Objects.equals(largeImageKey, presence.largeImageKey)
+ && Objects.equals(largeImageText, presence.largeImageText)
+ && Objects.equals(smallImageKey, presence.smallImageKey)
+ && Objects.equals(smallImageText, presence.smallImageText)
+ && Objects.equals(partyId, presence.partyId)
+ && Objects.equals(matchSecret, presence.matchSecret)
+ && Objects.equals(joinSecret, presence.joinSecret)
+ && Objects.equals(spectateSecret, presence.spectateSecret);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(state, details, startTimestamp, endTimestamp, largeImageKey, largeImageText, smallImageKey,
+ smallImageText, partyId, partySize, partyMax, matchSecret, joinSecret, spectateSecret, instance);
+ }
+
+ @Override
+ protected List getFieldOrder()
+ {
+ return FIELD_ORDER;
+ }
+}
diff --git a/src/main/java/club/minnced/discord/rpc/DiscordUser.java b/src/main/java/club/minnced/discord/rpc/DiscordUser.java
new file mode 100644
index 00000000..7ebd572d
--- /dev/null
+++ b/src/main/java/club/minnced/discord/rpc/DiscordUser.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 - 2019 Florian Spieß and the java-discord-rpc contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package club.minnced.discord.rpc;
+
+import com.sun.jna.Structure;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/*
+typedef struct DiscordUser {
+ const char* userId;
+ const char* username;
+ const char* discriminator;
+ const char* avatar;
+} DiscordUser;
+ */
+
+/**
+ * Struct binding for a discord join request.
+ */
+public class DiscordUser extends Structure
+{
+ private static final List FIELD_ORDER = Collections.unmodifiableList(Arrays.asList(
+ "userId",
+ "username",
+ "discriminator",
+ "avatar"
+ ));
+
+ public DiscordUser(String encoding) {
+ super();
+ setStringEncoding(encoding);
+ }
+
+ public DiscordUser() {
+ this("UTF-8");
+ }
+
+ /**
+ * The userId for the user that requests to join
+ */
+ public String userId;
+
+ /**
+ * The username of the user that requests to join
+ */
+ public String username;
+
+ /**
+ * The discriminator of the user that requests to join
+ */
+ public String discriminator;
+
+ /**
+ * The avatar of the user that requests to join
+ */
+ public String avatar;
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ if (!(o instanceof DiscordUser))
+ return false;
+ DiscordUser that = (DiscordUser) o;
+ return Objects.equals(userId, that.userId)
+ && Objects.equals(username, that.username)
+ && Objects.equals(discriminator, that.discriminator)
+ && Objects.equals(avatar, that.avatar);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(userId, username, discriminator, avatar);
+ }
+
+ @Override
+ protected List getFieldOrder()
+ {
+ return FIELD_ORDER;
+ }
+}
diff --git a/src/main/java/club/minnced/discord/rpc/package-info.java b/src/main/java/club/minnced/discord/rpc/package-info.java
new file mode 100644
index 00000000..c77e41b7
--- /dev/null
+++ b/src/main/java/club/minnced/discord/rpc/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 - 2019 Florian Spieß and the java-discord-rpc contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Java bindings for the official Discord RPC SDK.
+ */
+package club.minnced.discord.rpc;
diff --git a/src/main/java/me/sdashb/kamiblue/DiscordKBlueRPC.java b/src/main/java/me/sdashb/kamiblue/DiscordKBlueRPC.java
new file mode 100644
index 00000000..dde1528d
--- /dev/null
+++ b/src/main/java/me/sdashb/kamiblue/DiscordKBlueRPC.java
@@ -0,0 +1,157 @@
+package me.sdashb.kamiblue;
+
+import me.zeroeightsix.kami.module.Module;
+import me.zeroeightsix.kami.module.ModuleManager;
+import me.zeroeightsix.kami.setting.Setting;
+import me.zeroeightsix.kami.setting.Settings;
+
+// discord imports
+import club.minnced.discord.rpc.*;
+import com.google.common.hash.Hashing;
+import net.minecraft.client.multiplayer.ServerData;
+import net.minecraftforge.fml.common.FMLLog;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Random;
+
+/**
+ * @author cookiedragon234
+ * Updated by S-B99 on 28/10/19
+ */
+@Module.Info(name = "DiscordRPC", category = Module.Category.MISC, description = "Discord Rich Presence")
+public class DiscordKBlueRPC extends Module {
+
+ //1//protected void onEnable() {
+ //1//
+ //1// if (isDisabled()) {
+ //1// this.disable();
+ //1// return;
+ //1// }
+ //1//}
+
+ private static final String APP_ID = "638403216278683661";
+ private static final DiscordKBlueRPC rpc = DiscordKBlueRPC.INSTANCE;
+
+ private static DiscordRichPresence presence = new DiscordRichPresence();
+
+ private static boolean hasStarted = false;
+
+ public static boolean start()
+ {
+ FMLLog.log.info("Starting Discord RPC");
+
+ if(hasStarted) return false;
+
+ hasStarted = true;
+
+ DiscordEventHandlers handlers = new DiscordEventHandlers();
+
+ handlers.disconnected = (int var1, String var2) ->
+ {
+ System.out.println("Discord RPC disconnected, var1: " + String.valueOf(var1) + ", var2: " + var2);
+ };
+
+ rpc.Discord_Initialize(APP_ID, handlers, true, "");
+
+ presence.startTimestamp = System.currentTimeMillis() / 1000;
+ presence.details = "Main Menu";
+ presence.state = "discord.gg/ncQkFKU";
+ //presence.smallImageKey = "backdoored_logo";
+ presence.largeImageKey = "backdoored_logo";
+ //presence.spectateSecret = String.valueOf(new Random().nextInt((9000000 - 100000) + 1) + 100000);
+ //presence.joinSecret = String.valueOf(new Random().nextInt((9000000 - 100000) + 1) + 100000);
+
+ rpc.Discord_UpdatePresence(presence);
+
+ new Thread(() ->
+ {
+ while(!Thread.currentThread().isInterrupted())
+ {
+
+ try
+ {
+ // Run callbacks
+ rpc.Discord_RunCallbacks();
+
+ String details = "";
+ String state = "";
+ int players = 0;
+ int maxPlayers = 0;
+
+ // If we're in singleplayer
+ if (Globals.mc.isIntegratedServerRunning())
+ {
+ details = "Singleplayer";
+ }
+ else
+ {
+ if (Globals.mc.getCurrentServerData() != null)
+ {
+ ServerData svr = Globals.mc.getCurrentServerData();
+ if (!svr.serverIP.equals(""))
+ {
+ // If we're on multiplayer
+ details = "Multiplayer";
+ state = svr.serverIP;
+ if(svr.populationInfo != null)
+ {
+ String[] popInfo = svr.populationInfo.split("/");
+ if(popInfo.length > 2)
+ {
+ players = Integer.valueOf(popInfo[0]);
+ maxPlayers = Integer.valueOf(popInfo[1]);
+ }
+ }
+
+ if(state.contains("2b2t.org"))
+ {
+ try
+ {
+ if(Backdoored.lastChat.startsWith("Position in queue: "))
+ {
+ state = state + " " + Integer.parseInt(Backdoored.lastChat.substring(19)) + " in queue";
+ }
+ } catch(Throwable e){ e.printStackTrace(); }
+ }
+ }
+ }
+ // If we're in the main menu
+ else
+ {
+ details = "Main Menu";
+ state = "discord.gg/ncQkFKU";
+ }
+ }
+
+ if(!details.equals(presence.details) || !state.equals(presence.state))
+ {
+ presence.startTimestamp = System.currentTimeMillis() / 1000;
+ }
+
+ presence.details = details;
+ presence.state = state;
+ //presence.partySize = players;
+ //presence.partyMax = maxPlayers;
+
+ /*if(players > 0)
+ {
+ presence.partyId = String.valueOf(new Random().nextInt((9000000 - 100000) + 1) + 100000);
+ }*/
+
+ rpc.Discord_UpdatePresence(presence);
+ } catch(Exception e){e.printStackTrace();}
+
+ try
+ {
+ Thread.sleep(5000);
+ }
+ catch(InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }, "Discord-RPC-Callback-Handler").start();
+ FMLLog.log.info("Discord RPC initialised succesfully");
+ return true;
+ }
+}
diff --git a/src/main/java/me/sdashb/kamiblue/DiscordRPC.java b/src/main/java/me/sdashb/kamiblue/DiscordRPC.java
deleted file mode 100644
index 276b292b..00000000
--- a/src/main/java/me/sdashb/kamiblue/DiscordRPC.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package me.sdashb.kamiblue;
-
-import me.zeroeightsix.kami.module.Module;
-import me.zeroeightsix.kami.setting.Setting;
-import me.zeroeightsix.kami.setting.Settings;
-
-//import club.minnced.discord.rpc.*;
-
-/**
- * @author 086
- * Updated by S-B99 on 27/10/19
- */
-@Module.Info(name = "DiscordRPC", category = Module.Category.PLAYER, description = "Discord Rich Presence")
-public class DiscordRPC extends Module {
-
-}
\ No newline at end of file